{
"schema_version": 1,
"type": "skill",
"slug": "adom-desktop-demo",
"title": "Demo",
"brief": "Run an interactive demo of Adom Desktop features.",
"version": "1.0.0",
"tags": [],
"license": "MIT",
"source_path": "SKILL.md",
"readme": "# Adom Desktop Demo\n\nAn interactive, guided demo of Adom Desktop's features. Claude walks the user through each capability (notifications, screenshots, browser automation, KiCad, Fusion 360, and file transfer) while showing live results in a Hydrogen webview.\n\n## REQUIRED: every demo starts with a plan card\n\nBefore running any demo steps, push a demo plan manifest card to the webview as the first step. This is a permanent fixture of every Adom demo. No exceptions. Without it the viewer has no idea what they are about to watch and the final video feels disorienting.\n\nUse `push_demo_plan <manifest.json>` from `demo-helpers.sh` (see `adom-desktop/skills/demo/SKILL.md` for the full spec + manifest JSON schema). The manifest MUST include the 11-item preamble checklist (demo server up, webview rendering intro, target app alive, HWNDs exported, sharing on monitor, mic disabled, conflicting tabs removed, helpers sourced in this shell not a subshell, markers initialized, captions ralph-tested, one dry-run push_step cycle verified) and a step-by-step table with speedup + clipped + reasoning columns per step.\n\n`render-demo-plan.py` generates a branded PNG from the manifest that's embedded in the push_step call. The viewer sees the whole plan before the demo begins.\n\n## Architecture\n\n```\nClaude (you — orchestrator)\n │\n ├── Start demo web server (Node.js, port 8790)\n ├── Open Hydrogen Web View tab → /proxy/8790/\n ├── Walk through demo steps, running adom-desktop commands\n └── POST results to http://127.0.0.1:8790/api/step at each step\n → Web UI updates in real-time via SSE\n```\n\n## Setup — Run This First\n\n### 1. Start the demo web server\n\n```bash\n# Kill any old instance\npkill -f \"node.*adom-desktop-demo/server.cjs\" 2>/dev/null || true\n\n# Start fresh\nnode ~/project/adom-desktop/skills/demo/server.cjs &\nsleep 1\ncurl -sf http://127.0.0.1:8790/api/state\n```\n\n### 2. Open the demo webview in Hydrogen\n\n```bash\n# Get workspace layout to find a leaf pane ID\nLAYOUT=$(adom-cli hydrogen workspace get 2>/dev/null)\n# Parse out a leaf pane ID (any leaf will do)\nLEAF_ID=$(echo \"$LAYOUT\" | python3 -c \"\nimport sys, json\nlayout = json.load(sys.stdin)\ndef find_leaf(node):\n if node.get('type') == 'leaf':\n return node['id']\n for child in node.get('children', []):\n result = find_leaf(child)\n if result: return result\n return None\nprint(find_leaf(layout.get('root', layout)))\n\")\n\n# Add a Web View tab with the demo URL\nadom-cli hydrogen workspace add-tab \\\n --panel-id \"$LEAF_ID\" \\\n --panel-type \"adom/a1b2c3d4-0031-4000-a000-000000000031\" \\\n --display-name \"Desktop Demo\" \\\n --display-icon \"mdi:monitor-cellphone\" \\\n --initial-state '{\"url\":\"/proxy/8790/\"}'\n```\n\nAfter adding the tab, bring it to the foreground if it isn't already visible. You may need to parse the response for the new `tabId` and call `adom-cli hydrogen workspace active-tab --tab-id <id>`.\n\n### 3. Check desktop connection\n\n```bash\nadom-desktop ping\n```\n\n- If **connected** → proceed to `adom-desktop status`\n- If **not connected** → follow the **First-Time Setup** flow from the `adom-desktop` skill (steps 1-7). Do NOT duplicate the setup instructions here — defer to that skill. Return here after `ping` succeeds.\n\n### 4. Detect installed apps\n\n```bash\nadom-desktop status\n```\n\nParse the `desktop.apps` field:\n- `kicad.installed` → enable KiCad demo section\n- `fusion360.installed` → enable Fusion 360 demo section\n- Browser/Puppeteer auto-starts — assume available if Node.js is on the desktop\n\nPush the welcome step to the webview:\n\n```bash\ncurl -s -X POST http://127.0.0.1:8790/api/step \\\n -H 'Content-Type: application/json' \\\n -d '{\"step\":0,\"total\":7,\"title\":\"Welcome\",\"description\":\"Connected to your desktop! Detected apps: ...\",\"status\":\"Connected\",\"statusColor\":\"#3fb950\"}'\n```\n\n## Demo Steps\n\nFor each step: narrate in chat, run the command, push results to the webview, then move to the next step. Use this curl pattern to push updates:\n\n```bash\ncurl -s -X POST http://127.0.0.1:8790/api/step \\\n -H 'Content-Type: application/json' \\\n -d '<JSON>'\n```\n\n### Step 1: Notifications (always runs)\n\nTell the user: \"Let's start simple — I'll send a notification to your desktop from this cloud container.\"\n\n```bash\nadom-desktop notify_user '{\"title\":\"Hello from the cloud!\",\"body\":\"This was sent from your Docker container via Adom Desktop.\",\"level\":\"info\"}'\n```\n\nPush to webview: `{\"step\":1,\"total\":7,\"title\":\"Desktop Notifications\",\"description\":\"Sent a notification to your desktop. Check your system tray! I can use these to alert you when builds finish, tests fail, or anything needs your attention.\",\"status\":\"Sent\",\"statusColor\":\"#3fb950\"}`\n\n### Step 2: Screenshots (always runs)\n\nTell the user: \"Now let me grab a screenshot of your entire desktop and show it right here.\"\n\n```bash\nadom-desktop desktop_screenshot_screen\n```\n\nThe command returns a JSON with the screenshot file path (usually `/tmp/conduit-screenshots/screen-*.png`). Read the file, base64-encode it, and push to the webview:\n\n```bash\n# Get the screenshot path from the command output (the \"savedTo\" field)\n# Base64-encoded images are too large for command-line curl -d. Write JSON to a file\n# and use --data-binary @file:\nIMG=$(base64 -w0 /tmp/conduit-screenshots/<filename>.png)\ncat > /tmp/step2.json <<EOF\n{\"step\":2,\"total\":8,\"title\":\"Desktop Screenshots\",\"description\":\"This is your desktop right now — captured from the cloud.\",\"image\":\"data:image/png;base64,$IMG\",\"status\":\"Captured\",\"statusColor\":\"#3fb950\"}\nEOF\ncurl -s -X POST http://127.0.0.1:8790/api/step -H 'Content-Type: application/json' --data-binary @/tmp/step2.json\n```\n**Gotcha:** base64-encoded screenshots routinely exceed the shell arg-list limit (~128 KB). Using `-d \"...\"` directly will fail with \"Argument list too long\". ALWAYS write the JSON payload to a file first.\n\nThen optionally: `desktop_list_windows` → pick an interesting window → `desktop_screenshot_window` → push another update with that screenshot.\n\n### Step 3: Pup — Browser Automation (runs if available)\n\nTell the user: \"I can also open and control Chrome on your desktop using pup. Watch this.\"\n\n```bash\nadom-desktop browser_open_window '{\"sessionId\":\"demo\",\"profile\":\"demo\",\"url\":\"https://adom.inc\"}'\n```\n\nWait 3 seconds for the page to load, then:\n\n```bash\nadom-desktop browser_screenshot '{\"sessionId\":\"demo\"}'\n```\n\nRead the screenshot, base64-encode, push to webview. Then:\n\n```bash\nadom-desktop browser_eval '{\"sessionId\":\"demo\",\"expr\":\"document.title\"}'\n```\n\nPush the eval result as data.\n\nTell the user: \"I opened Chrome, navigated to adom.inc, took a screenshot, and read the page title — all from this cloud container.\"\n\nClose when done:\n\n```bash\nadom-desktop browser_close_window '{\"sessionId\":\"demo\"}'\n```\n\n### Step 4: KiCad (only if `kicad.installed`)\n\nIf KiCad is NOT installed, push a skip message and move on:\n`{\"step\":4,\"total\":7,\"title\":\"KiCad\",\"description\":\"KiCad is not installed — skipping this section. Install KiCad from kicad.org to see this in action!\",\"status\":\"Skipped\",\"statusColor\":\"#d29922\"}`\n\nIf installed:\n\n```bash\nadom-desktop kicad_install_symbol '{\"filePath\":\"/home/adom/project/gallia/server/samples/ti-bq76952.kicad_sym\"}'\nadom-desktop kicad_open_symbol_editor\n```\n\nWait 5 seconds for the editor to open, then verify with window screenshots:\n\n```bash\n# Discover all KiCad windows and screenshot each one by HWND\nEDITORS=$(adom-desktop kicad_window_info 2>&1 | python3 -c \"\nimport sys,json\ninfo = json.loads(json.load(sys.stdin)['output'])['data']\nfor e in info['editors']:\n print(f\\\"{e['hwnd']}|{e['title']}\\\")\n\")\nwhile IFS='|' read -r HWND TITLE; do\n adom-desktop desktop_screenshot_window \"{\\\"hwnd\\\":$HWND}\"\ndone <<< \"$EDITORS\"\n```\n\nRead the screenshots to confirm the symbol is loaded, then push to webview.\n\nTell the user: \"I installed a TI BQ76952 battery monitor symbol into your KiCad libraries and opened the Symbol Editor. For a deeper dive, try /tour.\"\n\nClose KiCad:\n\n```bash\nadom-desktop kicad_close '{\"force\": true}'\n```\n\n### Step 5: Fusion 360 (only if `fusion360.installed`)\n\nIf NOT installed, push a skip message.\n\nIf installed:\n\n```bash\nadom-desktop fusion_launch\n```\n\nWait for it to return (15-30 seconds). Then:\n\n```bash\nadom-desktop fusion_import_step '{\"filePath\":\"/home/adom/project/gallia/services/wiki/static/3dcomps/3d-soic-8/3d-soic-8.step\"}'\n```\n\nTake a desktop screenshot and push to webview.\n\nTell the user: \"I launched Fusion 360 and imported a SOIC-8 3D model.\"\n\n```bash\nadom-desktop fusion_close\n```\n\n### Step 6: File Transfer (always runs)\n\nTell the user: \"Finally, let me send a file from this cloud container directly to your desktop.\"\n\n```bash\nadom-desktop send_files '{\"filePaths\":[\"/home/adom/project/gallia/server/samples/ti-bq76952.kicad_sym\"],\"targetApp\":\"general\",\"destinationFolder\":\"adom-demo\"}'\n```\n\nParse the returned `destinationPaths` and push to webview as data.\n\n### Step 7: Wrap-up\n\nPush a final summary step to the webview with all features listed and green status. Send a completion notification:\n\n```bash\nadom-desktop notify_user '{\"title\":\"Demo complete!\",\"body\":\"You have seen the full Adom Desktop experience.\",\"level\":\"info\"}'\n```\n\nIn chat, suggest next steps:\n- `/tour` — deep KiCad walkthrough (12 steps)\n- \"Open a browser to [url]\" — Puppeteer\n- \"Send [file] to my desktop\" — file transfer\n- \"Take a screenshot of my desktop\" — screenshots\n\n## Cleanup\n\nAfter the demo ends:\n\n```bash\n# Kill the demo server\npkill -f \"node.*adom-desktop-demo/server.cjs\" 2>/dev/null || true\n```\n\nOptionally close the webview tab via `adom-cli hydrogen workspace remove-tab`.\n\n## Pushing updates — API reference\n\n| Endpoint | Method | Description |\n|----------|--------|-------------|\n| `/api/step` | POST | Push a step update (JSON body) |\n| `/api/reset` | POST | Reset state for a fresh run |\n| `/api/state` | GET | Get current state |\n| `/api/events` | GET | SSE stream |\n| `/screenshots/<file>` | GET | Serve screenshot files from `/tmp/conduit-screenshots/` |\n\n### Step update JSON fields\n\n| Field | Type | Description |\n|-------|------|-------------|\n| `step` | number | Current step number (0-7) |\n| `total` | number | Total steps (7) |\n| `title` | string | Step title |\n| `description` | string | What happened / what the user should see |\n| `image` | string | Base64 data URI (`data:image/png;base64,...`) or URL path |\n| `data` | string | Monospace text (command output, eval results, file paths) |\n| `dataColor` | string | Color for data text (default: #3fb950 green) |\n| `status` | string | Status badge text (\"Sent\", \"Captured\", \"Skipped\", etc.) |\n| `statusColor` | string | Status badge color (#3fb950 green, #d29922 yellow, etc.) |\n\n## Verifying KiCad commands — use kicad_screenshot_all\n\nAfter ANY KiCad command, use `kicad_screenshot_all` to capture every KiCad window at once. This is the native command — no manual HWND loop needed:\n\n```bash\n# 1. Run your KiCad command\nadom-desktop kicad_open_schematic '{\"filePath\":\"C:/Users/john/Downloads/demo.kicad_sch\"}'\nsleep 5\n\n# 2. Screenshot ALL KiCad windows at once (native — uses PID-based detection)\nadom-desktop kicad_screenshot_all\n# → screenshots: [{type:\"editor\", hwnd:123, title:\"Schematic Editor\", savedTo:\"C:/tmp/...\"},\n# {type:\"dialog\", hwnd:456, title:\"File Open Warning\", savedTo:\"C:/tmp/...\"}]\n\n# 3. Pull screenshots from Windows to Docker\nadom-desktop pull_file '{\"filePaths\":[\"C:/tmp/conduit-screenshots/kicad-editor-....webp\"],\"saveTo\":\"/tmp\"}'\n\n# 4. Read each screenshot to verify:\n# - Did the schematic load? Or is it blank?\n# - Any modal dialogs? (type:\"dialog\" — shown in red in the grid)\n# - Is the right file open in each editor?\n```\n\n**Why `kicad_screenshot_all`:** Uses PID-based window detection — finds ALL KiCad windows regardless of title. Returns screenshots saved on Windows; use `pull_file` to get them to Docker.\n\n**For demo recordings:** Build a grid image from the screenshots (Pillow) — editors labeled green, dialogs labeled red. Push the grid to the webview to prove the AI sees every window simultaneously.\n\n## Recovering from stuck KiCad dialogs\n\nIf a KiCad command fails or times out, a modal dialog may be blocking. Use `kicad_window_info` to detect:\n\n```bash\n# 1. Check for modal dialogs\nadom-desktop kicad_window_info\n# → hasModalDialogs: true, modalDialogs: [{hwnd:456, title:\"File Open Warning\", ownerHwnd:123}]\n\n# 2. Screenshot the dialog\nadom-desktop kicad_screenshot_all # captures everything including dialogs\n# OR: adom-desktop desktop_screenshot_window '{\"hwnd\": 456}'\n\n# 3. AI reads the screenshot and decides:\n# - \"Save changes?\" → kicad_close '{\"force\": true}'\n# - \"File already open\" → click \"Open Anyway\" or cancel\n# - \"Format upgrade\" → usually safe to dismiss, retry\n# - Unknown → tell the user what you see and ask\n```\n\n## Recovering from stuck Fusion dialogs\n\nFusion can show Qt modal dialogs that block the add-in (all commands return \"add-in not responding\"). The CLI auto-detects this and returns a `_hint` with recovery steps, but here's the full pattern:\n\n```bash\n# 1. Command fails with \"add-in not responding\"\nadom-desktop fusion_export_bom\n# → error: \"Fusion 360 is running but AdomBridge add-in not responding...\"\n# _hint: \"Fusion add-in is blocked — likely by a modal dialog...\"\n\n# 2. Find the blocking dialog\nadom-desktop fusion_window_info\n# → dialogs: [{hwnd: 7016348, title: \"Fusion360\", rect: {width: 900, height: 489}}]\n# Large dialogs (width > 200) are likely the blocker\n\n# 3. Screenshot the dialog to read it\nadom-desktop desktop_screenshot_window '{\"hwnd\": 7016348}'\n# → Shows \"Select Electronics Design File\" or save prompt or error\n\n# 4. Dismiss based on what you see:\n# - \"Select Electronics Design File\" → fusion_send_key escape (cancel — file already open)\n# NOTE: Enter does NOT work on this dialog (no row is keyboard-selected).\n# Escape cancels cleanly and the previously opened document stays active.\n# - Save prompt → fusion_send_key escape (don't save)\n# - Error dialog → fusion_send_key enter (dismiss OK)\nadom-desktop fusion_send_key '{\"key\":\"enter\"}'\n\n# 5. Verify recovery\nadom-desktop fusion_get_app_state\n# → Should now return success with active document\n```\n\n**Common Fusion dialog chains (they cascade — dismiss one and another appears):**\n1. `open_cloud_file` with multiple linked electronics designs → \"Select Electronics Design File\" (900x489)\n - Escape cancels. To proceed: click the row you want (relative coords x=0.2, y=0.50), then click OK (x=0.88, y=0.93)\n2. After selecting electronics design → \"Linked Schematic file has new version(s)\" (498x239)\n - Click Yes (x=0.7, y=0.8) to load latest\n3. After loading schematic → \"Linked PCB file has new version(s)\" (498x239)\n - Click Yes (x=0.7, y=0.8) to load latest\n4. Progress bar may appear briefly — not a real dialog, ignore it\n\n**CRITICAL PATTERN: Modal-first loop, not sleep-first.**\nAfter ANY Fusion command, check for modals BEFORE sleeping:\n\n```bash\nfor i in 1 2 3 4 5 6 7 8 9 10; do\n sleep 2\n # Check app state — if ok, we're done\n STATE=$(adom-desktop fusion_get_app_state 2>&1 | python3 -c \"...\")\n if [ \"$STATE\" = \"ok\" ]; then break; fi\n # Check for dialogs — handle them immediately\n DHWND=$(adom-desktop fusion_window_info 2>&1 | python3 -c \"...\")\n if [ -n \"$DHWND\" ]; then\n # Screenshot → read → click Yes/OK/dismiss\n adom-desktop desktop_screenshot_window \"{\\\"hwnd\\\":$DHWND}\"\n adom-desktop fusion_click_fusion \"{\\\"hwnd\\\":$DHWND,\\\"x\\\":0.7,\\\"y\\\":0.8}\"\n fi\ndone\n```\n\nNever just `sleep 10` and hope — always poll for state + modals.\n\n**Other dialog triggers:**\n- Closing modified documents → \"Save changes?\"\n- Network issues → \"Cannot connect to cloud\"\n- Add-in crashes → Recovery dialog\n\n## Fusion 360 workspace prerequisite\n\nManufacturing exports, design rules, and EAGLE commands require the **Electronics workspace** to be active. Check with `fusion_get_app_state` — `isElectronics` must be `true` and `activeWorkspace` must be `PCB Editor` (not `3D PCB`).\n\nIf `isElectronics` is false:\n- The active document tab is the 3D model view, not the electronics board\n- Switch with `fusion_activate_document '{\"name\":\"...\"}'` or reopen the board file\n- Common trap: `fusion_show_3d_board` switches to 3D PCB workspace — you need `fusion_show_2d_board` to get back to Electronics\n\n## Fusion 360 design rules (InstaPCB / JLCPCB)\n\nApply Adom's optimized design rules for JLCPCB manufacturing:\n\n```bash\n# Show available rules (2-layer and 4-layer with detailed specs)\nadom-desktop fusion_set_design_rules '{\"action\":\"show\"}'\n\n# Auto-detect layer count and apply matching rules\nadom-desktop fusion_set_design_rules '{\"action\":\"apply\"}'\n# → Applies JLCPCB-optimized track widths, via sizes, clearances, annular rings\n\n# Force 4-layer rules\nadom-desktop fusion_set_design_rules '{\"action\":\"apply\",\"layers\":\"4\"}'\n```\n\n## Fusion 360 manufacturing exports\n\nAfter opening a board in Fusion (Electronics workspace active), export manufacturing files for fab:\n\n```bash\n# Export gerbers (ZIP with all layers — ready for JLCPCB/PCBWay upload)\nadom-desktop fusion_export_gerbers\n# → zipPath, zipSizeKB, layerCount, files[]\n\n# Export BOM (CSV — component list grouped by value+package)\nadom-desktop fusion_export_bom\n# → outputPath, componentCount, uniquePartCount\n\n# Export CPL/pick-and-place (CSV — component XY coordinates for assembly)\nadom-desktop fusion_export_cpl\n# → outputPath, totalPlacements, topCount, bottomCount\n\n# Export board image (PNG with layer presets)\nadom-desktop fusion_export_board_image '{\"preset\":\"all\"}'\n# Presets: all, top_copper, bottom_copper, silkscreen, assembly_top, fabrication, etc.\n\n# Get board data (components, nets, traces, DRC violations)\nadom-desktop fusion_board_info\n\n# Pull files back to Docker\nadom-desktop pull_file '{\"filePaths\":[\"C:/tmp/adom-gerbers/demo_gerbers.zip\",\"C:/tmp/adom-bom.csv\",\"C:/tmp/adom-cpl.csv\"],\"saveTo\":\"/tmp/mfg\"}'\n```\n\n## Window management for recordings\n\nUse `desktop_bring_to_front` to surface windows during recordings. Pattern: show the app window to the user, pause, then bring the browser back so the screenshot appears in the webview:\n\n```bash\n# Open an app\nadom-desktop kicad_open_schematic '{\"filePath\":\"...\"}'\nsleep 5\n\n# Show it to the user (window pops to foreground)\nadom-desktop desktop_bring_to_front '{\"titleContains\":\"Schematic Editor\"}'\nsleep 3\n\n# Bring browser back so user sees the webview update\nadom-desktop desktop_bring_to_front '{\"titleContains\":\"galliaApril - Editor\"}'\nsleep 1\n\n# Now push screenshot to webview — user sees the result appear\n```\n\n## Shell execute — revoke approvals first for demos\n\nBefore demoing shell execute (to show the approval dialog), revoke any prior \"Approve All\" permissions:\n\n```bash\nadom-desktop desktop_revoke_approvals\n# → revokedCount, autoApproveCleared, deniedPendingApprovals\n\n# Now shell_execute will show the approval dialog fresh\nadom-desktop shell_execute '{\"command\":\"echo Hello from Adom Cloud!\"}'\n```\n\n## Important Notes\n\n- **Don't duplicate setup instructions** — defer to the `adom-desktop` skill for install/connect\n- **Clean up after each section** — close KiCad, Fusion, browser windows. Leave the desktop as you found it.\n- **Use session ID \"demo\"** for Puppeteer to avoid collisions\n- **Base64-encode screenshots** before pushing to the webview — the image field expects a data URI\n- **Narrate in chat AND push to webview** — the user should see progress in both places\n- **Skip unavailable features gracefully** — push a yellow \"Skipped\" status with a helpful message\n- **Path normalization** — The CLI auto-converts paths both ways. You can pass `C:/Users/john/file.step` (forward slashes) and responses always return forward slashes. No need to escape backslashes.\n- **kicad_screenshot_all** — Use this instead of manual `desktop_screenshot_window` loops. Native PID-based detection finds all KiCad windows.\n- **pull_file** — Required to get screenshots/exports from Windows back to Docker. Args: `filePaths` (array), `saveTo` (directory).\n- **CLI hints** — The CLI returns `_hint` fields on every command response. These are context-aware guidance from the CLI to the AI:\n - **KiCad open commands**: \"WARNING: KiCad may show modal dialogs... ALWAYS check kicad_window_info\"\n - **KiCad window_info**: \"To screenshot all windows: kicad_screenshot_all\"\n - **Fusion exports**: \"Requires Electronics workspace. Files saved on Windows — use pull_file\"\n - **Fusion open_cloud_file**: \"WARNING: May trigger Select Electronics Design File dialog\"\n - **Fusion set_design_rules**: \"Requires Electronics workspace. If 'Not an Electron document', switch tabs\"\n - **Fusion errors (\"not responding\")**: Auto-diagnosis with recovery steps + fusion_window_info\n - Always read `_hint` — it tells you exactly what to do next and what can go wrong.",
"author": {
"id": "695820315b5f1e4db2fcf602",
"name": "Kyle Bergstedt",
"email": "[email protected]"
},
"visibility": {
"public": true
},
"hero": null,
"sample_prompts": [],
"discovery_triggers": [],
"discovery_pitch": null,
"metadata": {},
"created_at": "2026-05-28T05:30:01.474Z",
"updated_at": "2026-05-28T05:30:01.474Z",
"sub_skills": [],
"parent_app": null
}