The ato language

SkillAI & models

Lets your agent write and review .ato files, a language for describing electronic circuits declaratively.

Available today. Use it from your connected AI after setup.

Connect ahel once, and every AI you use reads what you have installed.

Then ask your AI: use the The ato language skill

About this capability

Reference for the `.ato` declarative DSL: type system, connection semantics, constraint model, and standard library. Use when authoring or reviewing `.ato` code.

What this skill tells your AI

The instructions your AI receives, as published by atopile/atopile in .claude/skills/ato-language/SKILL.md and read by ahel’s review.

ato is a declarative, constraint-based DSL for describing electronic circuits. There is no control flow, no mutation, and no execution order — you declare what a circuit is, and the compiler + solver resolve it into a valid design.

Quick Start

A minimal complete .ato file:

#pragma experiment("BRIDGE_CONNECT")

import Resistor
import ElectricPower
import Capacitor

module PowerFilter:
    """A simple decoupled power input with a pull-down resistor."""
    power = new ElectricPower
    decoupling_capacitor = new Capacitor
    pulldown_resistor = new Resistor

    power.hv ~> decoupling_capacitor ~> power.lv
    power.hv ~> pulldown_resistor ~> power.lv

    decoupling_capacitor.capacitance = 100nF +/- 20%
    pulldown_resistor.resistance = 100kohm +/- 5%
    assert power.voltage within 3.0V to 3.6V

Validate with ato build from the package directory.

Core Concepts

1. Everything is a Node in a Graph

Every entity (a resistor, a power rail, an I2C bus, a voltage parameter) is a node in a typed graph. Nodes relate to each other through edges: composition (parent–child), connection (same-net), and traits (behavioral metadata). The .ato language is a surface syntax for constructing this graph declaratively.

2. Three Block Types

ato has exactly three ways to define a new type:

KeywordSemanticsTypical Use
moduleA design unit that contains children and connectionsCircuit blocks, subsystems
interfaceA connectable boundary; can be wired with ~Buses, power rails, signals
componentA physical part with footprint/symbolVendor ICs, connectors

All three compile to graph nodes. The distinction controls which traits the compiler attaches (is_module, is_interface) and what operations are legal (by convention, interfaces appear on both sides of ~).

Inheritance uses from:

module MyRegulator from Regulator:
    pass

3. Composition — Children and Instantiation

Types contain children. Inside a block body, new instantiates a child:

module Board:
    power = new ElectricPower      # interface child
    sensor = new BME280            # module child
    caps = new Capacitor[4]        # array of 4 capacitors

Children are accessed via dot-notation: sensor.power.voltage, caps[0].capacitance.

4. Connection — Declaring Electrical Identity

The wire operator ~ declares that two interfaces are the same net/bus. It is bidirectional and requires matching types:

power_3v3 ~ sensor.power          # ElectricPower ~ ElectricPower
i2c_bus ~ sensor.i2c              # I2C ~ I2C

The bridge operator ~> (requires #pragma experiment("BRIDGE_CONNECT")) inserts a component in series. The component must carry the can_bridge trait which defines its in/out mapping:

power_5v ~> regulator ~> power_3v3
i2c.scl.line ~> pullup ~> power.hv

5. Constraints — Physical Quantities and Assertions

Values in ato carry units and tolerances. The solver uses these to select real parts.

Assignment binds a value to a parameter:

power.voltage = 3.3V +/- 5%
resistor.resistance = 10kohm +/- 10%
i2c.frequency = 400kHz
i2c.address = 0x48

Assertions declare constraints the solver must satisfy:

assert power.voltage within 3.0V to 3.6V
assert i2c.frequency <= 400kHz
assert sensor.i2c.address is 0x50

Three value forms exist:

  • Exact: 3.3V
  • Bilateral tolerance: 10kohm +/- 5%
  • Bounded range: 3.0V to 3.6V

6. Traits — Behavioral Metadata

Traits attach capabilities or metadata to nodes. They are not children — they use trait edges in the graph.

#pragma experiment("TRAITS")

import has_part_removed
import is_atomic_part

module Placeholder:
    trait has_part_removed          # mark as non-physical placeholder
    trait is_atomic_part            # user-defined part with footprint

Key built-in traits:

TraitEffect
can_bridgeEnables use with ~> operator (defines in/out pin mapping)
has_part_removedNo physical part placed (symbolic node)
is_atomic_partUser-defined part with manufacturer, partnumber, footprint
has_datasheetAttaches a datasheet reference
has_designator_prefixSets PCB designator (R, C, U, etc.)

7. Import System

Bare imports resolve to standard library types (1 line per import):

import ElectricPower
import I2C
import Resistor

Path imports resolve to types defined in other .ato files (1 line per import):

from "atopile/vendor-part/vendor-part.ato" import Vendor_Part

8. Pragma Feature Flags

Experimental syntax is gated behind pragmas (file top, before imports):

#pragma experiment("BRIDGE_CONNECT")     # ~> operator
#pragma experiment("FOR_LOOP")           # for loops
#pragma experiment("TRAITS")             # trait keyword
#pragma experiment("MODULE_TEMPLATING")  # new Foo<p=v>
#pragma experiment("INSTANCE_TRAITS")    # traits on instances

Using gated syntax without the pragma is a compile error.

Statement Reference

Every statement inside a block body is one of:

StatementSyntaxPurpose
assignname = value or name = new TypeBind a value or instantiate a child
connecta ~ bWire two interfaces together
bridgea ~> b ~> cInsert bridgeable components in series
assertassert expr <op> exprDeclare a constraint
retypename -> NewTypeReplace an inherited child's type
pinpin VCCDeclare a physical pin
signalsignal resetDeclare an electrical signal
traittrait TraitNameAttach a trait
importimport TypeImport a type
forfor x in arr:Iterate over an array (pragma-gated)
string"""..."""Documentation string
passpassEmpty placeholder

Statements within a block are order-independent — the compiler resolves the full graph, not a sequence of operations.

Type System

Interfaces (connectable with ~ or ~>)

TypeChildren / ParametersPurpose
Electrical(single node)Raw electrical connection point
ElectricPower.hv, .lv (Electrical); .voltage, .max_currentPower rails
ElectricLogic.line (Electrical), .reference (ElectricPower)Digital signals with voltage context
ElectricSignal.line (Electrical), .reference (ElectricPower)Analog signals
I2C.scl, .sda (ElectricLogic); .frequency, .addressI2C bus
SPI.sclk, .mosi, .miso (ElectricLogic); .frequencySPI bus
UART / UART_Base.tx, .rx (ElectricLogic); flow control linesSerial
I2Saudio data bus linesDigital audio
DifferentialPair.p, .nDifferential signals
USB2_0 / USB3 / USB2_0_IFUSB data + powerUSB interfaces
CAN_TTLCAN bus linesCAN bus
SWD / JTAGdebug linesDebug interfaces
Ethernet / HDMI / RS232 / PDM / XtalIF / MultiSPIprotocol-specificOther protocols

Modules (instantiable with new)

TypeChildren / ParametersDesignator
Resistor.unnamed[0..1]; .resistance, .max_powerR
Capacitor.unnamed[0..1], .power; .capacitance, .max_voltage, .temperature_coefficientC
CapacitorPolarizedpolarized variant of CapacitorC
Inductor.unnamed[0..1]; .inductanceL
Fuse.unnamed[0..1]; .trip_current, .fuse_typeF
Diode.anode, .cathode; .forward_voltage, .currentD
LED.diode; .brightness, .colorD
MOSFET.source, .gate, .drain; .channel_type, .gate_source_threshold_voltageQ
BJT.emitter, .base, .collector; .doping_typeQ
Regulator / AdjustableRegulator.power_in, .power_out
Crystal.unnamed[0..1], .gnd; .frequency, .load_capacitanceXTAL
Crystal_Oscillatoroscillator module
ResistorVoltageDividervoltage divider circuit
FilterElectricalRCRC filter
Net.part_of (Electrical)
TestPoint.contact; .pad_size, .pad_typeTP
MountingHole / NetTiemechanical
SPIFlashSPI flash memory

Traits (attachable with trait)

has_part_removed, is_atomic_part, can_bridge, can_bridge_by_name, has_datasheet, has_designator_prefix, has_doc_string, has_net_name_affix, has_net_name_suggestion, has_package_requirements, has_single_electric_reference, is_auto_generated, requires_external_usage

Units and Literals

SI-prefixed units: V, mV | A, mA | ohm, kohm, Mohm | F, uF, nF, pF | Hz, kHz, MHz, GHz | s, ms | W, mW

Number formats: decimal (3.3), scientific (1e-6), hex (0x48), binary (0b1010), underscore-separated (1_000_000)

Booleans: True, False

Invariants

  1. Type-safe connections: ~ and ~> should connect matching interface types. ElectricPower ~ I2C is a type mismatch (enforcement is being strengthened).
  2. Pragma gates syntax: using ~>, for, trait, or <> without the matching pragma is a compile error.
  3. Tolerances on passives: resistance = 10kohm (zero tolerance) matches no real parts. Always use +/- N%.
  4. ElectricLogic needs a reference: logic signals require a power reference for voltage context. Set signal.reference ~ power_rail.
  5. Order independence: statements within a block are not sequentially executed. The solver resolves the full graph.
  6. No procedural logic: no if, while, return, functions, classes, or exceptions.

Signals

GitHub stars
4k
Forks
234
Last commit
Jun 2026
Advanced
Catalog kind
skill
Gateway key
ato-language
Source
github.com/atopile/atopile