PCB footprint staging & board ops
Engine: $(kx root)/kicad_lib/pcb.py
(python API: PYTHONPATH= or cwd=; CLI: kx is on PATH)
(netlist, load_footprint, stage, edge_cuts_bbox,
empty_board_from). Worked example: tests/test_pcb.py.
Staging flow (Update-PCB adopts, no duplicates)
pcb.netlist(SCH)→comps[ref]["tstamps"]— that uuid IS the link;netsis the connectivity ground truth (assert designed members!). Root-sheet local-label nets are prefixed "/" (/VOUT); power nets (GND, VCC) are not.pcb.load_footprint(mod_path, "Lib:Name")— renames for the board, strips file headers (.kicad_mod has no top-level uuid; instances do).pcb.stage(board, fpdef, ref, value, at, tstamps_uuid, sheetfile)— inserts after the layer clause: uuid, at, path "/", sheetname, sheetfile; sets Reference/Value; refreshes EVERY item uuid. Pads stay netless — the sync fills them.- Stage in a grid CLEAR of the outline:
pcb.edge_cuts_bbox(board). - Gates: save → reparse →
kicad-cli pcb export svgaccepts → render PNG → eyeball → commit.
Notes
pcb.empty_board_from(donor)builds a minimal valid board (header + layer stack + setup + net 0) from any existing .kicad_pcb, read-only.- DRC:
kicad-cli pcb drc --output drc.rpt --severity-all BOARD— set-diff vs baseline exactly like ERC (kicad-review skill). - .kicad_pcb round-trips BYTE-IDENTICAL (validated on a 2.3 MB real board): pcb pts dialect (≤5 points inline, then 4-per-line chunks) + token wrap at column 72 — sexp.dumps sniffs the root tag, or pass dialect="pcb" when serializing subtrees. Hand-edits diff zero-noise.
- Update-PCB direction is sch→pcb only; never edit refs on the board.