AI & vibecoding
Code-Native EDA: A Practical Guide to Circuit Boards as Code
Code-native EDA expresses circuits and constraints in text for Git, reuse, testing, and CI. Learn how SKiDL, atopile, tscircuit, and KiCad fit.
Published Updated
Code-native EDA makes intent text-addressable
Traditional EDA stores design data in structured files but expects engineers to work primarily through a graphical editor. Code-native EDA moves more of the circuit, parameters, hierarchy, constraints, and generation logic into text written with programming-language concepts.
That enables familiar software practices:
- meaningful Git diffs and code review;
- reusable, parameterized modules;
- package/version management;
- assertions and generated variants;
- scripted builds in a clean environment;
- automated ERC, DRC, BOM, and manufacturing output;
- agents that edit named objects rather than screen coordinates.
It does not mean raw search-and-replace inside .kicad_sch or .kicad_pcb. Those are structured formats with identities and invariants. Code-native tools expose an intentional API or language and compile into EDA or manufacturing representations.
Three active approaches in 2026
SKiDL is a Python library for describing components, pins, nets, buses, and hierarchy. It performs electrical checks and can generate KiCad-oriented netlists and schematics. It is useful when Python is already the team’s automation language and schematic connectivity is the main code-generated artifact.
A small SKiDL fragment looks like this:
from skidl import ERC, KICAD9, Net, Part, generate_netlist
vcc = Net("VCC")
gnd = Net("GND")
r1 = Part(
"Device", "R",
value="1k",
footprint="Resistor_SMD:R_0603_1608Metric",
)
led1 = Part(
"Device", "LED",
value="green",
footprint="LED_SMD:LED_0603_1608Metric",
)
vcc += r1[1]
r1[2] += led1[1]
led1[2] += gnd
ERC()
generate_netlist(tool=KICAD9)
This is connectivity, not a complete product. The current-limiting value still needs a voltage/current calculation, exact LED MPN, verified footprint, power context, and physical layout.
atopile provides a declarative electronics language, compiler, reusable modules, value constraints, part selection, and KiCad-native layout integration. Its workflow reaches further toward a compiled board and manufacturing output. The project is evolving quickly, so pin the tool and package versions and treat language/tool upgrades as design changes.
tscircuit uses TypeScript and React-style components to describe schematics and PCBs. Its ecosystem includes browser previews, packages, autorouting, and fabrication exports. It is approachable for teams that already think in TypeScript, JSX, and reusable component registries.
These descriptions are not a ranking. Test the exact library coverage, layout control, output quality, and round-trip behavior needed by your board.
Decide what is source and what is generated
The most important repository decision is ownership. A safe pattern is:
requirements/ reviewed inputs and constraints
circuit-src/ authoritative code-native design
eda-generated/ generated KiCad review/handoff files
layout-owned/ manually maintained physical layout, if applicable
release/ generated, immutable manufacturing bundle
If both code and a generated schematic are editable, they will diverge. Mark generated files, document the regeneration command, and either reject manual edits or define an explicit import path. Physical layout often contains valuable human decisions that a connectivity compiler cannot recreate, so confirm how placement and routing identities survive regeneration.
Review changes at two levels. A source diff should explain changed parameters, parts, and connections; a rendered schematic and PCB diff should expose the resulting geometry. Require both when a compiler update changes generated output without an obvious circuit-source edit.
Commit lockfiles and exact tool versions. A build that chooses new library parts or changes autorouting after an unpinned dependency update is not reproducible, even when the source diff is empty.
Put engineering assertions beside the design
Code makes repetitive invariants easier to express:
assert usb_cc_resistance_ohm == 5100
assert regulator_max_mA >= required_peak_mA * 1.25
assert all(part.mpn for part in fitted_parts)
assert set(bom_refs) == set(position_refs)
The exact API depends on the tool, but the principle is stable: turn review decisions into executable checks. Useful assertions cover required MPN fields, allowed footprints, rail loads, interface voltage compatibility, population variants, test points, and BOM/CPL parity.
Assertions are only as sound as their formulas and data. assert temperature < 85 proves nothing if temperature was never modeled correctly. Keep source references and units beside each non-obvious constraint.
Use KiCad as an independent backend check
When the flow produces KiCad source, run the official CLI outside the generator:
kicad-cli sch erc \
--severity-error --severity-warning \
--exit-code-violations \
-o build/erc.rpt generated/design.kicad_sch
kicad-cli pcb drc \
--schematic-parity \
--severity-error --severity-warning \
--exit-code-violations \
-o build/drc.rpt generated/design.kicad_pcb
The headless KiCad CLI guide covers reproducible automation. The parity flag implements the check described in keeping the schematic and PCB in sync.
Still open the schematic and board. Text diffs are excellent for values and connections but weak at communicating component placement, return-current geometry, copper-zone changes, and mechanical fit. Generate visual diffs or rendered plots for review where possible.
Why code-native EDA pairs well with AI
Models are effective at producing and modifying text with named structures. A code-native module gives an agent a constrained vocabulary, a compiler gives fast feedback, and Git shows exactly what changed. Reusing a reviewed regulator module is safer than asking the model to redraw its application circuit each time.
But compilation is not electrical validation. A model can call the wrong module, provide incorrect parameters, or create a valid circuit description for an unsafe requirement. Protect critical modules with tests and ownership, restrict dependency updates, and require primary-source review for new library content.
The natural-language-to-circuit-board pipeline works best when prose becomes typed requirements and reusable design objects, rather than arbitrary file edits.
When it pays off
Code-native EDA is strongest for product families, repeated channels, configurable variants, generated pin maps, large connector breakouts, automated test fixtures, and teams already comfortable with CI. A one-off analogue board with intensive spatial tuning may gain less from circuit generation, though release automation still helps.
Adopt it first on a bounded module. Compare review time, generated-output quality, regeneration stability, and the effort to make an engineering change. End every flow with the same manufacturing gate used for graphical design. Code improves traceability and reuse; copper still obeys physics rather than types.