Headless Flux.ai-style EDA engine
  • Rust 95.8%
  • Python 3.4%
  • HTML 0.4%
  • Shell 0.3%
  • Dockerfile 0.1%
Find a file
hermes-lxc 76df799ed9
All checks were successful
CI / referee-sim (push) Successful in 1m14s
CI / test (push) Successful in 1m18s
CI / referee-kicad (push) Successful in 5m13s
fix(engine): square-aware keepout stamping + exact pad geometry in DRC
Router stamped keepouts against cell centres only, letting diagonal moves
cut corners through foreign-pad keepouts; cells are now blocked when the
keepout reaches anywhere into the cell square, and foreign copper is
stamped with per-net-pair class_clearance. DRC track/via-pad checks use
the exact rotated-rect pad shape instead of a max-half-extent circle,
removing false positives near wide pads' short edges. One-Air-Max:
autoroute-introduced DRC violations 49 -> 0 (baseline 813 -> 501).
Corpus report regenerated: all 20 boards, exit 0, deterministic, referee
ok; new-DRC violations 0 on every routable board except RoyalBlue (1).
2026-10-26 05:26:45 +00:00
.forgejo/workflows fix(kicad): user layers are not copper; referee refills zones before DRC 2026-10-23 21:26:41 +00:00
benchmarks fix(engine): square-aware keepout stamping + exact pad geometry in DRC 2026-10-26 05:26:45 +00:00
crates fix(engine): square-aware keepout stamping + exact pad geometry in DRC 2026-10-26 05:26:45 +00:00
docs plan: MCP server added to P4 deliverables 2026-10-19 14:12:41 +00:00
fixtures fix(ir): KiCad board-file pad angles are absolute 2026-10-25 12:55:54 +00:00
scripts feat(release): headless container artifact + milestone smoke test 2026-10-25 21:16:57 +00:00
.dockerignore feat(release): headless container artifact + milestone smoke test 2026-10-25 21:16:57 +00:00
.gitignore chore: ignore python bytecode caches 2026-10-22 21:18:33 +00:00
Cargo.lock feat(server): P4 — MCP server, JSON-RPC command surface, NL→plan eval harness 2026-10-21 02:24:58 +00:00
Cargo.toml Phase 1: workspace skeleton (ir/kicad/altium/engine/server/cli), KiCad S-expression round-trip with golden tests, CLI import/export, CI 2026-10-18 15:10:33 +00:00
CHANGELOG.md fix(engine): square-aware keepout stamping + exact pad geometry in DRC 2026-10-26 05:26:45 +00:00
Dockerfile feat(release): headless container artifact + milestone smoke test 2026-10-25 21:16:57 +00:00
LICENSE Phase 1: workspace skeleton (ir/kicad/altium/engine/server/cli), KiCad S-expression round-trip with golden tests, CLI import/export, CI 2026-10-18 15:10:33 +00:00
README.md feat(release): headless container artifact + milestone smoke test 2026-10-25 21:16:57 +00:00
rust-toolchain Phase 1: workspace skeleton (ir/kicad/altium/engine/server/cli), KiCad S-expression round-trip with golden tests, CLI import/export, CI 2026-10-18 15:10:33 +00:00

NodeBound

A headless, AI-native EDA engine in the spirit of Flux.ai — the hard part (constraint engine, routing, DRC, format import/export) without any UI. Everything runs fully headless (CLI/CI) and is tested with golden files and property tests. The reactive engine is IR-first: importers/exporters are IR↔format codecs, which makes multi-format output cheap.

Phase 2 (current)

  • Board IR in ir: footprints (pads with shape/size/layers/net), tracks, vias, zones, stackup (copper layers, thickness), design rules (clearance, min track width, min via annular ring).
  • DRC engine in engine, run headless over the board IR: nodebound drc board.kicad_pcb prints a JSON report (violation type, location, nets) and exits nonzero on violations; --check is silent (exit 0/1) for CI. Checks: pad–pad / track–track / track–pad / via clearance (different nets), unconnected nets, track width below minimum, via annular ring below minimum, silkscreen over pads.
  • KiCad importer upgrades: footprints/pads/tracks/vias/zones/stackup parse into the board IR; the P1 S-expression round-trip is unchanged and still byte-stable.
  • SPICE netlist export: nodebound export-netlist board.kicad_pcb --out circuit.cir emits a ngspice-runnable netlist from board connectivity (each two-terminal footprint stubbed as a resistor, ground-like nets map to node 0); CI runs ngspice -b on it.
  • IPC-2581 export (altium crate): the open-standard XML fallback for Altium interop — nodebound export <in> --out out.xml --format ipc2581. Full .PcbDoc binary writing stays out of scope.
  • Phase 1 capabilities remain: KiCad S-expression round-trip (parse → IR → write, byte-identical from the second write on), CLI import/export.

Build & test

Requires Rust (stable; see rust-toolchain).

cargo build
cargo test --all
cargo clippy --all -- -D warnings
cargo fmt --check

CLI:

cargo run -p nodebound-cli -- import fixtures/golden.kicad_pcb
cargo run -p nodebound-cli -- export fixtures/golden.kicad_pcb --out out.kicad_pcb --format kicad
cargo run -p nodebound-cli -- export fixtures/golden.kicad_pcb --out out.xml --format ipc2581
cargo run -p nodebound-cli -- drc fixtures/golden.kicad_pcb          # JSON report
cargo run -p nodebound-cli -- drc fixtures/bad_board.kicad_pcb       # nonzero exit on violations
cargo run -p nodebound-cli -- drc --check fixtures/golden.kicad_pcb  # silent CI mode (0/1)
cargo run -p nodebound-cli -- export-netlist fixtures/golden.kicad_pcb --out circuit.cir
ngspice -b circuit.cir

# Controlled impedance -> KiCad net classes (project file):
# 50 ohm on the default FR-4 stackup stamps Power's track width;
# 90 ohm differential stamps USB's diff-pair width + gap.
cargo run -p nodebound-cli -- export-project fixtures/golden.kicad_pcb \
  --out out.kicad_pro --set Power=50 --set-diff USB=90
python3 scripts/referee/proj_load_check.py out.kicad_pcb ...  # pcbnew referee (needs an adjacent board)

# Web client (read-only by default): http://127.0.0.1:2581
cargo run -p nodebound-server --bin nodebound-web-server
# POST /rpc speaks the same JSON-RPC 2.0 envelope as the MCP server.

# Container release artifact (headless, no Rust toolchain needed):
docker build -t nodebound .
docker run --rm -v "$PWD:/data" nodebound drc /data/fixtures/golden.kicad_pcb
scripts/container_smoke.sh   # full command surface in one piped script

Layout

Crate Purpose
crates/ir S-expression tree + semantic netlist/board IR
crates/kicad KiCad 7/8 S-expression parser, writer, board extraction
crates/engine Board loading, DRC engine, SPICE netlist export
crates/server Headless JSON-RPC server skeleton
crates/cli The nodebound binary
crates/altium IPC-2581 (XML) exporter — open Altium fallback
fixtures/ Hand-written golden KiCad fixtures

The canonical formatting of the golden fixture is checked against fixtures/golden_canonical.kicad_pcb; regenerate with:

cargo run -p nodebound-kicad --example gen_canonical -- fixtures/golden.kicad_pcb \
  > fixtures/golden_canonical.kicad_pcb

Testing & open-source tooling policy

Headless, open-source-first: we compose mature open-source tools as referees in CI instead of reimplementing their logic.

  • KiCad pcbnew/kicad-cli — independent referee: kicad_load_check.py loads our exports with KiCad's own parser, and kicad-cli pcb drc runs KiCad's DRC on our exported golden board in the CI referee job.
  • ngspice — circuit simulation; netlists are extracted from the IR (nodebound export-netlist) and run in batch mode (ngspice -b) in CI.
  • pcb-rnd / py-altium — read-only references and cross-checks for format work.
  • LVS-style electrical checks compare the netlist extracted from layout against the schematic netlist.

Everything runs headless (no GUI) and deterministically (seeded RNG only).

Roadmap

See flux-clone-plan.md (P2 board semantics + DRC, P3 autorouter, P4 assistant layer, P5 UI).

License

MIT — see LICENSE.