Place footprints, autoroute traces, and validate a KiCad PCB. One-shot pipeline with human review at the end.
Generate component placement, autoroute via Freerouting, run DRC, and export review images. Human reviews at the end.
"Update PCB from Schematic" is GUI-only — no CLI or Python API exists for this.
uv run poe inspect-asmThis only needs to happen once per schematic change. After footprints are on the board, this skill handles everything else.
Read the netlist from the PCB to understand which components share signal nets:
python3 -c "
import pcbnew
from collections import defaultdict
board = pcbnew.LoadBoard('cad/cm4_carrier.kicad_pcb')
net_to_refs = defaultdict(set)
for pad in board.GetPads():
net = pad.GetNetname()
ref = pad.GetParentAsString()
if net and net not in ('GND', '+3V3', '+5V', ''):
net_to_refs[net].add(ref)
edges = defaultdict(list)
for net, refs in net_to_refs.items():
refs = sorted(refs)
for i in range(len(refs)):
for j in range(i+1, len(refs)):
edges[(refs[i], refs[j])].append(net)
for (a, b), nets in sorted(edges.items(), key=lambda x: -len(x[1])):
print(f'{a} <-> {b}: {len(nets)} nets: {nets}')
"
Get board size, block definitions (which components belong to which functional group), and board origin from cad/layout_spec.yaml.
Using the connectivity graph + block definitions + footprint courtyard sizes, write cad/pcb_placement.yaml with intelligent positions:
Placement strategy:
courtyard_width/2 + 3mm from board edge minimumCourtyard sizes (mm, from KiCad footprint files):
| Footprint | Width x Height |
|---|---|
| PinHeader_1x02 | 3.5 x 6.1 |
| PinHeader_1x04 | 3.5 x 11.2 |
| PinHeader_1x06 | 3.5 x 16.2 |
| PinHeader_1x08 | 3.5 x 21.3 |
| PinHeader_2x20 | 6.1 x 51.8 |
| Fuse_1812 | 5.9 x 3.9 |
| SOT-23 | 3.9 x 3.4 |
| C_1210 | 4.6 x 3.2 |
| C_0805 | 3.4 x 2.0 |
| C_0402 | 1.8 x 0.9 |
| SOIC-8 | 7.4 x 4.9 |
| R_0805 | 3.4 x 1.9 |
| R_0603 | 3.0 x 1.5 |
| QFN-20 | 5.2 x 5.2 |
| USB_Micro-B | 9.4 x 6.5 |
Format:
# AUTO-GENERATED by /layout-pcb skill
# Manual tweaks preserved until file is deleted and recomputed
board_size: [100, 80]
board_origin: [100, 80]