app
Adom Bridge
Public Made by Adomby adom
Adom Bridge unleashes your AI onto your full PC: full power, full safety. The AI breaks out of the container it runs in and onto your real machine, managing and running your entire laptop as you: launch apps, move files, drive any window, control KiCad, Fusion 360 or your real signed-in browser. Works with any AI, cloud or local (Claude Desktop, Claude Code, Codex), no Hydrogen required. Bridge and its bridges are an operating system for AI, with managed Node and Python runtimes, and a human-onl
← Commit history
Publish 2.1.145
6 files changed
+39−1622
SKILL.md+16−802@@ -191,11 +191,9 @@ adom-bridge <command> '<json-args>' ```bash adom-bridge ping adom-bridge status -adom-bridge pup_open_window '{"sessionId":"dart2","url":"https://example.com"}' -adom-bridge pup_eval '{"sessionId":"dart2","expr":"document.title"}' -adom-bridge pup_screenshot '{"sessionId":"dart2"}' -adom-bridge pup_list_windows -adom-bridge pup_close_window '{"sessionId":"dart2"}' +adom-bridge desktop_list_windows +adom-bridge desktop_screenshot_screen '{"reason":"see what is on the user's screen"}' +adom-bridge commands '{"bridge":"kicad"}' # a bridge's own verb list (any installed bridge) adom-bridge notify_user '{"title":"Hello","body":"From Docker"}' adom-bridge shell_execute '{"command":"echo hello"}' adom-bridge pull_file '{"filePaths":["C:\\Users\\john\\Downloads\\image.png"],"saveTo":"/tmp"}' @@ -295,7 +293,7 @@ If you're authoring a sibling Tauri app on the same machine (Hydrogen, or any fu The CLI does this automatically (see `cli/src/direct_probe.rs`). For sibling-app Rust code, see [`skills/DIRECT_API.md`](DIRECT_API.md) for a copy-paste-ready helper. -**Per-verb timeouts (v1.8.31+):** the direct API's command-timeout is no longer a hardcoded 120s — it mirrors the CLI dispatcher's per-verb table (`walk_cloud_tree`/`search_cloud_files`=620s; heavy exports=320s; `bridge_install`/`fusion_start`=300s; default=120s). Caller can override via `args.timeout` (seconds, clamped to 1800). +**Per-verb timeouts:** a bridge verb's budget is the bridge's own `bridge.json` `timeouts` block (exact bare verb, then prefix rule, then its default), applied by ab and, since 2.1.145, by the CLI's wait as well (ab keeps no table of any bridge's verbs, wiki #212). `timeouts` shows every installed bridge's declared block. Caller can override via `args.timeout` (seconds, clamped to 1800). Example — programmatic server registration without the CLI: @@ -499,15 +497,7 @@ Reference implementations: [`scripts/sample-bridges/hello-python/server.py`](../ The KiCad bridge is **cloud-owned** and ships its OWN full skill (wiki pkg `adom/kicad-bridge`). This page keeps only the pointer: run `adom-bridge sync_skills` after connecting and the full KiCad guide (project workflows, three-tier `kicad_open_*` routing, DRC recipes, library install) lands in `~/.claude/skills/`. -Most-used verbs to get moving: - -```bash -adom-bridge kicad_open_board '{"path": "C:/projects/board/board.kicad_pcb"}' -adom-bridge kicad_screenshot_all '{}' # every KiCad window incl. error dialogs, as an array -adom-bridge kicad_run_drc '{}' -adom-bridge kicad_window_info '{}' -adom-bridge kicad_open_symbol_editor '{"library": "Device"}' -``` +Its verbs: `adom-bridge commands '{"bridge":"kicad"}'` (the bridge describes itself). If KiCad is not installed, the bridge knows how to install it for the user — offer, never point them at a download page. Full details: the bridge's own skill. @@ -515,17 +505,9 @@ If KiCad is not installed, the bridge knows how to install it for the user — o The Fusion 360 bridge is **cloud-owned** and ships its OWN full skill (wiki pkg `adom/fusion-bridge`). Run `adom-bridge sync_skills` and the full guide (cloud files, import/export, add-in troubleshooting, APS search) lands in `~/.claude/skills/`. -Most-used verbs: +Its verbs: `adom-bridge commands '{"bridge":"fusion360"}'`. -```bash -adom-bridge fusion_start '{}' # launches Fusion; slow on cold start (minutes) -adom-bridge fusion_get_app_state '{}' # the status/poll verb -adom-bridge fusion_addin_status '{}' -adom-bridge fusion_dismiss_blocking_dialogs '{}' -adom-bridge fusion_send_key '{"key": "Escape"}' -``` - -Fusion launches take 2-4 minutes cold; respect `timeoutSeconds` + `statusVerb` on responses instead of re-issuing. Full details: the bridge's own skill. +Respect `timeoutSeconds` + `statusVerb` on responses instead of re-issuing a slow verb. Full details: the bridge's own skill. ### Launching apps (generic) @@ -536,600 +518,7 @@ Two generic CLI commands exist for launching any Windows executable safely — t **Where they run (2.1.143, wiki #210).** With `--target <box>`, or from a container / Linux CLI, both verbs run ON THAT BOX through its ab (mesh first, relay fallback, the same path as `shell_execute`): the path is resolved against the box's filesystem and the app starts there; the reply says `on: "<box>"`. Before 2.1.143 both ran inside the CLI process, so `--target arav-rog launch {path}` answered `find_exe: could not locate` for a file that existed on arav-rog. Only a Windows CLI with no `--target` still resolves and spawns locally. On a box `launch` is a Tier-2 exec verb like `launch_process` (gated the same way, `reason` required); `find_exe` is read-only. A target ab older than 2.1.143 answers unknown verb: use `launch_process {path, args}` there. -For Fusion specifically, use `fusion_start` — it wraps `launch` plus the full startup-picker / add-in-readiness dance. -- `fusion_import_step` -- Import a STEP/STL/IGES file into Fusion 360 -- `fusion_open_lbr` -- Open an EAGLE .lbr library file -- `fusion_open_electronics` -- Check if the Electronics workspace is active -- `fusion_electron_run` -- Execute any EAGLE command via Electron.run. Returns rich state: `activeWorkspace`, `activeDocument`, `commandType`, `_hint`, and `fusionOperations` (diff of Fusion's internal operation log showing what actually fired). **Avoid blocking commands** — see list below. **Full EAGLE command reference:** [`skills/eagle-commands.md`](./eagle-commands.md) — popular/safe commands split from blocking/modal ones, with layer reference and chaining syntax. -- `fusion_execute_text_command` -- Low-level app.executeTextCommand() access. Returns the command result plus workspace context. -- `fusion_board_info` -- Get structured board data from the open PCB layout. Returns: component placements (name, package, x, y, rotation), net names, copper traces, layer setup, board thickness, DRC violations. Much richer than a screenshot — gives exact coordinates and connectivity. Requires a .brd board open in PCB Editor. - -#### `fusion_electron_run` — EAGLE Command Execution - -Executes EAGLE commands inside Fusion 360's Electronics workspace. Works in **Schematic Editor**, **PCB Editor (Board Layout)**, and **Electronics Library** contexts. - -**How it works:** Sends the command string via Fusion's `Electron.run` text command. EAGLE's `Electron.run` is fire-and-forget — it never returns output or throws on invalid commands. To compensate, the handler snapshots Fusion's internal operation log (`Diagnostics.RecentOperations`) before and after execution, returning a diff showing what actually fired. - -**Usage:** -```bash -# Basic command -adom-bridge fusion_electron_run '{"command": "WINDOW FIT"}' - -# Multiple commands in sequence (use semicolons) -adom-bridge fusion_electron_run '{"command": "DISPLAY NONE; DISPLAY 1 16 17 18 20 21"}' - -# Navigate in library editor -adom-bridge fusion_electron_run '{"command": "EDIT SOIC8.pac"}' -adom-bridge fusion_electron_run '{"command": "EDIT RESISTOR.sym"}' -adom-bridge fusion_electron_run '{"command": "EDIT MYDEVICE.dev"}' -``` - -**Response fields:** -- `activeWorkspace` — Current workspace (Schematic Editor, PCB Editor, Electronics Library) -- `activeDocument` — Name of the open document -- `commandType` — Detected type: `view_control`, `layer_control`, `edit`, `design_rule`, etc. -- `editorType` — For EDIT commands: `package`, `symbol`, `device` -- `fusionOperations` — Array of Fusion operations that fired (diff of internal log) -- `hint` — Human-readable description of what happened -- `rawResult` — Raw return from Electron.run (usually empty) - -**EAGLE Command Reference — Safe for automation:** - -| Command | Context | Description | -|---------|---------|-------------| -| **View / Navigation** | | | -| `WINDOW FIT` | Any | Zoom to fit all content | -| `WINDOW (x1 y1 x2 y2)` | Any | Zoom to specific area (coordinates in current units) | -| `DISPLAY ALL` | Any | Show all layers | -| `DISPLAY NONE` | Any | Hide all layers | -| `DISPLAY 1 16 17 18 20 21` | Board | Show specific layers by number | -| **Grid** | | | -| `GRID MM 0.1` | Any | Set grid to 0.1mm | -| `GRID MIL 25` | Any | Set grid to 25mil | -| `GRID INCH 0.05` | Any | Set grid to 0.05 inch | -| **Board Layout** | | | -| `RATSNEST` | Board | Recalculate airwires (unrouted connections) | -| `RIPUP` | Board | Remove all routed traces | -| `RIPUP *` | Board | Remove all traces (same as RIPUP with no selection) | -| `ROUTE` | Board | Start auto-router | -| `DRC` | Board | Run design rule check | -| `BOARD` | Schematic | Switch to paired board layout | -| `SCHEMATIC` | Board | Switch to paired schematic | -| **Schematic** | | | -| `VALUE value` | Schematic | Set component value | -| `NAME name` | Any | Rename selected element | -| `SMASH` | Any | Detach name/value labels from components | -| **Library Editor** | | | -| `EDIT name.pac` | Library | Open a package (footprint) for editing | -| `EDIT name.sym` | Library | Open a symbol for editing | -| `EDIT name.dev` | Library | Open a deviceset for editing | -| `EXPORT SCRIPT 'path.scr'` | Library | Export entire library as EAGLE script | -| **Scripting / Settings** | | | -| `SET CONFIRM YES` | Any | Suppress confirmation dialogs | -| `SET CONFIRM OFF` | Any | Re-enable confirmation dialogs | -| `SCRIPT 'path.scr'` | Any | Run batch commands from a .scr script file | - -**EAGLE Layer Numbers (commonly used):** - -| Layer | Name | What it shows | -|-------|------|--------------| -| 1 | Top | Top copper | -| 16 | Bottom | Bottom copper | -| 17 | Pads | Through-hole pads | -| 18 | Vias | Via holes | -| 19 | Unrouted | Airwires (ratsnest) | -| 20 | Dimension | Board outline (required for 3D) | -| 21 | tPlace | Top silkscreen | -| 22 | bPlace | Bottom silkscreen | -| 25 | tNames | Top component names | -| 27 | tValues | Top component values | -| 29 | tStop | Top solder mask | -| 31 | tCream | Top stencil/paste | -| 51 | tDocu | Top documentation | - -**Blocking commands — AVOID from automation:** - -| Command | Why it blocks | -|---------|---------------| -| `WRITE` | Opens Save As dialog — use `fusion_save_lbr` or `fusion_close_document` instead | -| `ADD` | Opens component picker dialog | -| `SHOW name` | Opens interactive highlight mode | -| `SET` (no params) | Opens settings dialog | -| `GRID` (no params) | Opens grid settings dialog | -| `EDIT new.sym` | Opens "Create new?" confirmation if symbol doesn't exist | -| `CHANGE` | Opens interactive change mode | -| `MOVE` | Opens interactive move mode | - -**Tips:** -- Always run `WINDOW FIT` after opening a file or switching views -- Use `DISPLAY NONE` then `DISPLAY <layers>` to show only specific layers -- Combine commands with `;` — e.g., `SET CONFIRM YES; RIPUP *; RATSNEST` -- For board screenshots: `DISPLAY NONE; DISPLAY 1 16 17 18 20 21; WINDOW FIT` -- Use `fusion_board_info` instead of EAGLE commands when you need structured data -- `fusion_export_lbr` -- Export the open Electronics library as an EAGLE .scr script (note: does NOT include 3D package references — those are cloud-linked only) -- `fusion_save_lbr` -- Save the open Electronics library as a .flbr file - -#### EAGLE Libraries with 3D Packages - -Fusion 360's .lbr format supports `package3d` elements that link footprints to 3D models. Key facts: - -- **3D models are cloud-hosted** — each `package3d` has a `wip_urn` (e.g., `urn:adsk.wipprod:fs.file:vf.xxxxx`) pointing to a Fusion cloud document. You cannot embed STEP files directly in .lbr XML. -- **Creating 3D packages requires the Fusion UI** — use `Package3DCreateCmd` in Electronics Library Editor, which opens a new Design workspace where you model/import the 3D shape, then save to link it. -- **`EXPORT SCRIPT` strips 3D references** — the .scr export only contains 2D data (symbols, footprints, devicesets). To preserve 3D links, keep the .lbr XML format. -- **Fusion's built-in examples** have 3D packages — 34 of 37 libraries in the EAGLE examples directory (e.g., `Connector_USB.lbr`, `Resistor.lbr`, `Capacitor.lbr`) include `package3d` references. -- **Example libraries location**: `%LOCALAPPDATA%/Autodesk/webdeploy/production/<hash>/Applications/Electron/LibEagle/examples/libraries/examples/` - -To open a built-in example library for reference: -```bash -# Find the examples directory first -adom-bridge fusion_execute_text_command '{"command": "Python.RunScript C:/tmp/find_eagle_libs.py"}' -# Then open one -adom-bridge fusion_open_lbr '{"filePath": "<path>/Connector_USB.lbr"}' -``` -- `fusion_open_schematic` -- Open a .sch schematic in Fusion's Schematic Editor. Args: `filePath`. -- `fusion_open_board` -- Open a .brd board layout in Fusion's Board Layout editor. Args: `filePath`. -- `fusion_show_3d_board` -- Switch to 3D PCB board view (must have a .brd open). Board MUST have an outline on layer 20 (Dimension) or 3D generation fails. Auto-zooms to fit after switching. -- `fusion_show_2d_board` -- Switch back to 2D board layout from 3D PCB view. EAGLE commands via `fusion_electron_run` only work in 2D. -- `fusion_close_document` -- Close a document without save dialog. Args: `name` (optional, defaults to active doc), `save` (optional, default false). Essential for automation — avoids modal save dialog that blocks Fusion. -- `fusion_document_info` -- List ALL open documents/tabs with name, type, and active status, plus detailed cloud info for the active document. Returns `openDocuments` array (every tab) and active doc details (cloud project, folder, file ID, version, save status). Lightweight — uses only in-memory data, no cloud API calls. Use this instead of `fusion_walk_cloud_tree` when you just need to know what's open. -- `fusion_activate_document` -- Switch to a specific open document tab. Args: `name` (substring match, case-insensitive), `documentType` ("Electronics", "PCB", "FusionDesign", "Drawing"). Essential for automation — switch between schematic, board, and library tabs without user interaction. If no match found, returns the list of open documents so you can refine. -- `fusion_close` -- Close Fusion 360. **Always call this when done with Fusion 360 commands to clean up.** -- `fusion_dismiss_recovery` -- Dismiss recovery document dialogs (both "Recovered Documents" list and "Open recovery document instead?" prompts). Also relocates recovery files to `~/.adom/recovery/fusion/` for safekeeping. -- `fusion_relocate_recovery` -- Proactively move Fusion crash recovery files to `~/.adom/recovery/fusion/<timestamp>/` without dismissing any dialogs. Call this **before** launching Fusion to prevent recovery dialogs from appearing. Files are preserved (not deleted) so the user can manually restore them if needed. -- `fusion_close_all_documents` -- Close all open documents. Args: `saveChanges` (default: false). Use before force-killing Fusion to prevent recovery files. - -#### Fusion 360 UI Interaction - -Commands for interacting with Fusion 360's UI — detecting dialogs, taking screenshots, clicking, and sending keyboard input. Essential for handling blocking dialogs and automating CEF-based UI elements. - -- `fusion_window_info` -- Returns the Fusion main window HWND, title, rect, and a list of all Qt dialog windows (recovery dialogs, wizards, file pickers). Essential for detecting blocking dialogs before/after operations. - - Example: `adom-bridge fusion_window_info` - - Returns: `{hwnd, title, rect, dialogs: [{hwnd, title, className, rect}]}` - -- `fusion_screenshot_fusion` -- Captures the Fusion main window or a specific dialog by HWND. Uses PrintWindow (works without bringing to foreground). Saves WebP to `C:/tmp/adom-bridge-screenshots/` (falls back to PNG if WebP unavailable). Downscaled to ≤1568px — use relative coords (0.0-1.0) for clicking, they're scale-independent. DPI-aware. - - Args: `hwnd` (optional — dialog HWND to screenshot instead of main window) - - Example: `adom-bridge fusion_screenshot_fusion` (main window) - - Example: `adom-bridge fusion_screenshot_fusion '{"hwnd": 12345}'` (specific dialog) - -- `fusion_screenshot_all` -- Screenshots the main Fusion window and lists all dialog windows with their HWNDs. Use `fusion_screenshot_fusion {"hwnd": ...}` to capture each dialog. - - Example: `adom-bridge fusion_screenshot_all` - -- `fusion_click_fusion` -- Click at coordinates within the Fusion window or a specific dialog. x/y are relative (0.0-1.0) by default. Set `"relative": false` for pixel offsets. Uses SendInput for CEF dialog compatibility. **Prefer `fusion_send_key` for dialogs** — enter/escape/tab covers most cases. - - Args: `x` (required), `y` (required), `relative` (optional, default true), `hwnd` (optional — target a specific dialog HWND instead of main window) - - Example: `adom-bridge fusion_click_fusion '{"x": 0.5, "y": 0.7}'` (main window) - - Example: `adom-bridge fusion_click_fusion '{"hwnd": 12345, "x": 0.75, "y": 0.85}'` (dialog button) - -- `fusion_send_key` -- Send keyboard input to Fusion or a specific dialog via SendInput. **Preferred way to dismiss dialogs**: enter to confirm, escape to cancel, tab to cycle buttons. Use click only if tab order doesn't reach the right button. - - Args: `key` (required), `hwnd` (optional — target a specific dialog HWND) - - Example: `adom-bridge fusion_send_key '{"key": "escape"}'` (dismiss CEF dialog) - - Example: `adom-bridge fusion_send_key '{"key": "enter", "hwnd": 12345}'` (confirm dialog) - -#### Fusion 360 Workflow Guide - -##### Opening Electronics Projects -1. Open the `.fprj` file: `adom-bridge fusion_open_cloud_file '{"projectName":"Main","fileName":"DRV8411A","fileExtension":"fprj","folderPath":"Molecules/XRP/DRV8411A"}'` -2. Do NOT try to open `.fbrd` or `.fsch` directly — they fail or show a "Select Electronics Design File" dialog -3. Enter the board editor: `adom-bridge fusion_show_2d_board` -4. Enter the schematic editor: After step 3, use `adom-bridge fusion_electron_run '{"command":"EDIT .sch"}'` -5. Switch back to board: `adom-bridge fusion_electron_run '{"command":"EDIT .brd"}'` - -##### Auto-Screenshot on Open Commands - -**Open commands automatically screenshot Fusion and return the images in the response.** The following commands include `postOpenScreenshot` in their `data` field: -- `fusion_open_cloud_file`, `fusion_open_schematic`, `fusion_open_board`, `fusion_show_3d_board`, `fusion_show_2d_board` - -The response `data.postOpenScreenshot` contains: -- `screenshots[]` — array of `{type, savedTo, sizeKB, title?, hwnd?}`. Type is `"main_window"` or `"dialog"`. -- `message` — human-readable instruction to READ each screenshot and check for blocking dialogs -- `dialogBlocking` — `true` if a modal dialog was detected - -**After receiving the response, you MUST:** -1. **READ each screenshot file** using the Read tool to visually inspect what Fusion shows -2. Look for blocking dialogs in the screenshots: - - "What to design?" wizard → dismiss with `fusion_send_key {"key": "escape"}` - - "PCB out of date" banner → click Update or X - - "Recovered Documents" → `fusion_dismiss_recovery` - - "Save changes?" → `fusion_send_key {"key": "escape"}` - - Any other modal → identify and dismiss -3. **Screenshot again** after dismissing to confirm it's clear - -Screenshots are saved as WebP (lossless, ~20-40KB each, downscaled to ≤1568px) for token efficiency. Both the main Fusion window AND all Qt dialog windows are captured separately. - -**Why this matters**: Fusion shows Qt dialogs and CEF overlays that are invisible to the API. The `success: true` response from an open command does NOT mean the UI is ready — a dialog may be blocking all further operations. The API cannot detect these. Only a screenshot can. - -##### Detecting and Handling Blocking Dialogs -- The auto-screenshot captures dialog windows separately (look for `type: "dialog"` entries in `postOpenScreenshot.screenshots[]`) -- Common blocking dialogs: "What do you want to design?", "Recovered Documents", "Open recovery document instead?", "Select Electronics Design File" -- Dismiss recovery dialogs: `adom-bridge fusion_dismiss_recovery` -- Dismiss CEF dialogs (inside main window): `adom-bridge fusion_send_key '{"key": "escape"}'` or `fusion_click_fusion` -- Dismiss "What do you want to design?" wizard: `adom-bridge fusion_send_key '{"key": "escape"}'` -- For manual screenshot of specific dialogs: `adom-bridge desktop_screenshot_window '{"hwnd": <DIALOG_HWND>}'` - -##### Preventing Recovery Documents -- Recovery files are at: `%LOCALAPPDATA%\Autodesk\Autodesk Fusion 360\<USER_ID>\CrashRecovery\` -- Before force-killing Fusion, close all documents: `adom-bridge fusion_close_all_documents '{"saveChanges": false}'` -- **Best practice**: Call `adom-bridge fusion_relocate_recovery` before launching Fusion. This moves recovery files to `~/.adom/recovery/fusion/<timestamp>/` — preserving them for the user while preventing modal dialogs. -- The `fusion_start` command also auto-relocates recovery files before starting Fusion. -- The `fusion_dismiss_recovery` command handles both "Recovered Documents" list and "Open recovery document instead?" prompts, and also relocates files. - -##### EAGLE Export Limitations -- **Supported**: `EXPORT IMAGE`, `EXPORT NETLIST`, `EXPORT PARTLIST` -- **NOT supported** (fail silently): `EXPORT DXF`, `EXPORT SVG`, `EXPORT DRILL` -- Always verify export output: the updated `fusion_electron_run` now checks if the output file was created -- Use `fusion_export_bom` and `fusion_export_cpl` for manufacturing data (these use the add-in's XML parser, not EAGLE export) -- Use `fusion_export_gerbers` for Gerber files — produces a ZIP with all gerber layers (GTL, GBL, GTS, GBS, GTP, GBP, GTO, GBO, GKO, XLN). Auto-detects 2-layer vs 4-layer boards. - -##### 3D Model Exports -- From the 3D view (activate the .f3d document): `fusion_export_step`, `fusion_export_stl`, `fusion_export_3mf`, `fusion_export_f3d`, `fusion_export_usdz`, `fusion_export_iges`, `fusion_export_sat` -- Switch to 3D view: `fusion_show_3d_board` or activate the .f3d document -- **STEP** — Industry-standard CAD interchange (SolidWorks, CATIA, Creo). Highest geometric fidelity. -- **IGES** — Legacy CAD interchange. Use STEP for modern workflows. -- **SAT** — ACIS solid model format. Used by SolidWorks, SpaceClaim. -- **STL** — Mesh format for 3D printing and visualization. Options: refinement "low"/"medium"/"high". -- **3MF** — Modern 3D printing with color/material support and multi-body. -- **F3D** — Native Fusion 360 archive. Preserves parametric features, sketches, timeline, component refs. Best for archival. -- **USDZ** — **Best for digital twins and GLB conversion.** Preserves full component hierarchy (Board, copper layers, soldermask, Packages), PBR materials, and named nodes. Each component becomes a toggleable node in GLB viewers. Also viewable directly on iOS/macOS (Apple Quick Look / AR). - - Digital twin pipeline: `fusion_export_usdz` → pull_file → `blender --background --python-expr "import bpy; bpy.ops.wm.usd_import(filepath='board.usdz'); bpy.ops.export_scene.gltf(filepath='board.glb')"` -- **FBX** — Not available in current Fusion builds via the API. The command exists but fails clearly. Use `fusion_export_usdz` instead. -- **DXF/DWG/OBJ/SKP** — Not available via the Fusion API (dialog-only). Commands exist but return clear errors with alternatives. - -##### 3D Viewport Captures -- `fusion_take_screenshot` — Capture the Fusion viewport at any resolution without opening a dialog. Uses Fusion's render API (`saveAsImageFile`). - - Args: `outputPath` (required), `width` (default 1920), `height` (default 1080), `orientation` (optional) - - Orientations: `home`, `front`, `back`, `top`, `bottom`, `left`, `right` - - Example: Capture all 6 standard views for use as product images/icons: - ```bash - for orient in home front back top bottom left right; do - adom-bridge fusion_take_screenshot "{\"outputPath\": \"C:/tmp/3d-${orient}.png\", \"width\": 1920, \"height\": 1080, \"orientation\": \"${orient}\"}" - done - ``` - -##### Electronics Source File Export (`fusion_export_source`) -- `fusion_export_source` — Export the active electronics document as `.fsch`, `.fbrd`, or `.flbr` source file. - - Args: `outputPath` (required — full path with extension) - - The extension determines the format: `.fsch` (schematic), `.fbrd` (board), `.flbr` (library) - - Validates extension, creates output directory, verifies file was created, returns file size - -- **Full workflow to export both board and schematic from a cloud project:** - ```bash - # Step 1: Open the .fprj (NOT .fbrd/.fsch directly — those fail) - adom-bridge fusion_open_cloud_file '{"projectName":"Main", "fileName":"MyDesign", "fileExtension":"fprj", "folderPath":"Molecules/MyDesign"}' - - # Step 2: Screenshot to check for blocking dialogs (always do this after open) - adom-bridge fusion_screenshot_fusion - - # Step 3: Enter board view (MUST be Board Layout workspace, not 3D) - adom-bridge fusion_show_2d_board - - # Step 4: Export .fbrd (board first — it's already in board view) - adom-bridge fusion_export_source '{"outputPath": "C:/tmp/exports/MyDesign.fbrd"}' - - # Step 5: Switch to schematic (EDIT .s1 = first schematic sheet) - adom-bridge fusion_electron_run '{"command": "EDIT .s1"}' - - # Step 6: Export .fsch - adom-bridge fusion_export_source '{"outputPath": "C:/tmp/exports/MyDesign.fsch"}' - - # Step 7: Pull files to Docker - adom-bridge pull_file '{"filePaths":["C:/tmp/exports/MyDesign.fbrd","C:/tmp/exports/MyDesign.fsch"], "saveTo":"/tmp/exports"}' - ``` - -- **Critical gotchas:** - - You MUST open the `.fprj` first — opening `.fbrd`/`.fsch` directly fails or triggers blocking dialogs - - You MUST call `fusion_show_2d_board` before exporting `.fbrd` (the Electronics Design overview won't work) - - Always export `.fbrd` FIRST (from board view), then switch to schematic for `.fsch` - - If export fails with "file not found", the wrong workspace is active — screenshot to verify - - After `fusion_open_cloud_file`, always screenshot to check for "Select Electronics Design File" dialog - - `WRITE` command is blocked — it opens a blocking save dialog. Use `fusion_export_source` instead - -- Note: `WRITE` is blocked — it opens a "Version Description" dialog on cloud docs even with a path argument (tested 2026-04-10). Use `fusion_save_to_cloud` to save to cloud, `fusion_export_source` for Fusion-format, or `fusion_export_eagle_source` for plain EAGLE format. - -##### Plain EAGLE Source Export (`fusion_export_eagle_source`) -- `fusion_export_eagle_source` — Export the active electronics document as plain EAGLE XML `.sch` or `.brd`. - - Args: `outputPath` (required — full path ending in `.sch` or `.brd`) - - Internally: exports `.fsch`/`.fbrd` via `Document.CopyToDesktop`, then extracts the EAGLE XML from the ZIP container, cleans up the temp file. - - The output is valid EAGLE XML (`<?xml><eagle version="9.7.0">...`) parseable by standalone EAGLE, KiCad import, or any XML tool. - - Same workflow/prerequisites as `fusion_export_source` — just use `.sch`/`.brd` extensions instead of `.fsch`/`.fbrd`. - - ```bash - # Board (.brd) — must be in PCB Editor / Board Layout - adom-bridge fusion_show_2d_board - adom-bridge fusion_export_eagle_source '{"outputPath": "C:/tmp/exports/MyDesign.brd"}' - - # Schematic (.sch) — must be in Schematic Editor - adom-bridge fusion_electron_run '{"command": "EDIT .s1"}' - adom-bridge fusion_export_eagle_source '{"outputPath": "C:/tmp/exports/MyDesign.sch"}' - ``` - -##### Dialog Dismissal (`fusion_close_window`) -- `fusion_close_window` — Close a specific Fusion dialog by sending WM_CLOSE (equivalent to clicking X). - - Args: `hwnd` (required — from `fusion_window_info` or `fusion_dismiss_blocking_dialogs` remaining[]) - - Works on dialogs that Escape doesn't close — e.g. "Recovered Documents" - - Does NOT force-kill — the dialog can still intercept WM_CLOSE - -##### Electronics Import (Round-Trip) -- `fusion_import_electronics` — Import Fusion-native `.fsch`, `.fbrd`, or `.flbr` files as new local documents - - Uses `Document.newDesignFromLocal` under the hood - - Auto-screenshots after import (catches blocking dialogs) - - Args: `filePath` (required Windows path to .fsch, .fbrd, or .flbr) - - After import, use `fusion_save_to_cloud` to persist to Fusion cloud - - **`.fsch` import works standalone** — creates a new schematic project - - **`.fbrd` import may fail** — boards have external references to schematics/libraries. Error: "New design cannot be created from a local file containing external references" - - **`.flbr` import works standalone** — creates a new library project - - For legacy EAGLE files: use `fusion_open_schematic` (.sch), `fusion_open_board` (.brd), `fusion_open_lbr` (.lbr) - -##### Library Round-Trip Workflow -Export and re-import Fusion electronics libraries: -```bash -# 1. Open library from cloud -adom-bridge fusion_open_cloud_file '{"projectName":"Main","fileName":"Adom Common Components","folderPath":"Molecules/Libraries"}' - -# 2. Export as .flbr (Fusion-native binary) and .scr (EAGLE script text) -adom-bridge fusion_save_lbr '{"outputPath":"C:/tmp/library.flbr"}' -adom-bridge fusion_export_lbr '{"outputPath":"C:/tmp/library.scr"}' -adom-bridge fusion_close_document - -# 3. Re-import the .flbr -adom-bridge fusion_import_electronics '{"filePath":"C:/tmp/library.flbr"}' - -# 4. Verify symbols survived round-trip -adom-bridge fusion_export_lbr '{"outputPath":"C:/tmp/library-verify.scr"}' - -# 5. Save to cloud with new name -adom-bridge fusion_save_to_cloud '{"name":"Library-copy"}' -``` - -##### Demo Projects -171+ electronics molecules are exported in the `adom-bridge-demo` repo (separate from adom-bridge). -Three reference boards with full export formats: - -| Board | Cloud Path | Layers | Components | Files | -|-------|-----------|--------|------------|-------| -| DRV8411A | Main / Molecules / XRP / DRV8411A | 4 | 29 | 27 | -| DRV8323SR | Main / Molecules / Experiments / MotorControl / DRV8323SR | 2 | 43 | 27 | -| VL53L8BreakoutMolecule | Main / Molecules / XRP / TimeOfFlightVL53L8 / VL53L8BreakoutMolecule | 2 | 30 | 27 | - -Each folder contains: .fsch, .fbrd, bom.csv, cpl.csv, gerbers.zip, 6 board images, 7 3D renders (home/front/back/top/bottom/left/right), STEP, IGES, SAT, STL, 3MF, F3D, USDZ, board screenshot, 3D board screenshot. - -#### Cloud Document Management - -Manage Fusion 360 cloud documents (hub projects, files, versions). Required for 3D package workflows since EAGLE library 3D models are stored as cloud documents. - -- `fusion_save_to_cloud` -- Save the active Fusion document to the cloud. Args: `name` (required), `projectName` (optional, defaults to active project), `folderPath` (optional), `description` (optional). Returns: `fileId`, `versionNumber`, `wipUrn` (if cloud-hosted). -- `fusion_list_cloud_projects` -- List all cloud projects in the user's hub. Returns array of `{name, id}` per hub. -- `fusion_list_cloud_files` -- List files in a cloud project/folder. Args: `projectName` (optional), `folderPath` (optional). Returns: `files` array with `{name, id, versionNumber, fileExtension, dateModified}` and `subfolders` array. -- `fusion_create_cloud_folder` -- Create a folder in a cloud project. Args: `folderName` (required), `projectName` (optional), `parentPath` (optional). Returns `folderId`. Idempotent — returns existing folder if it already exists. -- `fusion_check_recovery` -- Check if a cloud file has a recovery document from a previous crash. Args: `fileName` (required), `projectName` (optional), `folderPath` (optional). Returns `hasRecovery: true/false`. Use this BEFORE opening files to avoid the blocking "Open recovery document instead?" dialog. If recovery exists, call `fusion_open_cloud_file` with `recovery: "open"` (restore unsaved work) or `recovery: "discard"` (delete recovery, open cloud version). -- `fusion_open_cloud_file` -- Open a cloud file in Fusion by name. **If a recovery document exists and no `recovery` arg is given, the command STOPS and reports the recovery instead of opening** — you must decide whether to preserve or discard unsaved work. Args: `fileName` (required), `projectName` (optional), `folderPath` (optional), `recovery` ("open" = restore unsaved work, "discard" = delete recovery and open cloud version). -- `fusion_export_cloud_file` -- Export the active Fusion document to a local file for transfer back to Docker. Args: `outputPath` (required), `format` (optional, default "step"). The exported file can then be pulled back to Docker via `pull_file`. -- `fusion_delete_cloud_file` -- Delete a cloud file by name. Args: `fileName` (required), `projectName` (optional), `folderPath` (optional). File must not be open in Fusion — close it first with `fusion_close_document`. -- `fusion_walk_cloud_tree` -- **Long-running.** BFS walk of a cloud folder tree. Returns a flat list of all files and folders. Runs entirely on the Fusion main thread — **blocks all other add-in commands** until done (check progress with `fusion_addin_status`). - - Args: `projectName` (optional), `folderPath` (optional, starting folder), `maxDepth` (default 10), `maxFolders` (default 500), `extensions` (optional list, e.g. `["f3d","fprj"]`), `nameContains` (optional substring filter), `includeFiles` (default true) - - Returns: `{project, rootFolder, folders[], files[], stats: {foldersVisited, foldersSkipped, filesFound, maxDepthReached, truncated}}` - - **Per-folder timeout (30s):** If a single folder's cloud API calls take >30s (common for large projects), the folder is skipped and counted in `foldersSkipped`. This prevents indefinite hangs. - - **Progress tracking:** While running, `fusion_addin_status` returns `walkProgress` with `{foldersVisited, filesFound, currentFolder, queueSize}` — poll this every 1–10s to monitor progress (see "Live folder progress streaming" below). - - **Non-blocking alternative:** Use `fusion_search_cloud_files` for targeted searches, or `fusion_list_cloud_files` for single-folder listings (these are faster but don't recurse). - - Example: `adom-bridge fusion_walk_cloud_tree '{"projectName":"Main","folderPath":"Molecules","nameContains":"DRV","extensions":["fprj"]}'` - -#### Live folder progress streaming with `watch` - -For long walks, use the built-in `watch` wrapper. It spawns the inner search command on a worker thread, polls `fusion_addin_status` internally, and emits one JSON event per line to stdout as the walker visits each folder. **No manual polling loop needed.** - -```bash -adom-bridge watch '{"command":"fusion_walk_cloud_tree","args":{"projectName":"Main","folderPath":"Molecules","nameContains":"BQ25792"}}' -``` - -Output is one JSON object per line, three event types: - -```jsonl -{"event":"started","command":"fusion_walk_cloud_tree","args":{...},"interval":2,"_hint":"streaming progress events follow, one per line, ending with 'complete' or 'error'"} -{"event":"progress","busyCommand":"walk_cloud_tree","elapsedSeconds":15.0,"foldersVisited":14,"queueSize":50,"filesFound":0,"currentFolder":"Molecules/Sensing"} -{"event":"progress","busyCommand":"walk_cloud_tree","elapsedSeconds":23.4,"foldersVisited":22,"queueSize":108,"filesFound":0,"currentFolder":"Molecules/Examples"} -{"event":"progress","busyCommand":"walk_cloud_tree","elapsedSeconds":31.8,"foldersVisited":30,"queueSize":100,"filesFound":0,"currentFolder":"Molecules/RAPID NAME TAGS/Connor Wood"} -... (one per real change in walkProgress, deduped) ... -{"event":"complete","result":{"folders":[...],"files":[...],"stats":{"foldersVisited":169,"filesFound":12,"truncated":false}}} -``` - -Read stdout line-by-line. Stop when you see `event:complete` or `event:error`. The full final result is in the `complete` event's `result` field. - -**Optional `interval` arg** (default 2s, clamped to [1, 30]): - -```bash -adom-bridge watch '{"command":"fusion_walk_cloud_tree","args":{...},"interval":1}' -``` - -**For Claude Code consumers**: pipe `watch` directly into the `Monitor` tool. Each JSON line becomes a real-time event notification in the chat — you (and the user) see folder names appear one-by-one as the walker visits them. No bash loop, no `disown`, no subprocess gymnastics. Verified live in 1.3.16 on a 169-folder walk that returned all 12 BQ25792 cloud files cleanly. - -**Watchable commands** (whitelist): `fusion_walk_cloud_tree`, `fusion_search_cloud_files`. Other commands return `success:false` with a `_hint` listing the watchable set. - -**When NOT to use watch**: short single-folder operations (`fusion_list_cloud_files`, `fusion_open_cloud_file`) — those return in <2s and don't need streaming. The `watch` wrapper is purely for the long BFS commands. -- `fusion_search_cloud_files` -- **Long-running.** Recursive substring search on file names across cloud folders. v1.0.2+ of the add-in adds: per-folder timeout, doEvents() every 50 files, per-file try/except, iterative BFS, and a stale-lock watchdog — Fusion stays responsive throughout (no "Not Responding" freeze). - - **Args (no hard upper caps in v1.0.2+):** `query` (required, substring, case-insensitive), `projectName` (optional, defaults to active), `folderPath` (optional starting subfolder — **narrow with this**), `recursive` (default false), `maxDepth` (default 2), `maxFolders` (default 10), `maxResults` (default 20), `folderTimeout` (default 30s), `searchTimeout` (default 120s), `timeout` (HTTP envelope, default 620s). - - **Before calling:** if the user knows roughly where the file is (e.g. customer-named folder), **ask them**. Naming a subfolder cuts 5-40 min searches down to ~10s. - - **Why slow:** Autodesk's free Fusion 360 Python API has no indexed file-search endpoint. We walk the Data API one folder at a time — each = one HTTP round-trip to Autodesk. **This is an Autodesk API limitation, not adom-bridge's.** When telling the user the search is taking a while, attribute it to Autodesk / Fusion 360, not to adom-bridge's bridge. **There is now a FAST native alternative — `aps_search` (see "APS — fast indexed cloud search" below).** It hits Autodesk Platform Services' indexed Data Management API and returns ~instantly, even when Fusion is CLOSED. Call `aps_status` first; if `configured:true`, prefer `aps_search` and only fall back to this folder-walking verb when APS isn't set up. - - **Interpreting results (critical for no-false-negatives):** the response contains `searchComplete` (bool), `foldersSkipped`, `filesSkipped`, `truncated`, `folderLimitReached`, `searchTimedOut`. `searchComplete:true` ONLY when **all five** are clean — that's the confidence flag. If `searchComplete:false`, the search hit a cap before exhausting the scope; **don't report "file not found"** — re-run with broader caps OR narrower `folderPath`. - - **Case sensitivity:** fully case-insensitive both directions (query and file names lowercased). Substring match, not whole-word — `"cosm"` matches `COSMIIC`, `COSMOCOIL`, etc. - - **Cost feedback in response:** `costAnalysis: {elapsedSeconds, foldersPerSecond, estimatedSecondsPer100Folders}` so the AI can budget the next search realistically. - - **Real numbers from a live test:** searching `Main/Molecules` recursively (173 folders deep, max 8 depth) for "cosmiic" returned in 168 s with `searchComplete:true, totalFound:3`. Fusion stayed `main_thread:responsive` throughout. - - **Pair with `watch`** for streaming progress updates: see below. - -#### APS — fast indexed cloud search (v1.8.182+) - -`aps_search` is a **native, ~instant** alternative to the folder-walking `fusion_search_cloud_files`. It queries **Autodesk Platform Services** (APS, formerly Forge) **Data Management API**, which has a real server-side index — so a search that takes minutes by folder-walking returns in well under a second, and it works **even when Fusion 360 is closed** (it's pure HTTPS, no bridge required). adom-bridge runs its own 3-legged **PKCE** OAuth, so the user's APS **client secret never leaves their machine**. - -**One-time setup (user side):** -1. Register a free app at <https://aps.autodesk.com> → enable the **Data Management API**. -2. Set the app's **Callback URL** to exactly `http://localhost:8910/aps/callback`. -3. Put the **Client ID** in ab config key `aps_client_id` (in `~/.adom/config.json`) or via Settings. -4. Run `aps_auth` once — it opens the system browser for Autodesk sign-in. Tokens cache in `~/.adom/aps_tokens.json` and auto-refresh; you won't be prompted again. - -**Verbs:** -- `aps_status` — **call this first.** Non-prompting. Returns `{configured, signedIn}`. `configured:false` → no client id; use `fusion_search_cloud_files`. `configured:true, signedIn:false` → run `aps_auth`. Both true → `aps_search` is ready. -- `aps_auth` — interactive sign-in (opens browser). One-time per device. -- `aps_hubs` — `{hubs[]{id,name}}` (your Autodesk teams). -- `aps_projects {hubId?}` — `{hubId, projects[]{id,name}}` (default: first hub). -- `aps_search {query, projectName?, projectId?, hubId?}` — `{query, hubId, count, results[]{name,id,type,lastModified,project}}`. `query` is a case-insensitive substring of the file's displayName. Without `projectName`/`projectId` it searches up to 8 projects in the hub. Open a hit with `fusion_open_cloud_file {fileName, projectName}`. - -**Decision flow for an AI doing a cloud file search:** `aps_status` → if `configured` (sign in with `aps_auth` if needed) use `aps_search`; else fall back to `fusion_search_cloud_files` and tell the user that registering a free APS app (above) would make future searches instant. - -**Export formats for `fusion_export_cloud_file`:** - -| Format | Extension | Use case | -|--------|-----------|----------| -| `step` | .step | Industry-standard CAD interchange (default) | -| `stl` | .stl | 3D printing, mesh-based | -| `f3d` | .f3d | Fusion 360 native archive (preserves all features) | -| `iges` | .iges | Legacy CAD interchange | -| `sat` | .sat | ACIS solid modeling kernel format | -| `smt` | .smt | Parasolid format | - -Also supported for import via `fusion_import_step`: STEP (.step/.stp), STL (.stl), IGES (.iges/.igs), SAT (.sat), SMT (.smt), OBJ (.obj), F3D (.f3d). - -**Round-trip: workspace → Fusion Cloud → workspace** - -```bash -# === workspace to Fusion Cloud === -# 1. Send file from Docker to Windows desktop -adom-bridge send_files '{"files": [{"path": "/home/user/component.step"}]}' -# 2. Import into Fusion -adom-bridge fusion_import_step '{"filePath": "C:/Users/john/Downloads/component.step"}' -# 3. Save to cloud (gets a wip_urn for 3D library linking) -adom-bridge fusion_save_to_cloud '{"name": "my-component", "projectName": "Personal"}' - -# === Fusion Cloud to Docker === -# 1. Find and open the cloud file -adom-bridge fusion_walk_cloud_tree '{"projectName": "Personal", "nameContains": "my-component"}' -adom-bridge fusion_open_cloud_file '{"fileName": "my-component", "projectName": "Personal"}' -# 2. Export to local filesystem -adom-bridge fusion_export_cloud_file '{"outputPath": "C:/tmp/export/my-component.step", "format": "step"}' -# 3. Pull back to Docker -adom-bridge pull_file '{"path": "C:/tmp/export/my-component.step"}' - -# === Cloud management === -adom-bridge fusion_list_cloud_projects '{}' -adom-bridge fusion_create_cloud_folder '{"folderName": "Electronics", "projectName": "Main"}' -adom-bridge fusion_list_cloud_files '{"projectName": "Main", "folderPath": "Electronics"}' -adom-bridge fusion_delete_cloud_file '{"fileName": "old-file", "projectName": "Main"}' -``` - -#### Manufacturing Exports (Gerbers, BOM, CPL) - -Export manufacturing files from an open PCB board — everything needed to fabricate boards and assemble components via Adom's PCBA service. **All manufacturing commands require a .brd board open in PCB Editor** (use `fusion_open_board` or `fusion_show_2d_board`). - -**Recommended workflow order:** `detect_layers` → `set_design_rules` → DRC → `export_gerbers` → `export_bom` → `export_cpl` → `pull_file` all back to Docker. - -Every manufacturing command returns structured JSON with: -- `message` — AI-oriented summary explaining what was produced and why it matters -- `nextSteps[]` — ordered list of what to run next in the manufacturing pipeline -- `hint` — tips for interpreting results or recovering from issues -- `data` — structured metadata (paths, counts, layer info) for programmatic use - -**Decision guide — which command to run:** -- **Don't know the layer count?** → Run `fusion_detect_layers` first -- **Need to check if the board meets fab specs?** → Run `fusion_set_design_rules` then DRC -- **Ready to generate fab files?** → Run `fusion_export_gerbers`, then `fusion_export_bom`, then `fusion_export_cpl` -- **Need visual review before export?** → Run `fusion_export_board_image` with preset `assembly_top` or `fabrication` -- **Something failed?** → Check `data.hint` and `data.recoverySteps` in the error response - -**Commands:** - -- `fusion_detect_layers` -- Detect if the open board is 2-layer or 4-layer. Uses ULP script (primary) and CAM comparison (fallback). Returns `layerCount`, `copperLayers[]`, `method` (how it was detected), and `nextSteps[]`. **Run this first** — all other manufacturing commands auto-detect layers too, but running this explicitly gives you the data before committing to exports. - -- `fusion_set_design_rules` -- Apply Adom's JLCPCB-derived design rules (.edru XML files) to the open board. Auto-detects 2-layer vs 4-layer and loads the appropriate rule set. Returns `description` (human-readable rule summary), `edruFile`, and `nextSteps[]`. - - `action`: `"apply"` (default) loads rules into the board; `"export"` saves current board rules to a file; `"show"` displays rule capabilities without modifying anything - - `layers`: `"auto"` (default), `"2"`, or `"4"` — force a specific rule set - - After applying: run `fusion_electron_run '{"command": "DRC"}'` to check for violations. DRC markers appear in the board editor. - -- `fusion_apply_instapcb_rules` -- Convenience wrapper that applies the bundled Adom InstaPCB design rule sets without needing a local `.edru` file. Args: `layers` (`"2"` or `"4"`). Sends the bundled `.edru` from Docker to Windows automatically and loads it via the EAGLE `drc load` command. Use this instead of `fusion_set_design_rules` when you just want Adom's standard 2-layer or 4-layer InstaPCB rules. - -- `fusion_load_design_rules` -- Generic loader for ANY custom `.edru` file by path. Args: `filePath`. Use this for third-party fab vendor rules (JLCPCB, PCBWay, OSHPark, etc.) that the user has on disk. - -- `fusion_export_gerbers` -- Export Gerber (RS-274X) + Excellon drill files as a ZIP. Auto-detects 2-layer vs 4-layer and selects the correct JLCPCB-compatible CAM job. Returns `zipPath`, `zipSizeKB`, `files[]` (list of gerber files in the ZIP with sizes), `layerCount`, and `nextSteps[]`. - - `outputDir`: directory for the output ZIP (default: `C:/tmp/adom-gerbers/`) - - `boardName`: prefix for the ZIP filename (default: from active document name) - - `layers`: `"auto"` (default), `"2"`, or `"4"` — force CAM job selection - - Output ZIP contains: GTL, GBL (copper), GTS, GBS (solder mask), GTP, GBP (paste), GTO, GBO (silkscreen), GKO (outline), XLN (drill). 4-layer boards also get G1, G2 (inner copper). - -- `fusion_export_bom` -- Export Bill of Materials as CSV. Groups identical parts by value+package with quantity counts. Returns `componentCount`, `uniquePartCount`, and `nextSteps[]`. - - `outputPath`: (default: `C:/tmp/adom-bom.csv`) - - `grouped`: `true` (default) groups by value+package; `false` lists every component individually - - Output columns: Comment, Designator, Footprint, Quantity, Library — compatible with JLCPCB, PCBWay, Mouser, Digi-Key. - -- `fusion_export_cpl` -- Export Component Placement List (pick-and-place) as CSV. Returns `totalPlacements`, `topCount`, `bottomCount`, and `nextSteps[]`. - - `outputPath`: (default: `C:/tmp/adom-cpl.csv`) - - `side`: `"all"` (default), `"top"`, or `"bottom"` — filter for single-sided assembly - - Output columns: Designator, Mid X, Mid Y, Layer, Rotation — coordinates in mm. - -- `fusion_export_board_image` -- Export PNG image of the board with layer presets. Returns `fileSize`, `preset`, and `nextSteps[]`. - - `outputPath`: (default: `C:/tmp/adom-board.png`) - - `dpi`: resolution (default: 300, max: 600) - - `preset`: layer preset name (see table below) - - `layers`: custom layer numbers as int array — overrides preset - - `monochrome`: `true` for black & white - - `listPresets`: set `true` to get available presets instead of exporting - -**Layer presets for `fusion_export_board_image`:** - -| Preset | Layers | Description | -|--------|--------|-------------| -| `all` | All | Every layer visible | -| `top_copper` | 1, 17, 18 | Top copper + pads + vias | -| `bottom_copper` | 16, 17, 18 | Bottom copper + pads + vias | -| `top_silkscreen` | 21, 25 | Top silkscreen + component names | -| `bottom_silkscreen` | 22, 26 | Bottom silkscreen + component names | -| `top_soldermask` | 29 | Top solder mask openings | -| `bottom_soldermask` | 30 | Bottom solder mask openings | -| `top_paste` | 31 | Top paste/stencil openings | -| `bottom_paste` | 32 | Bottom paste/stencil openings | -| `board_outline` | 20 | Board outline (dimension layer) | -| `drill` | 44, 45, 17, 18 | Drill holes + vias | -| `assembly_top` | 1, 17, 18, 20, 21, 25, 51 | Top assembly — copper + silk + outline | -| `assembly_bottom` | 16, 17, 18, 20, 22, 26, 52 | Bottom assembly — copper + silk + outline | -| `fabrication` | 1, 16, 17–20, 21, 22, 25, 26, 29, 30, 51 | Full fabrication view | - -**Adom InstapcbPCB manufacturing capabilities (used by `fusion_set_design_rules`):** - -| Parameter | Metric | Imperial | -|-----------|--------|----------| -| Layers | 1, 2, 4, 6 | — | -| Min trace width | 0.08mm | 3 mil | -| Min trace spacing | 0.08mm | 3 mil | -| Min via drill | 0.2mm | 8 mil | -| Min silkscreen text | 0.1mm | 4 mil | -| Board edge clearance | 0.05mm | 2 mil | -| Board thickness | 1.6mm | 63 mil | -| Copper weight | 0.5 oz (17.5 μm) | — | -| Solder mask | Green | — | -| Surface finish | HASL / ENIG | — | -| Turnaround | 4 hours (fab + assembly) | — | - -**Manufacturing workflow — Fusion to Adom PCBA:** - -```bash -# 1. Open the board -adom-bridge fusion_open_board '{"filePath": "C:/projects/myboard.brd"}' - -# 2. Detect layer count (auto-selects 2-layer or 4-layer rules/CAM) -adom-bridge fusion_detect_layers - -# 3. Apply Adom design rules for the detected layer count + run DRC -adom-bridge fusion_set_design_rules '{"action": "apply"}' -adom-bridge fusion_electron_run '{"command": "DRC"}' - -# 4. Export manufacturing files (gerbers auto-select correct CAM job) -adom-bridge fusion_export_gerbers '{"outputDir": "C:/tmp/mfg"}' -adom-bridge fusion_export_bom '{"outputPath": "C:/tmp/mfg/bom.csv"}' -adom-bridge fusion_export_cpl '{"outputPath": "C:/tmp/mfg/cpl.csv"}' - -# 5. Export board images for review -adom-bridge fusion_export_board_image '{"outputPath": "C:/tmp/mfg/top-copper.png", "preset": "top_copper"}' -adom-bridge fusion_export_board_image '{"outputPath": "C:/tmp/mfg/assembly-top.png", "preset": "assembly_top"}' -adom-bridge fusion_export_board_image '{"outputPath": "C:/tmp/mfg/board-outline.png", "preset": "board_outline"}' - -# 6. Pull files back to Docker for Adom PCBA ordering -adom-bridge pull_file '{"path": "C:/tmp/mfg/bom.csv"}' -adom-bridge pull_file '{"path": "C:/tmp/mfg/cpl.csv"}' -``` +**A bridge's verbs are documented by the bridge, not here (2.1.145, wiki #212).** `commands` lists the bridges the box has; `commands {"bridge":"<name>"}` is the bridge's own description; `sync_skills` installs its skill. Nothing below is about any one bridge. ### Desktop Tools @@ -1155,64 +544,9 @@ adom-bridge pull_file '{"path": "C:/tmp/mfg/cpl.csv"}' **Decision rule:** human-in-the-loop login flow → `desktop_open_url`. AI-driven automation → `pup_open_window` (defaults to Chrome for Testing). AI-driven automation that **must** be the user's real, signed-in profile (GCP Console with org/projects, internal SSO behind a managed-Chrome policy, anything Context-Aware Access blocks for non-enrolled browsers) → `pup_open_window` with the new `nativeBrowser` + `nativeProfile` args (v1.0.5+, see below). -#### When pup means "the user's real Chrome/Edge" — `pup_open_window` native mode (v1.0.6+, smart flow v1.0.11) - -Default `pup_open_window` (no native args) launches Chrome for Testing — same as day one. **Never auto-switch a plain pup request to native.** "Open this URL in pup", "screenshot this", "click that button" all stay on CfT. - -Native mode drives the user's **REAL browser** — their actual signed-in profile, with live cookies, org policies, and device enrollment intact (NOT a clone — v1.0.6 replaced the old clone approach). Opt-in via TWO additive args from `desktop_list_browsers`: - -```bash -adom-bridge desktop_list_browsers # installed browsers + profiles (+ the signed-in account per profile) -adom-bridge pup_open_window '{ - "sessionId":"gcp", - "nativeBrowser":"chrome", # chrome / edge / brave - "nativeProfile":"Default", # profile id: Default / Profile 1 / Profile 2 - "url":"https://console.cloud.google.com" -}' -``` - -**The smart flow.** CDP (the protocol pup drives) needs the browser running with `--remote-debugging-port`, which can only be set at launch. So the bridge handles each situation differently and tells you which happened: - -| Situation | What ab does | Response | -|---|---|---| -| Already driving that browser+profile | Reuse the live connection | `ok` + `narrative` | -| Running **with** a debug port (power-user launched it that way, or ab did earlier) | Connect, no relaunch | `ok` + `narrative` | -| **Not running at all** | **Launch it fresh with the debug port — NO prompt** (nothing to disrupt) | `ok`, `launchedFresh:true` + `narrative` — just proceed | -| **Open without** a debug port | **Ask the user** — ab must close+reopen it | `errorCode:"native_relaunch_required"` + `confirmArgs` + `alternatives` | -| Debug port **refuses to bind** (enterprise policy) | Won't close it again | `errorCode:"native_cdp_blocked"` + `diagnosis` + `alternatives` | - -**Handling the two consent/blocked codes:** - -- **`native_relaunch_required`** — the browser is open without the port, so driving it means closing + reopening it (with `--restore-last-session`, so all tabs/windows come back). **Ask the user's permission**, then re-call with `"nativeRelaunch":true`. The response's `alternatives` lists other installed browsers you could offer instead. -- **`native_cdp_blocked`** — the debug port won't open, almost always an **enterprise policy** (`RemoteDebuggingAllowed` disabled via Google Workspace / Chrome cloud management — affects **Chrome browser-wide, every profile**). `diagnosis` says whether it's a confirmed local-registry policy or a likely cloud-managed one. ab will **not** close that browser again. `alternatives` names other installed browsers — **Edge usually escapes Google management**, so it often drives natively when Chrome can't. Offer the user the alternative, or fall back to generic CfT. - -**Always available — generic CfT.** `pup_open_window` with NO `nativeBrowser`/`nativeProfile` drives a clean Chrome-for-Testing instance: no user session, no managed policy, fully controllable. If a task needs the user's logged-in session there, have them sign in once. This is the universal fallback whenever native is blocked. - -**Power-user shortcut:** if the user launches their browser at startup with `--remote-debugging-port=<N>`, ab reconnects every session with no prompt at all (a productized opt-in "keep native browsers debug-ready at boot" is on the roadmap, default OFF for security). - -**Routing rule — DON'T auto-escalate.** Treat native as opt-in: - -| User says | What to do | -|---|---| -| "pup" / "open in pup" / screenshot / eval / debug | DEFAULT pup (CfT). Never mention profiles. | -| "native chrome" / "my real browser" / "my work profile" / "my `<account>` profile" | Native. Call `desktop_list_browsers`. If exactly one profile clearly fits the request, use it and say which one ("opening in your `[email protected]` profile on Chrome"). If multiple profiles could fit (e.g. a `google.com` URL with both `[email protected]` and `[email protected]` profiles signed in), **ASK** ("Which profile — work `[email protected]` or personal `[email protected]`?") and then drive that pair. | -| anything else | Default pup. | - -**Anti-fingerprint:** native sessions launch without `--enable-automation` and with `--disable-blink-features=AutomationControlled`. `navigator.webdriver === false`. No "controlled by automated software" banner. Sites that probe for automation see a normal browser. - -**Firefox** appears in `desktop_list_browsers` but is rejected for native drive with `errorCode:"firefox_no_cdp"` — Firefox doesn't speak the Chrome DevTools Protocol, so puppeteer can't drive it. If the user wants Firefox, hand off via `desktop_open_url` instead. - -**Native-mode error codes:** -- `native_relaunch_required` — browser open without a port; ask the user, re-call with `nativeRelaunch:true` (see the smart-flow table above). -- `native_cdp_blocked` — debug port policy-blocked; read `diagnosis`, offer `alternatives` or generic CfT (see above). -- `firefox_no_cdp` — caller passed `nativeBrowser:"firefox"`. Firefox doesn't speak CDP; hand off via `desktop_open_url`. -- `native_browser_not_installed` — that browser isn't installed on this machine. -- `native_user_data_missing` — installed but never launched, so the User Data dir doesn't exist yet. Ask the user to open it once. -- `native_profile_not_found` — `nativeProfile` isn't a real profile id under this browser's User Data. Call `desktop_list_browsers` to see what's valid. - #### ⚠️ Common footgun — `localhost` / `file://` URLs from Docker AIs -If you're running this CLI from a remote Docker container (my-container, dartv4, etc.), `pup_open_window` / `pup_open_tab` / `pup_navigate` will load the URL inside the USER's local pup — NOT inside your container. So a URL like `http://localhost:8080/foo.html` resolves to the user's machine, not your container's service. +If you're running this CLI from a remote container, a `url` you pass to ANY verb (a bridge's window, `desktop_open_url`) is loaded on the DESKTOP: `localhost` there is the desktop, not your container, and `file://` names a file on the desktop's disk. **v1.7.10+ detects this.** When you pass a URL whose host is `localhost`, `127.0.0.1`, `0.0.0.0`, `::1`, or scheme is `file://`, the response includes a `_hint` field explaining the issue and suggesting the public-slug URL pattern (`https://<user>-<repo>-<suffix>.adom.cloud/proxy/<port>/<path>`). **The call still proceeds** — rare legitimate cases exist where the user actually does have something running on their localhost. @@ -1226,11 +560,8 @@ python3 -m http.server 8786 --bind 0.0.0.0 & # (look at their browser URL when they open hydrogen or claude.ai/code). # Slug looks like: <username>-<container>-<random-id> -# 3. Open the public URL — NOT localhost: -adom-bridge pup_open_window '{ - "sessionId":"demo", - "url":"https://<your-container-slug>.adom.cloud/proxy/8786/foo.html" -}' +# 3. Open the public URL — NOT localhost — in whichever browser verb you use: +adom-bridge desktop_open_url '{"url":"https://<your-container-slug>.adom.cloud/proxy/8786/foo.html"}' ``` If you don't have the suffix handy, just ask the user. Or if the file you wanted to show pup is one your container already wrote to disk, push it to a public location (wiki asset, S3) and load from there. @@ -1495,17 +826,9 @@ adom-bridge settings_set '{"settings": {"launch_on_boot": true, "update_mode": " The pup bridge is **cloud-owned** and ships its OWN full skill (its wiki page / skill pkg — `bridge_list` names it; `adom-bridge sync_skills` installs it). This page keeps only the pointer plus first-touch examples; sessions/profiles, credential vault, downloads, recording, CDP details are the bridge's skill. -Most-used verbs: - -```bash -adom-bridge pup_open_window '{"sessionId": "s1", "profile": "p1", "url": "https://example.com"}' -adom-bridge pup_navigate '{"sessionId": "s1", "url": "https://example.com/page2"}' -adom-bridge pup_screenshot '{"sessionId": "s1"}' -adom-bridge pup_eval '{"sessionId": "s1", "expression": "document.title"}' -adom-bridge pup_fetch_url '{"url": "https://example.com/data.json"}' -``` +Its verbs: `adom-bridge commands '{"bridge":"puppeteer"}'`. -`pup_readiness` is the read-only probe (never spawns or downloads). Full details: the bridge's own skill via `sync_skills`. +`bridge_readiness {"name":"puppeteer"}` is the read-only probe (never spawns or downloads). Full details: the bridge's own skill via `sync_skills`. ### Screen recording — ab's desktop recorder (tab recording is pup's) @@ -1574,7 +897,7 @@ Composes `desktop_list_files` (or `desktop_watch_files` if `wait:true`) with the ```bash BEFORE=$(date +%s) -# … trigger the download click via pup_input_dispatch … +# … trigger the download click (a browser bridge verb, or desktop_ui_click) … adom-bridge desktop_pull_glob "{ \"path\": \"%USERPROFILE%\\\\Downloads\", \"glob\": \"ul_*.zip\", @@ -2009,7 +1332,7 @@ adom-bridge status ### Handling "not installed" errors -When a command returns `errorCode: "node_not_found"`, `errorCode: "kicad_not_installed"`, or `errorCode: "fusion_not_installed"`, guide the user through installation: +When a command returns `errorCode: "node_not_found"` (a bridge runtime ab manages: see `runtimes`), or a bridge reports its host app missing, guide the user through installation: **Picking the right native browser + profile (v1.7.1+):** @@ -2122,116 +1445,7 @@ If `desktop_install_node` returns `errorCode:"winget_unavailable"` (older Window If detection still misses an install on a user's machine, get the actual `node.exe` path from the user — that's a real bug to file. -**KiCad not installed:** - -**KiCad not installed:** - -v1.6.0+ — try the unattended winget install FIRST before asking the user to download manually: - -```bash -adom-bridge desktop_install_kicad '{}' -# → runs `winget install --id KiCad.KiCad --silent ...` (Windows only). -# → 2-5 minutes; downloads ~700 MB then installs. -# → returns {ok:true, exitCode:0, _hint:"Run kicad_list_versions to verify"} on success. -# → on failure (no winget / network failure / corporate-managed device): -# {ok:false, errorCode:"winget_unavailable" | "winget_install_failed", _hint, ...} -``` - -If `desktop_install_kicad` fails with `errorCode:"winget_unavailable"`, fall back to manual: - -> KiCad isn't installed and winget isn't available. Download from https://www.kicad.org/download/ — it's free and open source, install the latest stable (9.x or 10.x). -> Let me know when the install is done and I'll verify the connection. - -After EITHER path, have them restart Adom Bridge OR call `kicad_list_versions` again — the kicad bridge caches detection results, so a fresh scan may be needed to pick up freshly-installed binaries. - -**v1.6.0+ — improved KiCad detection.** The bridge now scans for KiCad in: -- `C:\Program Files\KiCad\<version>\` (the standard location) -- `C:\Program Files (x86)\KiCad\<version>\` (32-bit edge cases) -- `%LOCALAPPDATA%\Programs\KiCad\<version>\` (winget per-user installs) -- `%LOCALAPPDATA%\KiCad\<version>\` (rare manual installs) -- Windows registry: `HKLM\SOFTWARE\KiCad\<version>\InstallationPath` and the `WOW6432Node` mirror -- `HKCU` mirrors of the above for per-user installs -- macOS: `/Applications/KiCad/` and `/Applications/` directly - -If detection still misses an install on a user's machine, that's a real bug to file — get the actual install path from the user and we'll add it to the scan list. - -**Fusion 360 not installed:** -> Fusion 360 isn't installed on your desktop. Would you like to install it? -> Download from: https://www.autodesk.com/products/fusion-360 -> It's free for personal/hobby use (requires an Autodesk account). -> Let me know when the install is done and I'll verify the connection. - -After install, have them restart Adom Bridge, then run `adom-bridge status` to verify. - -### Handling "not running" errors - -When `errorCode: "fusion_not_running"`, launch it programmatically with the first-class startup command: -```bash -adom-bridge fusion_start -# On Windows: discovers exe via %LOCALAPPDATA% env var webdeploy glob. -# On Docker: delegates to the bridge on the connected desktop via relay. -# ~15-30s typical. Auto-dismisses startup dialogs. -# Returns {"addinReady": true, "pickerDismissed": true|false, ...} -``` - -KiCad doesn't need to be running for most commands (the bridge launches it on demand). - -### Handling "add-in not installed" errors - -When Fusion is running but `addinInstalled: false` or `addinConnected: false`: -> The AdomBridge add-in needs to be installed in Fusion 360. I can install it for you — this lets me control Fusion remotely. - -The add-in auto-installs when the Fusion bridge starts and Fusion is detected. - -### Handling `fusion_addin_not_responding` errors - -When `errorCode: "fusion_addin_not_responding"`, Fusion is running but the AdomBridge add-in isn't answering. Call `fusion_dismiss_blocking_dialogs` FIRST — a modal dialog is the most common cause. If that doesn't help, try `fusion_start` to restart Fusion cleanly. Last resort: user enables add-in manually via UTILITIES > ADD-INS > AdomBridge > Run on Startup + Run. - -### Handling `main_thread_busy` errors - -When `errorCode: "main_thread_busy"`, the Fusion add-in's main thread is occupied by a long-running command (typically `walk_cloud_tree` or `search_cloud_files`). This applies **across all bridges/sessions** — even if you didn't start the walk, another session might have. - -**Do NOT:** -- Retry the failed command — it will block behind the same lock -- Call `fusion_dismiss_blocking_dialogs` — there's no dialog to dismiss, and sending Escape will interrupt the active walk -- Force-kill Fusion — the walk will complete on its own - -**Do:** -- Wait for the walk/search to finish. If you started it, you should be using `adom-bridge watch` (see "Live folder progress streaming with `watch`" above) which streams live progress automatically. If another session started it, poll `fusion_addin_status` every 2–5s to check progress. -- Use commands that **don't need the main thread** while waiting: - - `fusion_addin_status` — check busy state and walk progress - - `fusion_window_info` — get window HWND, title, dialogs - - `fusion_screenshot_fusion` — capture what Fusion looks like - - `fusion_click_fusion` — click in the Fusion window - - `fusion_send_key` — send keyboard input - - `fusion_close_window` — close a specific dialog by HWND - -The response includes progress info: -```json -{ - "errorCode": "main_thread_busy", - "busyCommand": "walk_cloud_tree", - "elapsedSeconds": 42.3, - "walkProgress": { - "foldersVisited": 15, - "filesFound": 87, - "currentFolder": "Molecules/XRP", - "queueSize": 8 - }, - "_hint": "Add-in is busy with a long-running command. Do NOT retry..." -} -``` - -**Stalled walk detection**: If `fusion_addin_status` returns `busy: true` but `walkProgress` is missing and `mainThreadStalled: true`, a modal dialog is blocking the event loop — the walk was dispatched but never started. Call `fusion_dismiss_blocking_dialogs`, then the walk auto-resumes. - -### Auto-recovery (`_autoRecovery` field) - -When a fusion_* command fails with "not responding" / "not connected", the CLI automatically: -1. Calls `fusion_dismiss_blocking_dialogs` to clear any modal -2. If successful, retries the original command -3. Attaches `_autoRecovery: {action, dismissed[]}` to the retry result - -If you see `_autoRecovery` in a response, the command already succeeded after auto-dismissal — no manual intervention needed. The field is informational. +**A bridge's host app not installed or not running:** the bridge owns that story. `bridge_readiness {"name":"<bridge>"}` says `no-app` / `warming` / `ready` and its `_hint` says what to do; the bridge's own skill (`sync_skills`) has the install and launch flow. Do not hand the user a download link before asking the bridge: several can install their app unattended. ## Troubleshooting
dist/linux/adom-bridge⋯ 1 unchanged line ⋯
package.json+1−1@@ -1,6 +1,6 @@ { "slug": "adom-bridge", - "version": "2.1.144", + "version": "2.1.145", "type": "app", "brief": "Adom Bridge unleashes your AI onto your full PC: full power, full safety. The AI breaks out of the container it runs in and onto your real machine, managing and running your entire laptop as you: launch apps, move files, drive any window, control KiCad, Fusion 360 or your real signed-in browser. Works with any AI, cloud or local (Claude Desktop, Claude Code, Codex), no Hydrogen required. Bridge and its bridges are an operating system for AI, with managed Node and Python runtimes, and a human-only permission system keeps you in charge of every side-effecting command.", "description": "Install this package in a cloud or Hydrogen Desktop container, not on the PC. It delivers two things: the Linux adom-bridge-cli (linked onto PATH) and the Claude skill set that teaches an AI every desktop verb (shell, files, screenshots, windows, notifications, KiCad, Fusion 360, browser automation). The CLI drives the Adom Bridge app running on your Windows PC over the relay; the Windows app itself is the separate installer in the Download box, not part of this package. Run adom-wiki pkg update to keep the CLI and skills current.",
page.json+1−1@@ -1,6 +1,6 @@ { "slug": "adom-bridge",- "version": "2.1.144",+ "version": "2.1.145", "type": "app", "description": "Install this package in a cloud or Hydrogen Desktop container, not on the PC. It delivers two things: the Linux adom-bridge-cli (linked onto PATH) and the Claude skill set that teaches an AI every desktop verb (shell, files, screenshots, windows, notifications, KiCad, Fusion 360, browser automation). The CLI drives the Adom Bridge app running on your Windows PC over the relay; the Windows app itself is the separate installer in the Download box, not part of this package. Run adom-wiki pkg update to keep the CLI and skills current.", "keywords": [
skills/adom-bridge-cli-guide/SKILL.md+5−16@@ -64,8 +64,9 @@ An unknown verb returns `errorCode:"unknown_verb"` with a fuzzy did-you-mean `_h Read it; do not conclude a capability is missing from a guessed name. Recognized help namespaces (`adom-bridge help <topic>` or `adom-bridge <topic> help`): -`pup`/`browser`, `kicad`, `fusion`, `hd`, `shell`, `files`, `notifications`, `watch`, -`setup`, `connectivity`, `system`, `record`, `server`, `bridge`, `wiki`. +`hd`, `shell`, `files`, `notifications`, `setup`, `connectivity`, `system`, `record`, +`server`, `bridge`, `bridges`, `wiki`. A bridge namespace (`pup`/`browser`, `kicad`, `fusion`) +prints a pointer at the bridge's own description instead of a list. ## Invoking a verb @@ -170,21 +171,9 @@ Health check: `curl -sf http://127.0.0.1:8766/health`. If another relay is alrea answering, `serve` skips with a friendly message; `--force-bind` overrides (only for deliberate parallel relays). -## `watch`: stream long operations +## Long operations: `responseMode:"stream"` -For long-running walks, use the built-in `watch` wrapper instead of a polling loop. It -spawns the inner command, polls status internally, and emits one JSON event per line to -stdout as progress happens: - -```bash -adom-bridge watch '{"command":"fusion_walk_cloud_tree","args":{"projectName":"Main","nameContains":"BQ25792"}}' -adom-bridge watch '{"command":"fusion_walk_cloud_tree","args":{...},"interval":1}' -``` - -Watchable commands (whitelist): `fusion_walk_cloud_tree`, `fusion_search_cloud_files`. -Others return `success:false` with a `_hint` listing the watchable set. Do not use it -for short operations that return in under 2 seconds. From Claude Code, pipe `watch` -into the Monitor tool for real-time events. +Any verb accepts `responseMode:"stream"`: the CLI runs it as a job and prints one JSON line per lifecycle event as it arrives, the final result last (`streamTimeoutSeconds` caps the follow; detaching never cancels the job). This replaced the Fusion-only `watch` wrapper in 2.1.145 (wiki #212): a bridge's progress is the bridge's to report, and this path is the same for every bridge. ## `janitor`: the screenshot cache
skills/adom-bridge/SKILL.md+16−802@@ -191,11 +191,9 @@ adom-bridge <command> '<json-args>' ```bash adom-bridge ping adom-bridge status -adom-bridge pup_open_window '{"sessionId":"dart2","url":"https://example.com"}' -adom-bridge pup_eval '{"sessionId":"dart2","expr":"document.title"}' -adom-bridge pup_screenshot '{"sessionId":"dart2"}' -adom-bridge pup_list_windows -adom-bridge pup_close_window '{"sessionId":"dart2"}' +adom-bridge desktop_list_windows +adom-bridge desktop_screenshot_screen '{"reason":"see what is on the user's screen"}' +adom-bridge commands '{"bridge":"kicad"}' # a bridge's own verb list (any installed bridge) adom-bridge notify_user '{"title":"Hello","body":"From Docker"}' adom-bridge shell_execute '{"command":"echo hello"}' adom-bridge pull_file '{"filePaths":["C:\\Users\\john\\Downloads\\image.png"],"saveTo":"/tmp"}' @@ -295,7 +293,7 @@ If you're authoring a sibling Tauri app on the same machine (Hydrogen, or any fu The CLI does this automatically (see `cli/src/direct_probe.rs`). For sibling-app Rust code, see [`skills/DIRECT_API.md`](DIRECT_API.md) for a copy-paste-ready helper. -**Per-verb timeouts (v1.8.31+):** the direct API's command-timeout is no longer a hardcoded 120s — it mirrors the CLI dispatcher's per-verb table (`walk_cloud_tree`/`search_cloud_files`=620s; heavy exports=320s; `bridge_install`/`fusion_start`=300s; default=120s). Caller can override via `args.timeout` (seconds, clamped to 1800). +**Per-verb timeouts:** a bridge verb's budget is the bridge's own `bridge.json` `timeouts` block (exact bare verb, then prefix rule, then its default), applied by ab and, since 2.1.145, by the CLI's wait as well (ab keeps no table of any bridge's verbs, wiki #212). `timeouts` shows every installed bridge's declared block. Caller can override via `args.timeout` (seconds, clamped to 1800). Example — programmatic server registration without the CLI: @@ -499,15 +497,7 @@ Reference implementations: [`scripts/sample-bridges/hello-python/server.py`](../ The KiCad bridge is **cloud-owned** and ships its OWN full skill (wiki pkg `adom/kicad-bridge`). This page keeps only the pointer: run `adom-bridge sync_skills` after connecting and the full KiCad guide (project workflows, three-tier `kicad_open_*` routing, DRC recipes, library install) lands in `~/.claude/skills/`. -Most-used verbs to get moving: - -```bash -adom-bridge kicad_open_board '{"path": "C:/projects/board/board.kicad_pcb"}' -adom-bridge kicad_screenshot_all '{}' # every KiCad window incl. error dialogs, as an array -adom-bridge kicad_run_drc '{}' -adom-bridge kicad_window_info '{}' -adom-bridge kicad_open_symbol_editor '{"library": "Device"}' -``` +Its verbs: `adom-bridge commands '{"bridge":"kicad"}'` (the bridge describes itself). If KiCad is not installed, the bridge knows how to install it for the user — offer, never point them at a download page. Full details: the bridge's own skill. @@ -515,17 +505,9 @@ If KiCad is not installed, the bridge knows how to install it for the user — o The Fusion 360 bridge is **cloud-owned** and ships its OWN full skill (wiki pkg `adom/fusion-bridge`). Run `adom-bridge sync_skills` and the full guide (cloud files, import/export, add-in troubleshooting, APS search) lands in `~/.claude/skills/`. -Most-used verbs: +Its verbs: `adom-bridge commands '{"bridge":"fusion360"}'`. -```bash -adom-bridge fusion_start '{}' # launches Fusion; slow on cold start (minutes) -adom-bridge fusion_get_app_state '{}' # the status/poll verb -adom-bridge fusion_addin_status '{}' -adom-bridge fusion_dismiss_blocking_dialogs '{}' -adom-bridge fusion_send_key '{"key": "Escape"}' -``` - -Fusion launches take 2-4 minutes cold; respect `timeoutSeconds` + `statusVerb` on responses instead of re-issuing. Full details: the bridge's own skill. +Respect `timeoutSeconds` + `statusVerb` on responses instead of re-issuing a slow verb. Full details: the bridge's own skill. ### Launching apps (generic) @@ -536,600 +518,7 @@ Two generic CLI commands exist for launching any Windows executable safely — t **Where they run (2.1.143, wiki #210).** With `--target <box>`, or from a container / Linux CLI, both verbs run ON THAT BOX through its ab (mesh first, relay fallback, the same path as `shell_execute`): the path is resolved against the box's filesystem and the app starts there; the reply says `on: "<box>"`. Before 2.1.143 both ran inside the CLI process, so `--target arav-rog launch {path}` answered `find_exe: could not locate` for a file that existed on arav-rog. Only a Windows CLI with no `--target` still resolves and spawns locally. On a box `launch` is a Tier-2 exec verb like `launch_process` (gated the same way, `reason` required); `find_exe` is read-only. A target ab older than 2.1.143 answers unknown verb: use `launch_process {path, args}` there. -For Fusion specifically, use `fusion_start` — it wraps `launch` plus the full startup-picker / add-in-readiness dance. -- `fusion_import_step` -- Import a STEP/STL/IGES file into Fusion 360 -- `fusion_open_lbr` -- Open an EAGLE .lbr library file -- `fusion_open_electronics` -- Check if the Electronics workspace is active -- `fusion_electron_run` -- Execute any EAGLE command via Electron.run. Returns rich state: `activeWorkspace`, `activeDocument`, `commandType`, `_hint`, and `fusionOperations` (diff of Fusion's internal operation log showing what actually fired). **Avoid blocking commands** — see list below. **Full EAGLE command reference:** [`skills/eagle-commands.md`](./eagle-commands.md) — popular/safe commands split from blocking/modal ones, with layer reference and chaining syntax. -- `fusion_execute_text_command` -- Low-level app.executeTextCommand() access. Returns the command result plus workspace context. -- `fusion_board_info` -- Get structured board data from the open PCB layout. Returns: component placements (name, package, x, y, rotation), net names, copper traces, layer setup, board thickness, DRC violations. Much richer than a screenshot — gives exact coordinates and connectivity. Requires a .brd board open in PCB Editor. - -#### `fusion_electron_run` — EAGLE Command Execution - -Executes EAGLE commands inside Fusion 360's Electronics workspace. Works in **Schematic Editor**, **PCB Editor (Board Layout)**, and **Electronics Library** contexts. - -**How it works:** Sends the command string via Fusion's `Electron.run` text command. EAGLE's `Electron.run` is fire-and-forget — it never returns output or throws on invalid commands. To compensate, the handler snapshots Fusion's internal operation log (`Diagnostics.RecentOperations`) before and after execution, returning a diff showing what actually fired. - -**Usage:** -```bash -# Basic command -adom-bridge fusion_electron_run '{"command": "WINDOW FIT"}' - -# Multiple commands in sequence (use semicolons) -adom-bridge fusion_electron_run '{"command": "DISPLAY NONE; DISPLAY 1 16 17 18 20 21"}' - -# Navigate in library editor -adom-bridge fusion_electron_run '{"command": "EDIT SOIC8.pac"}' -adom-bridge fusion_electron_run '{"command": "EDIT RESISTOR.sym"}' -adom-bridge fusion_electron_run '{"command": "EDIT MYDEVICE.dev"}' -``` - -**Response fields:** -- `activeWorkspace` — Current workspace (Schematic Editor, PCB Editor, Electronics Library) -- `activeDocument` — Name of the open document -- `commandType` — Detected type: `view_control`, `layer_control`, `edit`, `design_rule`, etc. -- `editorType` — For EDIT commands: `package`, `symbol`, `device` -- `fusionOperations` — Array of Fusion operations that fired (diff of internal log) -- `hint` — Human-readable description of what happened -- `rawResult` — Raw return from Electron.run (usually empty) - -**EAGLE Command Reference — Safe for automation:** - -| Command | Context | Description | -|---------|---------|-------------| -| **View / Navigation** | | | -| `WINDOW FIT` | Any | Zoom to fit all content | -| `WINDOW (x1 y1 x2 y2)` | Any | Zoom to specific area (coordinates in current units) | -| `DISPLAY ALL` | Any | Show all layers | -| `DISPLAY NONE` | Any | Hide all layers | -| `DISPLAY 1 16 17 18 20 21` | Board | Show specific layers by number | -| **Grid** | | | -| `GRID MM 0.1` | Any | Set grid to 0.1mm | -| `GRID MIL 25` | Any | Set grid to 25mil | -| `GRID INCH 0.05` | Any | Set grid to 0.05 inch | -| **Board Layout** | | | -| `RATSNEST` | Board | Recalculate airwires (unrouted connections) | -| `RIPUP` | Board | Remove all routed traces | -| `RIPUP *` | Board | Remove all traces (same as RIPUP with no selection) | -| `ROUTE` | Board | Start auto-router | -| `DRC` | Board | Run design rule check | -| `BOARD` | Schematic | Switch to paired board layout | -| `SCHEMATIC` | Board | Switch to paired schematic | -| **Schematic** | | | -| `VALUE value` | Schematic | Set component value | -| `NAME name` | Any | Rename selected element | -| `SMASH` | Any | Detach name/value labels from components | -| **Library Editor** | | | -| `EDIT name.pac` | Library | Open a package (footprint) for editing | -| `EDIT name.sym` | Library | Open a symbol for editing | -| `EDIT name.dev` | Library | Open a deviceset for editing | -| `EXPORT SCRIPT 'path.scr'` | Library | Export entire library as EAGLE script | -| **Scripting / Settings** | | | -| `SET CONFIRM YES` | Any | Suppress confirmation dialogs | -| `SET CONFIRM OFF` | Any | Re-enable confirmation dialogs | -| `SCRIPT 'path.scr'` | Any | Run batch commands from a .scr script file | - -**EAGLE Layer Numbers (commonly used):** - -| Layer | Name | What it shows | -|-------|------|--------------| -| 1 | Top | Top copper | -| 16 | Bottom | Bottom copper | -| 17 | Pads | Through-hole pads | -| 18 | Vias | Via holes | -| 19 | Unrouted | Airwires (ratsnest) | -| 20 | Dimension | Board outline (required for 3D) | -| 21 | tPlace | Top silkscreen | -| 22 | bPlace | Bottom silkscreen | -| 25 | tNames | Top component names | -| 27 | tValues | Top component values | -| 29 | tStop | Top solder mask | -| 31 | tCream | Top stencil/paste | -| 51 | tDocu | Top documentation | - -**Blocking commands — AVOID from automation:** - -| Command | Why it blocks | -|---------|---------------| -| `WRITE` | Opens Save As dialog — use `fusion_save_lbr` or `fusion_close_document` instead | -| `ADD` | Opens component picker dialog | -| `SHOW name` | Opens interactive highlight mode | -| `SET` (no params) | Opens settings dialog | -| `GRID` (no params) | Opens grid settings dialog | -| `EDIT new.sym` | Opens "Create new?" confirmation if symbol doesn't exist | -| `CHANGE` | Opens interactive change mode | -| `MOVE` | Opens interactive move mode | - -**Tips:** -- Always run `WINDOW FIT` after opening a file or switching views -- Use `DISPLAY NONE` then `DISPLAY <layers>` to show only specific layers -- Combine commands with `;` — e.g., `SET CONFIRM YES; RIPUP *; RATSNEST` -- For board screenshots: `DISPLAY NONE; DISPLAY 1 16 17 18 20 21; WINDOW FIT` -- Use `fusion_board_info` instead of EAGLE commands when you need structured data -- `fusion_export_lbr` -- Export the open Electronics library as an EAGLE .scr script (note: does NOT include 3D package references — those are cloud-linked only) -- `fusion_save_lbr` -- Save the open Electronics library as a .flbr file - -#### EAGLE Libraries with 3D Packages - -Fusion 360's .lbr format supports `package3d` elements that link footprints to 3D models. Key facts: - -- **3D models are cloud-hosted** — each `package3d` has a `wip_urn` (e.g., `urn:adsk.wipprod:fs.file:vf.xxxxx`) pointing to a Fusion cloud document. You cannot embed STEP files directly in .lbr XML. -- **Creating 3D packages requires the Fusion UI** — use `Package3DCreateCmd` in Electronics Library Editor, which opens a new Design workspace where you model/import the 3D shape, then save to link it. -- **`EXPORT SCRIPT` strips 3D references** — the .scr export only contains 2D data (symbols, footprints, devicesets). To preserve 3D links, keep the .lbr XML format. -- **Fusion's built-in examples** have 3D packages — 34 of 37 libraries in the EAGLE examples directory (e.g., `Connector_USB.lbr`, `Resistor.lbr`, `Capacitor.lbr`) include `package3d` references. -- **Example libraries location**: `%LOCALAPPDATA%/Autodesk/webdeploy/production/<hash>/Applications/Electron/LibEagle/examples/libraries/examples/` - -To open a built-in example library for reference: -```bash -# Find the examples directory first -adom-bridge fusion_execute_text_command '{"command": "Python.RunScript C:/tmp/find_eagle_libs.py"}' -# Then open one -adom-bridge fusion_open_lbr '{"filePath": "<path>/Connector_USB.lbr"}' -``` -- `fusion_open_schematic` -- Open a .sch schematic in Fusion's Schematic Editor. Args: `filePath`. -- `fusion_open_board` -- Open a .brd board layout in Fusion's Board Layout editor. Args: `filePath`. -- `fusion_show_3d_board` -- Switch to 3D PCB board view (must have a .brd open). Board MUST have an outline on layer 20 (Dimension) or 3D generation fails. Auto-zooms to fit after switching. -- `fusion_show_2d_board` -- Switch back to 2D board layout from 3D PCB view. EAGLE commands via `fusion_electron_run` only work in 2D. -- `fusion_close_document` -- Close a document without save dialog. Args: `name` (optional, defaults to active doc), `save` (optional, default false). Essential for automation — avoids modal save dialog that blocks Fusion. -- `fusion_document_info` -- List ALL open documents/tabs with name, type, and active status, plus detailed cloud info for the active document. Returns `openDocuments` array (every tab) and active doc details (cloud project, folder, file ID, version, save status). Lightweight — uses only in-memory data, no cloud API calls. Use this instead of `fusion_walk_cloud_tree` when you just need to know what's open. -- `fusion_activate_document` -- Switch to a specific open document tab. Args: `name` (substring match, case-insensitive), `documentType` ("Electronics", "PCB", "FusionDesign", "Drawing"). Essential for automation — switch between schematic, board, and library tabs without user interaction. If no match found, returns the list of open documents so you can refine. -- `fusion_close` -- Close Fusion 360. **Always call this when done with Fusion 360 commands to clean up.** -- `fusion_dismiss_recovery` -- Dismiss recovery document dialogs (both "Recovered Documents" list and "Open recovery document instead?" prompts). Also relocates recovery files to `~/.adom/recovery/fusion/` for safekeeping. -- `fusion_relocate_recovery` -- Proactively move Fusion crash recovery files to `~/.adom/recovery/fusion/<timestamp>/` without dismissing any dialogs. Call this **before** launching Fusion to prevent recovery dialogs from appearing. Files are preserved (not deleted) so the user can manually restore them if needed. -- `fusion_close_all_documents` -- Close all open documents. Args: `saveChanges` (default: false). Use before force-killing Fusion to prevent recovery files. - -#### Fusion 360 UI Interaction - -Commands for interacting with Fusion 360's UI — detecting dialogs, taking screenshots, clicking, and sending keyboard input. Essential for handling blocking dialogs and automating CEF-based UI elements. - -- `fusion_window_info` -- Returns the Fusion main window HWND, title, rect, and a list of all Qt dialog windows (recovery dialogs, wizards, file pickers). Essential for detecting blocking dialogs before/after operations. - - Example: `adom-bridge fusion_window_info` - - Returns: `{hwnd, title, rect, dialogs: [{hwnd, title, className, rect}]}` - -- `fusion_screenshot_fusion` -- Captures the Fusion main window or a specific dialog by HWND. Uses PrintWindow (works without bringing to foreground). Saves WebP to `C:/tmp/adom-bridge-screenshots/` (falls back to PNG if WebP unavailable). Downscaled to ≤1568px — use relative coords (0.0-1.0) for clicking, they're scale-independent. DPI-aware. - - Args: `hwnd` (optional — dialog HWND to screenshot instead of main window) - - Example: `adom-bridge fusion_screenshot_fusion` (main window) - - Example: `adom-bridge fusion_screenshot_fusion '{"hwnd": 12345}'` (specific dialog) - -- `fusion_screenshot_all` -- Screenshots the main Fusion window and lists all dialog windows with their HWNDs. Use `fusion_screenshot_fusion {"hwnd": ...}` to capture each dialog. - - Example: `adom-bridge fusion_screenshot_all` - -- `fusion_click_fusion` -- Click at coordinates within the Fusion window or a specific dialog. x/y are relative (0.0-1.0) by default. Set `"relative": false` for pixel offsets. Uses SendInput for CEF dialog compatibility. **Prefer `fusion_send_key` for dialogs** — enter/escape/tab covers most cases. - - Args: `x` (required), `y` (required), `relative` (optional, default true), `hwnd` (optional — target a specific dialog HWND instead of main window) - - Example: `adom-bridge fusion_click_fusion '{"x": 0.5, "y": 0.7}'` (main window) - - Example: `adom-bridge fusion_click_fusion '{"hwnd": 12345, "x": 0.75, "y": 0.85}'` (dialog button) - -- `fusion_send_key` -- Send keyboard input to Fusion or a specific dialog via SendInput. **Preferred way to dismiss dialogs**: enter to confirm, escape to cancel, tab to cycle buttons. Use click only if tab order doesn't reach the right button. - - Args: `key` (required), `hwnd` (optional — target a specific dialog HWND) - - Example: `adom-bridge fusion_send_key '{"key": "escape"}'` (dismiss CEF dialog) - - Example: `adom-bridge fusion_send_key '{"key": "enter", "hwnd": 12345}'` (confirm dialog) - -#### Fusion 360 Workflow Guide - -##### Opening Electronics Projects -1. Open the `.fprj` file: `adom-bridge fusion_open_cloud_file '{"projectName":"Main","fileName":"DRV8411A","fileExtension":"fprj","folderPath":"Molecules/XRP/DRV8411A"}'` -2. Do NOT try to open `.fbrd` or `.fsch` directly — they fail or show a "Select Electronics Design File" dialog -3. Enter the board editor: `adom-bridge fusion_show_2d_board` -4. Enter the schematic editor: After step 3, use `adom-bridge fusion_electron_run '{"command":"EDIT .sch"}'` -5. Switch back to board: `adom-bridge fusion_electron_run '{"command":"EDIT .brd"}'` - -##### Auto-Screenshot on Open Commands - -**Open commands automatically screenshot Fusion and return the images in the response.** The following commands include `postOpenScreenshot` in their `data` field: -- `fusion_open_cloud_file`, `fusion_open_schematic`, `fusion_open_board`, `fusion_show_3d_board`, `fusion_show_2d_board` - -The response `data.postOpenScreenshot` contains: -- `screenshots[]` — array of `{type, savedTo, sizeKB, title?, hwnd?}`. Type is `"main_window"` or `"dialog"`. -- `message` — human-readable instruction to READ each screenshot and check for blocking dialogs -- `dialogBlocking` — `true` if a modal dialog was detected - -**After receiving the response, you MUST:** -1. **READ each screenshot file** using the Read tool to visually inspect what Fusion shows -2. Look for blocking dialogs in the screenshots: - - "What to design?" wizard → dismiss with `fusion_send_key {"key": "escape"}` - - "PCB out of date" banner → click Update or X - - "Recovered Documents" → `fusion_dismiss_recovery` - - "Save changes?" → `fusion_send_key {"key": "escape"}` - - Any other modal → identify and dismiss -3. **Screenshot again** after dismissing to confirm it's clear - -Screenshots are saved as WebP (lossless, ~20-40KB each, downscaled to ≤1568px) for token efficiency. Both the main Fusion window AND all Qt dialog windows are captured separately. - -**Why this matters**: Fusion shows Qt dialogs and CEF overlays that are invisible to the API. The `success: true` response from an open command does NOT mean the UI is ready — a dialog may be blocking all further operations. The API cannot detect these. Only a screenshot can. - -##### Detecting and Handling Blocking Dialogs -- The auto-screenshot captures dialog windows separately (look for `type: "dialog"` entries in `postOpenScreenshot.screenshots[]`) -- Common blocking dialogs: "What do you want to design?", "Recovered Documents", "Open recovery document instead?", "Select Electronics Design File" -- Dismiss recovery dialogs: `adom-bridge fusion_dismiss_recovery` -- Dismiss CEF dialogs (inside main window): `adom-bridge fusion_send_key '{"key": "escape"}'` or `fusion_click_fusion` -- Dismiss "What do you want to design?" wizard: `adom-bridge fusion_send_key '{"key": "escape"}'` -- For manual screenshot of specific dialogs: `adom-bridge desktop_screenshot_window '{"hwnd": <DIALOG_HWND>}'` - -##### Preventing Recovery Documents -- Recovery files are at: `%LOCALAPPDATA%\Autodesk\Autodesk Fusion 360\<USER_ID>\CrashRecovery\` -- Before force-killing Fusion, close all documents: `adom-bridge fusion_close_all_documents '{"saveChanges": false}'` -- **Best practice**: Call `adom-bridge fusion_relocate_recovery` before launching Fusion. This moves recovery files to `~/.adom/recovery/fusion/<timestamp>/` — preserving them for the user while preventing modal dialogs. -- The `fusion_start` command also auto-relocates recovery files before starting Fusion. -- The `fusion_dismiss_recovery` command handles both "Recovered Documents" list and "Open recovery document instead?" prompts, and also relocates files. - -##### EAGLE Export Limitations -- **Supported**: `EXPORT IMAGE`, `EXPORT NETLIST`, `EXPORT PARTLIST` -- **NOT supported** (fail silently): `EXPORT DXF`, `EXPORT SVG`, `EXPORT DRILL` -- Always verify export output: the updated `fusion_electron_run` now checks if the output file was created -- Use `fusion_export_bom` and `fusion_export_cpl` for manufacturing data (these use the add-in's XML parser, not EAGLE export) -- Use `fusion_export_gerbers` for Gerber files — produces a ZIP with all gerber layers (GTL, GBL, GTS, GBS, GTP, GBP, GTO, GBO, GKO, XLN). Auto-detects 2-layer vs 4-layer boards. - -##### 3D Model Exports -- From the 3D view (activate the .f3d document): `fusion_export_step`, `fusion_export_stl`, `fusion_export_3mf`, `fusion_export_f3d`, `fusion_export_usdz`, `fusion_export_iges`, `fusion_export_sat` -- Switch to 3D view: `fusion_show_3d_board` or activate the .f3d document -- **STEP** — Industry-standard CAD interchange (SolidWorks, CATIA, Creo). Highest geometric fidelity. -- **IGES** — Legacy CAD interchange. Use STEP for modern workflows. -- **SAT** — ACIS solid model format. Used by SolidWorks, SpaceClaim. -- **STL** — Mesh format for 3D printing and visualization. Options: refinement "low"/"medium"/"high". -- **3MF** — Modern 3D printing with color/material support and multi-body. -- **F3D** — Native Fusion 360 archive. Preserves parametric features, sketches, timeline, component refs. Best for archival. -- **USDZ** — **Best for digital twins and GLB conversion.** Preserves full component hierarchy (Board, copper layers, soldermask, Packages), PBR materials, and named nodes. Each component becomes a toggleable node in GLB viewers. Also viewable directly on iOS/macOS (Apple Quick Look / AR). - - Digital twin pipeline: `fusion_export_usdz` → pull_file → `blender --background --python-expr "import bpy; bpy.ops.wm.usd_import(filepath='board.usdz'); bpy.ops.export_scene.gltf(filepath='board.glb')"` -- **FBX** — Not available in current Fusion builds via the API. The command exists but fails clearly. Use `fusion_export_usdz` instead. -- **DXF/DWG/OBJ/SKP** — Not available via the Fusion API (dialog-only). Commands exist but return clear errors with alternatives. - -##### 3D Viewport Captures -- `fusion_take_screenshot` — Capture the Fusion viewport at any resolution without opening a dialog. Uses Fusion's render API (`saveAsImageFile`). - - Args: `outputPath` (required), `width` (default 1920), `height` (default 1080), `orientation` (optional) - - Orientations: `home`, `front`, `back`, `top`, `bottom`, `left`, `right` - - Example: Capture all 6 standard views for use as product images/icons: - ```bash - for orient in home front back top bottom left right; do - adom-bridge fusion_take_screenshot "{\"outputPath\": \"C:/tmp/3d-${orient}.png\", \"width\": 1920, \"height\": 1080, \"orientation\": \"${orient}\"}" - done - ``` - -##### Electronics Source File Export (`fusion_export_source`) -- `fusion_export_source` — Export the active electronics document as `.fsch`, `.fbrd`, or `.flbr` source file. - - Args: `outputPath` (required — full path with extension) - - The extension determines the format: `.fsch` (schematic), `.fbrd` (board), `.flbr` (library) - - Validates extension, creates output directory, verifies file was created, returns file size - -- **Full workflow to export both board and schematic from a cloud project:** - ```bash - # Step 1: Open the .fprj (NOT .fbrd/.fsch directly — those fail) - adom-bridge fusion_open_cloud_file '{"projectName":"Main", "fileName":"MyDesign", "fileExtension":"fprj", "folderPath":"Molecules/MyDesign"}' - - # Step 2: Screenshot to check for blocking dialogs (always do this after open) - adom-bridge fusion_screenshot_fusion - - # Step 3: Enter board view (MUST be Board Layout workspace, not 3D) - adom-bridge fusion_show_2d_board - - # Step 4: Export .fbrd (board first — it's already in board view) - adom-bridge fusion_export_source '{"outputPath": "C:/tmp/exports/MyDesign.fbrd"}' - - # Step 5: Switch to schematic (EDIT .s1 = first schematic sheet) - adom-bridge fusion_electron_run '{"command": "EDIT .s1"}' - - # Step 6: Export .fsch - adom-bridge fusion_export_source '{"outputPath": "C:/tmp/exports/MyDesign.fsch"}' - - # Step 7: Pull files to Docker - adom-bridge pull_file '{"filePaths":["C:/tmp/exports/MyDesign.fbrd","C:/tmp/exports/MyDesign.fsch"], "saveTo":"/tmp/exports"}' - ``` - -- **Critical gotchas:** - - You MUST open the `.fprj` first — opening `.fbrd`/`.fsch` directly fails or triggers blocking dialogs - - You MUST call `fusion_show_2d_board` before exporting `.fbrd` (the Electronics Design overview won't work) - - Always export `.fbrd` FIRST (from board view), then switch to schematic for `.fsch` - - If export fails with "file not found", the wrong workspace is active — screenshot to verify - - After `fusion_open_cloud_file`, always screenshot to check for "Select Electronics Design File" dialog - - `WRITE` command is blocked — it opens a blocking save dialog. Use `fusion_export_source` instead - -- Note: `WRITE` is blocked — it opens a "Version Description" dialog on cloud docs even with a path argument (tested 2026-04-10). Use `fusion_save_to_cloud` to save to cloud, `fusion_export_source` for Fusion-format, or `fusion_export_eagle_source` for plain EAGLE format. - -##### Plain EAGLE Source Export (`fusion_export_eagle_source`) -- `fusion_export_eagle_source` — Export the active electronics document as plain EAGLE XML `.sch` or `.brd`. - - Args: `outputPath` (required — full path ending in `.sch` or `.brd`) - - Internally: exports `.fsch`/`.fbrd` via `Document.CopyToDesktop`, then extracts the EAGLE XML from the ZIP container, cleans up the temp file. - - The output is valid EAGLE XML (`<?xml><eagle version="9.7.0">...`) parseable by standalone EAGLE, KiCad import, or any XML tool. - - Same workflow/prerequisites as `fusion_export_source` — just use `.sch`/`.brd` extensions instead of `.fsch`/`.fbrd`. - - ```bash - # Board (.brd) — must be in PCB Editor / Board Layout - adom-bridge fusion_show_2d_board - adom-bridge fusion_export_eagle_source '{"outputPath": "C:/tmp/exports/MyDesign.brd"}' - - # Schematic (.sch) — must be in Schematic Editor - adom-bridge fusion_electron_run '{"command": "EDIT .s1"}' - adom-bridge fusion_export_eagle_source '{"outputPath": "C:/tmp/exports/MyDesign.sch"}' - ``` - -##### Dialog Dismissal (`fusion_close_window`) -- `fusion_close_window` — Close a specific Fusion dialog by sending WM_CLOSE (equivalent to clicking X). - - Args: `hwnd` (required — from `fusion_window_info` or `fusion_dismiss_blocking_dialogs` remaining[]) - - Works on dialogs that Escape doesn't close — e.g. "Recovered Documents" - - Does NOT force-kill — the dialog can still intercept WM_CLOSE - -##### Electronics Import (Round-Trip) -- `fusion_import_electronics` — Import Fusion-native `.fsch`, `.fbrd`, or `.flbr` files as new local documents - - Uses `Document.newDesignFromLocal` under the hood - - Auto-screenshots after import (catches blocking dialogs) - - Args: `filePath` (required Windows path to .fsch, .fbrd, or .flbr) - - After import, use `fusion_save_to_cloud` to persist to Fusion cloud - - **`.fsch` import works standalone** — creates a new schematic project - - **`.fbrd` import may fail** — boards have external references to schematics/libraries. Error: "New design cannot be created from a local file containing external references" - - **`.flbr` import works standalone** — creates a new library project - - For legacy EAGLE files: use `fusion_open_schematic` (.sch), `fusion_open_board` (.brd), `fusion_open_lbr` (.lbr) - -##### Library Round-Trip Workflow -Export and re-import Fusion electronics libraries: -```bash -# 1. Open library from cloud -adom-bridge fusion_open_cloud_file '{"projectName":"Main","fileName":"Adom Common Components","folderPath":"Molecules/Libraries"}' - -# 2. Export as .flbr (Fusion-native binary) and .scr (EAGLE script text) -adom-bridge fusion_save_lbr '{"outputPath":"C:/tmp/library.flbr"}' -adom-bridge fusion_export_lbr '{"outputPath":"C:/tmp/library.scr"}' -adom-bridge fusion_close_document - -# 3. Re-import the .flbr -adom-bridge fusion_import_electronics '{"filePath":"C:/tmp/library.flbr"}' - -# 4. Verify symbols survived round-trip -adom-bridge fusion_export_lbr '{"outputPath":"C:/tmp/library-verify.scr"}' - -# 5. Save to cloud with new name -adom-bridge fusion_save_to_cloud '{"name":"Library-copy"}' -``` - -##### Demo Projects -171+ electronics molecules are exported in the `adom-bridge-demo` repo (separate from adom-bridge). -Three reference boards with full export formats: - -| Board | Cloud Path | Layers | Components | Files | -|-------|-----------|--------|------------|-------| -| DRV8411A | Main / Molecules / XRP / DRV8411A | 4 | 29 | 27 | -| DRV8323SR | Main / Molecules / Experiments / MotorControl / DRV8323SR | 2 | 43 | 27 | -| VL53L8BreakoutMolecule | Main / Molecules / XRP / TimeOfFlightVL53L8 / VL53L8BreakoutMolecule | 2 | 30 | 27 | - -Each folder contains: .fsch, .fbrd, bom.csv, cpl.csv, gerbers.zip, 6 board images, 7 3D renders (home/front/back/top/bottom/left/right), STEP, IGES, SAT, STL, 3MF, F3D, USDZ, board screenshot, 3D board screenshot. - -#### Cloud Document Management - -Manage Fusion 360 cloud documents (hub projects, files, versions). Required for 3D package workflows since EAGLE library 3D models are stored as cloud documents. - -- `fusion_save_to_cloud` -- Save the active Fusion document to the cloud. Args: `name` (required), `projectName` (optional, defaults to active project), `folderPath` (optional), `description` (optional). Returns: `fileId`, `versionNumber`, `wipUrn` (if cloud-hosted). -- `fusion_list_cloud_projects` -- List all cloud projects in the user's hub. Returns array of `{name, id}` per hub. -- `fusion_list_cloud_files` -- List files in a cloud project/folder. Args: `projectName` (optional), `folderPath` (optional). Returns: `files` array with `{name, id, versionNumber, fileExtension, dateModified}` and `subfolders` array. -- `fusion_create_cloud_folder` -- Create a folder in a cloud project. Args: `folderName` (required), `projectName` (optional), `parentPath` (optional). Returns `folderId`. Idempotent — returns existing folder if it already exists. -- `fusion_check_recovery` -- Check if a cloud file has a recovery document from a previous crash. Args: `fileName` (required), `projectName` (optional), `folderPath` (optional). Returns `hasRecovery: true/false`. Use this BEFORE opening files to avoid the blocking "Open recovery document instead?" dialog. If recovery exists, call `fusion_open_cloud_file` with `recovery: "open"` (restore unsaved work) or `recovery: "discard"` (delete recovery, open cloud version). -- `fusion_open_cloud_file` -- Open a cloud file in Fusion by name. **If a recovery document exists and no `recovery` arg is given, the command STOPS and reports the recovery instead of opening** — you must decide whether to preserve or discard unsaved work. Args: `fileName` (required), `projectName` (optional), `folderPath` (optional), `recovery` ("open" = restore unsaved work, "discard" = delete recovery and open cloud version). -- `fusion_export_cloud_file` -- Export the active Fusion document to a local file for transfer back to Docker. Args: `outputPath` (required), `format` (optional, default "step"). The exported file can then be pulled back to Docker via `pull_file`. -- `fusion_delete_cloud_file` -- Delete a cloud file by name. Args: `fileName` (required), `projectName` (optional), `folderPath` (optional). File must not be open in Fusion — close it first with `fusion_close_document`. -- `fusion_walk_cloud_tree` -- **Long-running.** BFS walk of a cloud folder tree. Returns a flat list of all files and folders. Runs entirely on the Fusion main thread — **blocks all other add-in commands** until done (check progress with `fusion_addin_status`). - - Args: `projectName` (optional), `folderPath` (optional, starting folder), `maxDepth` (default 10), `maxFolders` (default 500), `extensions` (optional list, e.g. `["f3d","fprj"]`), `nameContains` (optional substring filter), `includeFiles` (default true) - - Returns: `{project, rootFolder, folders[], files[], stats: {foldersVisited, foldersSkipped, filesFound, maxDepthReached, truncated}}` - - **Per-folder timeout (30s):** If a single folder's cloud API calls take >30s (common for large projects), the folder is skipped and counted in `foldersSkipped`. This prevents indefinite hangs. - - **Progress tracking:** While running, `fusion_addin_status` returns `walkProgress` with `{foldersVisited, filesFound, currentFolder, queueSize}` — poll this every 1–10s to monitor progress (see "Live folder progress streaming" below). - - **Non-blocking alternative:** Use `fusion_search_cloud_files` for targeted searches, or `fusion_list_cloud_files` for single-folder listings (these are faster but don't recurse). - - Example: `adom-bridge fusion_walk_cloud_tree '{"projectName":"Main","folderPath":"Molecules","nameContains":"DRV","extensions":["fprj"]}'` - -#### Live folder progress streaming with `watch` - -For long walks, use the built-in `watch` wrapper. It spawns the inner search command on a worker thread, polls `fusion_addin_status` internally, and emits one JSON event per line to stdout as the walker visits each folder. **No manual polling loop needed.** - -```bash -adom-bridge watch '{"command":"fusion_walk_cloud_tree","args":{"projectName":"Main","folderPath":"Molecules","nameContains":"BQ25792"}}' -``` - -Output is one JSON object per line, three event types: - -```jsonl -{"event":"started","command":"fusion_walk_cloud_tree","args":{...},"interval":2,"_hint":"streaming progress events follow, one per line, ending with 'complete' or 'error'"} -{"event":"progress","busyCommand":"walk_cloud_tree","elapsedSeconds":15.0,"foldersVisited":14,"queueSize":50,"filesFound":0,"currentFolder":"Molecules/Sensing"} -{"event":"progress","busyCommand":"walk_cloud_tree","elapsedSeconds":23.4,"foldersVisited":22,"queueSize":108,"filesFound":0,"currentFolder":"Molecules/Examples"} -{"event":"progress","busyCommand":"walk_cloud_tree","elapsedSeconds":31.8,"foldersVisited":30,"queueSize":100,"filesFound":0,"currentFolder":"Molecules/RAPID NAME TAGS/Connor Wood"} -... (one per real change in walkProgress, deduped) ... -{"event":"complete","result":{"folders":[...],"files":[...],"stats":{"foldersVisited":169,"filesFound":12,"truncated":false}}} -``` - -Read stdout line-by-line. Stop when you see `event:complete` or `event:error`. The full final result is in the `complete` event's `result` field. - -**Optional `interval` arg** (default 2s, clamped to [1, 30]): - -```bash -adom-bridge watch '{"command":"fusion_walk_cloud_tree","args":{...},"interval":1}' -``` - -**For Claude Code consumers**: pipe `watch` directly into the `Monitor` tool. Each JSON line becomes a real-time event notification in the chat — you (and the user) see folder names appear one-by-one as the walker visits them. No bash loop, no `disown`, no subprocess gymnastics. Verified live in 1.3.16 on a 169-folder walk that returned all 12 BQ25792 cloud files cleanly. - -**Watchable commands** (whitelist): `fusion_walk_cloud_tree`, `fusion_search_cloud_files`. Other commands return `success:false` with a `_hint` listing the watchable set. - -**When NOT to use watch**: short single-folder operations (`fusion_list_cloud_files`, `fusion_open_cloud_file`) — those return in <2s and don't need streaming. The `watch` wrapper is purely for the long BFS commands. -- `fusion_search_cloud_files` -- **Long-running.** Recursive substring search on file names across cloud folders. v1.0.2+ of the add-in adds: per-folder timeout, doEvents() every 50 files, per-file try/except, iterative BFS, and a stale-lock watchdog — Fusion stays responsive throughout (no "Not Responding" freeze). - - **Args (no hard upper caps in v1.0.2+):** `query` (required, substring, case-insensitive), `projectName` (optional, defaults to active), `folderPath` (optional starting subfolder — **narrow with this**), `recursive` (default false), `maxDepth` (default 2), `maxFolders` (default 10), `maxResults` (default 20), `folderTimeout` (default 30s), `searchTimeout` (default 120s), `timeout` (HTTP envelope, default 620s). - - **Before calling:** if the user knows roughly where the file is (e.g. customer-named folder), **ask them**. Naming a subfolder cuts 5-40 min searches down to ~10s. - - **Why slow:** Autodesk's free Fusion 360 Python API has no indexed file-search endpoint. We walk the Data API one folder at a time — each = one HTTP round-trip to Autodesk. **This is an Autodesk API limitation, not adom-bridge's.** When telling the user the search is taking a while, attribute it to Autodesk / Fusion 360, not to adom-bridge's bridge. **There is now a FAST native alternative — `aps_search` (see "APS — fast indexed cloud search" below).** It hits Autodesk Platform Services' indexed Data Management API and returns ~instantly, even when Fusion is CLOSED. Call `aps_status` first; if `configured:true`, prefer `aps_search` and only fall back to this folder-walking verb when APS isn't set up. - - **Interpreting results (critical for no-false-negatives):** the response contains `searchComplete` (bool), `foldersSkipped`, `filesSkipped`, `truncated`, `folderLimitReached`, `searchTimedOut`. `searchComplete:true` ONLY when **all five** are clean — that's the confidence flag. If `searchComplete:false`, the search hit a cap before exhausting the scope; **don't report "file not found"** — re-run with broader caps OR narrower `folderPath`. - - **Case sensitivity:** fully case-insensitive both directions (query and file names lowercased). Substring match, not whole-word — `"cosm"` matches `COSMIIC`, `COSMOCOIL`, etc. - - **Cost feedback in response:** `costAnalysis: {elapsedSeconds, foldersPerSecond, estimatedSecondsPer100Folders}` so the AI can budget the next search realistically. - - **Real numbers from a live test:** searching `Main/Molecules` recursively (173 folders deep, max 8 depth) for "cosmiic" returned in 168 s with `searchComplete:true, totalFound:3`. Fusion stayed `main_thread:responsive` throughout. - - **Pair with `watch`** for streaming progress updates: see below. - -#### APS — fast indexed cloud search (v1.8.182+) - -`aps_search` is a **native, ~instant** alternative to the folder-walking `fusion_search_cloud_files`. It queries **Autodesk Platform Services** (APS, formerly Forge) **Data Management API**, which has a real server-side index — so a search that takes minutes by folder-walking returns in well under a second, and it works **even when Fusion 360 is closed** (it's pure HTTPS, no bridge required). adom-bridge runs its own 3-legged **PKCE** OAuth, so the user's APS **client secret never leaves their machine**. - -**One-time setup (user side):** -1. Register a free app at <https://aps.autodesk.com> → enable the **Data Management API**. -2. Set the app's **Callback URL** to exactly `http://localhost:8910/aps/callback`. -3. Put the **Client ID** in ab config key `aps_client_id` (in `~/.adom/config.json`) or via Settings. -4. Run `aps_auth` once — it opens the system browser for Autodesk sign-in. Tokens cache in `~/.adom/aps_tokens.json` and auto-refresh; you won't be prompted again. - -**Verbs:** -- `aps_status` — **call this first.** Non-prompting. Returns `{configured, signedIn}`. `configured:false` → no client id; use `fusion_search_cloud_files`. `configured:true, signedIn:false` → run `aps_auth`. Both true → `aps_search` is ready. -- `aps_auth` — interactive sign-in (opens browser). One-time per device. -- `aps_hubs` — `{hubs[]{id,name}}` (your Autodesk teams). -- `aps_projects {hubId?}` — `{hubId, projects[]{id,name}}` (default: first hub). -- `aps_search {query, projectName?, projectId?, hubId?}` — `{query, hubId, count, results[]{name,id,type,lastModified,project}}`. `query` is a case-insensitive substring of the file's displayName. Without `projectName`/`projectId` it searches up to 8 projects in the hub. Open a hit with `fusion_open_cloud_file {fileName, projectName}`. - -**Decision flow for an AI doing a cloud file search:** `aps_status` → if `configured` (sign in with `aps_auth` if needed) use `aps_search`; else fall back to `fusion_search_cloud_files` and tell the user that registering a free APS app (above) would make future searches instant. - -**Export formats for `fusion_export_cloud_file`:** - -| Format | Extension | Use case | -|--------|-----------|----------| -| `step` | .step | Industry-standard CAD interchange (default) | -| `stl` | .stl | 3D printing, mesh-based | -| `f3d` | .f3d | Fusion 360 native archive (preserves all features) | -| `iges` | .iges | Legacy CAD interchange | -| `sat` | .sat | ACIS solid modeling kernel format | -| `smt` | .smt | Parasolid format | - -Also supported for import via `fusion_import_step`: STEP (.step/.stp), STL (.stl), IGES (.iges/.igs), SAT (.sat), SMT (.smt), OBJ (.obj), F3D (.f3d). - -**Round-trip: workspace → Fusion Cloud → workspace** - -```bash -# === workspace to Fusion Cloud === -# 1. Send file from Docker to Windows desktop -adom-bridge send_files '{"files": [{"path": "/home/user/component.step"}]}' -# 2. Import into Fusion -adom-bridge fusion_import_step '{"filePath": "C:/Users/john/Downloads/component.step"}' -# 3. Save to cloud (gets a wip_urn for 3D library linking) -adom-bridge fusion_save_to_cloud '{"name": "my-component", "projectName": "Personal"}' - -# === Fusion Cloud to Docker === -# 1. Find and open the cloud file -adom-bridge fusion_walk_cloud_tree '{"projectName": "Personal", "nameContains": "my-component"}' -adom-bridge fusion_open_cloud_file '{"fileName": "my-component", "projectName": "Personal"}' -# 2. Export to local filesystem -adom-bridge fusion_export_cloud_file '{"outputPath": "C:/tmp/export/my-component.step", "format": "step"}' -# 3. Pull back to Docker -adom-bridge pull_file '{"path": "C:/tmp/export/my-component.step"}' - -# === Cloud management === -adom-bridge fusion_list_cloud_projects '{}' -adom-bridge fusion_create_cloud_folder '{"folderName": "Electronics", "projectName": "Main"}' -adom-bridge fusion_list_cloud_files '{"projectName": "Main", "folderPath": "Electronics"}' -adom-bridge fusion_delete_cloud_file '{"fileName": "old-file", "projectName": "Main"}' -``` - -#### Manufacturing Exports (Gerbers, BOM, CPL) - -Export manufacturing files from an open PCB board — everything needed to fabricate boards and assemble components via Adom's PCBA service. **All manufacturing commands require a .brd board open in PCB Editor** (use `fusion_open_board` or `fusion_show_2d_board`). - -**Recommended workflow order:** `detect_layers` → `set_design_rules` → DRC → `export_gerbers` → `export_bom` → `export_cpl` → `pull_file` all back to Docker. - -Every manufacturing command returns structured JSON with: -- `message` — AI-oriented summary explaining what was produced and why it matters -- `nextSteps[]` — ordered list of what to run next in the manufacturing pipeline -- `hint` — tips for interpreting results or recovering from issues -- `data` — structured metadata (paths, counts, layer info) for programmatic use - -**Decision guide — which command to run:** -- **Don't know the layer count?** → Run `fusion_detect_layers` first -- **Need to check if the board meets fab specs?** → Run `fusion_set_design_rules` then DRC -- **Ready to generate fab files?** → Run `fusion_export_gerbers`, then `fusion_export_bom`, then `fusion_export_cpl` -- **Need visual review before export?** → Run `fusion_export_board_image` with preset `assembly_top` or `fabrication` -- **Something failed?** → Check `data.hint` and `data.recoverySteps` in the error response - -**Commands:** - -- `fusion_detect_layers` -- Detect if the open board is 2-layer or 4-layer. Uses ULP script (primary) and CAM comparison (fallback). Returns `layerCount`, `copperLayers[]`, `method` (how it was detected), and `nextSteps[]`. **Run this first** — all other manufacturing commands auto-detect layers too, but running this explicitly gives you the data before committing to exports. - -- `fusion_set_design_rules` -- Apply Adom's JLCPCB-derived design rules (.edru XML files) to the open board. Auto-detects 2-layer vs 4-layer and loads the appropriate rule set. Returns `description` (human-readable rule summary), `edruFile`, and `nextSteps[]`. - - `action`: `"apply"` (default) loads rules into the board; `"export"` saves current board rules to a file; `"show"` displays rule capabilities without modifying anything - - `layers`: `"auto"` (default), `"2"`, or `"4"` — force a specific rule set - - After applying: run `fusion_electron_run '{"command": "DRC"}'` to check for violations. DRC markers appear in the board editor. - -- `fusion_apply_instapcb_rules` -- Convenience wrapper that applies the bundled Adom InstaPCB design rule sets without needing a local `.edru` file. Args: `layers` (`"2"` or `"4"`). Sends the bundled `.edru` from Docker to Windows automatically and loads it via the EAGLE `drc load` command. Use this instead of `fusion_set_design_rules` when you just want Adom's standard 2-layer or 4-layer InstaPCB rules. - -- `fusion_load_design_rules` -- Generic loader for ANY custom `.edru` file by path. Args: `filePath`. Use this for third-party fab vendor rules (JLCPCB, PCBWay, OSHPark, etc.) that the user has on disk. - -- `fusion_export_gerbers` -- Export Gerber (RS-274X) + Excellon drill files as a ZIP. Auto-detects 2-layer vs 4-layer and selects the correct JLCPCB-compatible CAM job. Returns `zipPath`, `zipSizeKB`, `files[]` (list of gerber files in the ZIP with sizes), `layerCount`, and `nextSteps[]`. - - `outputDir`: directory for the output ZIP (default: `C:/tmp/adom-gerbers/`) - - `boardName`: prefix for the ZIP filename (default: from active document name) - - `layers`: `"auto"` (default), `"2"`, or `"4"` — force CAM job selection - - Output ZIP contains: GTL, GBL (copper), GTS, GBS (solder mask), GTP, GBP (paste), GTO, GBO (silkscreen), GKO (outline), XLN (drill). 4-layer boards also get G1, G2 (inner copper). - -- `fusion_export_bom` -- Export Bill of Materials as CSV. Groups identical parts by value+package with quantity counts. Returns `componentCount`, `uniquePartCount`, and `nextSteps[]`. - - `outputPath`: (default: `C:/tmp/adom-bom.csv`) - - `grouped`: `true` (default) groups by value+package; `false` lists every component individually - - Output columns: Comment, Designator, Footprint, Quantity, Library — compatible with JLCPCB, PCBWay, Mouser, Digi-Key. - -- `fusion_export_cpl` -- Export Component Placement List (pick-and-place) as CSV. Returns `totalPlacements`, `topCount`, `bottomCount`, and `nextSteps[]`. - - `outputPath`: (default: `C:/tmp/adom-cpl.csv`) - - `side`: `"all"` (default), `"top"`, or `"bottom"` — filter for single-sided assembly - - Output columns: Designator, Mid X, Mid Y, Layer, Rotation — coordinates in mm. - -- `fusion_export_board_image` -- Export PNG image of the board with layer presets. Returns `fileSize`, `preset`, and `nextSteps[]`. - - `outputPath`: (default: `C:/tmp/adom-board.png`) - - `dpi`: resolution (default: 300, max: 600) - - `preset`: layer preset name (see table below) - - `layers`: custom layer numbers as int array — overrides preset - - `monochrome`: `true` for black & white - - `listPresets`: set `true` to get available presets instead of exporting - -**Layer presets for `fusion_export_board_image`:** - -| Preset | Layers | Description | -|--------|--------|-------------| -| `all` | All | Every layer visible | -| `top_copper` | 1, 17, 18 | Top copper + pads + vias | -| `bottom_copper` | 16, 17, 18 | Bottom copper + pads + vias | -| `top_silkscreen` | 21, 25 | Top silkscreen + component names | -| `bottom_silkscreen` | 22, 26 | Bottom silkscreen + component names | -| `top_soldermask` | 29 | Top solder mask openings | -| `bottom_soldermask` | 30 | Bottom solder mask openings | -| `top_paste` | 31 | Top paste/stencil openings | -| `bottom_paste` | 32 | Bottom paste/stencil openings | -| `board_outline` | 20 | Board outline (dimension layer) | -| `drill` | 44, 45, 17, 18 | Drill holes + vias | -| `assembly_top` | 1, 17, 18, 20, 21, 25, 51 | Top assembly — copper + silk + outline | -| `assembly_bottom` | 16, 17, 18, 20, 22, 26, 52 | Bottom assembly — copper + silk + outline | -| `fabrication` | 1, 16, 17–20, 21, 22, 25, 26, 29, 30, 51 | Full fabrication view | - -**Adom InstapcbPCB manufacturing capabilities (used by `fusion_set_design_rules`):** - -| Parameter | Metric | Imperial | -|-----------|--------|----------| -| Layers | 1, 2, 4, 6 | — | -| Min trace width | 0.08mm | 3 mil | -| Min trace spacing | 0.08mm | 3 mil | -| Min via drill | 0.2mm | 8 mil | -| Min silkscreen text | 0.1mm | 4 mil | -| Board edge clearance | 0.05mm | 2 mil | -| Board thickness | 1.6mm | 63 mil | -| Copper weight | 0.5 oz (17.5 μm) | — | -| Solder mask | Green | — | -| Surface finish | HASL / ENIG | — | -| Turnaround | 4 hours (fab + assembly) | — | - -**Manufacturing workflow — Fusion to Adom PCBA:** - -```bash -# 1. Open the board -adom-bridge fusion_open_board '{"filePath": "C:/projects/myboard.brd"}' - -# 2. Detect layer count (auto-selects 2-layer or 4-layer rules/CAM) -adom-bridge fusion_detect_layers - -# 3. Apply Adom design rules for the detected layer count + run DRC -adom-bridge fusion_set_design_rules '{"action": "apply"}' -adom-bridge fusion_electron_run '{"command": "DRC"}' - -# 4. Export manufacturing files (gerbers auto-select correct CAM job) -adom-bridge fusion_export_gerbers '{"outputDir": "C:/tmp/mfg"}' -adom-bridge fusion_export_bom '{"outputPath": "C:/tmp/mfg/bom.csv"}' -adom-bridge fusion_export_cpl '{"outputPath": "C:/tmp/mfg/cpl.csv"}' - -# 5. Export board images for review -adom-bridge fusion_export_board_image '{"outputPath": "C:/tmp/mfg/top-copper.png", "preset": "top_copper"}' -adom-bridge fusion_export_board_image '{"outputPath": "C:/tmp/mfg/assembly-top.png", "preset": "assembly_top"}' -adom-bridge fusion_export_board_image '{"outputPath": "C:/tmp/mfg/board-outline.png", "preset": "board_outline"}' - -# 6. Pull files back to Docker for Adom PCBA ordering -adom-bridge pull_file '{"path": "C:/tmp/mfg/bom.csv"}' -adom-bridge pull_file '{"path": "C:/tmp/mfg/cpl.csv"}' -``` +**A bridge's verbs are documented by the bridge, not here (2.1.145, wiki #212).** `commands` lists the bridges the box has; `commands {"bridge":"<name>"}` is the bridge's own description; `sync_skills` installs its skill. Nothing below is about any one bridge. ### Desktop Tools @@ -1155,64 +544,9 @@ adom-bridge pull_file '{"path": "C:/tmp/mfg/cpl.csv"}' **Decision rule:** human-in-the-loop login flow → `desktop_open_url`. AI-driven automation → `pup_open_window` (defaults to Chrome for Testing). AI-driven automation that **must** be the user's real, signed-in profile (GCP Console with org/projects, internal SSO behind a managed-Chrome policy, anything Context-Aware Access blocks for non-enrolled browsers) → `pup_open_window` with the new `nativeBrowser` + `nativeProfile` args (v1.0.5+, see below). -#### When pup means "the user's real Chrome/Edge" — `pup_open_window` native mode (v1.0.6+, smart flow v1.0.11) - -Default `pup_open_window` (no native args) launches Chrome for Testing — same as day one. **Never auto-switch a plain pup request to native.** "Open this URL in pup", "screenshot this", "click that button" all stay on CfT. - -Native mode drives the user's **REAL browser** — their actual signed-in profile, with live cookies, org policies, and device enrollment intact (NOT a clone — v1.0.6 replaced the old clone approach). Opt-in via TWO additive args from `desktop_list_browsers`: - -```bash -adom-bridge desktop_list_browsers # installed browsers + profiles (+ the signed-in account per profile) -adom-bridge pup_open_window '{ - "sessionId":"gcp", - "nativeBrowser":"chrome", # chrome / edge / brave - "nativeProfile":"Default", # profile id: Default / Profile 1 / Profile 2 - "url":"https://console.cloud.google.com" -}' -``` - -**The smart flow.** CDP (the protocol pup drives) needs the browser running with `--remote-debugging-port`, which can only be set at launch. So the bridge handles each situation differently and tells you which happened: - -| Situation | What ab does | Response | -|---|---|---| -| Already driving that browser+profile | Reuse the live connection | `ok` + `narrative` | -| Running **with** a debug port (power-user launched it that way, or ab did earlier) | Connect, no relaunch | `ok` + `narrative` | -| **Not running at all** | **Launch it fresh with the debug port — NO prompt** (nothing to disrupt) | `ok`, `launchedFresh:true` + `narrative` — just proceed | -| **Open without** a debug port | **Ask the user** — ab must close+reopen it | `errorCode:"native_relaunch_required"` + `confirmArgs` + `alternatives` | -| Debug port **refuses to bind** (enterprise policy) | Won't close it again | `errorCode:"native_cdp_blocked"` + `diagnosis` + `alternatives` | - -**Handling the two consent/blocked codes:** - -- **`native_relaunch_required`** — the browser is open without the port, so driving it means closing + reopening it (with `--restore-last-session`, so all tabs/windows come back). **Ask the user's permission**, then re-call with `"nativeRelaunch":true`. The response's `alternatives` lists other installed browsers you could offer instead. -- **`native_cdp_blocked`** — the debug port won't open, almost always an **enterprise policy** (`RemoteDebuggingAllowed` disabled via Google Workspace / Chrome cloud management — affects **Chrome browser-wide, every profile**). `diagnosis` says whether it's a confirmed local-registry policy or a likely cloud-managed one. ab will **not** close that browser again. `alternatives` names other installed browsers — **Edge usually escapes Google management**, so it often drives natively when Chrome can't. Offer the user the alternative, or fall back to generic CfT. - -**Always available — generic CfT.** `pup_open_window` with NO `nativeBrowser`/`nativeProfile` drives a clean Chrome-for-Testing instance: no user session, no managed policy, fully controllable. If a task needs the user's logged-in session there, have them sign in once. This is the universal fallback whenever native is blocked. - -**Power-user shortcut:** if the user launches their browser at startup with `--remote-debugging-port=<N>`, ab reconnects every session with no prompt at all (a productized opt-in "keep native browsers debug-ready at boot" is on the roadmap, default OFF for security). - -**Routing rule — DON'T auto-escalate.** Treat native as opt-in: - -| User says | What to do | -|---|---| -| "pup" / "open in pup" / screenshot / eval / debug | DEFAULT pup (CfT). Never mention profiles. | -| "native chrome" / "my real browser" / "my work profile" / "my `<account>` profile" | Native. Call `desktop_list_browsers`. If exactly one profile clearly fits the request, use it and say which one ("opening in your `[email protected]` profile on Chrome"). If multiple profiles could fit (e.g. a `google.com` URL with both `[email protected]` and `[email protected]` profiles signed in), **ASK** ("Which profile — work `[email protected]` or personal `[email protected]`?") and then drive that pair. | -| anything else | Default pup. | - -**Anti-fingerprint:** native sessions launch without `--enable-automation` and with `--disable-blink-features=AutomationControlled`. `navigator.webdriver === false`. No "controlled by automated software" banner. Sites that probe for automation see a normal browser. - -**Firefox** appears in `desktop_list_browsers` but is rejected for native drive with `errorCode:"firefox_no_cdp"` — Firefox doesn't speak the Chrome DevTools Protocol, so puppeteer can't drive it. If the user wants Firefox, hand off via `desktop_open_url` instead. - -**Native-mode error codes:** -- `native_relaunch_required` — browser open without a port; ask the user, re-call with `nativeRelaunch:true` (see the smart-flow table above). -- `native_cdp_blocked` — debug port policy-blocked; read `diagnosis`, offer `alternatives` or generic CfT (see above). -- `firefox_no_cdp` — caller passed `nativeBrowser:"firefox"`. Firefox doesn't speak CDP; hand off via `desktop_open_url`. -- `native_browser_not_installed` — that browser isn't installed on this machine. -- `native_user_data_missing` — installed but never launched, so the User Data dir doesn't exist yet. Ask the user to open it once. -- `native_profile_not_found` — `nativeProfile` isn't a real profile id under this browser's User Data. Call `desktop_list_browsers` to see what's valid. - #### ⚠️ Common footgun — `localhost` / `file://` URLs from Docker AIs -If you're running this CLI from a remote Docker container (my-container, dartv4, etc.), `pup_open_window` / `pup_open_tab` / `pup_navigate` will load the URL inside the USER's local pup — NOT inside your container. So a URL like `http://localhost:8080/foo.html` resolves to the user's machine, not your container's service. +If you're running this CLI from a remote container, a `url` you pass to ANY verb (a bridge's window, `desktop_open_url`) is loaded on the DESKTOP: `localhost` there is the desktop, not your container, and `file://` names a file on the desktop's disk. **v1.7.10+ detects this.** When you pass a URL whose host is `localhost`, `127.0.0.1`, `0.0.0.0`, `::1`, or scheme is `file://`, the response includes a `_hint` field explaining the issue and suggesting the public-slug URL pattern (`https://<user>-<repo>-<suffix>.adom.cloud/proxy/<port>/<path>`). **The call still proceeds** — rare legitimate cases exist where the user actually does have something running on their localhost. @@ -1226,11 +560,8 @@ python3 -m http.server 8786 --bind 0.0.0.0 & # (look at their browser URL when they open hydrogen or claude.ai/code). # Slug looks like: <username>-<container>-<random-id> -# 3. Open the public URL — NOT localhost: -adom-bridge pup_open_window '{ - "sessionId":"demo", - "url":"https://<your-container-slug>.adom.cloud/proxy/8786/foo.html" -}' +# 3. Open the public URL — NOT localhost — in whichever browser verb you use: +adom-bridge desktop_open_url '{"url":"https://<your-container-slug>.adom.cloud/proxy/8786/foo.html"}' ``` If you don't have the suffix handy, just ask the user. Or if the file you wanted to show pup is one your container already wrote to disk, push it to a public location (wiki asset, S3) and load from there. @@ -1495,17 +826,9 @@ adom-bridge settings_set '{"settings": {"launch_on_boot": true, "update_mode": " The pup bridge is **cloud-owned** and ships its OWN full skill (its wiki page / skill pkg — `bridge_list` names it; `adom-bridge sync_skills` installs it). This page keeps only the pointer plus first-touch examples; sessions/profiles, credential vault, downloads, recording, CDP details are the bridge's skill. -Most-used verbs: - -```bash -adom-bridge pup_open_window '{"sessionId": "s1", "profile": "p1", "url": "https://example.com"}' -adom-bridge pup_navigate '{"sessionId": "s1", "url": "https://example.com/page2"}' -adom-bridge pup_screenshot '{"sessionId": "s1"}' -adom-bridge pup_eval '{"sessionId": "s1", "expression": "document.title"}' -adom-bridge pup_fetch_url '{"url": "https://example.com/data.json"}' -``` +Its verbs: `adom-bridge commands '{"bridge":"puppeteer"}'`. -`pup_readiness` is the read-only probe (never spawns or downloads). Full details: the bridge's own skill via `sync_skills`. +`bridge_readiness {"name":"puppeteer"}` is the read-only probe (never spawns or downloads). Full details: the bridge's own skill via `sync_skills`. ### Screen recording — ab's desktop recorder (tab recording is pup's) @@ -1574,7 +897,7 @@ Composes `desktop_list_files` (or `desktop_watch_files` if `wait:true`) with the ```bash BEFORE=$(date +%s) -# … trigger the download click via pup_input_dispatch … +# … trigger the download click (a browser bridge verb, or desktop_ui_click) … adom-bridge desktop_pull_glob "{ \"path\": \"%USERPROFILE%\\\\Downloads\", \"glob\": \"ul_*.zip\", @@ -2009,7 +1332,7 @@ adom-bridge status ### Handling "not installed" errors -When a command returns `errorCode: "node_not_found"`, `errorCode: "kicad_not_installed"`, or `errorCode: "fusion_not_installed"`, guide the user through installation: +When a command returns `errorCode: "node_not_found"` (a bridge runtime ab manages: see `runtimes`), or a bridge reports its host app missing, guide the user through installation: **Picking the right native browser + profile (v1.7.1+):** @@ -2122,116 +1445,7 @@ If `desktop_install_node` returns `errorCode:"winget_unavailable"` (older Window If detection still misses an install on a user's machine, get the actual `node.exe` path from the user — that's a real bug to file. -**KiCad not installed:** - -**KiCad not installed:** - -v1.6.0+ — try the unattended winget install FIRST before asking the user to download manually: - -```bash -adom-bridge desktop_install_kicad '{}' -# → runs `winget install --id KiCad.KiCad --silent ...` (Windows only). -# → 2-5 minutes; downloads ~700 MB then installs. -# → returns {ok:true, exitCode:0, _hint:"Run kicad_list_versions to verify"} on success. -# → on failure (no winget / network failure / corporate-managed device): -# {ok:false, errorCode:"winget_unavailable" | "winget_install_failed", _hint, ...} -``` - -If `desktop_install_kicad` fails with `errorCode:"winget_unavailable"`, fall back to manual: - -> KiCad isn't installed and winget isn't available. Download from https://www.kicad.org/download/ — it's free and open source, install the latest stable (9.x or 10.x). -> Let me know when the install is done and I'll verify the connection. - -After EITHER path, have them restart Adom Bridge OR call `kicad_list_versions` again — the kicad bridge caches detection results, so a fresh scan may be needed to pick up freshly-installed binaries. - -**v1.6.0+ — improved KiCad detection.** The bridge now scans for KiCad in: -- `C:\Program Files\KiCad\<version>\` (the standard location) -- `C:\Program Files (x86)\KiCad\<version>\` (32-bit edge cases) -- `%LOCALAPPDATA%\Programs\KiCad\<version>\` (winget per-user installs) -- `%LOCALAPPDATA%\KiCad\<version>\` (rare manual installs) -- Windows registry: `HKLM\SOFTWARE\KiCad\<version>\InstallationPath` and the `WOW6432Node` mirror -- `HKCU` mirrors of the above for per-user installs -- macOS: `/Applications/KiCad/` and `/Applications/` directly - -If detection still misses an install on a user's machine, that's a real bug to file — get the actual install path from the user and we'll add it to the scan list. - -**Fusion 360 not installed:** -> Fusion 360 isn't installed on your desktop. Would you like to install it? -> Download from: https://www.autodesk.com/products/fusion-360 -> It's free for personal/hobby use (requires an Autodesk account). -> Let me know when the install is done and I'll verify the connection. - -After install, have them restart Adom Bridge, then run `adom-bridge status` to verify. - -### Handling "not running" errors - -When `errorCode: "fusion_not_running"`, launch it programmatically with the first-class startup command: -```bash -adom-bridge fusion_start -# On Windows: discovers exe via %LOCALAPPDATA% env var webdeploy glob. -# On Docker: delegates to the bridge on the connected desktop via relay. -# ~15-30s typical. Auto-dismisses startup dialogs. -# Returns {"addinReady": true, "pickerDismissed": true|false, ...} -``` - -KiCad doesn't need to be running for most commands (the bridge launches it on demand). - -### Handling "add-in not installed" errors - -When Fusion is running but `addinInstalled: false` or `addinConnected: false`: -> The AdomBridge add-in needs to be installed in Fusion 360. I can install it for you — this lets me control Fusion remotely. - -The add-in auto-installs when the Fusion bridge starts and Fusion is detected. - -### Handling `fusion_addin_not_responding` errors - -When `errorCode: "fusion_addin_not_responding"`, Fusion is running but the AdomBridge add-in isn't answering. Call `fusion_dismiss_blocking_dialogs` FIRST — a modal dialog is the most common cause. If that doesn't help, try `fusion_start` to restart Fusion cleanly. Last resort: user enables add-in manually via UTILITIES > ADD-INS > AdomBridge > Run on Startup + Run. - -### Handling `main_thread_busy` errors - -When `errorCode: "main_thread_busy"`, the Fusion add-in's main thread is occupied by a long-running command (typically `walk_cloud_tree` or `search_cloud_files`). This applies **across all bridges/sessions** — even if you didn't start the walk, another session might have. - -**Do NOT:** -- Retry the failed command — it will block behind the same lock -- Call `fusion_dismiss_blocking_dialogs` — there's no dialog to dismiss, and sending Escape will interrupt the active walk -- Force-kill Fusion — the walk will complete on its own - -**Do:** -- Wait for the walk/search to finish. If you started it, you should be using `adom-bridge watch` (see "Live folder progress streaming with `watch`" above) which streams live progress automatically. If another session started it, poll `fusion_addin_status` every 2–5s to check progress. -- Use commands that **don't need the main thread** while waiting: - - `fusion_addin_status` — check busy state and walk progress - - `fusion_window_info` — get window HWND, title, dialogs - - `fusion_screenshot_fusion` — capture what Fusion looks like - - `fusion_click_fusion` — click in the Fusion window - - `fusion_send_key` — send keyboard input - - `fusion_close_window` — close a specific dialog by HWND - -The response includes progress info: -```json -{ - "errorCode": "main_thread_busy", - "busyCommand": "walk_cloud_tree", - "elapsedSeconds": 42.3, - "walkProgress": { - "foldersVisited": 15, - "filesFound": 87, - "currentFolder": "Molecules/XRP", - "queueSize": 8 - }, - "_hint": "Add-in is busy with a long-running command. Do NOT retry..." -} -``` - -**Stalled walk detection**: If `fusion_addin_status` returns `busy: true` but `walkProgress` is missing and `mainThreadStalled: true`, a modal dialog is blocking the event loop — the walk was dispatched but never started. Call `fusion_dismiss_blocking_dialogs`, then the walk auto-resumes. - -### Auto-recovery (`_autoRecovery` field) - -When a fusion_* command fails with "not responding" / "not connected", the CLI automatically: -1. Calls `fusion_dismiss_blocking_dialogs` to clear any modal -2. If successful, retries the original command -3. Attaches `_autoRecovery: {action, dismissed[]}` to the retry result - -If you see `_autoRecovery` in a response, the command already succeeded after auto-dismissal — no manual intervention needed. The field is informational. +**A bridge's host app not installed or not running:** the bridge owns that story. `bridge_readiness {"name":"<bridge>"}` says `no-app` / `warming` / `ready` and its `_hint` says what to do; the bridge's own skill (`sync_skills`) has the install and launch flow. Do not hand the user a download link before asking the bridge: several can install their app unattended. ## Troubleshooting