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
page.json+5−3@@ -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.112", "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_*` \u00b7 **Status verb:** `kicad_bridge_status` \u00b7 **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[](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\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\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\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\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\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\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\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_*` · **Status verb:** `kicad_bridge_status` · **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[](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\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\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\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\n\n### PCB editor (2D) — `kicad_open_board`\n\nThe routed breakout — copper, silkscreen, the QFN-56 land pattern, mounting holes.\n\n\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\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\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]"@@ -90,6 +90,8 @@ "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-dev/SKILL.md", "skills/kicad-bridge-publish/SKILL.md", "skills/kicad-bridge-hero/SKILL.md",@@ -128,4 +130,4 @@ "authors": null, "author_handle": "john", "authors_json": null-}+}
skills/kicad-bridge-dev/SKILL.md+40@@ -910,3 +910,43 @@ does NOT invalidate the tree cache - the IO cache and the tree cache are separate. And note the layer lesson: FootprintLoad/Save/Enumerate DO exist in KiCad 10 Python, as IO-class METHODS - a module-level `dir(pcbnew)` probe cannot see them.+++## Our parser is not KiCad's parser (wiki #71, measured 2026-09-03 on ConfRoomROG)++`kicad_lint_library`, `list_symbols`, `add_symbol`'s balance gate: all of these are the BRIDGE's+reader. They balance parentheses. KiCad's parser also checks tokens. A five-symbol Adom.kicad_sym+our reader called "parsed cleanly" got "Unable to load library" from `kicad-cli sym export svg`,+and the Symbol Editor listed the Adom library EMPTY. Three test symbols had bare `hide yes` inside+`(effects ...)`; the two well-formed symbols alone loaded fine. Rules that follow:++- One refused symbol hides the WHOLE library. Never append to a library KiCad reads without asking+ KiCad first. `handlers/kicad_parse_check.py` is the gate: `verdict_text` on the merged candidate+ before the write, `verdict_file` on an existing file, `refused_symbols` to find the culprit.+- The read-only KiCad parse is `kicad-cli sym export svg -o <tmp> <file>`; it prints one+ `Plotting symbol 'X' unit N` line per unit, so it is also KiCad's own symbol inventory. `sym upgrade`+ REWRITES the file: never use it as a check.+- "Verified with kicad-cli" is a claim about a subprocess you actually ran. The lint verb's docstring+ says it does not call kicad-cli; I still told a user it had. Read the code before naming the tool.+- KiCad's library index is PROCESS-WIDE. Reopening the editor frame while kicad.exe (the manager)+ stays up keeps the old symbol set; the tree showed one symbol from a file that then held three.+ Only a full close and cold reopen re-read the file. `_close_symbol_editor` alone is not a rescan.+- `kicad_show_library` auto-rescan closes and reopens a bridge-owned editor; a screenshot loop that+ holds an hwnd across that call is holding a dead handle. Re-list windows after every show call.+- Minimal hand-written test symbols must use the 20231120 shape KiCad writes: `(hide yes)` as its+ own list, never bare tokens. Copy a symbol KiCad already loads and rename it.++## Lessons from wiki #71, 2026-09-03 (measured on ConfRoomROG and by Ray)++- **One refused symbol drops the whole library.** KiCad loads a `.kicad_sym` all or nothing. A structurally balanced file that KiCad's parser rejects makes the library vanish from the Symbol Editor with no dialog and no stderr. `kicad_lint_library` therefore calls `kicad-cli sym export svg` (the real parser) and says plainly when it could not; a paren-balance check is not a KiCad verdict. Installs ask KiCad first and refuse with `errorCode: kicad_refuses_symbol`; `kicad_adom_library_heal {"mode":"prune"}` rebuilds a poisoned file from the accepted symbols.+- **A library KiCad refused stays refused for the whole process.** After repairing a poisoned file, closing and reopening the Symbol Editor while kicad.exe stays up still shows it empty; only a full close of KiCad re-reads it. New symbols added to a library KiCad already loads DO appear on an editor close and reopen (measured 2026-09-03: RAYTEST_B/C/D installed after open, loaded after the bridge's auto-rescan, about 105 s end to end). Say which of the two cases you are in before promising a reopen will help.+- **A fresh Symbol Editor has no selected row.** After the filter is typed, the tree lists the symbol but nothing is selected, so a posted Enter activates nothing and a posted double-click depends on row pixel geometry (DPI). Select from inside the tree with posted Down keys, then Enter, and let the window title judge (`Adom:<name> — Symbol Editor` is success, `[no symbol loaded]` is failure). Posted keys reach a background editor fine; the window does not need focus.+- **wx answers WM_GETTEXT with '' for its own windows.** Reading the search box back after WM_SETTEXT returns '' while the box visibly holds the text. Never treat that read as "filter not applied"; screenshot or title is the evidence.+- **`kicad_install_library` on a single-part file registers that part as its own library** and leaves Adom empty, with every call ok. It now says so and names `kicad_install_symbol` (wiki #72).++## Captions and the editor launch (John, 2026-09-03, supersedes "caption before any foreground")++- **No caption on a Symbol Editor launch or rescan reopen.** The one shipped in 0.9.285 was large, shown far too long, and on John's laptop it was wrong: it promised "behind your window" while KiCad raised itself in front as it finished loading. A caption that can be wrong is worse than none. The launch is silent.+- **Report the end state, measured.** `_foreground.editorInFrontAtEnd` is read from AD's z-order at return time. The early one-look guard can only see the frame's creation; KiCad activates itself later during load, so never claim "background" from the early look alone.+- **Never fight the user for the foreground.** One look within the guard window, one optional SetWindowPos, then hands off for the rest of the call and forever after. An earlier generation of guards left users unable to bring KiCad forward themselves; that is the failure to avoid.+- Captions remain only for the opt-in `allowFocusSteal` path: one short line (under 60 characters), 3 seconds, naming the thread.