← Commit history
SKILL.md+1
@@ -99,6 +99,7 @@ If you pass a version that's not installed, the bridge returns a hint listing th | `kicad_close` | `close` | Close KiCad (all editors). From 0.9.347 an editor with unsaved work is NOT killed: the reply says errorCode unsaved_changes with the dialog text. `discardChanges:true` presses Discard for the caller; `force:true` is the only kill | optional `discardChanges`, `force` | | `kicad_window_info` | `window_info` | Enumerate open KiCad windows (HWND, title, bounds, editor type) |: | | `kicad_install_library` | `install_library` | Register a `.kicad_sym` + `.pretty/` pair in sym-lib-table + fp-lib-table | `libraryPath`, `libraryType`, `libraryName`, optional `kicadVersion` |+| `kicad_uninstall_library` | `uninstall_library` | Remove a library row from sym-lib-table / fp-lib-table (the inverse of install). `deleteFiles:true` also deletes the installed copy, only under `Documents/KiCad/<ver>/`; refuses `Adom` and KiCad's stock libraries | `libraryName`, optional `libraryType` (symbol/footprint/both), `deleteFiles`, `kicadVersion` | | `kicad_install_symbol` | `install_symbol` | Add a single symbol to an existing library | `fileName`, `fileContent`, optional `kicadVersion` | | `kicad_install_footprint` | `install_footprint` | Add a single footprint to an existing library | `library`, `footprint_path`, optional `kicadVersion` | | `kicad_run_drc` | `run_drc` | Run DRC on the current board, return violations | `filePath`, optional `kicadVersion` |
package.json+1−1
@@ -1,6 +1,6 @@ {   "slug": "kicad-bridge",-  "version": "1.0.145",+  "version": "1.0.146",   "type": "app",   "description": "Skills for your container so your AI knows how to drive the KiCad bridge, and how to contribute a fix back (kicad-bridge-contributing). The bridge runtime itself is the release zip; Adom Bridge loads that.",   "tags": [
page.json+36−5
@@ -4,7 +4,7 @@   "slug": "kicad-bridge",   "title": "KiCad - the KiCad Bridge",   "brief": "Reference implementation of the KiCad bridge: multi-instance Python server, forward path via kicad-cli, reverse path via in-process plugin. Most complex of the three bundled bridges.",-  "version": "1.0.111",+  "version": "1.0.146",   "tags": [     "kicad",     "pcb",@@ -53,7 +53,7 @@     "install_hint": "",     "version_cmd": ""   },-  "readme": "# Adom Desktop \u2014 KiCad Bridge\n\nA **reverse bridge** that lets Adom Desktop (AD) \u2014 and the AI driving it \u2014 control the user's own\nKiCad on Windows: open and drive every editor, install symbol/footprint libraries, place parts, run\nDRC/ERC, export manufacturing files, and screenshot any window back to the AI.\n\nKiCad is the user's **host app**. The bridge *detects* an existing KiCad and, if none is present,\n*installs* one for them \u2014 it never asks the user to download or click through anything by hand.\n\n- **Page / docs:** https://wiki.adom.inc/adom/adom-desktop-kicad-bridge\n- **Bridge SDK:** https://wiki.adom.inc/adom/adom-desktop-bridges\n- **Verb namespace:** `kicad_*` &nbsp;\u00b7&nbsp; **Status verb:** `kicad_bridge_status` &nbsp;\u00b7&nbsp; **Health:** `GET /status`\n\n> Every screenshot in this README was captured on **ADOMBASELINE**, a stock Hyper-V VM with **no\n> GPU**, driven end-to-end through the bridge \u2014 install \u2192 libraries \u2192 editors \u2192 2D \u2192 3D. If it\n> renders there, it renders on a real laptop.\n\n---\n\n## Demo \u2014 narrated live editor tour (real screen recording)\n\n[![KiCad bridge live demo](https://wiki.adom.inc/blob/app/adom-desktop-kicad-bridge/kicad-bridge-demo-poster.png)](https://wiki.adom.inc/blob/app/adom-desktop-kicad-bridge/kicad-bridge-demo.mp4)\n\n**\u25b6 [Watch the demo](https://wiki.adom.inc/blob/app/adom-desktop-kicad-bridge/kicad-bridge-demo.mp4)** (48s, \ud83d\udd0a narrated) \u2014 the bridge driving real KiCad on a Windows VM: **select** a footprint and **zoom** the copper in the PCB editor, **rotate** the assembled board in 3D, then tour the schematic, symbol, and footprint editors. Genuine screen recording of the live windows (zoom / select / 3D rotation), narrated section by section \u2014 not animated stills.\n\n\n---\n\n## The demo verb \u2014 `kicad_demo`\n\nOne verb that shows the whole bridge off, built for the AI that demos Adom Desktop\nduring Hydrogen Desktop's install. Six beats, in the order a hardware person thinks:\n\n| Beat | Shows |\n|---|---|\n| 1 | the **schematic symbol** in the user's own Symbol Editor |\n| 2 | the **footprint** for that same part |\n| 3 | that part in **3D** |\n| 4 | a **schematic** using it (U1 + two 10k resistors) |\n| 5 | the **2D board layout** |\n| 6 | the finished **board in 3D** |\n\n```bash\nadom-desktop kicad_demo '{}'                      # start: prepares, warms KiCad, opens beat 1\nadom-desktop kicad_demo '{\"step\":\"footprint\"}'    # ...then follow data.nextCall each time\nadom-desktop kicad_demo '{\"all\":true}'            # bulk (non-interactive; slower than one request budget)\nadom-desktop kicad_close '{\"force\":true}'         # tear down\n```\n\n**It narrates itself.** Every beat returns `say` (a line to speak), `pointOut`\n(what's actually on screen), `window` (match it in `kicad_screenshot_all`) and\n`nextCall`. One beat per call is the default precisely so the AI can talk, screenshot,\nthen move on.\n\n**It ships nothing.** The two demo parts, the schematic and the board are all\ngenerated in code, and the 3D bodies come from KiCad's *own* bundled\n`3dmodels/*.3dshapes` \u2014 so the runtime zip stays small and the 3D views are real.\nParts install into the user's real `Adom` library; the project lands in\n`Documents/adom-kicad-demo`.\n\n**No KiCad? It offers to install it.** `kicad_demo` returns an offer instead of an\nerror; `kicad_demo '{\"installKiCad\": true}'` silently installs the official build\n(per-user, no UAC) and then runs the tour. Watching the AI install your EDA tool is\nitself a good demo beat.\n\n**It never takes your screen.** Every window opens in the background and all input is\nwindow-targeted (UIA / `PostMessage`), so you can keep working while it runs.\n\n---\n\n## How it fits together\n\nThe bridge is a `spawn.kind: python` process AD launches on the user's machine (`entrypoint:\nserver.py`, `port: 0` \u2014 AD picks the port and passes `ADOM_BIND_HOST`). It speaks HTTP\n(`POST /command`, `GET /status`) and reaches KiCad through **four control surfaces**, picking the\nlightest one that can do the job.\n\n![Control surfaces](https://wiki.adom.inc/blob/app/adom-desktop-kicad-bridge/control-surfaces.svg)\n\n| # | Surface | Used for | Where |\n|---|---------|----------|-------|\n| 1 | **kicad-cli** (subprocess) | headless DRC/ERC, gerber/pdf/svg/step/bom export, format upgrade | `handlers/export.py`, `run_drc`, `run_erc`, `lint_*` |\n| 2 | **KiCad IPC (kipy)** | board/schematic introspection, confirmed footprint placement (KiCad 9+) | `handlers/place_footprint.py` |\n| 3 | **Embedded Python** | JSON-RPC *inside* each KiCad process, dispatched on its wx UI thread | `plugin_payload/adom_bridge.py`, `handlers/bridge_client.py` |\n| 4 | **Win32 / UIA / SendKeys** | open editors, screenshots, clicks/keys, dialog handling, window management | `handlers/kicad_ui.py`, `handlers/close_windows.py` |\n\n---\n\n## The window tour\n\nEverything below was opened and captured on the GPU-less VM. Sample data is the **RP2040 breakout**\ngenerated by `tour-pack-rp2040/` (an `AdomRP2040` symbol + `QFN-56_AdomRP2040` footprint + a board).\n\n### Schematic editor \u2014 `kicad_open_schematic`\n\nThe RP2040 breakout: the MCU (U1), USB-C, a 12 MHz crystal, decoupling, and mounting pins.\n\n![Schematic editor](https://wiki.adom.inc/blob/app/adom-desktop-kicad-bridge/schematic-editor.png)\n\n### Symbol editor \u2014 `kicad_open_symbol_editor`\n\nOpens straight to a symbol (`kicad_install_symbol` puts it in a user library first).\n\n![Symbol editor](https://wiki.adom.inc/blob/app/adom-desktop-kicad-bridge/symbol-editor.png)\n\n### Footprint editor \u2014 `kicad_open_footprint_editor`\n\n`{\"footprintName\":\"QFN-56_AdomRP2040\",\"library\":\"AdomRP2040\"}` loads the part directly \u2014 56 pins +\nthermal pad, 7\u00d77 mm, 0.4 mm pitch, courtyard and silkscreen.\n\n![Footprint editor](https://wiki.adom.inc/blob/app/adom-desktop-kicad-bridge/footprint-editor.png)\n\n### PCB editor (2D) \u2014 `kicad_open_board`\n\nThe routed breakout \u2014 copper, silkscreen, the QFN-56 land pattern, mounting holes.\n\n![PCB editor 2D](https://wiki.adom.inc/blob/app/adom-desktop-kicad-bridge/pcb-editor-2d.png)\n\n### 3D viewer \u2014 `kicad_open_3d_viewer {\"editor\":\"pcb\"}`\n\nThe full board in 3D \u2014 board body, the USB-C connector's 3D model, the QFN chip body, SMD parts,\nplated through-holes. **Rendered on the CPU via the software-OpenGL fallback (below); reload 1.7 s.**\n\n![3D viewer](https://wiki.adom.inc/blob/app/adom-desktop-kicad-bridge/3d-viewer.png)\n\n---\n\n## Install & upgrade \u2014 zero manual steps\n\nThe bridge never tells the user to go download KiCad. `kicad_upgrade` fetches the official installer\nand runs it silently, picking the scope automatically:\n\n- **Elevated AD** \u2192 `/allusers /S` (system-wide, `%ProgramFiles%\\KiCad`).\n- **Non-elevated AD** \u2192 `/currentuser /S` (`%LocalAppData%\\Programs\\KiCad`, **no UAC prompt**).\n\n`kicad_readiness` reports whether KiCad is installed and ready without side effects; the AI routes on\nit before offering to install. Hard-won install details (all handled for you):\n\n- KiCad 10's NsisMultiUser installer **requires** a scope flag \u2014 bare `/S` errors `rc=666660`.\n- AD's portable Python has **no CA bundle**; the bridge ships `certs/cacert.pem` and uses it for TLS.\n- Downloads are size-checked against `Content-Length` (a truncated installer otherwise fails at NSIS).\n- `%APPDATA%/kicad/<ver>/` lib tables don't exist until first launch \u2014 the bridge **bootstraps** them\n  so `install_library`/`install_footprint` work on a never-opened KiCad.\n- `kicad_upgrade {\"diagnoseOnly\":true}` reports token-elevation type + `EnableLUA` without installing.\n\n---\n\n## Dialogs & error handling \u2014 the bridge clears the pointless ones\n\nKiCad throws modal dialogs that stall automation. The bridge **scans every window owned by a running\nKiCad process** (by PID \u2014 reliable, unlike title matching), auto-expires the benign ones, screenshots\nwhat it dismissed, and returns a hint so the AI can decide what (if anything) to tell the user.\n\nAuto-expired benign dialogs include:\n\n- **\"Could not use OpenGL / falling back to software rendering\"** (GPU-less hosts).\n- **\"Welcome to KiCad \u2014 starting for the first time\"** first-run wizard (dismissing accepts defaults).\n- **\"This file was created by an older version of KiCad\"** conversion notice.\n\n![First-run wizard, auto-dismissed](https://wiki.adom.inc/blob/app/adom-desktop-kicad-bridge/dialog-firstrun-wizard.png)\n\nVerbs:\n\n- `kicad_window_info` \u2014 lists windows and **self-heals** (auto-expires benign dialogs) by default.\n- `kicad_dismiss_dialogs {\"all\":true}` \u2014 clear everything blocking; `{\"screenshot\":true}` returns\n  images of each; `{\"forceSoftwareCanvas\":true}` persists Cairo canvas; `{\"debug\":true}` dumps the\n  raw PID-based scan.\n- `kicad_screenshot_all` \u2014 one call returns **every** open KiCad window, so the AI can spot an error\n  dialog it didn't expect and read the message.\n\n---\n\n## Software-OpenGL fallback (last resort)\n\n`kicad_enable_software_opengl` deploys Mesa's `llvmpipe` (a CPU OpenGL rasterizer) into KiCad's `bin`\nso a box with **no usable GPU** \u2014 Hyper-V, RDP, headless CI \u2014 can still render the editors and the 3D\nviewer. This is how every 3D shot above exists.\n\n> \u26a0\ufe0f It renders on the CPU and is **slow**. It is a worst-case fallback only \u2014 a real GPU (or GPU-P /\n> DDA passthrough) is vastly better. The bridge keeps it so a GPU-less box isn't a dead end; it is\n> never suggested proactively.\n\n---\n\n## Verb reference\n\nAll 41 verbs (prefix `kicad_`). Call `kicad_describe` for the live catalog with per-verb hints,\nrelated verbs, and pitfalls.\n\n**Windows & UI** \u2014 `open_board`, `open_schematic`, `open_symbol_editor`, `open_footprint_editor`,\n`open_3d_viewer`, `open_editors`, `close_symbol_editor`, `close_footprint_editor`, `close_3d_viewer`,\n`close`, `window_info`, `dismiss_dialogs`, `screenshot_all`, `send_key`, `click`, `fix_keyboard`\n\n**Libraries & parts** \u2014 `install_library`, `install_symbol`, `install_footprint`, `install_plugin`,\n`place_footprint`, `adom_library_status`\n\n**Checks & export** \u2014 `run_drc`, `run_erc`, `lint_board`, `lint_schematic`, `lint_library`,\n`format_upgrade`, `export_gerber`, `export_pdf`, `export_svg`, `export_step`, `export_bom_csv`\n\n**Detect, install & meta** \u2014 `list_versions`, `readiness`, `describe`, `enable_software_opengl`,\n`check_for_updates`, `upgrade`, `bridge_status`, `bridge_call`\n\n---\n\n## Running / dependencies\n\nAD provisions everything; there is nothing to install by hand.\n\n- **Python** \u2265 3.11 (AD provisions it) \u2014 stdlib only, plus the bundled `certs/cacert.pem`.\n- **KiCad** \u2265 7.0 (host app; `kicad_upgrade` installs it if absent).\n- **OS:** Windows (macOS/Linux detection stubs exist; the GUI surfaces are Windows-first).\n\nThe bridge binds `ADOM_BIND_HOST` on an AD-assigned port \u2014 never `0.0.0.0`. Auto-updates via\n`updateManifestUrl` in `bridge.json`.\n\n---\n\n*Developer & publish notes live in `dev-skills/` and `publish-skills/` (source-only, never shipped to\na user install).*\n",+  "readme": "# Adom Desktop — KiCad Bridge\n\nA **reverse bridge** that lets Adom Desktop (AD) — and the AI driving it — control the user's own\nKiCad on Windows: open and drive every editor, install symbol/footprint libraries, place parts, run\nDRC/ERC, export manufacturing files, and screenshot any window back to the AI.\n\nKiCad is the user's **host app**. The bridge *detects* an existing KiCad and, if none is present,\n*installs* one for them — it never asks the user to download or click through anything by hand.\n\n- **Page / docs:** https://wiki.adom.inc/adom/adom-desktop-kicad-bridge\n- **Bridge SDK:** https://wiki.adom.inc/adom/adom-desktop-bridges\n- **Verb namespace:** `kicad_*` &nbsp;·&nbsp; **Status verb:** `kicad_bridge_status` &nbsp;·&nbsp; **Health:** `GET /status`\n\n> Every screenshot in this README was captured on **ADOMBASELINE**, a stock Hyper-V VM with **no\n> GPU**, driven end-to-end through the bridge — install → libraries → editors → 2D → 3D. If it\n> renders there, it renders on a real laptop.\n\n---\n\n## Demo — narrated live editor tour (real screen recording)\n\n[![KiCad bridge live demo](https://wiki.adom.inc/blob/app/adom-desktop-kicad-bridge/kicad-bridge-demo-poster.png)](https://wiki.adom.inc/blob/app/adom-desktop-kicad-bridge/kicad-bridge-demo.mp4)\n\n**▶ [Watch the demo](https://wiki.adom.inc/blob/app/adom-desktop-kicad-bridge/kicad-bridge-demo.mp4)** (48s, 🔊 narrated) — the bridge driving real KiCad on a Windows VM: **select** a footprint and **zoom** the copper in the PCB editor, **rotate** the assembled board in 3D, then tour the schematic, symbol, and footprint editors. Genuine screen recording of the live windows (zoom / select / 3D rotation), narrated section by section — not animated stills.\n\n\n---\n\n## The demo verb — `kicad_demo`\n\nOne verb that shows the whole bridge off, built for the AI that demos Adom Desktop\nduring Hydrogen Desktop's install. Six beats, in the order a hardware person thinks:\n\n| Beat | Shows |\n|---|---|\n| 1 | the **schematic symbol** in the user's own Symbol Editor |\n| 2 | the **footprint** for that same part |\n| 3 | that part in **3D** |\n| 4 | a **schematic** using it (U1 + two 10k resistors) |\n| 5 | the **2D board layout** |\n| 6 | the finished **board in 3D** |\n\n```bash\nadom-desktop kicad_demo '{}'                      # start: prepares, warms KiCad, opens beat 1\nadom-desktop kicad_demo '{\"step\":\"footprint\"}'    # ...then follow data.nextCall each time\nadom-desktop kicad_demo '{\"all\":true}'            # bulk (non-interactive; slower than one request budget)\nadom-desktop kicad_close '{\"force\":true}'         # tear down\n```\n\n**It narrates itself.** Every beat returns `say` (a line to speak), `pointOut`\n(what's actually on screen), `window` (match it in `kicad_screenshot_all`) and\n`nextCall`. One beat per call is the default precisely so the AI can talk, screenshot,\nthen move on.\n\n**It ships nothing.** The two demo parts, the schematic and the board are all\ngenerated in code, and the 3D bodies come from KiCad's *own* bundled\n`3dmodels/*.3dshapes` — so the runtime zip stays small and the 3D views are real.\nParts install into the user's real `Adom` library; the project lands in\n`Documents/adom-kicad-demo`.\n\n**No KiCad? It offers to install it.** `kicad_demo` returns an offer instead of an\nerror; `kicad_demo '{\"installKiCad\": true}'` silently installs the official build\n(per-user, no UAC) and then runs the tour. Watching the AI install your EDA tool is\nitself a good demo beat.\n\n**It never takes your screen.** Every window opens in the background and all input is\nwindow-targeted (UIA / `PostMessage`), so you can keep working while it runs.\n\n---\n\n## How it fits together\n\nThe bridge is a `spawn.kind: python` process AD launches on the user's machine (`entrypoint:\nserver.py`, `port: 0` — AD picks the port and passes `ADOM_BIND_HOST`). It speaks HTTP\n(`POST /command`, `GET /status`) and reaches KiCad through **four control surfaces**, picking the\nlightest one that can do the job.\n\n![Control surfaces](https://wiki.adom.inc/blob/app/adom-desktop-kicad-bridge/control-surfaces.svg)\n\n| # | Surface | Used for | Where |\n|---|---------|----------|-------|\n| 1 | **kicad-cli** (subprocess) | headless DRC/ERC, gerber/pdf/svg/step/bom export, format upgrade | `handlers/export.py`, `run_drc`, `run_erc`, `lint_*` |\n| 2 | **KiCad IPC (kipy)** | board/schematic introspection, confirmed footprint placement (KiCad 9+) | `handlers/place_footprint.py` |\n| 3 | **Embedded Python** | JSON-RPC *inside* each KiCad process, dispatched on its wx UI thread | `plugin_payload/adom_bridge.py`, `handlers/bridge_client.py` |\n| 4 | **Win32 / UIA / SendKeys** | open editors, screenshots, clicks/keys, dialog handling, window management | `handlers/kicad_ui.py`, `handlers/close_windows.py` |\n\n---\n\n## The window tour\n\nEverything below was opened and captured on the GPU-less VM. Sample data is the **RP2040 breakout**\ngenerated by `tour-pack-rp2040/` (an `AdomRP2040` symbol + `QFN-56_AdomRP2040` footprint + a board).\n\n### Schematic editor — `kicad_open_schematic`\n\nThe RP2040 breakout: the MCU (U1), USB-C, a 12 MHz crystal, decoupling, and mounting pins.\n\n![Schematic editor](https://wiki.adom.inc/blob/app/adom-desktop-kicad-bridge/schematic-editor.png)\n\n### Symbol editor — `kicad_open_symbol_editor`\n\nOpens straight to a symbol (`kicad_install_symbol` puts it in a user library first).\n\n![Symbol editor](https://wiki.adom.inc/blob/app/adom-desktop-kicad-bridge/symbol-editor.png)\n\n### Footprint editor — `kicad_open_footprint_editor`\n\n`{\"footprintName\":\"QFN-56_AdomRP2040\",\"library\":\"AdomRP2040\"}` loads the part directly — 56 pins +\nthermal pad, 7×7 mm, 0.4 mm pitch, courtyard and silkscreen.\n\n![Footprint editor](https://wiki.adom.inc/blob/app/adom-desktop-kicad-bridge/footprint-editor.png)\n\n### PCB editor (2D) — `kicad_open_board`\n\nThe routed breakout — copper, silkscreen, the QFN-56 land pattern, mounting holes.\n\n![PCB editor 2D](https://wiki.adom.inc/blob/app/adom-desktop-kicad-bridge/pcb-editor-2d.png)\n\n### 3D viewer — `kicad_open_3d_viewer {\"editor\":\"pcb\"}`\n\nThe full board in 3D — board body, the USB-C connector's 3D model, the QFN chip body, SMD parts,\nplated through-holes. **Rendered on the CPU via the software-OpenGL fallback (below); reload 1.7 s.**\n\n![3D viewer](https://wiki.adom.inc/blob/app/adom-desktop-kicad-bridge/3d-viewer.png)\n\n---\n\n## Install & upgrade — zero manual steps\n\nThe bridge never tells the user to go download KiCad. `kicad_upgrade` fetches the official installer\nand runs it silently, picking the scope automatically:\n\n- **Elevated AD** → `/allusers /S` (system-wide, `%ProgramFiles%\\KiCad`).\n- **Non-elevated AD** → `/currentuser /S` (`%LocalAppData%\\Programs\\KiCad`, **no UAC prompt**).\n\n`kicad_readiness` reports whether KiCad is installed and ready without side effects; the AI routes on\nit before offering to install. Hard-won install details (all handled for you):\n\n- KiCad 10's NsisMultiUser installer **requires** a scope flag — bare `/S` errors `rc=666660`.\n- AD's portable Python has **no CA bundle**; the bridge ships `certs/cacert.pem` and uses it for TLS.\n- Downloads are size-checked against `Content-Length` (a truncated installer otherwise fails at NSIS).\n- `%APPDATA%/kicad/<ver>/` lib tables don't exist until first launch — the bridge **bootstraps** them\n  so `install_library`/`install_footprint` work on a never-opened KiCad.\n- `kicad_upgrade {\"diagnoseOnly\":true}` reports token-elevation type + `EnableLUA` without installing.\n\n---\n\n## Dialogs & error handling — the bridge clears the pointless ones\n\nKiCad throws modal dialogs that stall automation. The bridge **scans every window owned by a running\nKiCad process** (by PID — reliable, unlike title matching), auto-expires the benign ones, screenshots\nwhat it dismissed, and returns a hint so the AI can decide what (if anything) to tell the user.\n\nAuto-expired benign dialogs include:\n\n- **\"Could not use OpenGL / falling back to software rendering\"** (GPU-less hosts).\n- **\"Welcome to KiCad — starting for the first time\"** first-run wizard (dismissing accepts defaults).\n- **\"This file was created by an older version of KiCad\"** conversion notice.\n\n![First-run wizard, auto-dismissed](https://wiki.adom.inc/blob/app/adom-desktop-kicad-bridge/dialog-firstrun-wizard.png)\n\nVerbs:\n\n- `kicad_window_info` — lists windows and **self-heals** (auto-expires benign dialogs) by default.\n- `kicad_dismiss_dialogs {\"all\":true}` — clear everything blocking; `{\"screenshot\":true}` returns\n  images of each; `{\"forceSoftwareCanvas\":true}` persists Cairo canvas; `{\"debug\":true}` dumps the\n  raw PID-based scan.\n- `kicad_screenshot_all` — one call returns **every** open KiCad window, so the AI can spot an error\n  dialog it didn't expect and read the message.\n\n---\n\n## Software-OpenGL fallback (last resort)\n\n`kicad_enable_software_opengl` deploys Mesa's `llvmpipe` (a CPU OpenGL rasterizer) into KiCad's `bin`\nso a box with **no usable GPU** — Hyper-V, RDP, headless CI — can still render the editors and the 3D\nviewer. This is how every 3D shot above exists.\n\n> ⚠️ It renders on the CPU and is **slow**. It is a worst-case fallback only — a real GPU (or GPU-P /\n> DDA passthrough) is vastly better. The bridge keeps it so a GPU-less box isn't a dead end; it is\n> never suggested proactively.\n\n---\n\n## Verb reference\n\nAll 41 verbs (prefix `kicad_`). Call `kicad_describe` for the live catalog with per-verb hints,\nrelated verbs, and pitfalls.\n\n**Windows & UI** — `open_board`, `open_schematic`, `open_symbol_editor`, `open_footprint_editor`,\n`open_3d_viewer`, `open_editors`, `close_symbol_editor`, `close_footprint_editor`, `close_3d_viewer`,\n`close`, `window_info`, `dismiss_dialogs`, `screenshot_all`, `send_key`, `click`, `fix_keyboard`\n\n**Libraries & parts** — `install_library`, `install_symbol`, `install_footprint`, `install_plugin`,\n`place_footprint`, `adom_library_status`\n\n**Checks & export** — `run_drc`, `run_erc`, `lint_board`, `lint_schematic`, `lint_library`,\n`format_upgrade`, `export_gerber`, `export_pdf`, `export_svg`, `export_step`, `export_bom_csv`\n\n**Detect, install & meta** — `list_versions`, `readiness`, `describe`, `enable_software_opengl`,\n`check_for_updates`, `upgrade`, `bridge_status`, `bridge_call`\n\n---\n\n## Running / dependencies\n\nAD provisions everything; there is nothing to install by hand.\n\n- **Python** ≥ 3.11 (AD provisions it) — stdlib only, plus the bundled `certs/cacert.pem`.\n- **KiCad** ≥ 7.0 (host app; `kicad_upgrade` installs it if absent).\n- **OS:** Windows (macOS/Linux detection stubs exist; the GUI surfaces are Windows-first).\n\nThe bridge binds `ADOM_BIND_HOST` on an AD-assigned port — never `0.0.0.0`. Auto-updates via\n`updateManifestUrl` in `bridge.json`.\n\n---\n\n*Developer & publish notes live in `dev-skills/` and `publish-skills/` (source-only, never shipped to\na user install).*\n",   "author": {     "name": "John Lauer",     "email": "[email protected]"@@ -71,7 +71,7 @@   "skills": [],   "author_name": "John Lauer",   "source_visibility": "public",-  "description": "Your real KiCad, driven by AI in the background: a native Rust bridge (Windows) with 110+ kicad_* verbs for editors, libraries, placement, routing, pours, DRC, exports and screenshots. This page's repo is the full source; fixes come back as wiki PRs (skill kicad-bridge-contributing).",+  "description": "Skills for your container so your AI knows how to drive the KiCad bridge, and how to contribute a fix back (kicad-bridge-contributing). The bridge runtime itself is the release zip; Adom Bridge loads that.",   "dependencies": {     "adom/adom-bridge": "^2.0.3"   },@@ -87,9 +87,15 @@     "uninstall.sh",     "skills/kicad-interaction/SKILL.md",     "skills/kicad-3d-models/SKILL.md",+    "skills/kicad-autorouting/SKILL.md",+    "skills/kicad-place-route-loop/SKILL.md",+    "skills/kicad-copper-pours/SKILL.md",     "skills/kicad-tour/SKILL.md",     "skills/kicad-tour/tour_runner.py",     "skills/kicad-web-control/SKILL.md",+    "skills/kicad-uia/catalog.json",+    "skills/kicad-uia/SKILL.md",+    "skills/kicad-bridge-contributing/SKILL.md",     "skills/kicad-bridge-dev/SKILL.md",     "skills/kicad-bridge-publish/SKILL.md",     "skills/kicad-bridge-hero/SKILL.md",@@ -127,5 +133,30 @@   "binary_name": "adom-bridge-kicad",   "authors": null,   "author_handle": "john",-  "authors_json": null-}+  "authors_json": null,+  "agent_permissions": {+    "allow_bash": [+      "adom-desktop-kicad-bridge"+    ],+    "allow": [+      "adom-desktop-kicad-bridge status, readiness, describe, diagnostics, window_info, state and open_editors are read-only queries against KiCad and the bridge; they change nothing.",+      "adom-desktop-kicad-bridge list_versions, list_footprints, list_symbols, list_design_rules and adom_library_status read library tables and files; they change nothing.",+      "adom-desktop-kicad-bridge plugin_diagnose, verb_times, progress, errors, log_tail, get_settings and check_for_updates read bridge logs and settings; they change nothing.",+      "adom-desktop-kicad-bridge screenshot_all captures KiCad windows to images; it changes nothing in KiCad.",+      "adom-desktop-kicad-bridge extract_netlist, trace_net, find_connections and analyze_connections read the open design; they change nothing.",+      "adom-desktop-kicad-bridge lint_board, lint_schematic, lint_library, run_drc and run_erc run KiCad's own checks and produce reports; they change nothing."+    ],+    "soft_deny": [+      "adom-desktop-kicad-bridge install_library, install_library_bundle, install_symbol, install_footprint, pcm_install and pcm_uninstall write to the user's KiCad libraries.",+      "adom-desktop-kicad-bridge adom_library_heal, set_design_rules, format_upgrade and set_settings rewrite library files, rules or settings.",+      "adom-desktop-kicad-bridge launch, close, close_symbol_editor, close_footprint_editor, close_3d_viewer and dismiss_dialogs start or stop KiCad windows.",+      "adom-desktop-kicad-bridge uninstall, install_plugin, upgrade and enable_software_opengl reconfigure the user's KiCad or the bridge.",+      "adom-desktop-kicad-bridge export_gerber, export_gerbers, export_pdf, export_svg, export_step, export_molecule, export_bom_csv and export_part write files.",+      "adom-desktop-kicad-bridge make_part_project and place_footprint edit or create designs; demo, send_key and click drive KiCad's windows and inject input."+    ],+    "environment": [+      "adom-desktop-kicad-bridge is the KiCad Bridge; every kicad verb also passes Adom Bridge's human-approval gate on the user's desktop (caller identity, per-call reason, Activity Log).",+      "adom-desktop-kicad-bridge container approval is the first of two gates; the desktop gate is the second."+    ]+  }+}\ No newline at end of file
skills/kicad-bridge-test/SKILL.md+17−1
@@ -1,7 +1,7 @@ --- name: kicad-bridge-test user-invocable: false-description: DEVELOPER-only skill (user-invocable:false). The standard end-to-end verb test for the KiCad bridge - one runner that exercises EVERY kicad_* verb in the live catalog (117 as of 1.0.34) against a real Windows box with real sample files (the rp2040 tour pack), the way an actual user's AI drives them. Coverage-enforced: a new verb without a test turns the run red. Run it daily pre-release, after every runtime publish, and after any Adom Bridge (ab) core update. Trigger words - test the kicad bridge, verb test, daily test, test all verbs, regression test kicad, verb coverage, run_verb_tests, pre-release check, are any verbs failing.+description: DEVELOPER-only skill (user-invocable:false). The standard end-to-end verb test for the KiCad bridge - one runner that exercises EVERY kicad_* verb in the live catalog (118 as of 1.0.37) against a real Windows box with real sample files (the rp2040 tour pack), the way an actual user's AI drives them. Coverage-enforced: a new verb without a test turns the run red. Run it daily pre-release, after every runtime publish, and after any Adom Bridge (ab) core update. Trigger words - test the kicad bridge, verb test, daily test, test all verbs, regression test kicad, verb coverage, run_verb_tests, pre-release check, are any verbs failing. ---  # kicad-bridge-test@@ -116,6 +116,22 @@ Manual driving unchanged: run the one command, read `report.md`.   matrix entry or a justified skip; that is the contract.  +## Runner changes, 2026-09-20 evening (1.0.35 to 1.0.37, the from-scratch VM)++- **118 verbs, one stated skip** (`enable_software_opengl`). `install_library_bundle` is a real test now: a generated+  two-file bundle is installed, then removed with `kicad_uninstall_library {deleteFiles:true}` whether or not the+  install passed. `uninstall_library` (PR #20) removes the `AdomVerbTest` scratch library in phase 4.+- **A blank box needs two things before the battery.** File pushes are human-gated on a fresh Adom Bridge:+  `request_shell_approval {wait:true, timeoutSec:600}` raises the prompt and blocks until the user clicks. A VM with+  no GPU needs `kicad_enable_software_opengl` once, or every 3D frame is black.+- **What only a from-scratch box found** (winvm, KiCad 10.0.6, all fixed by 1.0.37): first-run seeding skipped the+  config `kicad-cli` had just written; a fresh KiCad 10 keeps its stock libraries in ONE nested row of type `Table`,+  which the bridge did not follow; an all-users install puts its shortcuts under ProgramData; tree navigation gave up+  while a slow editor was still loading libraries; rescan_libraries lacked the open verbs' foreground guard. Upgraded+  boxes (ConfRoomROG, arav-rog, AdomLapper) show none of these. Run the battery on a blank VM before a promotion.+- `send_files` will not create a folder whose name ends in `.pretty` (it reads the dest as a file). Install a footprint+  library from a single `.kicad_mod` instead; the verb accepts both.+ ## Runner changes, 2026-09-20 (full battery before the 1.0.34 promotion)  - **All 117 live verbs have a real test.** Two stated skips remain: `enable_software_opengl` (writes into KiCad's
skills/kicad-bridge-test/run_verb_tests.py+23−3
@@ -225,6 +225,8 @@ def matrix(w: dict) -> dict:         "install_symbol":    dict(phase=4, args={"__special": "install_symbol"}, timeout=160),         "install_footprint": dict(phase=4, args={"__special": "install_footprint"}, timeout=160),         "install_plugin":    dict(phase=4, args={}, timeout=160, note="idempotent payload re-deploy"),+        "uninstall_library": dict(phase=4, args={"libraryName": "AdomVerbTest", "deleteFiles": True}, timeout=60,+                                  note="removes the scratch library install_library registered above, so daily runs stop piling it up"),         "place_footprint":   dict(phase=4, args={"__special": "place_footprint"}, timeout=220),         "pcm_add_repository": dict(phase=4, args={"url": PCM_REPO_URL}, check="repo_added", timeout=90,                                   note="a REAL add of the sample repository (docs/pcm.md) into kicad.json, backup kept; "@@ -256,9 +258,9 @@ def matrix(w: dict) -> dict:             "menu_items", "3d_view", "refresh_board_views")},         # ---- phase 6.6: offline copper editing on a second copy that no editor has open         **{verb: dict(phase=6.6, live=True) for verb in ("add_track", "add_via", "route")},-        "install_library_bundle": dict(skip="needs a Cloud Library bundle zip staged on the box; covered by the "-                                            "install_library/install_symbol/install_footprint trio it wraps; "-                                            "and the bridge has no verb that unregisters a whole library, so a test install would stay on the box"),+        "install_library_bundle": dict(phase=4, args={"__special": "install_bundle"}, timeout=200,+                                  note="a generated two-file bundle (AdomVerbBundle: one symbol, one footprint), installed "+                                       "for real, then removed again with kicad_uninstall_library {deleteFiles:true}"),         # ---- phase 6.7: a REAL install of this page's tiny sample package, then its removal (KiCad closed)         "pcm_install":       dict(phase=6.7, live=True),         "pcm_uninstall":     dict(phase=6.7, live=True),@@ -276,6 +278,7 @@ SPECIALS_DOC = """Specials are composed calls the runner fills at runtime:   install_library    -> installs the tour pack's AdomRP2040 lib dir if present, else a generated 1-symbol lib   install_symbol     -> installs a generated test symbol ADOM_VERBTEST into the Adom lib   install_footprint  -> installs a generated 2-pad test footprint ADOM_VERBTEST into Adom.pretty+  install_bundle     -> installs a generated AdomVerbBundle.zip (one symbol, one footprint), then uninstalls it with deleteFiles   place_footprint    -> places Adom:ADOM_VERBTEST on a scratch copy of the template board   pcm_remove_repository -> removes the sample PCM repository row only if pcm_add_repository added it this run   move_footprint_dry -> dryRun move of the first footprint placement_state listed, to its own position, with that read's revision@@ -416,6 +419,13 @@ def main():     tl = Path(_tf.gettempdir()) / "AdomVerbTest.kicad_sym"     tl.write_text(SYMBOL_LIB_WRAP)     ab(a.target, "send_files", {"filePaths": [str(tl)], "dest": base}, timeout=120)+    # a Cloud-Library-shaped bundle for install_library_bundle: <Lib>.kicad_sym + <Lib>.pretty/<fp>.kicad_mod+    import zipfile as _zf+    bz = Path(_tf.gettempdir()) / "AdomVerbBundle.zip"+    with _zf.ZipFile(bz, "w", _zf.ZIP_DEFLATED) as z:+        z.writestr("AdomVerbBundle.kicad_sym", SYMBOL_LIB_WRAP)+        z.writestr("AdomVerbBundle.pretty/ADOM_VERBTEST.kicad_mod", TEST_FOOTPRINT)+    ab(a.target, "send_files", {"filePaths": [str(bz)], "dest": base}, timeout=120)      fg_violations = [] @@ -578,6 +588,8 @@ def main():             # which an open KiCad holds locked (WinError 32, run #2)             args = {"libraryPath": w["templib"], "libraryName": "AdomVerbTest",                     "description": "daily verb test scratch library"}+        elif special == "install_bundle":+            args = {"zipPath": base + "/AdomVerbBundle.zip", "libraryName": "AdomVerbBundle"}         elif special == "place_footprint":             import base64 as _b64             args = {"fileName": "ADOM_VERBTEST.kicad_mod",@@ -610,6 +622,14 @@ def main():                          # #85: the 400-char head hid errors behind long hints; keep the whole reply.                          "response": r}         print(f"  kicad_{verb:24} {'PASS' if passed else 'FAIL'}")+        if special == "install_bundle":+            # leave nothing behind: the bundle library comes out again whether or not the install passed+            cr = ab(a.target, "kicad_uninstall_library", {"libraryName": "AdomVerbBundle", "deleteFiles": True}, timeout=90)+            results[verb]["cleanup"] = {k: cr.get(k) for k in ("success", "errorCode", "removed", "filesDeleted")}+            if passed and not ok(cr):+                results[verb]["result"] = "FAIL"+                results[verb]["reason"] = f"installed, but kicad_uninstall_library could not remove it again: {cr.get('errorCode') or cr.get('error')}"+                print(f"    !! bundle cleanup failed: {json.dumps(cr)[:200]}")      PHASE3_ORDER = ["launch", "show_project", "open_board", "open_schematic", "open_symbol_editor",                     "show_schematic", "show_2d_board", "show_symbol", "show_footprint",