← Commit history

docs: Rust port plan and competitive comparison sub-readmes, feature guides index

John Lauer ·6da69cc938 ·29d ago ·parent 15fb60e
3 files changed +313
README.md+8
@@ -44,6 +44,14 @@ explains it. The same recording plays inline in the dashboard.  How the dock card, the dashboard and this demo fit together: [docs/dashboard.md](docs/dashboard.md). +## Feature guides++| guide | what it covers |+|---|---|+| [Dashboard](docs/dashboard.md) | The dock card, the dashboard and how the demo fits in. |+| [How the bridge compares](docs/comparison.md) | Feature matrix against every notable KiCad MCP server and AI tool, with the gaps on both sides. |+| [The Rust port plan](docs/rust-port-plan.md) | One dependency-free binary: what moves to KiCad's API, what ab already does, what PowerShell goes away, phases and risks. |+ ## Live routing (from 0.9.340)  Four verbs edit copper in the open PCB editor through KiCad's official IPC API (KiCad 10.0.1+
docs/comparison.mdadded+87
@@ -0,0 +1,87 @@+# How the KiCad bridge compares++A factual audit of every notable AI and MCP automation for KiCad, done 2026-09-11 against the public repositories, their READMEs and their open issues, so the claim that this bridge is the most complete automation of KiCad available to an AI can be checked line by line rather than taken on faith. Star counts and last-push dates were read from GitHub on that day. Where we are behind, it says so.++## The field++| Tool | Stars | Last push | Language | How it reaches KiCad | Platforms |+|---|---|---|---|---|---|+| [Adom KiCad Bridge](https://wiki.adom.inc/adom/kicad-bridge) (this) | n/a (wiki) | daily | Python, Rust port planned | IPC API, kicad-cli, file edit, background Win32 and UIA window control, Adom Bridge callbacks | Windows, partial macOS |+| [KiCAD-MCP-Server](https://github.com/mixelpixx/KiCAD-MCP-Server) | 2,198 | 2026-09-10 | Python and TypeScript | SWIG through KiCad's bundled Python, experimental IPC, kicad-cli, kicad-skip for schematics, a loopback GUI click plugin | Win, mac, Linux |+| [Konnect](https://github.com/mixelpixx/Konnect) | 619 | 2026-09-11 | Rust | IPC for PCB, own s-expression engine for schematics, kicad-cli | Windows primary |+| [kicad-happy](https://github.com/aklofas/kicad-happy) | 1,184 | 2026-09-01 | Python | File parsing only, read-only, no KiCad needed | all |+| [kicad-mcp](https://github.com/lamaalrajih/kicad-mcp) | 518 | 2025-10-17 | Python | File parsing, kicad-cli, launches KiCad by subprocess | all |+| [Seeed kicad-mcp-server](https://github.com/Seeed-Studio/kicad-mcp-server) | 127 | 2026-09-09 | Python | SWIG through bundled Python, text-parse fallback, kicad-cli | all |+| [kicad-mcp-pro](https://github.com/oaslananka/kicad-mcp-pro) | 84 | 2026-09-11 | Python 3.13 | File parsing, kicad-cli, 24 kipy IPC tools out of 387 | all, Tauri desktop app |+| [KiCad-AI-Assistant](https://github.com/paul356/KiCad-AI-Assistant) | 81 | 2026-09-09 | Python | In-KiCad action plugin with an embedded MCP server | Linux, Windows |+| [KiPilot](https://github.com/belaszalontai/kipilot-mcp) | 8 | 2026-08-30 | Python | kipy IPC only, KiCad 10 GUI must be running | Windows zip, others from source |+| [mcp-server-kicad](https://github.com/ProductOfAmerica/mcp-server-kicad) | 8 | 2026-08-15 | Python | Byte-preserving file edits, kicad-cli, pcbnew for zone fill and Freerouting | all |+| [kicad-agentic-mcp](https://github.com/nevenfo/kicad-agentic-mcp) | 3 | 2026-09-10 | Rust | IPC for PCB, s-expressions for schematics, kicad-cli verdicts | Windows tested |++Adjacent code-first tools that generate KiCad files rather than drive KiCad ([tscircuit](https://github.com/tscircuit/tscircuit), [atopile](https://github.com/atopile/atopile), Diode, JITX, Flux, Quilter, [DeepPCB](https://github.com/instadeepai/deeppcb-kicad-plugin)) are not in the matrix. None of them control a running KiCad.++## Feature matrix++Y = yes, P = partial, N = no. Columns: **Adom** this bridge, **MX** KiCAD-MCP-Server, **KN** Konnect, **HP** kicad-happy, **LA** kicad-mcp, **SD** Seeed, **PRO** kicad-mcp-pro, **AIA** KiCad-AI-Assistant, **KP** KiPilot, **POA** mcp-server-kicad.++| Feature | Adom | MX | KN | HP | LA | SD | PRO | AIA | KP | POA |+|---|---|---|---|---|---|---|---|---|---|---|+| Install KiCad itself, silently, then verify | Y | N | N | N | N | N | N | N | N | N |+| Launch KiCad, open a project or board in the GUI | Y | Y | P | N | Y | N | P | Y | N | N |+| Open the symbol, footprint, schematic, PCB editors and 3D viewer on a named part, in the background | Y | N | N | N | N | N | N | N | N | N |+| Screenshot of the real KiCad windows, dialogs included, without stealing focus | Y | N | N | N | N | N | N | N | N | N |+| Video recording of a narrated tour | Y | N | N | N | N | N | N | N | N | N |+| Schematic read (netlist, connections, lint) | Y | Y | Y | Y | Y | Y | Y | Y | P | Y |+| Schematic edit in place (symbols, wires, labels) | N | Y | Y | N | N | P | Y | Y | P | Y |+| BOM and netlist export | Y | Y | Y | Y | Y | Y | Y | Y | Y | Y |+| ERC and DRC with parsed results | Y | Y | Y | N | P | Y | Y | Y | N | Y |+| Board read (pads, nets, tracks, routing state) | Y | Y | Y | Y | P | Y | Y | Y | Y | Y |+| Board edit through KiCad's IPC API as native undo steps | Y | P | Y | N | N | N | P | Y | Y | N |+| Autorouting (Freerouting) | N | Y | Y | N | N | N | Y | N | N | Y |+| Gerber, drill, STEP, SVG, PDF export | Y | Y | Y | P | N | P | Y | P | P | Y |+| 3D image of a board or chip | Y (live viewer capture and kicad-cli render) | P | N | N | Y | N | Y | Y | N | N |+| 3D model diagnostics (missing, unresolved, wrong scale) | Y | N | N | N | N | N | N | N | N | N |+| Library management: install symbol, footprint, 3D model, edit lib tables, heal, rescan | Y | Y | P | N | N | P | Y | Y | N | Y |+| PCM plugin and library install without the GUI | Y | N | N | N | N | N | N | N | N | N |+| Dialog pre-emption and cleanup, with a screenshot of what was dismissed | Y | P | N | N | N | N | N | N | N | N |+| Foreground etiquette (never steal the user's screen, measured) | Y | N | N | N | N | N | N | N | N | N |+| Progress with measured percent and ETA on slow verbs, mirrored to the taskbar | Y | N | P | N | Y | N | ? | N | N | N |+| Multi-machine: drive a named desktop from a cloud agent | Y | N | N | N | N | N | N | N | N | N |+| Permission model with human-only grants and a reason per call | Y (Adom Bridge) | N | N | n/a | N | N | Y | N | Y | P |+| Caller identity and audit on every verb | Y | P | Y | N | N | N | P | N | N | N |+| Auto-update with an insiders tier | Y | N | N | N | N | N | P | N | N | N |+| Health and readiness verbs | Y | P | Y | N | N | N | Y | N | Y | N |+| Supported uninstall | Y | N | Y | P | N | N | N | N | N | N |+| Runs with no KiCad installed | N | N | N | Y | N | P | Y | N | N | Y |++## Where we lead, with the evidence++- **Window control that stays in the background.** No other tool opens KiCad's editors on a named part or captures the real window. The mechanism is a native menu walk with WM_COMMAND, UI Automation invoke, and PostMessage to one hwnd, all documented in the code with the measurements that led to them. The release gate on 2026-09-08 ran every window verb on two machines with the foreground-steal check on: 72 passed, 1 failed, 15 skipped on ConfRoomROG and 70, 3, 15 on winvm, and the six-beat narrated tour recorded on both.+- **Dialogs.** The bridge seeds KiCad's settings so the first-run wizard never appears, sweeps transient dialogs after every verb, refuses to click Cancel on progress dialogs, and attaches a screenshot of anything it dismissed. The nearest competitor has one environment variable that auto-confirms a reload prompt.+- **Install to uninstall.** `kicad_upgrade` performs the silent official KiCad install and verifies with kicad-cli; `kicad_uninstall` removes only our artifacts. ab polls the manifest every four hours and insiders get builds before the public tier. The audit found one competitor with a supported uninstall and none with an update path.+- **Library and PCM.** Symbol, footprint and 3D install with lib-table registration, an Adom library that heals itself, in-place rescan verified in the editor, and PCM installs that reproduce KiCad's own on-disk layout. Three competitors author parts; none touch PCM.+- **Cloud to desktop.** Every verb is addressable by machine name from a container, with the caller's thread and reason stamped on the request by Adom Bridge. Every competitor assumes the agent runs on the same desktop as KiCad or fully headless.+- **Volume of releases.** 290 insiders builds since 0.9.60, each staged on a test box and verified before the manifest moved, with the bug history public on the [issue tracker](https://wiki.adom.inc/adom/kicad-bridge/issues).++## Where others lead, honestly++- **Schematic editing.** Konnect, KiCAD-MCP-Server, kicad-mcp-pro and mcp-server-kicad rewrite `.kicad_sch` on disk to place symbols and wires. We generate part projects but do not edit an existing schematic's wires. Every one of those tools carries the same caveat (close and reopen the schematic editor to see the change) because KiCad 10 has no schematic API. We chose to wait for the KiCad 11 API rather than ship file rewrites that KiCad cannot validate; that is a judgment call, and it is a gap today.+- **Autorouting.** Four tools wrap Freerouting. Our routing verbs route the waypoints the AI chooses and DRC-check each step; there is no autorouter, on purpose, and no plan to add one.+- **Headless without KiCad.** kicad-happy runs anywhere with no KiCad and publishes corpus-scale validation (6,845 schematics parsed at 100 percent). We require an installed KiCad and are Windows-first.+- **Zero-install distribution.** kicad-mcp-pro runs from `uvx`; Konnect is one static binary with 7,648 downloads and PCM install. We need Adom Bridge on the desktop, and until the Rust port lands we still ship a Python program that ab hosts. See [the Rust port plan](rust-port-plan.md).+- **Permission profiles inside the tool.** kicad-mcp-pro ships a read-only default profile and a human-gated release profile. Ours is enforced one layer down by Adom Bridge (risk classes, human-only grants, a reason on every gated call), which is stronger but is not visible in the bridge's own README.+- **Tool discovery economy.** Konnect loads a 2K-token starter kit and pulls toolsets on demand. Our describe verb returns all 85 entries at once.++## What nobody else does at all++From the audit, no tool in the field does any of these: real window screenshots, video, driving a desktop from a cloud agent, per-call caller identity plus approval, PCM installs, dialog handling beyond one env var, auto-update, silent KiCad install, foreground etiquette, or 3D model diagnostics. That list is the argument for this bridge, and each item is a verb you can call today.++## The parts of this that are not ours to claim++- The GPT-6 Astra demo drove KiCad's GUI directly, per OpenAI's announcement and the KiCad forum thread. That is a lab demo, not a tool anyone can install, but it is the only other public example of GUI-level KiCad automation.+- Diode and atopile have the only public benchmark numbers for AI board design (EEBench). Those measure design quality of generated boards, not automation of KiCad, so they are not comparable to anything here.+- KiCad developers have said on the forum that the MCP scene is "experiments you run, not products you install once." The evidence that we are the exception is the release gate, the tour recordings and the issue tracker, not this page.++## Method++Twelve repositories were checked on 2026-09-11: README, install docs, tool lists, release assets, open issues. Stars, last push and license came from the GitHub API that day. A feature is marked Y only when the tool's own documentation names it. Marks for this bridge come from the verb catalog in `server.py` and the 2026-09-08 gate reports. Anyone who finds a mark wrong can file it on the [issue tracker](https://wiki.adom.inc/adom/kicad-bridge/issues) and it will be corrected.
docs/rust-port-plan.mdadded+218
@@ -0,0 +1,218 @@+# The Rust port plan++Status: proposal, written 2026-09-11 from a full audit of the 0.9.350 source, the Adom Bridge (ab) verb surface, the KiCad 10.0.6 IPC API and the KiCad 11 roadmap. Nothing here is built yet. Decisions John needs to make are collected at the end.++## The goal in one sentence++One `kicad-bridge.exe`, no Python, no PowerShell, no vendored wheels, nothing for ab to provision, that drives KiCad through its official API first and its window second, and that is measurably faster and more predictable than what ships today.++## Where we are today++| Fact | Value |+|---|---|+| Language | Python 3, run by ab's managed Python 3.12.13 (astral python-build-standalone) |+| Our code | 38,534 lines of Python, 1,983 lines of PowerShell, JS and HTML, 3,126 lines of skill docs |+| Vendored | 228,552 lines in `routing_deps/` (kicad-python, protobuf, pynng, cffi and friends), three copies for CPython 3.11, 3.12 and 3.13, 22 MB |+| Verbs | 85 in the catalog, plus a handful of hidden maintenance verbs |+| Release zip | 22 MB of routing wheels plus about 1 MB of our code |+| Third-party imports at runtime | Only `kipy` (routing verbs) and an optional `PIL` with a stdlib fallback. Everything else is stdlib plus raw `ctypes` |++The runtime is already close to dependency-free. The pain John has seen (which Python, which ABI, missing CA store, stripped environment, PowerShell crashing on .NET teardown, console windows blipping) all comes from the fact that we ship an interpreter-hosted program into an environment we do not own. A static binary removes the class of problem rather than each instance.++### How each verb reaches KiCad today++| Mechanism | Verbs | Where |+|---|---|---|+| KiCad IPC API (kipy over nng) | 9: routing_state, route_net, remove_route, routing_validate, board_pads, add_track, add_via, route, ipc_api | `handlers/live_routing.py`, `handlers/route.py` |+| kicad-cli subprocess | 16: run_drc, run_erc, lint_board, lint_schematic, lint_library, format_upgrade, extract_netlist, trace_net, find_connections, analyze_connections, export_gerber, export_pdf, export_svg, export_step, export_bom_csv, export_molecule | `handlers/export.py`, `run_drc.py`, `kicad_cli_lint.py`, `netlist.py` |+| File parsing and editing (s-expressions, lib tables, settings JSON) | 18: install_library, install_symbol, install_footprint, install_library_bundle, list_symbols, list_footprints, rescan_libraries, adom_library_status, adom_library_heal, model_check, pcm_install, pcm_list, pcm_uninstall, list_design_rules, set_design_rules, get_settings, set_settings, make_part_project, export_part | `adom_library.py`, `lib_table.py`, `parsers/`, `handlers/pcm.py`, `model_check.py` |+| Detection, install, upgrade, status | 12: readiness, list_versions, diagnostics, status, bridge_status, check_for_updates, upgrade, uninstall, describe, errors, log_tail, plugin_diagnose | `kicad_detect.py`, `handlers/upgrade.py`, `uninstall.py` |+| Windows window control (raw win32 through ctypes) | 20: launch, open_board, open_schematic, open_symbol_editor, open_footprint_editor, open_3d_viewer, open_editors, close, close_symbol_editor, close_footprint_editor, close_3d_viewer, dismiss_dialogs, window_info, state, screenshot_all, send_key, click, fix_keyboard, place_footprint, enable_software_opengl | `handlers/win_focus.py`, `close_windows.py`, `kicad_ui.py`, `win_menu.py`, `open_*.py` |+| Show family (window control plus evidence capture) | 8: show_project, show_symbol, show_footprint, show_3d_chip, show_schematic, show_2d_board, show_3d_board, show_library | `handlers/show.py` |+| Demo tour (ab delegation plus SendInput motion) | 1: demo | `handlers/demo.py`, `demo_motion.py` |+| SWIG plugin inside KiCad's Python (reverse bridge) | Used as tier 0 by open_symbol_editor, open_footprint_editor, open_3d_viewer, rescan_libraries | `plugin_payload/adom_bridge.py` (3,379 lines), `handlers/bridge_client.py` |++The window-control group is where the fragility, the sleeps and the PowerShell live. It is 21,702 lines of handlers, and the five largest files (demo, win_focus, open_symbol_editor, open_footprint_editor, close_windows, kicad_ui) are 9,776 lines between them.++### Every PowerShell use, and its replacement++| Today | Lines | What it does | In the Rust binary |+|---|---|---|---|+| `handlers/uia.py` | 144 | Spawns `powershell` with a .NET UIAutomation script to Invoke, Select or SetValue on a control by name, background | `uiautomation` crate (Windows UIA COM), in process, no subprocess, no 0xC0000409 teardown crash |+| `navigate_symbol.ps1` | 119 | UIA ValuePattern.SetValue on the library tree filter, WM_SETTEXT fallback, posted VK_RETURN | Same three calls through `uiautomation` and `windows` crates |+| `launch_editor.ps1` | 114 | Dead code, nothing calls it. Its fallback moves the real mouse | Delete now, before the port |+| `server.py` Get-Process probe | 20 | `Get-Process kicad` to list KiCad instances with titles | `CreateToolhelp32Snapshot` plus `EnumWindows`, or ab `app_instances` |+| `handlers/win_taskbar.py` .lnk repair | 80 | Inline C# through PowerShell to stamp KiCad's own AUMID on Start Menu shortcuts | `IShellLinkW` plus `IPropertyStore` through the `windows` crate, or drop the repair (John already asked for stock KiCad taskbar behaviour) |+| `handlers/demo.py` narration | 25 | Hidden PowerShell WPF MediaPlayer to play the tour mp3 | `windows::Media::Playback::MediaPlayer` (WinRT, in process), or ask ab for an audio verb so every bridge gets it |++Two `.bat` and `.sh` launch scripts exist only for hand runs and go away with `spawn.kind: "exe"`.++## What ab already does that we re-implement++The ab verb surface has grown a lot since the bridge was started. Several thousand lines of ours now duplicate it.++| Ours | Lines | ab has | Verdict |+|---|---|---|---|+| Local PrintWindow capture fallback in `kicad_ui._screenshot_hwnd`, including moving an iconic window off screen to capture it | ~130 | `desktop_screenshot_window` (PrintWindow, background, owned popups returned as separate images, coordMap) | Delete. Keep only the canvas-painted probe (`_canvas_probe`), which is KiCad-specific |+| Window enumeration (`_find_all_kicad_windows`, `_enum_kicad_hwnds`, `close_windows._win_find_*`) | ~250 | `desktop_list_windows` with pid, owner, z-order, hung flag; `enum_windows`; `find_window`; `wait_for_window` | Delete, keep a thin KiCad filter (exe name set) on top of ab's list |+| UIA through PowerShell | 144 + 119 | `desktop_ui_click` (InvokePattern), `desktop_ui_set` (ValuePattern), `desktop_ui_tree`, `find_controls` | Delete. Call ab for one-shot control actions. Keep an in-process UIA path only for the tight polling loops (library tree navigation) where an ab round trip per step is too slow |+| Taskbar progress and overlay ticker | 625 | `desktop_taskbar {progress, overlay, flash}` | Already delegated. The ticker thread stays, the COM code goes |+| Toast, captions, demo panel | ~200 | `notify_user`, `desktop_caption`, `demo_panel` | Already delegated |+| File fetch of the demo board, PCM zips, design rules | ~150 | none for outbound HTTP; keep | Keep, in Rust with `ureq` (rustls, bundled roots, so the CA store problem disappears) |+| Process kill (`taskkill`) | 30 | `process_kill {pid, tree}` | Delegate |+| Owned-popup dialog scan | ~200 | `screenshot_window` surfaces owned popups; `desktop_ui_click {scope:"popups"}` | Partially delegate. Keep the KiCad title and body pattern tables (benign versus progress versus save prompt); use ab to find and click |+| Focus sentinel, event hook, park sweep, guardian, placement heal | 1,696 | `get_foreground`, `send_to_bottom` (atomic check-and-skip), `raise_window`, `set_window_state`, `set_window_bounds`, `list_monitors` | Not a duplicate today: ab has the primitives but not the policy loop (120 ms sentinel, WinEventHook bounce, once-per-window ledger, idle rule). See the ab asks below |++Estimated deletion once the delegations land: about 3,000 lines of window plumbing, before any Rust is written.++### Asks for the ab-core thread (things every bridge needs, not just KiCad)++1. `desktop_guard_background {pids, seconds}`: the focus guardian as an ab service. Fusion needs the same etiquette and today only KiCad has it.+2. `desktop_menu_invoke {hwnd, path:["View","3D Viewer"]}`: walk a native Win32 menu bar and post WM_COMMAND. This is our most reliable background trigger and it is generic to every wx and MFC app.+3. `desktop_post_key {hwnd, vk}` and `desktop_post_text {hwnd, text}`: PostMessage and WM_SETTEXT to one window, no focus. ab's `type` and `press_key` are SendInput and global.+4. `desktop_play_audio {path}`: for narrated tours.+5. `desktop_menu_ids` is not needed if 2 lands.++If ab declines any of these, the Rust binary carries them itself with the `windows` crate. They are small (a few hundred lines each).++## What KiCad gives us, now and next++Researched against KiCad 10.0.6 (released 2026-08-29, the version on both test boxes) and the 10.99 nightlies that become KiCad 11.++### IPC API in KiCad 10++Served by the PCB editor only. Schematic, symbol editor, footprint editor and project manager are not on the API in any 10.x release. The proto files carry `DocumentType` values for all of them, so the client side is ready when KiCad is.++| Need | KiCad 10.0.6 | KiCad 11 (10.99 today) |+|---|---|---|+| Open a board or project | No. Launch the exe with the path | `kicad-cli api-server` headless plus `OpenDocument` |+| Run DRC and read results | No. `kicad-cli pcb drc --format json` | Same (DRC settings get an API, running it does not yet) |+| Edit a footprint in the editor | No. Edit `.kicad_mod` on disk | `OpenLibraryItem` (footprint only) |+| Edit schematic symbols or wires | No | Read-only hierarchy and netlist |+| 3D viewer or render | No. `kicad-cli pcb render` for an offline image | Same |+| Run a named action | Yes, `RunAction`, marked unstable | Same |+| Install a library into the tables | No. Edit `fp-lib-table` and `sym-lib-table` | Same |+| Reload libraries | No dedicated call. `RunAction` on the refresh action is untested | Same |+| Board items, nets, zones, stackup, commits, undo, selection, save | Yes, 59 commands | Plus design rules, plot settings, page settings, ImportNetlist |++New since we started: 10.0.1 added connectivity queries and dimension items, 10.0.6 added `FlipItems` and a `parent` field on every board item. Our routing verbs pin kicad-python 0.8.0, which already covers these.++### kicad-cli in KiCad 10++Every export we use is there (gerbers, drill, step, glb, svg, pdf, pos, ipc2581, odb, render with `--variant` since 10.0.2). `sch export png` and `gerber convert png` are 11 only. There is no PCM or library-table subcommand in 10 or 11.++### PCM without the GUI++PCM has no CLI, but its on-disk contract is simple and stable: unpack the package archive under `${KICAD10_3RD_PARTY}/<plugins|footprints|symbols|3dmodels|colors>/<identifier_with_underscores>/`, add a row to `installed_packages.json` (or let PCM rebuild it from directory names on next start), and for libraries add the `PCM_<name>` rows to the lib tables yourself, honouring `pcm.lib_auto_add` and `pcm.lib_prefix` from `kicad.json`. Our `pcm_install` verb already does this. So yes, we have full PCM capability today for plugins and libraries, and the port keeps it byte for byte.++More important: PCM can distribute IPC plugins with `"runtime": "ipc"`, and `plugin.json` accepts `runtime.type: "exec"`. KiCad then launches the executable itself with `KICAD_API_SOCKET` and `KICAD_API_TOKEN` in the environment. That means the Rust binary can also be registered as a KiCad API plugin and started by KiCad, which replaces the SWIG plugin and its lazy 30 to 45 second bind on 10.0.5.++### SWIG is ending++The pcbnew SWIG bindings are deprecated since 9.0 and removed in KiCad 11. `plugin_payload/adom_bridge.py` (3,379 lines) runs on them. Everything it does for us has a non-SWIG path already in the codebase (Win32 menu walk for editor and viewer opening, IPC for board state, in-place tree refresh for rescan). The port does not carry the plugin.++## Front-end control policy for the port++The audit found 129 `time.sleep` calls, 28 in `open_footprint_editor.py` alone, and seven hardcoded menu ids kept as fallbacks. The port fixes the pattern, not the instances. Every window verb picks the first rung it can reach on this ladder and records which rung it used in the response (`mechanism: "ipc" | "cli" | "file" | "menu" | "uia" | "post" | "input"`):++1. **IPC API.** Anything the running PCB editor can do for us. Add `RunAction` for zoom-fit, refill, 3D viewer toggle and library refresh once the action names are verified on 10.0.6.+2. **kicad-cli.** Every export, check and render that does not need the window.+3. **File edit.** Libraries, tables, settings, project files, PCM.+4. **Native menu walk plus WM_COMMAND.** Background, no focus, no cursor, version-proof (ids resolved from the live menu bar). This is our best trigger for "open the Footprint Editor" and "open the 3D Viewer" and stays.+5. **UI Automation.** Invoke and ValuePattern by control name. Needs no focus, but wx activates its own top-level window whenever a control's state changes (measured in `handlers/foreground_guard.py`), so every UIA action must be paired with the guardian's once-per-window demote.+6. **PostMessage keys and text to one hwnd.** For the library tree filter and Enter. Chords are unreliable this way and are never attempted.+7. **SendInput.** Only with an explicit opt-in argument and a reason, and only while our window is measured foreground. Today that is the tour's orbit and pan, the opt-in cursor click, and Ctrl+Shift+E after `bring_to_user`.++Waits become event-driven: `wait_for_window` (ab) or a WinEvent hook for window creation, `SendMessageTimeout(WM_NULL)` for responsiveness, and the canvas-painted probe for "ready", with a single deadline per verb instead of nested sleep ladders.++## Dialog pre-emption++Today we seed `kicad_common.json` (so the first-run wizard never appears), force the software canvas after an OpenGL failure, strip our projects from `system.open_projects`, seed lib tables from KiCad's own template, and sweep transient dialogs after every verb with a screenshot of what was dismissed.++The port adds, at first-run seeding time only (never on a settings file the user already has):++| Setting | File | Effect |+|---|---|---|+| `do_not_show_again.zone_fill_warning`, `env_var_overwrite_warning`, `scaled_3d_models_warning`, `data_collection_prompt`, `update_check_prompt`, `migrate_wrl_prompt` | `kicad_common.json` | The six modal nags KiCad 10 can raise on a fresh box |+| `system.check_for_kicad_updates`, `pcm.check_for_updates` | `kicad.json` | No update toasts during automation. Off only on bridge-seeded configs; we do not change a user's choice |+| `system.never_show_rescue_dialog`, `appearance.show_illegal_symbol_lib_dialog`, `show_sexpr_file_convert_warning`, `show_sheet_filename_case_sensitivity_dialog` | `eeschema.json` | Schematic open without prompts |+| `api.enable_server` | `kicad_common.json` | On, so routing works without the restart dance |+| Stale `*.lck` for bridge-owned projects | project dir | No "already open" prompt after a crash |++Two prompts have no setting: "Save changes?" and "3D model not found". The port avoids the first with `SaveDocument` over IPC before any close (or the existing `discardChanges` contract) and the second with the existing `kicad_model_check` pre-flight before opening a footprint in 3D.++## Target architecture++```+kicad-bridge.exe  (spawn.kind "exe", ADOM_BIND_HOST, --port from ab)+  http      tiny_http or axum, serde_json          /status /command+  catalog   one table: verb, handler, risk, timeout, mechanism, describe entry+  detect    registry + install dirs + kicad-cli version, config seeding+  cli       kicad-cli runner, JSON report parsers (drc, erc, netlist, bom)+  files     s-expression reader/writer (own crate, adom-inc/kicad_lib, or kiutils_kicad),+            lib tables, kicad_common/kicad/eeschema/pcbnew settings, PCM layout+  ipc       kicad-ipc-rs (prost + nng), or our own prost bindings over nng-sys+  win       windows crate: process, EnumWindows, menu walk, PostMessage, WinEventHook,+            SendMessageTimeout, placement, DPI; uiautomation crate for UIA+  ab        typed client for the ab callback API (screenshots, taskbar, notify, ui_*)+  etiquette focus sentinel, once-per-window demote, owned-pid ledger, idle rule+  show      evidence capture (via ab) + canvas-painted probe + thumbnail+  demo      tour beats, narration, motion+  net       ureq with rustls: KiCad installer, Mesa fallback, wiki fetches+```++Crate choices, checked 2026-09-11:++| Need | Crate | State |+|---|---|---|+| KiCad IPC | `kicad-ipc-rs` 0.5.1 (MIT, prost 0.14, nng 1.0.1, 59 of 59 KiCad 10.0.1 commands, used by Konnect) or the official `kicad-api-rs` 0.1.0 (GPL-3, undocumented) | Use kicad-ipc-rs, vendor if needed. Windows is not on its CI, so we test it |+| nng transport | `nng` 1.0.1 (`nng-sys` builds NNG 1.4 from source, static) | Needs CMake and a C compiler at build time only |+| UIA | `uiautomation` 0.24.1 (2026-05) | Mature |+| Win32 | `windows` crate | Mature |+| Capture | none. ab does it | |+| KiCad files | `kiutils_kicad` 0.3.0 (lossless round trip for pcb, mod, sch, sym, lib tables, pro) or `adom-inc/kicad_lib` | Evaluate both against our parsers' test fixtures |+| glTF check | `gltf` | Mature. STEP stays a header sanity check (Rust STEP parsers are immature) |+| HTTP out | `ureq` with rustls | Mature |+| HTTP in | `tiny_http` (what hello-rust uses) | Mature |++Expected binary: 5 to 15 MB stripped with nng, prost and UIA. Build on winvm or cross-compile from the container with `cargo-xwin` (nng-sys needs clang). Static CRT with `+crt-static`.++## Phased plan++Each phase ships to insiders through the existing release script and is gated by the verb runner (`skills/kicad-bridge-test/run_verb_tests.py`) running against both boxes. The Python bridge keeps shipping until the Rust binary passes the same runner with equal or better numbers; then the manifest flips. Same verb names, same response shapes, same skills package.++| Phase | Scope | Verbs | Effort | Exit test |+|---|---|---|---|---|+| 0. Prune in Python (now) | Delete `launch_editor.ps1`, `tour/` (older standalone tour), unused `foreground_guard.py`; delegate capture, enumeration and taskkill to ab; add the do_not_show_again seeding; record `mechanism` on every window verb | 0 new | 1 week | Runner unchanged, zip smaller, no PowerShell left except uia.py |+| 1. Rust skeleton and headless verbs | HTTP, catalog, describe, status, readiness, detect, diagnostics, kicad-cli group, file group, PCM, model_check, upgrade, uninstall, settings, design rules, part projects | ~45 | 3 to 4 weeks | Runner parity on those verbs, both boxes, zero Python |+| 2. IPC verbs | The nine routing verbs on kicad-ipc-rs; routing demo passes; `routing_deps/` deleted | 9 | 2 weeks | `demo/routing/run_demo.py --expect-version` green on 10.0.6 |+| 3. Window verbs | launch, open_*, close_*, show_*, state, screenshot_all, send_key, click, dismiss_dialogs, window_info, place_footprint, software OpenGL | ~28 | 4 to 5 weeks | Runner parity plus the six-beat tour |+| 4. Etiquette | Sentinel, WinEvent hook, ledger, idle rule, placement heal, ported or moved into ab | 0 | 2 weeks | Foreground-steal test from the runner (`fg_before`, `foreground_notes`) at zero steals |+| 5. Demo tour | Beats, narration, motion, evidence | 1 | 2 weeks | Recorded tour on ConfRoomROG and winvm |+| 6. Plugin retirement and KiCad 11 | Drop `plugin_payload`, register the exe as an IPC plugin through PCM, test on 10.99 nightly | 0 | 2 weeks | Runner on 10.0.6 and on the nightly |++Total: roughly 16 to 19 weeks of one AI thread's time with human test time on the boxes, or half that with two threads splitting phases 1+2 and 3+4 after the skeleton lands. The Python line count suggests 25,000 to 30,000 lines of Rust; the window group shrinks the most because ab absorbs the plumbing.++## Risks, stated plainly++- **wx physics do not change with the language.** KiCad raises its own window on UI state changes. The guardian stays necessary; Rust only makes it cheaper and tighter.+- **KiCad renumbers menu ids and renames actions.** The live menu walk handles ids. `RunAction` names are documented as unstable, so every action name gets a probe at readiness time and a fallback rung.+- **IPC is one connection per app, synchronous on the UI thread.** A hung KiCad hangs the call. Every IPC call gets a deadline and the responsiveness probe first.+- **`api.enable_server` needs a KiCad restart** and a running KiCad rewrites the file on exit. The seeding-at-first-run path avoids this for new boxes; existing boxes keep the documented restart.+- **nng-sys is a C build.** It is the one non-Rust piece. If it fights us on cross-compile we build on winvm.+- **Single zip, one OS.** ab manifests have no per-platform assets, so the Rust bridge is Windows-only until per-platform manifests exist. macOS keeps the Python bridge (its window code is `open -a` and osascript, a fraction of the Windows surface).+- **KiCad 11 timing is unannounced.** The plan makes us independent of SWIG before it matters.++## Decisions for John++1. **Windows first, macOS stays on Python until per-platform manifests land.** Recommended yes.+2. **Move the focus guardian into ab** (ab-core thread owns it, every bridge benefits) or keep it in the KiCad binary. Recommended: propose it to ab-core now; port it into the binary in phase 4 either way so we are not blocked.+3. **Audio verb in ab** for narration, or WinRT MediaPlayer in the binary. Recommended: ask ab, fall back to WinRT.+4. **Parallel threads.** One thread does the whole port in about four months; two threads finish in about two and a half.+5. **Source hosting.** The Rust source goes on the same wiki page as the Python source today, with `target/` ignored so the 50 MB registry limit never bites.++## Related++- [How the bridge compares](comparison.md): the competitive audit this plan was written alongside.+- [Dashboard](dashboard.md): the dock card and the dashboard.+- Verb reference and the live routing contract: the main [README](../README.md) and [SKILL.md](../SKILL.md).