app
KiCad - the KiCad Bridge
Public Made by Adomby adom
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.
← Commit history
Publish 1.0.5
4 files changed
+114−163
SKILL.md+110−159@@ -1,193 +1,144 @@-name: adom-desktop-kicad-bridge-description: KiCad bridge for Adom Desktop — reference + verbs.--# Reference bridge: KiCad - -## Source code + contributing (2026-05) - -The KiCad bridge moved out of `adom-inc/adom-desktop`'s monorepo into its own dedicated repo so the community can extend it without coordinating with Adom Desktop's release cycle. - -### Where the source lives - -The canonical repo is **[`adom-inc/adom-bridge-kicad`](https://github.com/adom-inc/adom-bridge-kicad)** on GitHub. It's private today and will go public after a review pass. - -In the meantime, the full source — code, history, contributing guide, license — is **mirrored on this wiki page**: - -| Download | What it is | How to use | -|---|---|---| -| [`adom-bridge-kicad-source.tar.gz`](https://wiki-ufypy5dpx93o.adom.cloud/static/apps/adom-desktop-kicad-bridge/adom-bridge-kicad-source.tar.gz) | Clean source tree, no `.git` directory. ~165 KB. | `tar xzf adom-bridge-kicad-source.tar.gz && cd adom-bridge-kicad/` | -| [`adom-bridge-kicad.bundle`](https://wiki-ufypy5dpx93o.adom.cloud/static/apps/adom-desktop-kicad-bridge/adom-bridge-kicad.bundle) | Git bundle with full commit history. ~240 KB. | `git clone https://wiki-ufypy5dpx93o.adom.cloud/static/apps/adom-desktop-kicad-bridge/adom-bridge-kicad.bundle adom-bridge-kicad && cd adom-bridge-kicad && git log` | - -No GitHub account needed to download either — both URLs are public. +--- +name: adom-desktop-kicad +public: true +description: "Launch and drive KiCad on the user's laptop (KiCad 7/8/9/10 supported, multi-version side-by-side) from this container via the adom-desktop CLI. Open schematics/boards/symbols/footprints, run DRC, install sym-lib-table / fp-lib-table libraries, show the 3D viewer, capture KiCad window screenshots, send keyboard shortcuts and click coordinates. Trigger words: kicad, open schematic, open board, open pcb, open symbol, open footprint, KiCad symbol editor, KiCad footprint editor, KiCad 3D viewer, run DRC, install KiCad library, sym-lib-table, fp-lib-table, KiCad screenshot, kicad_send_key, kicad_click, kicad_window_info, kicad_screenshot_all, close KiCad, kicad versions, kicad_list_versions, KiCad bridge." +--- -### How to contribute +# adom-desktop — KiCad bridge -We accept community improvements. Most useful targets right now: +All commands dispatch to the KiCad Python bridge running alongside the desktop app. Invoke from this container via Bash: -- **KiCad 11 support** — when KiCad 11 ships, the `kicad_detect.py` discovery + the in-process bridge plugin both need updates. Fork-friendly. -- **macOS / Linux ports** — bridge currently Windows-only; cross-platform PRs welcome. -- **New verbs** — anything KiCad exposes via `pcbnew.*` / `kicad-cli` that you'd find useful. +```bash +adom-desktop kicad_<action> '<json_args>' +``` -Two contribution paths, depending on your access: +The leading `kicad_` routes the call to the KiCad plugin; the `<action>` names below are the plugin-side command names. -**With a GitHub account (preferred):** wait until we make the repo public, then fork on GitHub and open a PR. We're aiming to flip the repo public in the next maintenance pass. +## FIRST-TIME / COLD-START — read before you panic -**Without GitHub access (patch-by-email-style, available right now):** Clone the bundle, make your changes, generate a patch with `git format-patch origin/main..HEAD --stdout > my-changes.patch`, and email it to **`[email protected]`**. Adom maintainers will review and apply. +A fresh machine can be missing KiCad, or the reverse-bridge plugin auto-installs on your first call. These states are **EXPECTED** — don't declare defeat. Branch on the stable `errorCode` (not the prose), and relay the returned `_hint` to the user verbatim. -See `CONTRIBUTING.md` inside the tarball/bundle for the full PR + ship workflow. +| Signal (`errorCode` / field) | What it means | What YOU do | +|---|---|---| +| `kicad_not_installed` | KiCad (the user's host app) isn't on this machine. AD detects host apps but never auto-installs them. | **Don't send the user to download it.** Offer to install it, then run `kicad_upgrade '{}'` — the agent installs the official build from scratch. Then retry. | +| `kicad_version_not_installed` | The `kicadVersion` you asked for isn't installed. | Run `kicad_list_versions '{}'`; retry with an installed version or omit `kicadVersion` to use the newest. | +| `pluginAutoInstall` present in a response | Your first `kicad_*` call auto-installed the reverse-bridge plugin into KiCad (idempotent). | Nothing — expected. Subsequent calls are near-zero cost. | +| bridge not responding on the first call | AD is lazy-spawning the bridge (+ ~9s KiCad detection). | Wait a beat and retry; it binds once and stays up. | -### How shipping works after merge +**Readiness before you drive:** +- `kicad_readiness '{}'` — read-only, zero side effects: is KiCad installed/ready? (`{detected, ready, versionCount, defaultVersion}`.) There's **no prewarm** — KiCad is a host app you install on request via `kicad_upgrade`, not a downloaded runtime asset. +- `kicad_describe '{}'` — the full machine-readable verb catalog (the completeness escape hatch; the per-call `_hint`s are what carry you in practice). +- For **"what EDA tools do I have"** across all bridges, use AD's `bridge_readiness` (see below). -1. Maintainer merges your PR into `main` -2. Maintainer tags `v<X.Y.Z>` + runs `bash scripts/release-bridge.sh kicad` on their box -3. New zip + manifest published to this wiki page (replaces current version) -4. Every Adom Desktop install running v1.7.19+ auto-picks up your change within 4 hours OR immediately via `adom-desktop refresh_bridges` +## Installing KiCad on a fresh machine (hard-won, v0.9.26+) -No NSIS installer rebuild required. Your code reaches real users in ~30s after merge. +`kicad_upgrade` downloads the official downloads.kicad.org installer and silent-installs it. Two things that WILL bite on a truly fresh machine, both handled for you now: -### License +- **Install scope is mandatory in silent mode.** KiCad 10's installer is NsisMultiUser: bare `/S` exits instantly with **`rc=666660`** ("invalid command-line parameters") and installs nothing. The bridge auto-picks the scope: **`/allusers`** when the AD process is elevated (installs to Program Files), else **`/currentuser`** (installs to `%LOCALAPPDATA%\Programs\KiCad` — **no admin, no UAC prompt at all**). Force it with `kicad_upgrade '{"scope":"user"}'` — that's your answer to *"install KiCad without a UAC prompt."* (Elevation note: on a VM/kiosk the AD process may already be elevated even though nobody clicked UAC — an elevated installer that launches the app hands down its admin token. `kicad_upgrade '{"diagnoseOnly":true}'` reports the real token/UAC facts.) +- **Library installs work before KiCad's first launch.** `%APPDATA%/kicad/<ver>/` (the per-user lib tables) doesn't exist until KiCad's first GUI run, so `kicad_install_library`/`_footprint` used to fail *"config directory not found."* The bridge now bootstraps that config (seeding the lib tables from the install template) automatically — installs just work on a never-launched KiCad. -MIT — see the `LICENSE` file in the tarball. +**GPU-less hosts (VM/RDP/server):** KiCad pops a blocking *"Could not use OpenGL"* dialog and the heavy editors may not render. The bridge auto-expires that dialog and switches KiCad to the Cairo software canvas — see **[kicad-interaction](skills/kicad-interaction/SKILL.md)** for the dialog/canvas details. +## Multi-version (KiCad 9 + KiCad 10 side-by-side) +Users can have multiple KiCad versions installed at the same time. The bridge auto-discovers everything under `C:/Program Files/KiCad/<version>/` and **defaults to the newest installed version** if you don't specify one. -The KiCad bridge is one of three reference implementations bundled with Adom Desktop. It's the most complex of the three — a multi-instance Python server that runs alongside KiCad GUI processes and provides both a forward path (CLI → bridge → kicad-cli) and a reverse path (CLI → bridge → in-process Python plugin inside KiCad). - -If you're authoring a new third-party bridge, see the [bridge SDK guide](https://wiki-ufypy5dpx93o.adom.cloud/wiki/apps/adom-desktop-bridges) first. Use this page for architectural reference once you've grasped the basics. - -## Quick facts - -| | | -|---|---| -| Name | `kicad` | -| Display | KiCad EDA | -| Spawn kind | Python (`server.py`) | -| Port | 8772 | -| Verb prefix | `kicad_*` (23 verbs) | -| Watcher | yes (`*.kicad_pcb`, `*.kicad_sch`, `*.kicad_pro`) | -| Source zip | [`kicad-bridge-v0.8.2.zip`](https://wiki-ufypy5dpx93o.adom.cloud/static/apps/adom-desktop/kicad-bridge-v0.8.2.zip) | -| Manifest | [`kicad-bridge-manifest.json`](https://wiki-ufypy5dpx93o.adom.cloud/static/apps/adom-desktop/kicad-bridge-manifest.json) | -| User-facing skill | [`kicad-SKILL.md`](https://wiki-ufypy5dpx93o.adom.cloud/static/apps/adom-desktop/kicad-SKILL.md) | - -## What it does - -- **Forward path** (CLI → bridge → kicad-cli): board/schematic linting (`kicad_lint_board`, `kicad_lint_schematic`, `kicad_lint_library`), DRC/ERC (`kicad_run_drc`, `kicad_run_erc`), format upgrades, exports. -- **Window automation** (CLI → bridge → Win32): launch editors (`kicad_open_board`, `kicad_open_schematic`, …), list open editors, capture screenshots of all KiCad windows, send keystrokes, click at coords. -- **Reverse path** (CLI → bridge → in-process plugin inside KiCad): `kicad_bridge_call` invokes a Python handler running INSIDE the running KiCad GUI exe, with access to `pcbnew.*` / future `kipy`. This gives Docker-side Claude live introspection of the actually-open board without a round-trip through file exports. - -## `bridge.json` - -```json -{ - "manifest_version": 1, - "name": "kicad", - "displayName": "KiCad EDA", - "version": "0.8.2", - "description": "Reverse bridge for KiCad — board/schematic introspection, lint via kicad-cli, plugin install, multi-instance probe, in-process DRC.", - "homepage": "https://github.com/adom-inc/adom-desktop", - "author": "Adom Inc.", - "license": "MIT", - "spawn": { - "kind": "python", - "entrypoint": "server.py", - "port": 8772, - "healthEndpoint": "http://127.0.0.1:8772/status", - "stopMethod": "kill", - "killImageName": "python.exe" - }, - "verbPrefixes": ["kicad_"], - "verbs": [ - "kicad_open_board", "kicad_open_schematic", "kicad_open_symbol_editor", - "kicad_open_footprint_editor", "kicad_open_3d_viewer", - "kicad_list_versions", - "kicad_run_drc", "kicad_run_erc", - "kicad_lint_board", "kicad_lint_schematic", "kicad_lint_library", - "kicad_format_upgrade", - "kicad_install_plugin", "kicad_install_symbol", "kicad_install_footprint", - "kicad_bridge_status", "kicad_bridge_call", - "kicad_open_editors", "kicad_window_info", "kicad_screenshot_all", - "kicad_send_key", "kicad_click", "kicad_close" - ], - "dependencies": { "python": ">=3.11", "kicad": ">=10.0" }, - "category": "EDA", - "tags": ["pcb", "schematic", "open-source", "kicad-10", "kicad-11-ready"], - "watcher": { - "supports": true, - "displayName": "Project Watch", - "description": "Monitors a KiCad project folder for file changes and syncs them to Docker.", - "defaultGlobs": ["*.kicad_pcb", "*.kicad_sch", "*.kicad_pro"], - "configKey": "project_watch" - } -} +```bash +# Discover what's installed (run this first if unsure) +adom-desktop kicad_list_versions '{}' +# → {"versions":[{"version":"10.0", "default":true, ...}, {"version":"9.0", ...}], "default":"10.0", "count":2} ``` -The `watcher` field declares that this bridge supports project-watching — the GUI renders a 👁 pip on the chip when watching is active. See the [bridge SDK guide](https://wiki-ufypy5dpx93o.adom.cloud/wiki/apps/adom-desktop-bridges#bridgejson-schema) for the full schema. +Every `kicad_open_*` (and `install_*`, `run_drc`) command accepts an optional **`kicadVersion`** arg to pin a specific install: -## Architecture highlights +```bash +# Open in KiCad 10 (newest — default if you omit kicadVersion) +adom-desktop kicad_open_board '{"filePath":"C:/designs/foo.kicad_pcb"}' +# Open in KiCad 9 explicitly (e.g. to check that an older project still works) +adom-desktop kicad_open_board '{"filePath":"C:/designs/foo.kicad_pcb","kicadVersion":"9.0"}' ``` -kicad/ -├── server.py ← HTTP entry point; routes /command to handlers/ -├── handlers/ ← One module per logical verb group -│ ├── board_ops.py ← kicad_run_drc, kicad_lint_board, kicad_open_board, … -│ ├── schematic_ops.py -│ ├── library_ops.py -│ ├── window_automation.py ← Win32 SendInput, PrintWindow, EnumWindows -│ ├── bridge_call.py ← Reverse bridge dispatch into the in-process plugin -│ └── … -├── kicad_detect.py ← Find installed KiCad versions, exe paths, USER_SITE -├── adom_library.py ← Symbol/footprint discovery in sym-lib-table.txt -├── lib_table.py ← Add/remove rows in *-lib-table files -├── plugin_install.py ← Copy adom_bridge.py into USER_SITE/usercustomize.py -├── plugin_payload/ -│ └── adom_bridge.py ← Reverse-bridge plugin loaded INSIDE every KiCad GUI exe -├── parsers/ ← .kicad_sym, .kicad_mod, .kicad_pcb tokenizers -└── start.bat ← Windows launcher for local dev -``` - -The reverse-bridge plugin (`plugin_payload/adom_bridge.py`) is what makes the kicad bridge special. KiCad's bundled Python interpreter overrides `site.USER_SITE` to `%USERPROFILE%\Documents\KiCad\10.0\3rdparty\Python311\site-packages\`, and the `usercustomize.py` import hook fires on every KiCad GUI exe start (`kicad.exe`, `pcbnew.exe`, `eeschema.exe`, `kicad-cli.exe`). Our plugin uses this hook to launch a tiny websocket client that connects to the bridge — turning every running KiCad into a remote-controllable instance. -## Reverse-bridge example +If you pass a version that's not installed, the bridge returns a hint listing the installed versions. The success response includes `kicadVersionUsed` so you can confirm which install actually ran. + +> **Note on libraries / config**: each KiCad version has its own `sym-lib-table` and `fp-lib-table` (in `%APPDATA%/kicad/<version>/`). `kicad_install_library` writes to the table of whichever version was selected — so if the user installs a library and then asks "open it in KiCad 9", you may need to install it under both versions. + +## "What EDA tools do I have?" — readiness & host-app detection + +**KiCad is the user's HOST APP. Adom Desktop *detects* it — it won't silently auto-install it as a prewarm/dependency** (AD v1.9.47+). But if KiCad isn't found, **do NOT hand the user a manual download** — offer to install it for them and run `kicad_upgrade '{}'`. That verb installs the latest stable from the official downloads.kicad.org installer (silent `/S`, Windows only; may raise a UAC prompt) and **installs from scratch, not just upgrades**. The distinction: AD-core never auto-installs a host app, but a user-requested, agent-run install is exactly right. + +- To answer **"what EDA tools / host apps do I have?"** across every bridge, call the AD-level verb **`adom-desktop bridge_readiness '{}'`** — AD aggregates each bridge's host-app detection (KiCad, Fusion 360, …) into one report. Start here for any "do I have X installed?" question. +- For **KiCad specifically**, `adom-desktop kicad_readiness '{}'` is a zero-side-effect read-only probe: `{hostApp, detected, ready, versionCount, defaultVersion, versions[]}`. It does not install the plugin or spawn subprocesses, and works even when KiCad is absent (`detected:false`). Use `kicad_list_versions` when you need the full per-version detail (paths, IPC API, lib tables). + +## Commands + +| CLI form | Action | Purpose | Key args | +|---|---|---|---| +| `kicad_list_versions` | `list_versions` | Enumerate every installed KiCad version with paths and which one is the default | — | +| `kicad_readiness` | `readiness` | Read-only host-app detection: is KiCad installed/ready? Zero side effects (no plugin load, no subprocess); works even when KiCad is absent. For cross-bridge "what do I have", use AD's `bridge_readiness` | — | +| `kicad_check_for_updates` | `check_for_updates` | Read-only: installed KiCad vs latest STABLE (from downloads.kicad.org / KiCad GitLab tags); flags when the install predates the modern IPC/kipy automation API and should be upgraded | — | +| `kicad_upgrade` | `upgrade` | Download the **official** KiCad installer from downloads.kicad.org and silent-install it (`/S`) — **not winget** (winget lags the real release). May raise a UAC prompt to approve | optional `version`, `force` | +| `kicad_open_schematic` | `open_schematic` | Open a `.kicad_sch` in the Schematic Editor | `filePath`, optional `kicadVersion` | +| `kicad_open_board` | `open_board` | Open a `.kicad_pcb` in the PCB Editor | `filePath`, optional `kicadVersion` | +| `kicad_open_symbol_editor` | `open_symbol_editor` | Launch Symbol Editor (optional: open specific library/symbol) | `libraryName`, `symbolName`, optional `kicadVersion` | +| `kicad_open_footprint_editor` | `open_footprint_editor` | Launch Footprint Editor | `libraryName`, `footprintName`, optional `kicadVersion` | +| `kicad_open_3d_viewer` | `open_3d_viewer` | Show the board (or footprint) in 3D viewer | `editor` ("auto"/"pcb"/"fp" — "auto" prefers the board when both editors are open, no need to close sub-editors), optional `kicadVersion` | +| `kicad_close_symbol_editor` | `close_symbol_editor` | Close Symbol Editor | — | +| `kicad_close_footprint_editor` | `close_footprint_editor` | Close Footprint Editor | — | +| `kicad_close_3d_viewer` | `close_3d_viewer` | Close 3D viewer | — | +| `kicad_close` | `close` | Close KiCad (all editors) | — | +| `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_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` | +| `kicad_fix_keyboard` | `fix_keyboard` | Workaround stuck-modifier bug after screen lock | — | +| `kicad_screenshot_all` | `screenshot_all` | Capture every open KiCad window (lossless PNGs) | — | +| `kicad_send_key` | `send_key` | Send a keystroke to a KiCad window — supports modifier combos ("alt+3", "ctrl+s", "ctrl+shift+s") | `hwnd`, `key` | +| `kicad_click` | `click` | Send a click at (x, y) in a KiCad window | `hwnd`, `x`, `y` | +| `kicad_adom_library_status` | `adom_library_status` | Report whether the Adom shared library is registered | — | + +## Quick examples ```bash -# From cloud Docker: list every open KiCad GUI exe + which board it has loaded -adom-desktop kicad_open_editors +# Open a schematic +adom-desktop kicad_open_schematic '{"path":"C:/designs/foo.kicad_sch"}' -# Direct in-process call: ask the running pcbnew.exe what board it has open -adom-desktop kicad_bridge_call '{"method":"get_board_info"}' +# List open KiCad windows +adom-desktop kicad_window_info '{}' -# Run a DRC IN-PROCESS — no file write, no kicad-cli detour -adom-desktop kicad_bridge_call '{"method":"run_drc","args":{"severity":"error"}}' +# Screenshot every KiCad window +adom-desktop kicad_screenshot_all '{}' + +# Run DRC +adom-desktop kicad_run_drc '{"board_path":"C:/designs/foo.kicad_pcb"}' + +# Install a library pair +adom-desktop kicad_install_library '{ + "name":"my-lib", + "sym_path":"C:/libs/my-lib.kicad_sym", + "fp_path":"C:/libs/my-lib.pretty" +}' ``` -The bridge dispatches these to `adom_bridge.py` running inside pcbnew. The handler executes against the live `pcbnew.GetBoard()` and returns JSON over the websocket. +## Error shape -## Reference: install the source locally to read +Every failing response includes a `_hint` field with a human-readable next step — surface it to the user verbatim when a KiCad command fails. -```bash -# Pull the zip (no auth needed — wiki static URL) -curl -L https://wiki-ufypy5dpx93o.adom.cloud/static/apps/adom-desktop/kicad-bridge-v0.8.2.zip -o /tmp/kicad-bridge.zip +## Bridge architecture (v1.8.31+) — you don't need to know any port -# Extract -mkdir -p /tmp/kicad-bridge && cd /tmp/kicad-bridge && python3 -c "import zipfile; zipfile.ZipFile('/tmp/kicad-bridge.zip').extractall()" -ls -la -``` +Earlier versions of the KiCad bridge listened on hardcoded port `8772`. **As of v1.8.31, bridges use OS-assigned ephemeral ports** — every spawn gets a new free port. You never need to know it. + +- The CLI (`adom-desktop kicad_*`) automatically routes through adom-desktop's direct API (default port 47200 as of v1.8.33, with auto-fallback to 47201-47209 if 47200 is taken). adom-desktop then forwards to the bridge's actual runtime port. +- The bridge port is internal plumbing and can change every spawn. `bridge_list` reports it as `spawn.runtimePort` for debugging only — do NOT hardcode that anywhere. +- Why: this lets adom-desktop coexist with Hydrogen Desktop (which used to claim 8772 itself) and any other tool that grabs ports in the 8000 range. Side-by-side bridges from different apps no longer collide. +- The relay path (Docker → wss proxy → Windows GUI) is unchanged — same `adom-desktop kicad_*` verbs, same JSON shape. -You'll see `server.py`, `bridge.json`, `handlers/`, `plugin_payload/`, etc. — fork the layout for your own bridge. +If you ever find yourself wanting to talk directly to the KiCad bridge process: don't. Go through the verb dispatch. If the verb you need doesn't exist, request a feature in `adom-inc/adom-desktop`. ## Related -- **[Bridge SDK guide](https://wiki-ufypy5dpx93o.adom.cloud/wiki/apps/adom-desktop-bridges)** — `bridge.json` schema, packaging recipe, lifecycle -- **[Puppeteer bridge reference](https://wiki-ufypy5dpx93o.adom.cloud/wiki/apps/adom-desktop-puppeteer-bridge)** — simpler architecture, single-instance, Node + Chrome for Testing -- **[Fusion 360 bridge reference](https://wiki-ufypy5dpx93o.adom.cloud/wiki/apps/adom-desktop-fusion-bridge)** — passthrough-to-add-in pattern -- **[adom-desktop main page](https://wiki-ufypy5dpx93o.adom.cloud/wiki/apps/adom-desktop)** — install the parent app first-------+- `adom-desktop-discovery` (gallia) — ensures the CLI + relay are installed. +- `adom-desktop-fusion` — sibling bridge for Fusion 360. +- `adom-desktop-direct-api` — the direct API contract (port 47200 + 47201-47209 fallback, discovery file at `~/.adom/direct-api-port`). +- Repo: `adom-inc/adom-desktop/plugins/kicad/`
package.json+1−1@@ -1,6 +1,6 @@ { "slug": "adom-desktop-kicad-bridge",- "version": "1.0.4",+ "version": "1.0.5", "type": "app", "description": "KiCad bridge for Adom Desktop.", "tags": [
page.json+1−1@@ -4,7 +4,7 @@ "slug": "adom-desktop-kicad-bridge", "title": "Adom Desktop - 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.4",+ "version": "1.0.5", "tags": [ "kicad", "pcb",
skills/kicad-interaction/SKILL.md+2−2@@ -11,11 +11,11 @@ Read this skill BEFORE any KiCad desktop operation. It prevents the most common KiCad throws blocking modal dialogs constantly (OpenGL fallback notices, "older file format" warnings, save prompts, config nags). A blocking dialog **stalls every other verb** — an editor open can't complete, a screenshot captures only the dialog. The bridge now handles this **programmatically** so you rarely babysit it: -- **`kicad_window_info` auto-expires *benign* dialogs by default.** It scans EVERY window owned by any running KiCad process (matched by PID — reliable, never misses one), clicks OK on the harmless ones (e.g. *"Could not use OpenGL, falling back to software rendering"*), and reports them in `data.autoDismissed[]` + `data._autoDismissHint`. Pass `{"autoDismiss": false}` to inspect without touching them. +- **`kicad_window_info` auto-expires *benign* dialogs by default.** It scans EVERY window owned by any running KiCad process (matched by PID — reliable, never misses one), clicks OK on the harmless ones (e.g. *"Could not use OpenGL, falling back to software rendering"*, the *"Welcome to KiCad — starting for the first time"* first-run wizard, and the *"created by an older version of KiCad"* conversion notice), and reports them in `data.autoDismissed[]` + `data._autoDismissHint`. Pass `{"autoDismiss": false}` to inspect without touching them. - **A NON-benign dialog is left up and reported** in `data.modalDialogs[]` with its `body` text (read from the dialog's Static controls — no screenshot needed) so YOU decide: read `body`, then dismiss with `kicad_send_key {hwnd, key:"return"}` (OK) / `"escape"` (Cancel), or surface it to the user. - **`kicad_dismiss_dialogs`** — force-clear on demand. `{}` = benign only; `{"all": true}` = clear EVERY KiCad dialog (use after you've read a modal you want gone). It **screenshots each dialog before expiring it** (returned in `dismissed[].screenshot`) so you can show the user what was auto-closed and let them decide what it meant. Returns `dismissed[]`, `remaining[]`, hints. -**GPU-less hosts (VMs / RDP / servers):** KiCad tries OpenGL, fails, and pcbnew/3D may not render. When the bridge expires the OpenGL notice it also persists `graphics.canvas_type=2` (Cairo software) to `kicad_common.json` so future launches skip OpenGL — or force it up front with `kicad_dismiss_dialogs {"forceSoftwareCanvas": true}` then reopen the editor. (Note: a truly headless VM with no usable graphics stack still may not render the heavy editors even in Cairo — that's the hardware, not the bridge.) +**GPU-less hosts (VMs / RDP / servers):** KiCad tries OpenGL, fails, and pcbnew/3D may not render. When the bridge expires the OpenGL notice it also persists `graphics.canvas_type=2` (Cairo software) to `kicad_common.json` so future launches skip OpenGL — or force it up front with `kicad_dismiss_dialogs {"forceSoftwareCanvas": true}` then reopen the editor. (Note: a truly headless VM with no usable graphics stack may still not render the heavy editors or the 3D viewer even in Cairo. Last resort only: `kicad_enable_software_opengl` deploys Mesa `llvmpipe` (CPU OpenGL) so even 3D renders — it's SLOW and for GPU-less hosts only; do NOT suggest it proactively on a normal machine.) **Pattern:** `open_* → window_info (auto-clears benign) → screenshot_all`. If an open "fails," a benign modal was almost certainly blocking it — call `window_info` or `kicad_dismiss_dialogs` and retry.