Restructures the router so occupancy is tracked per connection, then adds a rip-up-and-retry loop that recovers from bad greedy net orderings. When a connection cannot reach its target through free space, a rip-up search may pass through other nets' traces at an escalating penalty; the router rips up the connections that path crosses (fully removing their occupancy), routes the failing connection, and re-queues the ripped connections. Passes iterate up to max_passes, keeping the best (fewest-unrouted) result and stopping on full success or when a pass changes nothing. Thrash prevention: each connection may be ripped at most rip_cap times, and the rip penalty escalates with a connection's rip count, so repeatedly-ripped connections harden into walls. Fully deterministic (sorted rip sets, connection-creation order, tuple-keyed A* — no RNG). route()/route_dsn_board()/route_board() take rip_up and max_passes; rip_up=False reproduces the previous greedy single-pass behaviour for comparison. RouteResult now reports the unrouted connection count.
freeroute
A native Python PCB autorouter — a Java-free port of the FreeRouting engine.
Why
kicad-mcp currently autoroutes by shelling out to freerouting.jar, which
drags in a JVM dependency. freeroute reimplements the routing engine in
pure Python so the toolchain needs no Java at all.
The contract
The entire integration surface is two Specctra files:
board.dsn ──▶ freeroute ──▶ board.ses
(unrouted) (routed session: traces + vias)
kicad-cli already exports .dsn and imports .ses, so freeroute is a
drop-in replacement for the JAR step — nothing else in the pipeline changes.
Status
Pre-alpha. Under active development. See docs/PORTING_PLAN.md
for the architecture and porting roadmap.
Usage (target)
freeroute board.dsn -o board.ses
Development
uv sync
uv run pytest
uv run ruff check src/ tests/
License
GPL-3.0-or-later, matching the FreeRouting source it is ported from.
Languages
Python
100%