Introducing

Autoroute KiCad boards in minutes, not days.

Connect your agent

Sign in and create an API key on your account page, then save it as $HOME/zap-key.txt and run chmod 600 $HOME/zap-key.txt.

No key yet? Any MCP client: npx -y zap-pcb-mcp routes small boards (up to 300 pads, 2 or 4 copper layers) through the free trial, no sign-up.

terminal, then restart Claude Code
mkdir -p $HOME/zap && cd $HOME/zap && curl -sO https://zap.mutual.solutions/downloads/zap_mcp.py
claude mcp add zap -e ZAP_API_KEY_FILE=$HOME/zap-key.txt -- python3 $HOME/zap/zap_mcp.py
$HOME/.cursor/mcp.json, then restart Cursor
{"mcpServers": {"zap": {"command": "python3",
  "args": ["/absolute/path/to/zap_mcp.py"],
  "env": {"ZAP_API_KEY_FILE": "/absolute/path/to/zap-key.txt"}}}}
$HOME/.codex/config.toml, then restart Codex
[mcp_servers.zap]
command = "python3"
args = ["/absolute/path/to/zap_mcp.py"]
env = { ZAP_API_KEY_FILE = "/absolute/path/to/zap-key.txt" }
terminal (Claude Code), then /mcp to sign in
claude mcp add --transport http zap https://zap.mutual.solutions/mcp
terminal
curl -sO https://zap.mutual.solutions/downloads/zap.py
export ZAP_API_KEY_FILE=$HOME/zap-key.txt
python3 zap.py run myboard.kicad_pcb

Then restart the agent.

Upload a boardAll 25 boards
FTDI JTAG programmer
Lower is better

1 CPU core each, up to 60 minutes per board.

Zap!

Time
20 s
Unrouted
0
Errors
1

TraceMaker

Time
72 s
Unrouted
0
Errors
3

tscircuit

Time
89 s
Unrouted
0
Errors
419

Freerouting

Time
205 s
Unrouted
11
Errors
4

FTDI JTAG programmer by Anthony Bernaert · CERN-OHL-P-2.0 · source

Your rules, in full

Rule types it cannot take · lower is better

Zap!0
TraceMaker1
Freerouting9
tscircuit18
Zap!TraceMakerFreeroutingtscircuit
Track and via spacingfullfullapproximatedcannot be given
Net-class widths and via sizesfullfullfullapproximated
Differential pairs: coupling and lengthfullfullcannot be givenapproximated
Copper poursfullcannot be givencannot be givencannot be given
Keep-out areasfullfullapproximatedapproximated
Custom rules (.kicad_dru)fullfullcannot be givencannot be given

fullapproximatedcannot be given

All rule types

tscircuit: 18 rule types

rule typeboards
Rounded, oval and chamfered pads are given as rectangles of the pad size, corners filled in (the input format has no rounded shape; tscircuit's own KiCad import does the same)25
No track-to-track or via-to-via spacing rule; the pad spacing is used instead, and some solver stages use a fixed 0.1 mm25
No copper pours: power and ground are routed as tracks25
One track width per connection: no width ranges, neck-downs or length tuning25
No length-matching limits for differential pairs17
Differential pairs that reach more than two pads are routed as ordinary nets12
Keep-out areas that only forbid pours or parts are ignored (it makes no pours)12
Custom-shape pads are covered by rectangles that follow the pad outline (exact where its edges are straight and square)7
Spacing overrides on single pads or parts are dropped5
Odd-shaped copper inside parts is covered by rectangles that follow its outline5
One spacing for every net class (the default class)3
The board's custom design rules (.kicad_dru) cannot be expressed2
Odd-shaped keep-out areas are covered by rectangles that follow their outline2
Internal cut-outs are blocked on every layer2
Via-only keep-outs are left out (vias placed there count as errors)2
One via size for every net class (the default class)1
Track-only keep-outs also block vias (stricter than the board)1
Odd-shaped board cut-outs are covered by rectangles that follow their outline1

Freerouting: 9 rule types

rule typeboards
No hole clearance rule (KiCad's minimum hole clearance; Freerouting used 0)25
No minimum hole-to-hole distance25
No copper pours: power and ground are routed as tracks25
No length or skew rules (net-class or custom)25
Differential pairs: no coupling, gap, uncoupled-length or skew rule; routed as independent nets17
Keep-out areas that only forbid pours or parts were removed so tracks may pass, as KiCad allows11
Copper-to-edge spacing above 0.25 mm not passed on (Freerouting used 0.25 mm)10
The board's custom design rules (.kicad_dru) are not exported2
Track-only keep-outs also block vias (stricter than the board)1

TraceMaker: 1 rule type

rule typeboards
No copper pours: power and ground are routed as tracks25

TraceMaker reported no other board rule it could not evaluate on the 25 public boards; it writes no copper pours.

Zap! reads KiCad net classes and custom rules itself and refuses a job whose rules it cannot read; it refused none of the 25 boards.

Every measure

Unrouted connections

total over 25 boards · lower is better

Zap! 60 minutes124
Exact numbers
25 boardsFully connectedboards ↑Unroutedconnections ↓Shortscount ↓Rule errorscount ↓Secondsmedian, all boards ↓Longestseconds ↓Timed outboards ↓Connected, no errorsboards ↑Manufacturing findingsJLCPCB limits ↓
Zap!141960187184937061,181
Zap!, 60 minutesoption minutes: 60151240166427timed out1061,214
TraceMaker78080439timed out (14 of 25)timed out1432,202
tscircuit60-minute limit104,8641,0818,617130timed out105,100
Freerouting112,07342,318529timed out522,376
Human designs250082–––133,235
Variants
Zap! previous buildserved until 2026-10-1310230020042770056,009
TraceMakerwithout pairs first71,1430370601605022,067
tscircuit10-minute limit105,8856486,693142694003,452

Manufacturing findings: Zap!'s check against JLCPCB standard limits.

Boards from the other routers' own projects

KiCad default rules (no rules file in their repositories).

boardrouted byUnrouted↓Shorts↓Rule errors↓Seconds↓
KiCad demo: PIC programmerZap! (earlier run)00021
TraceMaker (earlier 10-minute run)400108
tscircuit (10 min)0207219
Published (human-routed)000–
KiCad demo: videoZap! (earlier run)23100699
TraceMaker (earlier 10-minute run)24800601
tscircuit (10 min)1,45800603
Published (human-routed)000–
TraceMaker test board (plane + SMD)Zap! (earlier run)1001
TraceMaker (earlier 10-minute run)100267
tscircuit (10 min)049262231
Published (published unrouted)4700–
tscircuit Core1106 carrierZap! (earlier run)00146
TraceMaker (earlier 10-minute run)501601
tscircuit (10 min)02464100
Published (routed by tscircuit's own pipeline)001,452–
tscircuit RP2040 LiPo chargerZap! (earlier run)20067
TraceMaker (earlier 10-minute run)406601
tscircuit (10 min)0525849
Published (routed by tscircuit's own pipeline)05510–
Method
  • Measured 12–14 Oct 2026.
  • Boards: 25 public KiCad projects, open licence, human-routed. Placement kept; tracks, vias and pours removed; the board's own net classes and rules.
  • TraceMaker and Freerouting: 1 CPU core, up to 60 min per board, no GPU; TraceMaker used up to 25 GB, more than Zap!'s 14 GB; Freerouting's Java memory capped at 12 GB.
  • tscircuit: 1 CPU core, up to 60 min per board; it checks its limit only between solver steps, so a run still inside one step was stopped at 75 min. Zap! stops after a fixed amount of work on 1 CPU core: 3.1 min median, 16 min longest.
  • Zap!: router build re92d124, the build zap.mutual.solutions runs now; the same machines and session as the others, 1 CPU core, single run (the service default). One board, the Antmicro ECP5 DC-SCM, can't yet be routed on zap.mutual.solutions: the service runs several routing attempts at once, and on this board together they need more than its 14 GB job limit.
  • Zap!, 60 minutes: the upload option minutes: 60, in the same session on 1 CPU core per board; 10 of 25 boards used the full 60 minutes. The hosted service runs up to 6 of its attempts at once.
  • Check: KiCad 10.0.6 design-rule check after refilling pours, each board's rules; at most 199 findings of one kind per board (499 for spacing).
  • Fully connected: every pad that should be joined is joined.
  • Time: for each router, the median seconds on the boards that both it and Zap! fully connected within 3,600 s, beside Zap!'s median on those same boards; the board view lists every board's time.
  • Timed out: a run over 3,600 s; its time reads timed out, its other numbers are scored from the board it left.
  • Unrouted: pad pairs that should be joined but are not (KiCad's count).
  • Short: copper of two nets touching.
  • Errors: design-rule errors, shorts included; 74 per router come from the placement.
  • Time: start to finished board file.
  • Colour: Zap! cyan, others grey; board view log10(1 + value) against the column's largest value.
  • Race: FTDI JTAG programmer, a dense board where every router finished; shown as one of the 25.
  • Race, Zap!: copper per net in the order of a traced re-run, byte-identical to the measured run, its times scaled to the measured run; final shapes.
  • Race, others: TraceMaker, tscircuit, Freerouting: in-between states recorded from runs of the same versions and settings, final board identical to the benchmark, times scaled to the benchmark run.
  • Race clock: 6 times real time until Zap! finishes, then moved by scrolling. Unrouted starts at KiCad's count on the unrouted board (260). Number colours: best of the four cyan, worst coral, log scale.

Versions and settings

Zap!Zap! router build re92d124.57335f59, the build zap.mutual.solutions runs now; boards routed 2026-10-14the same machines and session as the others, 1 CPU core per board, single run (the service default); no clock: stops after a fixed amount of work (3.1 min median, 16 min longest here); makes its own copper pours
Zap!, 60 minutesoption minutes: 60Zap! router build re92d124.57335f59, the build zap.mutual.solutions runs now; boards routed 2026-10-14the same machines and session as the others, 1 CPU core per board: the single run, then more attempts one after another (twice and four times the work, then other router settings) until one has every connection and no short, or 60 minutes pass; keeps the best
TraceMakerTraceMaker v0.9.0-116-g49fbd3c (main branch, commit 49fbd3c of 2026-10-14, the latest public version when run), built CPU-only with GCC 14.2; boards routed 2026-10-14--time 3600 --threads 1 --no-kb --diff-pairs --keep-vias-off-pads --vias-off-pads-below 1000; 1 CPU core per board, no GPU
tscircuit60-minute limit@tscircuit/capacity-autorouter 0.0.973 (AutoroutingPipelineSolver9_PreloadedTraceGraph) on Node.js v24.21.0, through this page's runner from the corrected input conversion; boards routed 2026-10-14 (UTC)effort 1 (tscircuit's default); 1 CPU core per board; solver limit 3,600 s (60 minutes, the Zap! service's job limit), stopped at 75 minutes at the latest; a board stopped at the limit has no routing, since tscircuit returns routing only after its last stage
FreeroutingFreerouting 2.5.0 (latest stable release, published 2026-10-05; tag v2.5.0, build revision b647a2f824cfbc54bc4dcaee71b03b7cd945eb76 from the jar manifest), routed through the Specctra DSN and SES files that KiCad's Freerouting plugin uses (exported and imported with KiCad 10.0.6); boards routed 2026-10-141 CPU core, 60-minute job limit, 12 GB Java memory cap, its own defaults otherwise
Zap! previous buildserved until 2026-10-13Zap! router build r009e659.8f766f9f, served until service release 2026.10.13.29 on 2026-10-13; boards routed 2026-10-12same settings as the served build
TraceMakerwithout pairs firstTraceMaker v0.9.0-90-gc6fcb7b (an earlier build, commit of 2026-10-11); boards routed 2026-10-13--time 600 --threads 1, without --diff-pairs (TraceMaker's own default pair handling)
tscircuit10-minute limit@tscircuit/capacity-autorouter 0.0.973 (AutoroutingPipelineSolver9_PreloadedTraceGraph) on Node.js v24.21.0; boards routed 2026-10-13 (UTC) from the corrected input conversioneffort 1 (tscircuit's default); solver stopped at 600 s. tscircuit routes in stages and returns routing only after its last stage, so a board stopped at the limit has no routing at all: it never returns a partial result

Where tscircuit wrote no routing

causeboards
Error: its pre-check reported a connection as impossible, but the designers' own route for it fits the converted board2
Limit: a fixed step limit inside one solver stage (it ran out of iterations)1
Error after 1442 s: repair04 merge rejected a new via in the boundary collar1
Killed at the 75-minute backstop, past its 60-minute time limit, while still inside one solver step; no routing written1

On tscircuit's own benchmark

problem setProblemsZap!verified %tscircuitverified %Zap!solver says %tscircuitsolver says %
dataset0185100.0100.0100.0100.0
srj1815100.086.7100.0100.0
srj1920071.092.071.093.5
srj2020051.579.051.579.0
srj2110100.0100.0100.0100.0
srj2376100.097.486.898.7

Run 2026-10-13. tscircuit's checker for both; verified = every requested connection complete. Zap!: build 009e659 (served until 2026-10-13), JLC minimum via (0.4 mm; the problems use 0.3 mm). tscircuit: @tscircuit/capacity-autorouter 0.0.976 at 1256328 (commit of 2026-10-12), MIT licence. srj18 without one problem that overlaps our held-out boards.

Reproduce

# TraceMaker 49fbd3c, CPU-only build, on 1 CPU core
tracemaker route in.kicad_pcb -o routed.kicad_pcb --time 3600 --threads 1 --no-kb --diff-pairs \
    --keep-vias-off-pads --vias-off-pads-below 1000

# Freerouting 2.5.0 on 1 CPU core, on the DSN that KiCad exports
java -Xmx12g -Xms256m -jar \
  freerouting-2.5.0.jar -de in.dsn -do \
  out.ses --gui.enabled=false --api_server.enabled=false --profile.allow_telemetry=false \
  --usage_and_diagnostic_data.disable_analytics=true --router.max_threads=1 --router.job_timeout=01:00:00 --router.result_json=result.json

# tscircuit: @tscircuit/capacity-autorouter 0.0.973 on 1 CPU core through this page's runner,
# effort 1, 60-minute limit, stopped at 75 minutes at the latest

# Zap! through the service (API key: sign in at /auth/login and create one on your account page)
python3 zap.py run in.kicad_pcb

# check any result
kicad-cli pcb drc --refill-zones --severity-all --format json -o drc.json routed.kicad_pcb

Data: compare.json, written 2026-10-14 15:17:52 UTC. Questions or a board to add: hello@mutual.solutions.

Boards and licences
boardbylicencesource
Antmicro CM4 baseboard LVDS adapterAntmicroApache-2.04af945e
Antmicro CVBS-to-MIPI bridgeAntmicroApache-2.07cbcec2
Antmicro dual IPEX CSI interposerAntmicroApache-2.06b6bd0a
Antmicro ECP5 DC-SCMAntmicroApache-2.00019313
Antmicro GMSL serializerAntmicroApache-2.058641df
Antmicro PMOD I3C sensor boardAntmicroApache-2.05ee5d34
Antmicro signal-integrity test boardAntmicroApache-2.0de0b592
Antmicro STM32H7 HDMI SO-DIMM boardAntmicroApache-2.027e3ac9
Arduino water-level monitorSrushti DMIT7b47f46
Argos demo boardCNESCERN-OHL-S-2.01eccb3f
Bitaxe Ultra (fork)BastelPichi, fork of skot/bitaxeCERN-OHL-S-2.00c3e71f
Buildbotics controllerBuildbotics LLCCERN-OHL-S-2.01a2f36d
discretesim test boardcnlohrMITf7a169e
ECP5 BGA-381 FT2232HQ FIFO boardgildobjanschiMIT81403f7
EmberOne256 FoundationCERN-OHL-S-2.0b21b32c
Ender-3 load-cell bed-levelling sensorLakshminarayananMITeae5c6f
FTDI JTAG programmerAnthony BernaertCERN-OHL-P-2.0c33005e
HackRF ProGreat Scott GadgetsCERN-OHL-P-2.0359b98f
Kintex PCIe boardPiotr BinkowskiApache-2.0056792c
RP2040 development boardaconMITd943286
RP2350-PICO2-BB48Olimex LtdMIT74b0303
SevenID8 Engineering ABCERN-OHL-P-2.07c69a14
Tiliqua (apfaudio)Sebastian HolzapfelCERN-OHL-S-2.04ee5878
Trellis CoreProtolux Electronics SARL-SCERN-OHL-P-2.0db4fe71
XerxesRapid AnalysisApache-2.043abf57

No routing images for CERN-OHL-S boards (the licence asks that modified designs be shared in full). Licences checked 2026-10-13.

Connect your agent