Loading files…
A fast Rust-accelerated A* autorouter for KiCad PCB files. Compatible with KiCad 9 and KiCad 10. Available as both a KiCad Plugin with full GUI and a Command-Line Interface for scripting and automation.
(keepout (tracks not_allowed) (vias not_allowed) ...)), blocking only the disallowed item on the keepout's listed layers (or all routing layers if none are listed). Track/via copper is kept clear of the boundary by the configured clearance, e.g. an antenna-flange RF exclusion--no-fix-polarity to forbid pad swaps (default in the plugin GUI) - the pair is then skipped with a warning if no opposite-side route exists; crossing tracks are never written--schematic-dir is specified, updates KiCad schematic files with any pad swaps (target swaps or polarity swaps) to keep schematics in sync with PCB. Handles multi-unit symbols correctly by updating all schematic files containing the lib_symbol. Disabled by default--bus flag. Configurable detection radius, attraction radius, and attraction bonus. See Bus Routing for detailsUser.1) in KiCad and the selected nets are routed to follow it as waypoints — source → along your drawn path → target — getting as close to the line as obstacles allow. For multi-point nets each waypoint steers the nearest segment of the net's existing MST, so endpoints/topology are untouched. It's strictly best-effort: a waypoint it can't follow on the current layer is skipped (so a guide never makes a route fail or adds vias the direct route wouldn't need), and multiple nets following the same corridor pack alongside without overlapping. Enable with --guide-corridor (CLI) or the "Follow User-layer guide path" checkbox (plugin); configurable layer and waypoint spacing. See Guide Corridor Options for detailsUser.2) in KiCad and routed tracks (and vias) are kept out of those areas on every copper layer. It's a hard keepout that applies across single-ended, multipoint, and differential-pair routing, plus plane via-stitching and plane repair — useful for reserving analog regions, antenna clearances, or mechanical exclusions. Enable with --keepout (route.py / route_diff.py) or the "Keep out of User-layer polygon(s)" checkbox (plugin); configurable layer. (Don't draw a zone over a pad you need to route.)--time-matching to enable. Tolerance specified in picoseconds. See Length Matching for details--power-nets "*GND*" "*VCC*" --power-nets-widths 0.4 0.5). First matching pattern determines width for each net. Obstacle clearances automatically adjust for wider power traces. Power net widths are never smaller than the base track width--neckdown-length (default 2.5mm) of the pads, returning to the power width beyond that wherever clearance allows, with a stepped width taper at each transition (--neckdown-taper-length, default 0.5mm). Disable with --no-power-tap-neckdown/analyze-power-nets skill to identify power nets and recommend track widths. The skill uses WebSearch to look up component datasheets, classifies components by their role (power source, current sink, pass-through, shunt), traces current paths, and generates ready-to-use --power-nets configurations. See Power Net Analysis for details--same-net-pad-clearance >= 0, forces vias outside same-net pads with the given edge-to-edge clearance), then spirals outward with A* routing to pads. Optional blocker rip-up removes interfering nets to maximize via placement, with automatic re-routing of ripped netsroute_disconnected_planes.py script detects disconnected regions and routes wide, short tracks between them to ensure electrical continuity--add-gnd-vias with route_planes.pyroute.py --visualize), with pause/step, zoom/pan, per-layer filtering, and speed control/plan-pcb-routing) that fills the dialog's parameters and executes as a checkable step list in-process on the live board, plus one-click reviews and per-field "Ask Claude" buttons on the Basic/Differential/Planes tabs (power nets, diff pairs, plane mappings, GND via distance, stackup). See Claude Skills - Plugin GUI Integration/find-high-speed-nets skill to identify which nets carry high-speed signals. Looks up component datasheets via WebSearch to find max interface frequencies and rise times, traces signals through series passives, and recommends --gnd-via-distance values based on the fastest signals on the board. See Claude Skills and the GND return via distance guidance in the planes documentation# Clone with git
git clone https://github.com/drandyhaas/KiCadRoutingTools.git
cd KiCadRoutingTools
Or download the ZIP and extract it.
python build_router.py
By default this downloads a prebuilt binary for your OS from the project's GitHub Releases — no Rust toolchain required. Prebuilts are published for:
If a prebuilt isn't available for your platform (e.g. Linux arm64) or the download fails, the script falls back to building locally with cargo.
If you'd rather build locally — or you're on a platform without a prebuilt — install Rust from rustup.rs:
# macOS / Linux
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
# Windows: Download and run rustup-init.exe from https://rustup.rs/
After installation, restart your terminal or run source ~/.cargo/env, then:
python build_router.py --from-source # build locally instead of downloading
python build_router.py --tag v0.15.0 # download a specific release
python build_router.py --clean # remove all build artifacts
Option A: KiCad Plugin (Recommended for interactive use)
# Install the plugin
python install_plugin.py
# Then in KiCad: Tools → External Plugins → KiCadRoutingTools
Option B: Claude Code (AI-assisted routing)
Use Claude Code to analyze your PCB and generate a routing plan:
> /plan-pcb-routing kicad_files/my_board.kicad_pcb
Claude will:
Other useful skills:
> /find-high-speed-nets kicad_files/my_board.kicad_pcb # Identify high-speed nets via datasheet lookup
> /analyze-power-nets kicad_files/my_board.kicad_pcb # Identify power nets and track widths
> /identify-diff-pairs kicad_files/my_board.kicad_pcb # Find diff pairs by pin function, recommend gap/impedance
> /recommend-stackup kicad_files/my_board.kicad_pcb # Stackup advice for impedance/time-matching accuracy
> /diagnose-routing-failures my_board.kicad_pcb /tmp/route_output.txt # Root-cause failed routes, get a retry command
> /review-routed-board my_board_routed.kicad_pcb # Post-route QA: DRC, connectivity, length match, GND vias
See Claude Skills for what each skill does and how they fit together.
All of these are also available inside KiCad without leaving the plugin - see AI assistance in the plugin below.
Option C: Manual Command Line (For scripting and automation)
# Optionally optimize an existing placement for routability (before routing)
python place_optimize.py my_board.kicad_pcb --max-displacement 3
# Route all nets
python route.py my_board.kicad_pcb
# Route differential pairs
python route_diff.py my_board.kicad_pcb --nets "*lvds*"
# Create power planes
python route_planes.py my_board.kicad_pcb --nets GND --plane-layers B.Cu
The plugin provides a full graphical interface for all routing features, running directly within KiCad 9 or 10.
With Claude Code installed, the routing dialog gains AI assistance throughout (the plugin spawns claude headless, streams a live transcript, and fills GUI controls from the results):
/plan-pcb-routing: the plan fills the parameter fields across the tabs and appears as a checkable step list, which Run Selected Steps executes sequentially in-process on the live board with per-step status marks. Review Routed Board and Diagnose Routing Failures give post-route QA and failure root-causing. Model and effort dropdowns control every AI run and persist with the dialog settings.The full button-to-skill map is in Claude Skills - Plugin GUI Integration. Datasheet-based skills use web lookups and take a few minutes; every run shows a live transcript with cancel.
Two ways to install:
A. KiCad Plugin and Content Manager (PCM) — the recommended path for end users. Open the PCM from the KiCad main window, find KiCad Routing Tools, and click Install. (The package is in the process of being added to the official repository; once accepted, this will be available out-of-the-box.) On first launch, the plugin checks the Python packages listed in requirements.txt (currently scipy and shapely — KiCad already bundles numpy) and offers a one-click pip install for any that are missing into KiCad's Python.
B. Manual install from source — for development or for using the CLI tools as well:
# Install the plugin (copies to KiCad plugins directory)
python install_plugin.py
# For development: create symlink instead of copying
python install_plugin.py --symlink
# Remove the plugin
python install_plugin.py --uninstall
The installer automatically detects your KiCad installation directory (supports KiCad 9.0 and 10.0):
~/Documents/KiCad/<version>/3rdparty/plugins/~/.local/share/kicad/<version>/3rdparty/plugins/~/Documents/KiCad/<version>/3rdparty/plugins/If you previously installed this plugin through the Plugin & Content Manager, that copy sits next to the local install and would shadow it on sys.path (causing stale-code errors). The installer detects any such PCM copy and moves it aside to <kicad-base>/disabled_pcm_plugins/<version>/, leaving it recoverable. Pass --keep-pcm to skip this.
The full release flow — version bump, GitHub Release, and the merge request to the official KiCad PCM repository — is documented step by step in docs/release-pipeline.md.
Short version:
VERSION and the versions[] entry in metadata.json.git tag v0.15.6 && git push --tags — CI builds all 4 platform binaries, packages a single KiCadRoutingTools-<ver>.zip (the PCM validator rejects duplicate version strings, so we ship one cross-platform zip), patches metadata.json with real sha256/size values, and attaches everything to the GitHub Release.gitlab.com/kicad/addons/metadata and open an MR. See the docs page for the exact commands.To build a zip locally for testing:
python package_pcm.py --binary-dir ./path/to/release/artifacts
Basic Tab:
User.1) and tick "Follow User-layer guide path" to route the selected nets along it (waypoints, avoiding obstacles, packed non-overlapping)User.2) and tick "Keep out of User-layer polygon(s)" to keep routed tracks out of those areas (hard keepout, all routed nets)Advanced Tab:
Differential Tab:
Fanout Tab:
Planes Tab:
Log Tab:
About Tab:
General Features:
All --nets options support fnmatch-style wildcards and exclusion patterns:
| Pattern | Description |
|---|---|
* | All nets |
*DATA* | Nets containing "DATA" |
/* | Nets starting with "/" (hierarchical) |
Net-(U1-*) | Nets matching "Net-(U1-...)" |
!GND | Exclude net named "GND" |
!*VCC* | Exclude nets containing "VCC" |
"*" "!GND" "!VCC" | All nets except GND and VCC |
Notes:
!) remove matching nets from the result# Route all nets (default) - outputs to input_routed.kicad_pcb
python route.py kicad_files/input.kicad_pcb
# Route all nets, overwrite input file
python route.py kicad_files/input.kicad_pcb --overwrite
# Route all nets to a specific output file
python route.py kicad_files/input.kicad_pcb kicad_files/output.kicad_pcb
# Route specific nets (using --nets option)
python route.py kicad_files/input.kicad_pcb kicad_files/output.kicad_pcb --nets "Net-(U2A-DATA_0)" "Net-(U2A-DATA_1)"
# Route with wildcard patterns
python route.py kicad_files/input.kicad_pcb kicad_files/output.kicad_pcb --nets "Net-(U2A-DATA_*)"
# Route all nets on a component (auto-excludes GND/VCC/VDD/unconnected)
python route.py kicad_files/input.kicad_pcb kicad_files/output.kicad_pcb --component U1
# Route specific patterns on a component (no auto-exclusion)
python route.py kicad_files/input.kicad_pcb kicad_files/output.kicad_pcb --nets "/DDAT*" --component U1
# Route ALL nets on a component including power (use "*" pattern)
python route.py kicad_files/input.kicad_pcb kicad_files/output.kicad_pcb --nets "*" --component U1
# Route all nets except GND and VCC (exclusion patterns with ! prefix)
python route.py kicad_files/input.kicad_pcb kicad_files/output.kicad_pcb --nets "*" "!GND" "!VCC"
# Route differential pairs (use route_diff.py)
python route_diff.py kicad_files/input.kicad_pcb kicad_files/output.kicad_pcb --nets "*lvds*" --no-bga-zones
# Route with wider tracks for power nets
python route.py kicad_files/input.kicad_pcb kicad_files/output.kicad_pcb --nets "Net*" \
--power-nets "*GND*" "*VCC*" "+3.3V" --power-nets-widths 0.4 0.5 0.3 --track-width 0.2
# Typical workflow: create GND plane first, then route all signals
python route_planes.py kicad_files/flat_hierarchy.kicad_pcb --nets GND --plane-layers B.Cu
python route.py kicad_files/flat_hierarchy_routed.kicad_pcb --overwrite
# Create GND zone on B.Cu with via connections to all GND pads (outputs to input_routed.kicad_pcb)
python route_planes.py kicad_files/input.kicad_pcb --nets GND --plane-layers B.Cu
# Create GND zone, overwrite input file
python route_planes.py kicad_files/input.kicad_pcb --overwrite --nets GND --plane-layers B.Cu
# Create GND zone to specific output file
python route_planes.py kicad_files/input.kicad_pcb kicad_files/output.kicad_pcb --nets GND --plane-layers B.Cu
# Create multiple planes at once (each net paired with corresponding plane layer)
python route_planes.py kicad_files/input.kicad_pcb --nets GND +3.3V --plane-layers In1.Cu In2.Cu
# Create VCC plane with larger vias
python route_planes.py kicad_files/input.kicad_pcb --nets VCC --plane-layers In2.Cu --via-size 0.5 --via-drill 0.4
# Rip up blocking nets and automatically re-route them
python route_planes.py kicad_files/input.kicad_pcb --nets GND +3.3V --plane-layers In1.Cu In2.Cu --rip-blocker-nets --reroute-ripped-nets
# Multiple nets sharing same layer via Voronoi partitioning (use | separator)
python route_planes.py kicad_files/input.kicad_pcb --nets GND "VA19|VA11" --plane-layers In4.Cu In5.Cu
# Dry run to see what would be placed
python route_planes.py kicad_files/input.kicad_pcb --nets GND --plane-layers B.Cu --dry-run
After creating power planes, regions may become split by vias and traces from other nets. Use route_disconnected_planes.py to reconnect them:
# Auto-detect all zones in PCB and repair disconnected regions (outputs to input_routed.kicad_pcb)
python route_disconnected_planes.py kicad_files/input.kicad_pcb
# Auto-detect all zones, overwrite input
python route_disconnected_planes.py kicad_files/input.kicad_pcb --overwrite
# Auto-detect all zones to specific output file
python route_disconnected_planes.py kicad_files/input.kicad_pcb kicad_files/output.kicad_pcb
# Specific nets and layers
python route_disconnected_planes.py kicad_files/input.kicad_pcb --nets GND --plane-layers B.Cu
# Customize track width and clearance
python route_disconnected_planes.py kicad_files/input.kicad_pcb kicad_files/output.kicad_pcb \
--track-width 0.5 --clearance 0.2
# Check for DRC violations (default clearance: 0.2mm)
python check_drc.py kicad_files/output.kicad_pcb
# Cross-check with KiCad's own DRC engine (requires KiCad; --refill-zones avoids
# bogus zone-clearance errors from stale pours - see tests/README.md for details)
kicad-cli pcb drc --refill-zones --format json -o drc.json kicad_files/output.kicad_pcb
# Check connectivity (detects unrouted nets, broken routes, and T-junctions)
python check_connected.py kicad_files/output.kicad_pcb
# Check connectivity for specific nets
python check_connected.py kicad_files/output.kicad_pcb --nets "*DATA*"
# Check connectivity for all nets on a component
python check_connected.py kicad_files/output.kicad_pcb --component U1
# Only check routed nets (skip unrouted net detection)
python check_connected.py kicad_files/output.kicad_pcb --routed-only
# Check for orphan stubs (traces ending without proper connection)
python check_orphan_stubs.py kicad_files/output.kicad_pcb
Use the /analyze-power-nets skill to identify power nets and get track width recommendations:
# Ask Claude to analyze your board with datasheet lookup
/analyze-power-nets kicad_files/my_board.kicad_pcb
The skill:
--power-nets configurationsSee Power Net Analysis for detailed documentation.
Use the /find-high-speed-nets skill to identify high-speed nets and get GND return via recommendations:
# Ask Claude to analyze signal speeds with datasheet lookup
/find-high-speed-nets kicad_files/my_board.kicad_pcb
The skill:
--gnd-via-distanceThe /plan-pcb-routing skill includes a lightweight version of this analysis (net name and
footprint pattern matching only, no datasheet lookup) and automatically includes a GND return
via step when GND planes are present. Run /find-high-speed-nets first for more accurate
recommendations based on actual component specifications.
# Run full integration test (fanout + routing + checks)
python tests/test_fanout_and_route.py --all
# Quick mode for faster testing
python tests/test_fanout_and_route.py --all --quick
See tests/README.md for detailed documentation of all test scripts.
| Document | Description |
|---|---|
| Routing Architecture | Module structure, obstacle maps, A* algorithm |
| Python API | Using the modules as a library: parser, writer, modification, config, net analysis, impedance — with runnable examples |
| Configuration | Command-line options, GridRouteConfig parameters |
| Differential Pairs | P/N pairing, polarity swaps, via handling |
| Net Ordering | MPS algorithm, inside-out ordering, strategy comparison |
| Rip-Up and Reroute | Blocking analysis, progressive N+1 escalation, reroute loop |
| Length Matching | Trombone meanders, via barrel lengths, DDR auto-grouping, time matching |
| Bus Routing | Bus detection, middle-out ordering, neighbor attraction |
| Guide Corridor | User-layer guide paths, waypoints, best-effort following |
| Power/Ground Planes | Copper zones with automatic via placement |
| Utilities | DRC checker, connectivity checker, fanout generators, layer switcher |
| BGA Fanout | BGA escape routing generator |
| QFN Fanout | QFN/QFP escape routing generator |
| Rust Router | Building and using the Rust A* module |
| Visualizer | Real-time A* visualization with PyGame |
| Power Net Analysis | Power net detection, AI analysis, track width guidelines |
| Claude Skills | All eight AI skills: routing plans, power/high-speed/diff-pair analysis, stackup, plane mappings, failure diagnosis, board review |
| Placement | Placement optimization for routability |
| Integration Tests | Test scripts and performance benchmarks |
| Release Pipeline | How to tag a release and submit it to the KiCad PCM (maintainers) |
KiCadRoutingTools/
├── place_optimize.py # Main CLI - placement optimization (quench)
├── place_route_loop.py # Main CLI - router-in-the-loop placement repair
├── route.py # Main CLI - single-ended routing
├── route_diff.py # Main CLI - differential pair routing
├── route_planes.py # Main CLI - power/ground plane via connections
├── route_disconnected_planes.py # CLI - repair disconnected plane regions
├── plane_io.py # Plane I/O utilities (zone extraction, output writing)
├── plane_obstacle_builder.py # Obstacle map building for plane via placement
├── plane_blocker_detection.py # Blocker detection and rip-up for plane vias
├── plane_zone_geometry.py # Voronoi zone computation for multi-net layers
├── plane_resistance.py # Plane resistance and current capacity calculations
├── plane_region_connector.py # Detect and route between disconnected plane regions
├── routing_config.py # GridRouteConfig, GridCoord, DiffPair classes
├── routing_defaults.py # Default routing parameter values
├── routing_exceptions.py # Routing exception classes
├── routing_state.py # RoutingState class - tracks routing progress
├── routing_context.py # Helper functions for obstacle building
├── routing_common.py # Shared utilities for route.py and route_diff.py
├── routing_utils.py # Shared utilities (pos_key, etc.)
├── obstacle_map.py # Obstacle map building functions
├── obstacle_cache.py # Net obstacle caching for incremental builds
├── obstacle_costs.py # Stub/track proximity cost calculations
├── bresenham_utils.py # Bresenham line-walking utilities for grid operations
│
├── diff_pair_loop.py # Differential pair routing loop
├── single_ended_loop.py # Single-ended routing loop
├── reroute_loop.py # Reroute queue processing
├── phase3_routing.py # Phase 3 multi-point tap routing
├── diff_pair_routing.py # Diff pair A* routing implementation
├── single_ended_routing.py # Single-ended A* routing implementation
│
├── net_ordering.py # MPS, inside-out, and original ordering
├── net_queries.py # Net queries (diff pairs, MPS, endpoints)
├── connectivity.py # Stub endpoints, connected groups
├── layer_swap_optimization.py # Upfront layer swap optimization
├── layer_swap_fallback.py # Fallback layer swap on failure
├── stub_layer_switching.py # Stub layer swap utilities
├── mps_layer_swap.py # MPS-aware layer swap for crossing conflicts
├── polarity_swap.py # P/N polarity swap handling
├── target_swap.py # Target assignment optimization
├── rip_up_reroute.py # Rip-up and reroute logic
├── blocking_analysis.py # Analyze blocking nets
├── length_matching.py # Length matching with trombone meanders
│
├── kicad_parser.py # KiCad .kicad_pcb file parser
├── kicad_writer.py # KiCad S-expression generator
├── output_writer.py # Route output and swap application
├── pcb_modification.py # Add/remove routes from PCB data
├── schematic_updater.py # Update .kicad_sch files with pad swaps
├── chip_boundary.py # Chip boundary detection
├── geometry_utils.py # Shared geometry calculations
├── impedance.py # Impedance calculation (microstrip/stripline formulas)
├── memory_debug.py # Memory usage statistics
│
├── check_drc.py # DRC violation checker
├── check_connected.py # Connectivity checker (with T-junction detection)
├── check_orphan_stubs.py # Orphan stub detector
├── bga_fanout.py # BGA fanout CLI wrapper
├── bga_fanout/ # BGA fanout package
│ ├── __init__.py # Main fanout logic and public API
│ ├── types.py # Track, BGAGrid, FanoutRoute, Channel, DiffPairPads
│ ├── escape.py # Escape channel finding and assignment
│ ├── reroute.py # Collision resolution and rerouting
│ ├── layer_balance.py # Layer rebalancing for even distribution
│ ├── layer_assignment.py # Layer assignment for collision avoidance
│ ├── tracks.py # Track generation and collision detection
│ ├── geometry.py # 45° stub and jog calculations
│ ├── collision.py # Low-level collision detection utilities
│ ├── grid.py # BGA grid analysis
│ ├── diff_pair.py # Differential pair detection
│ └── constants.py # Configuration constants
├── qfn_fanout.py # QFN/QFP fanout CLI wrapper
├── qfn_fanout/ # QFN/QFP fanout package
│ ├── __init__.py # Main fanout logic and public API
│ ├── layout.py # Layout analysis functions
│ ├── geometry.py # Stub position calculations
│ └── types.py # QFNLayout, PadInfo, FanoutStub
├── list_nets.py # List nets on a component
├── build_router.py # Rust module build script (--clean to remove artifacts)
├── startup_checks.py # Startup checks (Python deps, Rust library version)
│
├── tests/ # Integration tests
│ ├── test_fanout_and_route.py # Full integration test (fanout + route)
│ ├── test_kit_route.py # Pad-to-pad routing test (no fanout)
│ ├── test_flat_hierarchy.py # 2-layer board with GND plane test
│ ├── test_interf_u.py # 2-layer board with non-rectangular outline test
│ ├── test_sonde_u.py # Wide track routing test
│ └── run_utils.py # Shared test utilities
│
├── rust_router/ # Rust A* implementation
├── pygame_visualizer/ # Real-time visualization
├── kicad_routing_plugin/ # KiCad ActionPlugin
│ ├── action_plugin.py # ActionPlugin entry point
│ ├── swig_gui.py # Main routing dialog (Basic/Advanced tabs)
│ ├── differential_gui.py # Differential pair routing tab
│ ├── fanout_gui.py # BGA/QFN fanout tab and net selection panel
│ ├── planes_gui.py # Power/ground planes tab
│ ├── about_tab.py # About tab with version info
│ ├── gui_utils.py # Shared GUI utilities
│ └── settings_persistence.py # Save/restore dialog settings between sessions
├── placement/ # Component placement
│ ├── engine.py # Core placement algorithm
│ ├── parser.py # Courtyard boundary extraction
│ ├── writer.py # Footprint position modification
│ └── utility.py # Shared placement utilities
├── install_plugin.py # Plugin installer script
├── docs/ # Documentation
└── .claude/skills/ # Claude Code skills
├── analyze-power-nets/ # AI-powered power net analysis skill
├── find-high-speed-nets/ # AI-powered high-speed net identification skill
├── plan-pcb-routing/ # AI-powered routing plan generation skill (orchestrates the others)
├── identify-diff-pairs/ # Datasheet-based diff pair detection skill
├── recommend-stackup/ # Stackup review/recommendation skill
├── diagnose-routing-failures/ # Failure root-cause and retry skill
├── review-routed-board/ # Post-route QA and sign-off skill
└── stress-test-router/ # Batch stress-test on real-world boards + issue filing (dev/QA)
One-line summaries below; the Python API documentation has full per-module references (signatures, dataclass fields, gotchas) with runnable examples.
| Module | Purpose |
|---|---|
route.py | CLI for single-ended routing |
route_diff.py | CLI for differential pair routing |
route_planes.py | CLI for power/ground plane via connections |
route_disconnected_planes.py | CLI for repairing disconnected plane regions |
routing_config.py | Configuration dataclasses (GridRouteConfig, GridCoord, DiffPair) |
routing_state.py | RoutingState class tracking progress, results, and PCB modifications |
routing_context.py | Helper functions for building obstacles and recording success |
routing_common.py | Shared utilities for route.py and route_diff.py (BGA zones, net resolution, length matching) |
routing_utils.py | Shared utilities (build_layer_map, iter_pad_blocked_cells) |
obstacle_map.py | Obstacle map building from PCB data |
obstacle_cache.py | Net obstacle caching for incremental obstacle map builds |
obstacle_costs.py | Stub and track proximity cost calculations |
bresenham_utils.py | Bresenham line-walking utilities for grid-based segment operations |
geometry_utils.py | Shared geometry calculations (point-to-segment distance, segment intersection, UnionFind) |
routing_constants.py | Shared constants (default layer stack, power net patterns, tolerances) |
terminal_colors.py | ANSI color codes for terminal output |
| Module | Purpose |
|---|---|
diff_pair_loop.py | Main loop for routing differential pairs |
single_ended_loop.py | Main loop for routing single-ended nets |
reroute_loop.py | Processes reroute queue for failed routes |
phase3_routing.py | Phase 3 multi-point tap routing (connects remaining pads after length matching) |
diff_pair_routing.py | Differential pair A* with centerline + offset and GND vias |
single_ended_routing.py | Single-ended net A* routing |
| Module | Purpose |
|---|---|
net_ordering.py | MPS, inside-out, and original net ordering strategies |
net_queries.py | Net queries (diff pair detection, MPS ordering, power net detection, chip pad positions) |
connectivity.py | Stub endpoints, connected groups, multi-point net detection |
Key functions in net_queries.py:
identify_power_nets(pcb, patterns, widths) - Pattern-based power net detection for --power-nets CLI optioncompute_mps_net_ordering(pcb, net_ids) - MPS algorithm for optimal net orderingfind_differential_pairs(pcb, patterns) - Detect P/N pairs from net names (suffix-style aware: +/- nets only pair with each other, never with _P/_N nets sharing the same base name)Key functions in analyze_power_paths.py (used by /analyze-power-nets skill):
analyze_pcb(filepath) - Load PCB and extract components for analysisget_components_needing_analysis(components) - Get components requiring AI classificationclassify_component(components, ref, role, current_ma, notes) - Set component classificationtrace_power_paths(pcb, components) - Trace current from sinks to sourcesget_power_net_recommendations(pcb, components, paths) - Get recommended track widths| Module | Purpose |
|---|---|
layer_swap_optimization.py | Upfront layer swap optimization before routing |
layer_swap_fallback.py | Try layer swap when route fails |
stub_layer_switching.py | Low-level stub layer swap utilities |
mps_layer_swap.py | MPS-aware layer swap for crossing conflicts |
polarity_swap.py | P/N polarity swap for differential pairs |
target_swap.py | Hungarian algorithm for optimal target assignment |
rip_up_reroute.py | Rip-up blocking routes and retry |
blocking_analysis.py | Analyze which nets are blocking |
length_matching.py | Length matching with trombone-style meanders |
| Module | Purpose |
|---|---|
kicad_parser.py | KiCad .kicad_pcb file parser (extracts stackup, footprint values, pintypes) |
kicad_writer.py | KiCad S-expression generator |
output_writer.py | Write routed output with swaps and debug geometry |
pcb_modification.py | Add/remove routes from PCB data structure |
schematic_updater.py | Update .kicad_sch files with pad swaps from routing |
impedance.py | Impedance calculations (microstrip/stripline, width from target Z) |
memory_debug.py | Memory usage statistics and debugging |
Integration test results (tests/test_fanout_and_route.py):
| Stage | Nets | Time | Iterations |
|---|---|---|---|
| FTDI single-ended | 47/47 | 8.6s | 319K |
| LVDS diff pairs (batch 1) | 28/28 | 29.7s | 10.2M |
| LVDS diff pairs (batch 2) | 28/28 | 28.0s | 12.0M |
| DDR diff pairs | 5/5 | 0.3s | 25K |
| DDR single-ended | 51/51 | 6.2s | 565K |
Rust acceleration provides ~10x speedup vs pure Python.
python route.py kicad_files/input.kicad_pcb [output.kicad_pcb] [OPTIONS]
# Output options (default: input_routed.kicad_pcb)
--overwrite, -O # Overwrite input file instead of creating _routed copy
# Net selection (default: "*" = all nets)
--nets "pattern" ... # Net names or wildcard patterns to route
# Supports exclusion: --nets "*" "!GND" "!VCC" = all except GND/VCC
--component U1 # Route all nets on U1 (auto-excludes GND/VCC/VDD/unconnected unless --nets given)
# Geometry
--track-width 0.3 # Track width (mm), ignored if --impedance specified
--impedance 50 # Target single-ended impedance (ohms), calculates width per layer from stackup
--clearance 0.25 # Track clearance (mm)
--via-size 0.5 # Via diameter (mm)
--via-drill 0.3 # Via drill (mm)
# Power net routing (wider tracks for power/ground)
--power-nets "*GND*" "*VCC*" # Glob patterns for power nets
--power-nets-widths 0.4 0.5 # Widths in mm for each pattern (must match --power-nets length)
--neckdown-length 2.5 # Narrow track length (mm) from the pads when a failed wide power
# route is retried at the default width (neck-down)
--neckdown-taper-length 0.5 # Narrow-to-wide width taper length in mm (0 = abrupt)
--no-power-tap-neckdown # Disable the neck-down retry of failed wide power routes
# Algorithm
--grid-step 0.1 # Grid resolution (mm)
--via-cost 50 # Via penalty in 0.1mm grid steps (50 = 5mm of path; all cost knobs
# are mm-calibrated, so behavior is independent of --grid-step)
--max-iterations 200000 # A* iteration limit
--max-probe-iterations 5000 # Quick probe per direction to detect stuck routes
--heuristic-weight 1.9 # A* greediness (>1 = faster)
--proximity-heuristic-factor 0.02 # Proximity cost estimate (only applied when endpoints in zones, diff pairs use 1/10th)
--turn-cost 1000 # Penalty for direction changes (straighter paths)
--direction-preference-cost 50 # Penalty for non-preferred layer direction (0=disabled)
# Alternates H/V: F.Cu=horizontal, In1.Cu=vertical, etc.
--max-ripup 3 # Max blockers to rip up at once (1-N progressive)
--routing-clearance-margin 1.0 # Multiplier on track-via clearance (1.0 = min DRC, default)
--hole-to-hole-clearance 0.2 # Minimum drill hole edge-to-edge clearance (mm)
--board-edge-clearance 0.0 # Clearance from board edge (0 = use track clearance)
# Strategy
--ordering mps # mps | inside_out | original
--layers F.Cu B.Cu # Routing layers (default: 2-layer)
--layer-costs 1.0 3.0 # Per-layer cost multipliers (1.0-1000)
# Default: 4+ layers = all 1.0; 2 layers = F.Cu=1.0, B.Cu=3.0
# Order matches --layers. Use to prefer certain layers (e.g., keep signals on F.Cu)
--no-bga-zones # Allow routing through all BGA areas
--no-bga-zones U1 U3 # Allow routing through specific BGAs only (or all if none given)
# Proximity penalties
--stub-proximity-radius 2.0 # Radius around stubs to penalize (mm)
--stub-proximity-cost 0.2 # Cost penalty near stubs (mm equivalent)
--bga-proximity-radius 7.0 # Radius around BGA edges to penalize (mm)
--bga-proximity-cost 0.2 # Cost penalty near BGA edges (mm equivalent)
--track-proximity-distance 2.0 # Radius around routed tracks (mm, same layer)
--track-proximity-cost 0.0 # Cost penalty near tracks (0 = disabled)
--vertical-attraction-radius 1.0 # Radius for cross-layer track attraction (mm)
--vertical-attraction-cost 0.0 # Cost bonus for cross-layer alignment (0 = disabled)
--ripped-route-avoidance-radius 1.0 # Radius around ripped route corridors (mm)
--ripped-route-avoidance-cost 0.1 # Cost penalty for routing through ripped corridors (0 = disabled)
# Bus routing (parallel groups of nets)
# Detects groups of nets with clustered endpoints and routes them together.
# Routes middle net first (guide track), then alternates outward with attraction
# to keep traces parallel. Use --verbose to see routing order and attraction relationships.
--bus # Enable bus detection and parallel routing
--bus-detection-radius 5.0 # Max endpoint distance to form bus group (mm)
--bus-attraction-radius 5.0 # Attraction radius from neighbor track (mm)
--bus-attraction-bonus 5000 # Cost bonus for staying parallel to neighbor
--bus-min-nets 2 # Minimum nets to form a bus group
# Guide corridor: route selected nets to follow a polyline drawn on a User layer (issue #7)
--guide-corridor # Steer routed nets along the drawn guide polyline
--guide-corridor-layer User.1 # User layer the guide polyline is drawn on
--guide-corridor-spacing 0.0 # Max mm between waypoints (0 = drawn vertices only; >0 subdivides)
# Keepout zones: keep routed tracks out of polygons drawn on a User layer (issue #27)
--keepout # Keep routed tracks out of the drawn keepout polygons
--keepout-layer User.2 # User layer the keepout polygons are drawn on
# Layer optimization
--no-stub-layer-swap # Disable stub layer switching
# Target swap optimization
--swappable-nets "*rx*" # Glob patterns for nets that can have targets swapped
--schematic-dir /path/to/kicad # Optional: sync pad swaps to .kicad_sch files (disabled by default)
# Updates lib_symbols in ALL files containing the symbol
--crossing-penalty 1000 # Penalty for crossing assignments (default: 1000)
--no-crossing-layer-check # Count crossings regardless of layer (default: same-layer only)
--mps-reverse-rounds # Route most-conflicting MPS groups first (instead of least)
--mps-layer-swap # Try layer swaps to resolve MPS crossing conflicts
--mps-segment-intersection # Force segment intersection method for MPS (auto when no BGAs)
# Length matching (for DDR4 DQ/DQS signals)
--length-match-group auto # Auto-group DDR4 nets by byte lane (DQ0-7+DQS0, DQ8-15+DQS1, etc)
--length-match-group "pattern1" "pattern2" # Manual grouping by net patterns
--length-match-tolerance 0.1 # Acceptable length variance within group (mm)
--meander-amplitude 1.0 # Height of meanders perpendicular to trace (mm)
# Time matching (alternative to length matching)
--time-matching # Match propagation time instead of length (accounts for layer dielectric)
--time-match-tolerance 1.0 # Acceptable time variance within group (ps)
# Debug
--verbose # Print detailed diagnostic output
--debug-lines # Output debug geometry on User layers
--skip-routing # Skip routing, only do swaps and write debug info
--debug-memory # Print memory usage statistics during routing
--add-teardrops # Add teardrop settings to all pads in output file
--stats # Print A* search statistics (cells expanded, heuristic efficiency, etc.)
python route_diff.py kicad_files/input.kicad_pcb [output.kicad_pcb] [OPTIONS]
# Output options (default: input_routed.kicad_pcb)
--overwrite, -O # Overwrite input file instead of creating _routed copy
# Net selection (default: "*" = all nets)
# All nets specified with --nets are treated as differential pairs (P/N naming convention)
# Diff pair specific options
--impedance 100 # Target differential impedance (ohms), calculates width per layer from stackup
--diff-pair-gap 0.101 # P-N gap (mm), also used as spacing for impedance calculation
--diff-pair-centerline-setback # Setback distance (default: 2x P-N spacing)
--min-turning-radius 0.2 # Min turn radius (mm)
--max-turn-angle 180 # Max cumulative turn (degrees, prevents U-turns)
--max-setback-angle 45 # Max angle for setback search (degrees)
--direction backward # Route from target to source
--no-gnd-vias # Disable GND via placement (enabled by default)
--diff-chamfer-extra 1.5 # Chamfer multiplier for diff pair meanders (>1 avoids P/N crossings)
--diff-pair-intra-match # Match P/N lengths within each diff pair (meander shorter track)
# Layer optimization
--no-stub-layer-swap # Disable stub layer switching
--can-swap-to-top-layer # Allow swapping stubs to F.Cu (off by default)
# Target/polarity swap with schematic sync
--swappable-nets "*rx*" # Glob patterns for nets that can have targets swapped
--schematic-dir /path/to/kicad # Optional: sync pad swaps to .kicad_sch files (disabled by default)
# Syncs target swaps (P1_P<->P2_P, P1_N<->P2_N) and polarity swaps (P<->N)
# Updates ALL schematic files containing the lib_symbol
# All other options from route.py also apply (geometry, strategy, proximity, length matching, etc.)
python route_planes.py kicad_files/input.kicad_pcb [output.kicad_pcb] --nets GND --plane-layers B.Cu [OPTIONS]
# Output options (default: input_routed.kicad_pcb)
--overwrite, -O # Overwrite input file instead of creating _routed copy
# Required (can specify multiple nets/plane layers)
--nets, -n GND VCC # Net name(s) for planes (e.g., GND VCC +3.3V)
# Use | to share a layer: "VA19|VA11" creates Voronoi-partitioned zones
--plane-layers, -p In1.Cu In2.Cu # Plane layer(s), one per net (or one per net group)
# Via/trace geometry
--via-size 0.5 # Via outer diameter (mm)
--via-drill 0.3 # Via drill size (mm)
--track-width 0.3 # Track width for via-to-pad connections (mm)
--clearance 0.25 # Clearance (mm)
# Zone options
--zone-clearance 0.2 # Zone clearance from other copper (mm)
--min-thickness 0.1 # Minimum zone copper thickness (mm)
# Algorithm
--grid-step 0.1 # Grid resolution (mm)
--max-search-radius 10.0 # Max radius to search for valid via position (mm)
--max-via-reuse-radius 1.0 # Max radius to prefer reusing existing via (mm)
--close-via-radius 0.5 # Radius to check for nearby vias before placing new one (default: 2.5 * via-size)
--hole-to-hole-clearance 0.2 # Minimum drill hole clearance (mm)
--layers, -l F.Cu In1.Cu In2.Cu B.Cu # All copper layers for routing and via span
--layer-costs 1.0 1.0 1.0 1.0 # Per-layer cost multipliers (1.0-1000)
# Default: 4+ layers = all 1.0; 2 layers = F.Cu=1.0, B.Cu=3.0
--board-edge-clearance 0.5 # Zone clearance from board edge (mm)
# Multi-net plane layers (Voronoi partitioning)
--plane-proximity-radius 2.0 # Proximity radius for routing around other nets' vias (mm)
--plane-proximity-cost 5.0 # Proximity cost for routing around other nets' vias
--plane-track-via-clearance 0.8 # Clearance from MST track center to other nets' via centers (mm)
--voronoi-seed-interval 2.0 # Sample interval for seed points along connection routes (mm)
--plane-max-iterations 200000 # Max A* iterations for plane connection routing
# Blocker rip-up
--rip-blocker-nets # Rip up nets blocking via placement
--max-rip-nets 3 # Max blocker nets to rip up per pad (default: 3)
--reroute-ripped-nets # Automatically re-route ripped nets after via placement
--power-nets "*GND*" "*VCC*" # Glob patterns for power nets (wider tracks when rerouting)
--power-nets-widths 0.4 0.5 # Track widths for each power-net pattern
# Debug
--dry-run # Analyze without writing output
--verbose, -v # Print detailed debug messages
--debug-lines # Draw MST routes on User.1, User.2, etc. per net
--add-teardrops # Add teardrop settings to all pads in output file
# GND return via placement (for signal integrity)
--add-gnd-vias # Add GND vias near signal vias for return current paths
--gnd-via-net GND # Net name for GND vias (default: GND)
--gnd-via-distance 2.0 # Max distance from signal via to place GND via (mm, default: 2.0)
Features:
| separator (e.g., "VA19|VA11"). Each net's vias get non-overlapping zone polygons. MST edges are routed between all vias using A* pathfinding, with routes sampled as Voronoi seeds to ensure connected zones. Retries with failed nets first (up to 5 iterations)See Power/Ground Planes for detailed documentation.
After creating power planes, regions may become split by vias and traces from other nets cutting through. This script detects disconnected regions within each plane zone and routes wide, short tracks between them.
python route_disconnected_planes.py kicad_files/input.kicad_pcb [output.kicad_pcb] [OPTIONS]
# Output options (default: input_routed.kicad_pcb)
--overwrite, -O # Overwrite input file instead of creating _routed copy
# Zone selection (auto-detects all zones if not specified)
--nets, -n GND +3.3V # Net name(s) to process
--plane-layers, -p B.Cu In1.Cu # Plane layer(s) to process
--layers, -l F.Cu In1.Cu In2.Cu B.Cu # Layers available for routing (default: all copper)
# Track width
--max-track-width 2.0 # Maximum track width for connections (mm)
--min-track-width 0.2 # Minimum track width for connections (mm)
--track-width 0.3 # Default track width for routing config (mm)
# Clearance
--clearance 0.25 # Trace-to-trace clearance (mm)
--zone-clearance 0.2 # Zone fill clearance around obstacles (mm)
--track-via-clearance 0.8 # Clearance from tracks to other nets' vias (mm)
--board-edge-clearance 0.5 # Clearance from board edge (mm)
--hole-to-hole-clearance 0.3 # Minimum clearance between drill holes (mm)
# Via options
--via-size 0.5 # Via outer diameter (mm)
--via-drill 0.3 # Via drill diameter (mm)
# Grid
--grid-step 0.1 # Routing grid step (mm)
--analysis-grid-step 0.5 # Grid step for connectivity analysis (coarser = faster)
# Routing
--max-iterations 200000 # Maximum A* iterations per route attempt
# Debug
--dry-run # Analyze without writing output
--verbose, -v # Print detailed debug messages
--debug-lines # Add debug lines on User.4 layer showing route paths
Features:
pip3 install numpy)pip3 install scipy) - used for optimal target assignment and Voronoi partitioningpip3 install shapely) - used for polygon union in multi-net plane layerspython build_router.py --from-source); not required when using the prebuilt binarypip3 install pygame-ce)MIT License
No comments yet. Be the first to ask about this board.