← Commit history

Initial commit: app/adom-desktop-puppeteer-bridge

Kyle Bergstedt ·218c40a450 ·
2 files changed +251
README.mdadded+181
@@ -0,0 +1,181 @@+# Reference bridge: Puppeteer
+
+## Source code + contributing (2026-05)
+
+The Puppeteer (Chrome) bridge moved out of `adom-inc/adom-desktop`'s monorepo into its own dedicated repo so the community can extend it without coordinating with Adom Desktop's release cycle.
+
+### Where the source lives
+
+The canonical repo is **[`adom-inc/adom-bridge-puppeteer`](https://github.com/adom-inc/adom-bridge-puppeteer)** on GitHub. It's private today and will go public after a review pass.
+
+In the meantime, the full source — code, history, contributing guide, license — is **mirrored on this wiki page**:
+
+| Download | What it is | How to use |
+|---|---|---|
+| [`adom-bridge-puppeteer-source.tar.gz`](https://wiki-ufypy5dpx93o.adom.cloud/static/apps/adom-desktop-puppeteer-bridge/adom-bridge-puppeteer-source.tar.gz) | Clean source tree, no `.git` directory. ~98 KB. | `tar xzf adom-bridge-puppeteer-source.tar.gz && cd adom-bridge-puppeteer/` |
+| [`adom-bridge-puppeteer.bundle`](https://wiki-ufypy5dpx93o.adom.cloud/static/apps/adom-desktop-puppeteer-bridge/adom-bridge-puppeteer.bundle) | Git bundle with full commit history. ~157 KB. | `git clone https://wiki-ufypy5dpx93o.adom.cloud/static/apps/adom-desktop-puppeteer-bridge/adom-bridge-puppeteer.bundle adom-bridge-puppeteer && cd adom-bridge-puppeteer && git log` |
+
+No GitHub account needed to download either — both URLs are public.
+
+### How to contribute
+
+We accept community improvements. Most useful targets right now:
+
+- **macOS / Linux ports** — bridge currently Windows-only; cross-platform PRs welcome.
+- **New browser-automation verbs** — Puppeteer surface is big; we wrap a useful subset. Add more if you need them.
+- **Recording features** — desktop recorder is new (v1.8.x); plenty of polish room (annotations, audio, GIF export).
+
+Two contribution paths, depending on your access:
+
+**With a GitHub account (preferred):** wait until we make the repo public, then fork on GitHub and open a PR. We're aiming to flip the repo public in the next maintenance pass.
+
+**Without GitHub access (patch-by-email-style, available right now):** Clone the bundle, make your changes, generate a patch with `git format-patch origin/main..HEAD --stdout > my-changes.patch`, and email it to **`[email protected]`**. Adom maintainers will review and apply.
+
+See `CONTRIBUTING.md` inside the tarball/bundle for the full PR + ship workflow.
+
+### How shipping works after merge
+
+1. Maintainer merges your PR into `main`
+2. Maintainer tags `v<X.Y.Z>` + runs `bash scripts/release-bridge.sh puppeteer` on their box
+3. New zip + manifest published to this wiki page (replaces current version)
+4. Every Adom Desktop install running v1.7.19+ auto-picks up your change within 4 hours OR immediately via `adom-desktop refresh_bridges`
+
+No NSIS installer rebuild required. Your code reaches real users in ~30s after merge.
+
+### License
+
+MIT — see the `LICENSE` file in the tarball.
+
+---
+
+
+The Puppeteer bridge is one of three reference implementations bundled with Adom Desktop. It wraps `puppeteer-core` + Chrome for Testing to give Docker-side Claude full headful browser automation on the user's desktop — multi-window, multi-tab, file uploads, network interception, video recording.
+
+If you're authoring a new third-party bridge, see the [bridge SDK guide](https://wiki-ufypy5dpx93o.adom.cloud/wiki/apps/adom-desktop-bridges) first. Use this page when you want to see how a Node-based bridge is wired.
+
+## Quick facts
+
+| | |
+|---|---|
+| Name | `puppeteer` |
+| Display | Puppeteer (Chrome for Testing) |
+| Spawn kind | Node (`server.js`) |
+| Port | 8851 |
+| Verb prefixes | `browser_*`, `desktop_recorder_*`, `desktop_record_*` (22 verbs) |
+| Source zip | [`puppeteer-bridge-v1.0.0.zip`](https://wiki-ufypy5dpx93o.adom.cloud/static/apps/adom-desktop/puppeteer-bridge-v1.0.0.zip) |
+| Manifest | [`puppeteer-bridge-manifest.json`](https://wiki-ufypy5dpx93o.adom.cloud/static/apps/adom-desktop/puppeteer-bridge-manifest.json) |
+| User-facing skill | [`pup-SKILL.md`](https://wiki-ufypy5dpx93o.adom.cloud/static/apps/adom-desktop/pup-SKILL.md) |
+
+## What it does
+
+- **Sessions + tabs** — `browser_open_window` spawns Chrome for Testing with a per-session profile (cookies, IndexedDB, localStorage isolated). `browser_open_tab` / `browser_close_tab` manage tabs within a session.
+- **Navigation + introspection** — `browser_navigate`, `browser_back/forward/reload`, `browser_screenshot` (full-page or viewport), `browser_evaluate` (run JS, return result).
+- **Input synthesis** — `browser_click`, `browser_type`, `browser_press_key`, `browser_input_dispatch` (low-level CDP `Input.dispatchKeyEvent` for cases where typing through React state handlers fails).
+- **Recording** — `browser_record_start` per-tab via CDP `Page.startScreencast`, `desktop_record_start` for full-desktop via `getDisplayMedia` + `MediaRecorder` in a hidden Chrome window.
+- **Network capture** — `browser_fetch_url` runs `fetch()` from inside the page context (uses session cookies); useful for endpoints that gate by SameSite/CORS.
+
+## `bridge.json`
+
+```json
+{
+  "manifest_version": 1,
+  "name": "puppeteer",
+  "displayName": "Puppeteer (Chrome for Testing)",
+  "version": "1.0.0",
+  "description": "Headful browser automation via puppeteer-core + Chrome for Testing. Multi-window, multi-tab, recording, file uploads, network interception.",
+  "homepage": "https://github.com/adom-inc/adom-desktop",
+  "author": "Adom Inc.",
+  "license": "MIT",
+  "spawn": {
+    "kind": "node",
+    "entrypoint": "server.js",
+    "port": 8851,
+    "healthEndpoint": "http://127.0.0.1:8851/status",
+    "stopMethod": "kill",
+    "killImageName": "node.exe"
+  },
+  "verbPrefixes": ["browser_", "desktop_recorder_", "desktop_record_"],
+  "verbs": [
+    "browser_open_window", "browser_open_tab", "browser_close_tab", "browser_close_window",
+    "browser_navigate", "browser_back", "browser_forward", "browser_reload",
+    "browser_click", "browser_type", "browser_press_key",
+    "browser_screenshot", "browser_evaluate", "browser_fetch_url",
+    "browser_input_dispatch",
+    "browser_record_start", "browser_record_stop", "browser_record_status", "browser_record_list",
+    "desktop_recorder_open", "desktop_record_start", "desktop_record_stop"
+  ],
+  "dependencies": { "node": ">=20", "chrome": ">=120" },
+  "category": "Browser Automation",
+  "tags": ["puppeteer", "chrome", "headful", "recording"]
+}
+```
+
+Note: `verbPrefixes` is an array with THREE entries (`browser_*`, `desktop_recorder_*`, `desktop_record_*`). One bridge can own multiple prefixes.
+
+## Architecture highlights
+
+```
+puppeteer/
+├── server.js              ← HTTP entry point; routes /command → handler functions
+├── credential_vault.js    ← Per-session cookie/storage isolation
+├── adom-icon.svg          ← Window icon for spawned Chrome instances
+└── (npm install lays down node_modules + puppeteer-core)
+```
+
+The bridge intentionally keeps minimal on-disk state — `puppeteer-core` does the heavy lifting and Chrome for Testing is downloaded into `~/.cache/puppeteer/` on first run. The bridge code itself is one large `server.js` (~2k lines) using `http.createServer` for the JSON-over-HTTP dispatch layer (same shape as the hello sample, just more handlers).
+
+## Session model
+
+```bash
+# Open a window for session "design-review" with its own Chrome profile
+adom-desktop browser_open_window '{"sessionId":"design-review","profile":"design-review","url":"https://staging.example.com"}'
+
+# Add a tab in the same window
+adom-desktop browser_open_tab '{"sessionId":"design-review","url":"https://staging.example.com/cart"}'
+
+# Screenshot the active tab
+adom-desktop browser_screenshot '{"sessionId":"design-review"}'
+
+# Evaluate JS in the page (returns the resolved value)
+adom-desktop browser_evaluate '{"sessionId":"design-review","expr":"document.querySelectorAll(\"button\").length"}'
+
+# Close the whole window when done
+adom-desktop browser_close_window '{"sessionId":"design-review"}'
+```
+
+The `sessionId` is the persistence key — close + reopen the same session and you get the cookies + localStorage from before. `profile` defaults to the sessionId but can be shared across sessions for IndexedDB / login state sharing.
+
+## Recording example
+
+```bash
+# Per-tab recording → CDP screencast → JPEG frames → ffmpeg-mux'd tar on stop
+adom-desktop browser_record_start '{"sessionId":"design-review","tabId":"tab-1","fps":30}'
+# … drive the page …
+adom-desktop browser_record_stop '{"recordingId":"rec-tab-…"}'
+
+# Full-desktop recording → hidden Chrome window with getDisplayMedia + MediaRecorder → WebM
+adom-desktop desktop_recorder_open
+adom-desktop desktop_record_start '{"reason":"Demoing the alignment dialog flow","monitor":"primary"}'
+# … drive the desktop …
+adom-desktop desktop_record_stop
+```
+
+Reason is required for desktop recording so the user always knows why the recorder activated — it's shown in the HUD panel that opens.
+
+## Reference: install the source locally to read
+
+```bash
+curl -L https://wiki-ufypy5dpx93o.adom.cloud/static/apps/adom-desktop/puppeteer-bridge-v1.0.0.zip -o /tmp/puppeteer-bridge.zip
+mkdir -p /tmp/puppeteer-bridge && cd /tmp/puppeteer-bridge && python3 -c "import zipfile; zipfile.ZipFile('/tmp/puppeteer-bridge.zip').extractall()"
+ls -la
+```
+
+Open `server.js` to see the dispatch shape, recorder lifecycle, and per-session profile management.
+
+## Related
+
+- **[Bridge SDK guide](https://wiki-ufypy5dpx93o.adom.cloud/wiki/apps/adom-desktop-bridges)** — `bridge.json` schema, packaging recipe, lifecycle
+- **[KiCad bridge reference](https://wiki-ufypy5dpx93o.adom.cloud/wiki/apps/adom-desktop-kicad-bridge)** — most complex of the three; multi-instance, reverse-bridge
+- **[Fusion 360 bridge reference](https://wiki-ufypy5dpx93o.adom.cloud/wiki/apps/adom-desktop-fusion-bridge)** — passthrough-to-add-in pattern
+- **[adom-desktop main page](https://wiki-ufypy5dpx93o.adom.cloud/wiki/apps/adom-desktop)** — install the parent app first
+
page.jsonadded+70
@@ -0,0 +1,70 @@+{+  "schema_version": 1,+  "type": "app",+  "slug": "adom-desktop-puppeteer-bridge",+  "title": "Reference bridge: Puppeteer",+  "brief": "Reference implementation of the Puppeteer bridge — Node + puppeteer-core + Chrome for Testing for headful browser automation, multi-window, per-tab CDP screencast recording.",+  "version": "1.0.0",+  "tags": [],+  "license": "MIT",+  "discovery_triggers": [+    "puppeteer bridge",+    "pup bridge",+    "puppeteer bridge source",+    "chrome automation bridge",+    "puppeteer-core",+    "chrome for testing",+    "browser_open_window",+    "browser_screenshot",+    "browser_record_start",+    "desktop_record_start",+    "pup session profile",+    "headful chrome",+    "browser bridge source",+    "fork the pup bridge",+    "node bridge example"+  ],+  "discovery_pitch": "Reference implementation of the Puppeteer bridge — Node + puppeteer-core + Chrome for Testing for headful browser automation. Multi-window, multi-tab, per-session profile isolation, per-tab CDP screencast recording, full-desktop MediaRecorder capture.",+  "sample_prompts": [+    {+      "label": "Read puppeteer bridge source",+      "prompt": "Download the puppeteer-bridge zip from the wiki and walk me through server.js"+    },+    {+      "label": "Add a browser verb",+      "prompt": "Help me add a new browser_extract_pdfs verb to the puppeteer bridge"+    },+    {+      "label": "Open a window in pup",+      "prompt": "adom-desktop browser_open_window with a test URL"+    },+    {+      "label": "Record a tab",+      "prompt": "Record a 30-second video of a pup tab via browser_record_start/stop"+    },+    {+      "label": "Understand sessions",+      "prompt": "Explain how pup session profiles isolate cookies + IndexedDB"+    }+  ],+  "install": {+    "binary_name": "adom-desktop-puppeteer-bridge",+    "install_dir": "",+    "install_hint": "",+    "version_cmd": ""+  },+  "readme": "# Reference bridge: Puppeteer\r\n\r\n## Source code + contributing (2026-05)\r\n\r\nThe Puppeteer (Chrome) bridge moved out of `adom-inc/adom-desktop`'s monorepo into its own dedicated repo so the community can extend it without coordinating with Adom Desktop's release cycle.\r\n\r\n### Where the source lives\r\n\r\nThe canonical repo is **[`adom-inc/adom-bridge-puppeteer`](https://github.com/adom-inc/adom-bridge-puppeteer)** on GitHub. It's private today and will go public after a review pass.\r\n\r\nIn the meantime, the full source — code, history, contributing guide, license — is **mirrored on this wiki page**:\r\n\r\n| Download | What it is | How to use |\r\n|---|---|---|\r\n| [`adom-bridge-puppeteer-source.tar.gz`](https://wiki-ufypy5dpx93o.adom.cloud/static/apps/adom-desktop-puppeteer-bridge/adom-bridge-puppeteer-source.tar.gz) | Clean source tree, no `.git` directory. ~98 KB. | `tar xzf adom-bridge-puppeteer-source.tar.gz && cd adom-bridge-puppeteer/` |\r\n| [`adom-bridge-puppeteer.bundle`](https://wiki-ufypy5dpx93o.adom.cloud/static/apps/adom-desktop-puppeteer-bridge/adom-bridge-puppeteer.bundle) | Git bundle with full commit history. ~157 KB. | `git clone https://wiki-ufypy5dpx93o.adom.cloud/static/apps/adom-desktop-puppeteer-bridge/adom-bridge-puppeteer.bundle adom-bridge-puppeteer && cd adom-bridge-puppeteer && git log` |\r\n\r\nNo GitHub account needed to download either — both URLs are public.\r\n\r\n### How to contribute\r\n\r\nWe accept community improvements. Most useful targets right now:\r\n\r\n- **macOS / Linux ports** — bridge currently Windows-only; cross-platform PRs welcome.\r\n- **New browser-automation verbs** — Puppeteer surface is big; we wrap a useful subset. Add more if you need them.\r\n- **Recording features** — desktop recorder is new (v1.8.x); plenty of polish room (annotations, audio, GIF export).\r\n\r\nTwo contribution paths, depending on your access:\r\n\r\n**With a GitHub account (preferred):** wait until we make the repo public, then fork on GitHub and open a PR. We're aiming to flip the repo public in the next maintenance pass.\r\n\r\n**Without GitHub access (patch-by-email-style, available right now):** Clone the bundle, make your changes, generate a patch with `git format-patch origin/main..HEAD --stdout > my-changes.patch`, and email it to **`[email protected]`**. Adom maintainers will review and apply.\r\n\r\nSee `CONTRIBUTING.md` inside the tarball/bundle for the full PR + ship workflow.\r\n\r\n### How shipping works after merge\r\n\r\n1. Maintainer merges your PR into `main`\r\n2. Maintainer tags `v<X.Y.Z>` + runs `bash scripts/release-bridge.sh puppeteer` on their box\r\n3. New zip + manifest published to this wiki page (replaces current version)\r\n4. Every Adom Desktop install running v1.7.19+ auto-picks up your change within 4 hours OR immediately via `adom-desktop refresh_bridges`\r\n\r\nNo NSIS installer rebuild required. Your code reaches real users in ~30s after merge.\r\n\r\n### License\r\n\r\nMIT — see the `LICENSE` file in the tarball.\r\n\r\n---\r\n\r\n\r\nThe Puppeteer bridge is one of three reference implementations bundled with Adom Desktop. It wraps `puppeteer-core` + Chrome for Testing to give Docker-side Claude full headful browser automation on the user's desktop — multi-window, multi-tab, file uploads, network interception, video recording.\r\n\r\nIf you're authoring a new third-party bridge, see the [bridge SDK guide](https://wiki-ufypy5dpx93o.adom.cloud/wiki/apps/adom-desktop-bridges) first. Use this page when you want to see how a Node-based bridge is wired.\r\n\r\n## Quick facts\r\n\r\n| | |\r\n|---|---|\r\n| Name | `puppeteer` |\r\n| Display | Puppeteer (Chrome for Testing) |\r\n| Spawn kind | Node (`server.js`) |\r\n| Port | 8851 |\r\n| Verb prefixes | `browser_*`, `desktop_recorder_*`, `desktop_record_*` (22 verbs) |\r\n| Source zip | [`puppeteer-bridge-v1.0.0.zip`](https://wiki-ufypy5dpx93o.adom.cloud/static/apps/adom-desktop/puppeteer-bridge-v1.0.0.zip) |\r\n| Manifest | [`puppeteer-bridge-manifest.json`](https://wiki-ufypy5dpx93o.adom.cloud/static/apps/adom-desktop/puppeteer-bridge-manifest.json) |\r\n| User-facing skill | [`pup-SKILL.md`](https://wiki-ufypy5dpx93o.adom.cloud/static/apps/adom-desktop/pup-SKILL.md) |\r\n\r\n## What it does\r\n\r\n- **Sessions + tabs** — `browser_open_window` spawns Chrome for Testing with a per-session profile (cookies, IndexedDB, localStorage isolated). `browser_open_tab` / `browser_close_tab` manage tabs within a session.\r\n- **Navigation + introspection** — `browser_navigate`, `browser_back/forward/reload`, `browser_screenshot` (full-page or viewport), `browser_evaluate` (run JS, return result).\r\n- **Input synthesis** — `browser_click`, `browser_type`, `browser_press_key`, `browser_input_dispatch` (low-level CDP `Input.dispatchKeyEvent` for cases where typing through React state handlers fails).\r\n- **Recording** — `browser_record_start` per-tab via CDP `Page.startScreencast`, `desktop_record_start` for full-desktop via `getDisplayMedia` + `MediaRecorder` in a hidden Chrome window.\r\n- **Network capture** — `browser_fetch_url` runs `fetch()` from inside the page context (uses session cookies); useful for endpoints that gate by SameSite/CORS.\r\n\r\n## `bridge.json`\r\n\r\n```json\r\n{\r\n  \"manifest_version\": 1,\r\n  \"name\": \"puppeteer\",\r\n  \"displayName\": \"Puppeteer (Chrome for Testing)\",\r\n  \"version\": \"1.0.0\",\r\n  \"description\": \"Headful browser automation via puppeteer-core + Chrome for Testing. Multi-window, multi-tab, recording, file uploads, network interception.\",\r\n  \"homepage\": \"https://github.com/adom-inc/adom-desktop\",\r\n  \"author\": \"Adom Inc.\",\r\n  \"license\": \"MIT\",\r\n  \"spawn\": {\r\n    \"kind\": \"node\",\r\n    \"entrypoint\": \"server.js\",\r\n    \"port\": 8851,\r\n    \"healthEndpoint\": \"http://127.0.0.1:8851/status\",\r\n    \"stopMethod\": \"kill\",\r\n    \"killImageName\": \"node.exe\"\r\n  },\r\n  \"verbPrefixes\": [\"browser_\", \"desktop_recorder_\", \"desktop_record_\"],\r\n  \"verbs\": [\r\n    \"browser_open_window\", \"browser_open_tab\", \"browser_close_tab\", \"browser_close_window\",\r\n    \"browser_navigate\", \"browser_back\", \"browser_forward\", \"browser_reload\",\r\n    \"browser_click\", \"browser_type\", \"browser_press_key\",\r\n    \"browser_screenshot\", \"browser_evaluate\", \"browser_fetch_url\",\r\n    \"browser_input_dispatch\",\r\n    \"browser_record_start\", \"browser_record_stop\", \"browser_record_status\", \"browser_record_list\",\r\n    \"desktop_recorder_open\", \"desktop_record_start\", \"desktop_record_stop\"\r\n  ],\r\n  \"dependencies\": { \"node\": \">=20\", \"chrome\": \">=120\" },\r\n  \"category\": \"Browser Automation\",\r\n  \"tags\": [\"puppeteer\", \"chrome\", \"headful\", \"recording\"]\r\n}\r\n```\r\n\r\nNote: `verbPrefixes` is an array with THREE entries (`browser_*`, `desktop_recorder_*`, `desktop_record_*`). One bridge can own multiple prefixes.\r\n\r\n## Architecture highlights\r\n\r\n```\r\npuppeteer/\r\n├── server.js              ← HTTP entry point; routes /command → handler functions\r\n├── credential_vault.js    ← Per-session cookie/storage isolation\r\n├── adom-icon.svg          ← Window icon for spawned Chrome instances\r\n└── (npm install lays down node_modules + puppeteer-core)\r\n```\r\n\r\nThe bridge intentionally keeps minimal on-disk state — `puppeteer-core` does the heavy lifting and Chrome for Testing is downloaded into `~/.cache/puppeteer/` on first run. The bridge code itself is one large `server.js` (~2k lines) using `http.createServer` for the JSON-over-HTTP dispatch layer (same shape as the hello sample, just more handlers).\r\n\r\n## Session model\r\n\r\n```bash\r\n# Open a window for session \"design-review\" with its own Chrome profile\r\nadom-desktop browser_open_window '{\"sessionId\":\"design-review\",\"profile\":\"design-review\",\"url\":\"https://staging.example.com\"}'\r\n\r\n# Add a tab in the same window\r\nadom-desktop browser_open_tab '{\"sessionId\":\"design-review\",\"url\":\"https://staging.example.com/cart\"}'\r\n\r\n# Screenshot the active tab\r\nadom-desktop browser_screenshot '{\"sessionId\":\"design-review\"}'\r\n\r\n# Evaluate JS in the page (returns the resolved value)\r\nadom-desktop browser_evaluate '{\"sessionId\":\"design-review\",\"expr\":\"document.querySelectorAll(\\\"button\\\").length\"}'\r\n\r\n# Close the whole window when done\r\nadom-desktop browser_close_window '{\"sessionId\":\"design-review\"}'\r\n```\r\n\r\nThe `sessionId` is the persistence key — close + reopen the same session and you get the cookies + localStorage from before. `profile` defaults to the sessionId but can be shared across sessions for IndexedDB / login state sharing.\r\n\r\n## Recording example\r\n\r\n```bash\r\n# Per-tab recording → CDP screencast → JPEG frames → ffmpeg-mux'd tar on stop\r\nadom-desktop browser_record_start '{\"sessionId\":\"design-review\",\"tabId\":\"tab-1\",\"fps\":30}'\r\n# … drive the page …\r\nadom-desktop browser_record_stop '{\"recordingId\":\"rec-tab-…\"}'\r\n\r\n# Full-desktop recording → hidden Chrome window with getDisplayMedia + MediaRecorder → WebM\r\nadom-desktop desktop_recorder_open\r\nadom-desktop desktop_record_start '{\"reason\":\"Demoing the alignment dialog flow\",\"monitor\":\"primary\"}'\r\n# … drive the desktop …\r\nadom-desktop desktop_record_stop\r\n```\r\n\r\nReason is required for desktop recording so the user always knows why the recorder activated — it's shown in the HUD panel that opens.\r\n\r\n## Reference: install the source locally to read\r\n\r\n```bash\r\ncurl -L https://wiki-ufypy5dpx93o.adom.cloud/static/apps/adom-desktop/puppeteer-bridge-v1.0.0.zip -o /tmp/puppeteer-bridge.zip\r\nmkdir -p /tmp/puppeteer-bridge && cd /tmp/puppeteer-bridge && python3 -c \"import zipfile; zipfile.ZipFile('/tmp/puppeteer-bridge.zip').extractall()\"\r\nls -la\r\n```\r\n\r\nOpen `server.js` to see the dispatch shape, recorder lifecycle, and per-session profile management.\r\n\r\n## Related\r\n\r\n- **[Bridge SDK guide](https://wiki-ufypy5dpx93o.adom.cloud/wiki/apps/adom-desktop-bridges)** — `bridge.json` schema, packaging recipe, lifecycle\r\n- **[KiCad bridge reference](https://wiki-ufypy5dpx93o.adom.cloud/wiki/apps/adom-desktop-kicad-bridge)** — most complex of the three; multi-instance, reverse-bridge\r\n- **[Fusion 360 bridge reference](https://wiki-ufypy5dpx93o.adom.cloud/wiki/apps/adom-desktop-fusion-bridge)** — passthrough-to-add-in pattern\r\n- **[adom-desktop main page](https://wiki-ufypy5dpx93o.adom.cloud/wiki/apps/adom-desktop)** — install the parent app first\r\n\r\n",+  "author": {+    "id": "695820315b5f1e4db2fcf602",+    "name": "Kyle Bergstedt",+    "email": "[email protected]"+  },+  "visibility": {+    "public": true+  },+  "hero": null,+  "metadata": {},+  "created_at": "2026-05-28T05:28:43.991Z",+  "updated_at": "2026-05-28T05:28:43.991Z",+  "skills": []+}\ No newline at end of file