← Commit history
._README.mdadded
⋯ 1 unchanged line ⋯
.__preview.htmladded
⋯ 1 unchanged line ⋯
._docsadded
⋯ 1 unchanged line ⋯
._package.jsonadded
⋯ 1 unchanged line ⋯
._postinstall.shadded
⋯ 1 unchanged line ⋯
._skillsadded
⋯ 1 unchanged line ⋯
README.md+63−47
@@ -1,63 +1,77 @@-# adom/hd-bootstrap+# adom/hd-bootstrap: Hydrogen Desktop Bootstrap (apps + skills) -Hydrogen Desktop's workspace layer, as a registry bootstrap. It's a thin-package: a dependency list + one config hook. Installing it converges a-workspace to "ready to run inside Hydrogen Desktop."+Hydrogen Desktop's workspace layer, as a registry bootstrap. One package that+carries BOTH the dependency list (apps) and the platform-generic hd-* skills+(bundled in `skills/`, deployed by the postinstall hook). Installing it+converges a workspace to "ready to run inside Hydrogen Desktop."  ``` adom-wiki pkg install adom/hd-bootstrap ``` -> **Tooling note (2026-07-16):** `adompkg` is deprecated — all install/update-> flows use the [adom-wiki CLI](/adom/adom-wiki-cli) (`adom-wiki pkg …`). The+> **Tooling note (2026-07-16):** `adompkg` is deprecated. All install/update+> flows use the [adom-wiki CLI](/adom/adom-wiki-cli) (`adom-wiki pkg ...`). The > golden image v17 was still baked with adompkg; **v18 must bake with > `adom-wiki pkg`** (planned). -The golden WSL2 image runs exactly that line at bake time and ships the-result pre-converged. A live workspace can run the same line on demand. The-bake is an optimization of the runtime flow, not a different mechanism.+The golden WSL2 image runs exactly that install line at bake time and ships the+result pre-converged. A live workspace can run the same line on demand, and+`adom-wiki pkg update` (via the [adom/hook](/adom/hook) prompt hook) keeps every+package, this one included, current at runtime. The bake is an optimization of+the runtime flow, not a different mechanism. -## How it layers+## How it layers (apps as deps, skills bundled per layer) -`adom/hd-bootstrap` depends on [`adom/core`](/adom/core) and adds only what's-specific to running inside HD. Layering is not a special feature — a layer is-just a bootstrap that depends on the one below it. `core` is pulled unmodified.+`adom/hd-bootstrap` depends on [`adom/core`](/adom/core) and adds only what is+specific to running inside HD. A layer is just a bootstrap that depends on the+one below it. Each layer bundles ITS OWN skills (decision John + Kyle,+2026-07-16): skills are documentation for the layer, they live with the layer,+and they install as part of the layer's package. There is no separate skills+package (`adom/hd-skillpack` is deprecated; its content lives here now).  ```-adom/core                 ← the Adom ecosystem (shared with web Hydrogen)-  └─ adom/hd-bootstrap    ← THIS: platform-generic HD layer (editor config, HD skills delivery)-       ├─ adom/hd-windows-bootstrap   ← Windows/WSL2 platform layer-       └─ adom/hd-mac-bootstrap       ← macOS sibling (in progress)+adom/core                        the Adom ecosystem (shared with web Hydrogen)+  └─ adom/hd-bootstrap           THIS: HD apps (deps) + platform-generic hd-* skills (bundled)+       ├─ adom/hd-windows-bootstrap   Windows/WSL2 layer + wsl2 hd-* skills (bundled)+       └─ adom/hd-mac-bootstrap       macOS sibling + mac skills (in progress, Kyle) ``` +Tool-specific skills are NOT here: a skill that documents a tool ships inside+that tool's package (the `webview` skill rides+[`adom/adom-workspace-control`](/adom/adom-workspace-control), the `pup` skill+rides the puppeteer bridge, the adom-google skill rides+[`adom/adom-google`](/adom/adom-google)). This package's bundle is HD's own+manual: the hd-* skills.+ This is the public **reference design**: other orgs build their own bootstrap the same way. A vendor publishes `<org>/bootstrap` depending on [`adom/core`](/adom/core) (plus this package only if their capability needs HD's runtime), and their users get set up by telling their AI "I use <org>."-*(The BOOTSTRAP-CONVENTION doc isn't hosted on the wiki yet — TODO: publish it+*(The BOOTSTRAP-CONVENTION doc is not hosted on the wiki yet. TODO: publish it and link here.)*  ## What's a dependency vs. what's in the hook -The rule: **anything that is a package is a dependency; environment config-that isn't a package is the `postinstall` hook; the OS baseline is the golden-image's build (not this package at all).**+The rule: **apps that are packages are dependencies; this layer's skills are+bundled content deployed by the hook; environment config that isn't a package+is also the hook; the OS baseline is the golden image's build (not this+package at all).**  ### Dependencies  | Dep | Why it's here | Status | |-----|---------------|--------|-| [`adom/core`](/adom/core) | The whole Adom ecosystem — skills hub, distributor search, KiCad/Fusion, pup, `adom-cli`, the `adom-vscode` binary, the registry CLI. | ✅ current (4.13.x), anon + sudo-free |+| [`adom/core`](/adom/core) | The whole Adom ecosystem: skills hub, distributor search, KiCad/Fusion, pup, `adom-cli`, the `adom-vscode` binary, the registry CLI. | ✅ current (4.13.x), anon + sudo-free | | [`adom/adom-desktop`](/adom/adom-desktop) | The Adom Desktop relay CLI. | ✅ current, anon |-| [`adom/hd-skillpack`](/adom/hd-skillpack) | The 52 `hd-*` skills. | ⏳ **wiring pending** — delivery is moving from "bundled `skills/` dir" to this dependency (part of the 2026-07-16 workspace-updater retirement; see below) |  > **Retired (2026-07-16):** [`adom/adom-workspace-updater`](/adom/adom-workspace-updater)-> — the in-distro updater daemon. Never a dep of THIS package (it rode-> [`adom/hd-windows-bootstrap`](/adom/hd-windows-bootstrap), removed there in-> 0.2.3). Updates are now registry-native: `adom-wiki pkg update` via the-> [`adom/hook`](/adom/hook) prompt hook. This also removes the only-> `needs_sudo` package from the tree — the old `ADOMPKG_ALLOW_SUDO=1`-> requirement should die with it (verify on the v18 bake).+> (the in-distro updater daemon; removed from+> [`adom/hd-windows-bootstrap`](/adom/hd-windows-bootstrap) in 0.2.3) and+> [`adom/hd-skillpack`](/adom/hd-skillpack) (the short-lived separate skills+> package; its skills are bundled HERE as of 0.2.7). Updates are registry-native+> via `adom-wiki pkg update` + [`adom/hook`](/adom/hook). The updater retirement+> also removes the only `needs_sudo` package from the tree, so the old+> `ADOMPKG_ALLOW_SUDO=1` requirement should die with it (verify on the v18 bake).  ### postinstall.sh (deploy bundled skills + environment config) @@ -65,14 +79,13 @@ Runs as the workspace user after all deps install (`sudo` only for the system-owned workbench file). Mirrors the config sections of [hd-wsl2-image](https://github.com/adom-inc/hd-wsl2-image)'s `bake-hd-setup.sh`: -0. Deploy the bundled `hd-*` skills (`skills/` dir → `~/.claude/skills/`) —-   *transitioning to the [`adom/hd-skillpack`](/adom/hd-skillpack) dep, which-   symlinks instead of copying*-1. Claude Code CLI (claude.ai installer → `~/.local/bin/claude`)+0. Deploy the bundled platform-generic hd-* skills (`skills/` dir, 38 of them,+   to `~/.claude/skills/`)+1. Claude Code CLI (claude.ai installer, lands at `~/.local/bin/claude`) 2. Claude Code extension (Open VSX) registered in code-server 3. `adom-vscode` extension `.vsix` registered in code-server (binary from the `core` dep) 4. code-server `settings.json` (dark theme, Claude Code perms, chat/agent panel-   off, silent ports, git notifications quieted — no model pin)+   off, silent ports, git notifications quieted, no model pin) 5. code-server `config.yaml` (telemetry + update-check off) 6. `workbench.html` IndexedDB seed (trusted domains `*` + activity-bar unpin) 7. tidy (`rm ~/project/.mcp.json`)@@ -89,24 +102,27 @@ The Carbon API key, `DefaultUid=1001`, the `host.docker.internal` alias.  ## Resolved / superseded decisions (history) -- ✅ **InstaPCB is EXCLUDED (2026-07-16)** — supersedes the 2026-06-19 decision-  to include it. `hd-instapcb` moved out of the public bucket (InstaPCB is not+- ✅ **Skills live IN the bootstraps (2026-07-16, John + Kyle).** Supersedes the+  one-day experiment with a separate `adom/hd-skillpack` package (1.0.0-1.0.4,+  now deprecated). Rationale: skills are the layer's documentation, they change+  at product cadence, and two humans maintain them next to the layer they+  document. `pkg update` is per-package, so bundling costs only a bootstrap+  version bump per skills change.+- ✅ **InstaPCB is EXCLUDED (2026-07-16).** Supersedes the 2026-06-19 decision to+  include it. `hd-instapcb` moved out of the public bucket (InstaPCB is not   releasable yet); the setup prompts no longer reference it.-- ✅ **Skills delivery**: originally bundled in `skills/`; now published as-  [`adom/hd-skillpack`](/adom/hd-skillpack) (1.0.4, 52 skills) — the dep wiring-  into this package lands with the workspace-updater-retirement merge.-- ✅ **The `adom/fusion-update-libraries` signature blocker is RESOLVED** — the+- ✅ **The `adom/fusion-update-libraries` signature blocker is RESOLVED.** The   v17 golden image baked and ships (`adom-golden-v17.tar.gz`). - ⏳ **Verify [`adom/core`](/adom/core) carries `adom-google` / `adom-tts` /-  `adom-gchat`** so HD inherits them (was planned 2026-06-19; core is now-  4.13.x — confirm before the v18 bake).+  `adom-gchat`** so HD inherits them (planned 2026-06-19; core is now 4.13.x,+  confirm before the v18 bake).  ## Status (2026-07-16) -**PUBLISHED + PUBLIC**, latest `adom/[email protected]`. Deps resolve+**PUBLISHED + PUBLIC**, latest `adom/[email protected]` (apps + skills model,+38 platform-generic skills bundled, incl. `hd-webview` + `hd-pup`). Deps resolve anonymously. Golden image **v17** ships from [hd-wsl2-image](https://github.com/adom-inc/hd-wsl2-image/releases) (baked with-the deprecated adompkg — **v18 re-bake with `adom-wiki pkg` planned**, which-also picks up hd-windows-bootstrap 0.2.3 (no retired daemon) and the skillpack-wiring). Build the image on the laptop via AD or in CI, never in the cloud-container.+the deprecated adompkg; **v18 re-bake with `adom-wiki pkg` planned**, picking up+this version, hd-windows-bootstrap 0.2.4, and no retired packages). Build the+image on the laptop via AD or in CI, never in the cloud container.
docs/._hero.htmladded
⋯ 1 unchanged line ⋯
docs/._hero.pngadded
⋯ 1 unchanged line ⋯
package.json+4−4
@@ -2,10 +2,10 @@   "schema_version": 1,   "slug": "hd-bootstrap",   "type": "bootstrap",-  "title": "Hydrogen Desktop",+  "title": "Hydrogen Desktop Bootstrap (apps + skills)",   "brief": "Layer Hydrogen Desktop's workspace onto a standard Adom workstation.",-  "version": "0.2.5",-  "description": "Hydrogen Desktop's PLATFORM-GENERIC workspace layer on top of adom/core. Installs adom/core for the full Adom ecosystem, then adds everything common to running inside Hydrogen Desktop on ANY platform: the runtime-neutral hd-* skills and the generic HD editor configuration (Claude Code CLI + extension, VS Code settings, trusted domains). Platform-specific layers depend on THIS: adom/hd-windows-bootstrap (WSL2), adom/hd-mac-bootstrap, adom/hd-ubuntu-bootstrap. The reference design other orgs copy to build their own bootstrap on adom/core.",+  "version": "0.2.7",+  "description": "Hydrogen Desktop's PLATFORM-GENERIC workspace layer on top of adom/core. Installs adom/core for the full Adom ecosystem, then adds everything common to running inside Hydrogen Desktop on ANY platform: the platform-generic hd-* skills (BUNDLED in this package by design; wsl2 skills ride adom/hd-windows-bootstrap, mac skills ride adom/hd-mac-bootstrap) and the generic HD editor configuration (Claude Code CLI + extension, VS Code settings, trusted domains). Platform-specific layers depend on THIS: adom/hd-windows-bootstrap, adom/hd-mac-bootstrap.",   "org": "adom",   "tags": [     "bootstrap",@@ -24,4 +24,4 @@   "hero": {     "path": "docs/hero.png"   }-}\ No newline at end of file+}
page.json+5−4
@@ -2,10 +2,10 @@   "schema_version": 1,   "slug": "hd-bootstrap",   "type": "bootstrap",-  "title": "Hydrogen Desktop",+  "title": "Hydrogen Desktop Bootstrap (apps + skills)",   "brief": "Layer Hydrogen Desktop's workspace onto a standard Adom workstation.",-  "version": "0.2.6",-  "description": "Hydrogen Desktop's PLATFORM-GENERIC workspace layer on top of adom/core. Installs adom/core for the full Adom ecosystem, then adds everything common to running inside Hydrogen Desktop on ANY platform: the runtime-neutral hd-* skills and the generic HD editor configuration (Claude Code CLI + extension, VS Code settings, trusted domains). Platform-specific layers depend on THIS: adom/hd-windows-bootstrap (WSL2), adom/hd-mac-bootstrap, adom/hd-ubuntu-bootstrap. The reference design other orgs copy to build their own bootstrap on adom/core.",+  "version": "0.2.7",+  "description": "Hydrogen Desktop's PLATFORM-GENERIC workspace layer on top of adom/core. Installs adom/core for the full Adom ecosystem, then adds everything common to running inside Hydrogen Desktop on ANY platform: the platform-generic hd-* skills (BUNDLED in this package by design; wsl2 skills ride adom/hd-windows-bootstrap, mac skills ride adom/hd-mac-bootstrap) and the generic HD editor configuration (Claude Code CLI + extension, VS Code settings, trusted domains). Platform-specific layers depend on THIS: adom/hd-windows-bootstrap, adom/hd-mac-bootstrap.",   "org": "adom",   "tags": [     "bootstrap",@@ -28,5 +28,6 @@   "hero": {     "type": "image",     "path": "docs/hero.png"-  }+  },+  "visibility": "public" }\ No newline at end of file
skills/hd-adom-auth/SKILL.md+17−23
@@ -7,8 +7,8 @@ description: >   READ when troubleshooting Adom login failures, session token expiry, the   profile dropdown, or virgin-reset Adom-auth options. Trigger words —   adom login, login, logout, auth, session token, auth intent, confirmation-  code, profile menu, avatar, sign in, sign out, auth proxy, clear session,-  HD adom login, Your profile, Your repositories.+  code, profile menu, avatar, sign in, sign out, hydrogen-session.txt, auth+  proxy, clear session, HD adom login, Your profile, Your repositories. ---  # Hydrogen Desktop -- Authentication Reference@@ -16,13 +16,13 @@ description: > ## Auth Flow Overview  HD uses an **auth intent** flow (no email/password entry in the app).-The backend creates a short-lived intent token on the Carbon API,+The Tauri backend creates a short-lived intent token on the Carbon API, opens the user's default browser to the Adom login page, and polls until the user completes sign-in in the browser.  ### Sequence -1. HD calls `invoke('auth_intent_start')` -> backend POSTs to+1. HD calls `invoke('auth_intent_start')` -> Rust POSTs to    `https://carbon.adom.inc/auth/intents` with `{"max_age": 7776000}`    (90-day session). 2. Carbon returns `{token, confirmation_code, expires_at, auth_url}`.@@ -31,17 +31,17 @@ the user completes sign-in in the browser.    token as a query param — NOT `/auth/intents/{token}`). 4. HD displays the confirmation code on screen and shows a spinner. 5. Frontend polls `invoke('auth_intent_poll', {token})` every 2 seconds.-   Backend GETs `https://carbon.adom.inc/auth/intents/{token}/status`.+   Rust GETs `https://carbon.adom.inc/auth/intents/{token}/status`. 6. When the user confirms in the browser, the response includes    `{state: "authenticated", session_token: "..."}`.-7. The backend saves the session token to HD's app-data directory on the host-   (the `hydrogen-session.txt` file) and a replay copy alongside it.+7. Rust saves the session token to `%APPDATA%\hydrogen-desktop\hydrogen-session.txt`+   and a replay copy to `%APPDATA%\hydrogen-desktop\replay-session.txt`. 8. Frontend redirects to the dashboard.  ### Source files  - **Login page**: `src/routes/auth/login/+page.svelte`-- **Auth backend**: `src-tauri/crates/hd-app/src/lib.rs` (functions+- **Auth Rust backend**: `src-tauri/crates/hd-app/src/lib.rs` (functions   `auth_intent_start`, `auth_intent_poll`, `auth_proxy`,   `check_replay_credentials`, `replay_adom_login`). NOTE: the old   `src-tauri/src/lib.rs` is a pre-crate-split vestige — the live code is in the@@ -54,8 +54,7 @@ the user completes sign-in in the browser.  ## Session Token -**Location**: HD's app-data directory on the host (the `hydrogen-session.txt`-file).+**Location**: `%APPDATA%\hydrogen-desktop\hydrogen-session.txt`  A plain-text file containing the Adom session cookie value. Created by either: - The auth intent flow (on successful poll)@@ -69,7 +68,7 @@ as a `Cookie: session_token=...` header on every request to `carbon.adom.inc`. - **Created**: on login (auth intent or browser set-cookie capture) - **Refreshed**: automatically when the auth proxy receives a new set-cookie - **Cleared**: on logout (`auth_proxy({path: "/auth/clear-local"})`) or on-  401 response (backend auto-deletes the file)+  401 response (Rust auto-deletes the file) - **Max age**: 90 days (set at intent creation)  ### Reading the token programmatically@@ -79,18 +78,15 @@ as a `Cookie: session_token=...` header on every request to `carbon.adom.inc`. curl http://127.0.0.1:47084/auth-token  # From inside the workspace (injected by setup step inject-api-key, mode 644)+# run inside the workspace — WSL2: `wsl -d Adom-Workspace -u adom -- cat /var/run/adom/api-key`; Docker: `docker exec <container> cat /var/run/adom/api-key` cat /var/run/adom/api-key ``` -For the host-specific path table and the runtime-specific way to read-`/var/run/adom/api-key` from outside the workspace, see the-[[hd-adom-auth-windows]] companion skill.- ---  ## Auth Proxy -The backend command `auth_proxy` is the gateway for all authenticated requests+The Tauri command `auth_proxy` is the gateway for all authenticated requests to the Adom Carbon API. It:  1. Reads the session token from disk@@ -118,7 +114,7 @@ On login page mount, HD checks for saved credentials before starting the full auth intent flow:  1. `invoke('check_replay_credentials')` checks if replay files exist on disk.-2. If the replay-session file exists (has_adom = true), HD shows a "REPLAY"+2. If `replay-session.txt` exists (has_adom = true), HD shows a "REPLAY"    badge and a 5-second countdown. 3. `invoke('replay_adom_login')` attempts to authenticate using the saved    session token.@@ -132,8 +128,7 @@ preserve the Adom session token.  ## Claude Credentials -**Location**: HD's app-data directory on the host (the-`replay-claude-credentials.json` file).+**Location**: `%APPDATA%\hydrogen-desktop\replay-claude-credentials.json`  Stores Claude Code OAuth credentials so they can be replayed into the workspace during bootstrap. The setup step `inject-api-key` reads the@@ -231,7 +226,7 @@ avatar ? avatar.alt : 'unknown';  1. User clicks "Log out" in profile menu. 2. `showConfirm('Are you sure you want to log out?', 'Log Out')` -- confirmation dialog.-3. If confirmed (app mode):+3. If confirmed (Tauri mode):    - `invoke('auth_proxy', {path: '/auth/logout', method: 'DELETE'})` -- server-side logout    - `invoke('auth_proxy', {path: '/auth/clear-local', method: 'POST'})` -- deletes `hydrogen-session.txt`    - Clears auth-related domain preferences from `localStorage['hd-url-routing-prefs']`@@ -243,7 +238,7 @@ avatar ? avatar.alt : 'unknown';  **Route**: `/auth/login` -### App mode (auth intent)+### Tauri mode (auth intent) - Adom logo + "Log in to Hydrogen" header - Confirmation code in a monospace box (`.confirmation-code`) - Spinner + "Waiting for you to sign in..."@@ -296,7 +291,7 @@ The setup/bootstrap process depends on a valid session token: 1. **inject-api-key** -- reads the HD-side `hydrogen-session.txt`, writes the    token into the workspace at `/var/run/adom/api-key` (mode 644) as the Adom    API key. If the token is missing or expired, this step fails and downstream-   steps (adom-cli, etc.) cannot authenticate.+   steps (adom-cli, gallia, etc.) cannot authenticate.  2. **Claude auth** -- uses `replay-claude-credentials.json` if available;    otherwise requires the user to complete the Claude OAuth flow inside the@@ -324,7 +319,6 @@ full endpoint reference.  ## Cross-references -- **hd-adom-auth-windows** -- host app-data path table + WSL2 specifics - **hd-ui** -- menu layout, where profile menu lives - **hd-setup** -- bootstrap steps that depend on auth - **hd-settings** -- API Explorer (auth endpoints tab)
skills/hd-adom-desktop/SKILL.md+48−47
@@ -4,12 +4,12 @@ description: >   What Hydrogen Desktop (HD) and Adom Desktop (AD) are, what each does, and how   they work together — so the AI in the workspace knows it has HANDS on the   user's real operating system. HD is the workspace app the user looks at; AD is-  the bridge that reaches the user's actual machine to create files & folders,-  run shell commands, take OS screenshots, launch apps, open browsers (Pup /-  native), and drive KiCad / Fusion 360. HD bundles AD during install and runs-  it in embedded mode, but AD is a standalone product that ALSO connects Adom-  cloud containers to a user's machine. HD also has a BUILT-IN desktop bridge of-  its own that serves a subset of AD's verbs.+  the bridge that reaches the user's actual Windows machine (macOS/Linux coming+  soon) to create files & folders, run shell commands, take OS screenshots,+  launch apps, open browsers (Pup / native), and drive KiCad / Fusion 360. HD+  bundles AD during install and runs it in embedded mode, but AD is a standalone+  product that ALSO connects Adom cloud containers to a user's machine. HD also+  has a BUILT-IN desktop bridge of its own that serves a subset of AD's verbs.   READ THIS to understand your reach beyond the workspace and how to invoke it.   Trigger words — adom desktop, AD, ad cli, what can you do on my computer, reach   my machine, create a file on my pc, make a folder on my desktop, run a command@@ -23,18 +23,16 @@ description: >  # Hydrogen Desktop ↔ Adom Desktop — your reach onto the user's real machine -You (the AI) run inside the **HD workspace** (a local Linux workspace on the-user's machine). That's a sandbox. **Adom Desktop (AD) is how you reach OUT of it-onto the user's actual operating system** — their real files, shell, screen, and-desktop apps. Knowing AD exists is the difference between "I can only work in-here" and "I can create that file on your Desktop, screenshot your screen, and-open it in KiCad."+You (the AI) run inside the **HD workspace** (a WSL2 Ubuntu distro by default).+That's a sandbox. **Adom Desktop (AD) is how you reach OUT of it onto the user's+actual operating system** — their real files, shell, screen, and desktop apps.+Knowing AD exists is the difference between "I can only work in here" and "I can+create that file on your Desktop, screenshot your screen, and open it in KiCad." -> **Platform note:** HD's host layer (file/shell/screenshot/notification/window-> control) is platform-specific. Before promising a host action on a given OS,-> verify the capability with `adom-desktop status` rather than assuming it.-> For Windows/WSL2-specific host behavior, see the [[hd-adom-desktop-windows]]-> companion skill.+> **Platform reality (2026-06-12):** AD reaches the user's real **Windows**+> machine. macOS and Linux are *coming soon* — HD's host layer (screenshots,+> notifications, captions, window control) is currently Windows-only. Don't+> promise file/shell/screenshot actions on a Mac or Linux box yet.  ## Two apps, two jobs @@ -86,7 +84,7 @@ bridge is — so recording / multi-monitor / glob-pull aren't available until AD is up. Screenshots, window control, files, shell, captions, notifications and the KiCad/Fusion/browser bridges all work off HD's built-in bridge regardless. -## What AD/HD let you do on the user's real machine+## What AD/HD let you do on the user's real Windows machine  All via the `adom-desktop` CLI from inside the workspace. Rather than re-document every verb here, this is a **capability map → the focused skill**:@@ -95,7 +93,7 @@ re-document every verb here, this is a **capability map → the focused skill**: |---|---|---| | **Create files/folders on the host** | `send_files` (container → desktop) | [hd-file-transfer](../hd-file-transfer/SKILL.md) | | **Pull files from the host** | `pull_file` (desktop → container, SHA256-verified); browse + watch via `list_files` / `watch_files` | [hd-file-transfer](../hd-file-transfer/SKILL.md) |-| **Run a shell command on the host** | `shell_execute` (real host shell) | shell-trust model below |+| **Run a shell command on the host** | `shell_execute` (real PowerShell/shell) | shell-trust model below | | **Screen/window control + screenshots** | `desktop_screenshot_screen` / `desktop_screenshot_window` / `desktop_list_windows`, `desktop_set_window_state`, `desktop_bring_to_front` | [hd-self-screenshot](../hd-self-screenshot/SKILL.md) | | **Record the screen / a tab** | `desktop_record_*` (whole screen), `browser_record_*` (one tab) | [hd-recording](../hd-recording/SKILL.md) — AD-served, verify `record` capability | | **Desktop notifications** | `notify_user` (title/body/level + action buttons) | [hd-notifications](../hd-notifications/SKILL.md) |@@ -109,8 +107,8 @@ For the complete verb list run `adom-desktop list_commands` (or see the  ### Host shell-trust model -`shell_execute` runs a **real command on the user's machine** (the host's native-shell). In **embedded mode HD auto-approves** shell commands so the AI isn't+`shell_execute` runs a **real command on the user's machine** (`cmd /C` on+Windows). In **embedded mode HD auto-approves** shell commands so the AI isn't blocked on per-command approval dialogs — convenient, but it means anything you run there really runs. Revoke the standing auto-approval at any time: @@ -121,18 +119,22 @@ adom-desktop shell_auto_approve '{"duration_secs":0}'   # turn auto-approve off When you *don't* need a free-form shell, prefer the **no-escape structured runners** over hand-quoted `shell_execute` (AD ≥ 1.8.50): `adom-desktop run_script '{"interpreter":"bash|cmd|powershell","scriptB64":"<b64>"}'`-and `adom-desktop wsl_exec '{"distro":"<workspace-distro>","user":"adom","scriptB64":"<b64>"}'`-— base64 the script so no quoting survives to be mangled. (`wsl_exec` is a-Windows/WSL2 path — see the [[hd-adom-desktop-windows]] companion.)+and `adom-desktop wsl_exec '{"distro":"Adom-Workspace","user":"adom","scriptB64":"<b64>"}'`+— base64 the script so no quoting survives to be mangled. -### Auto-installing missing apps+### Auto-installing missing apps (winget) -If KiCad or Node.js is missing on the host, HD can trigger an unattended-install on platforms that support it (see the [[hd-adom-desktop-windows]]-companion for the Windows winget verbs). The triggers: `install_kicad` fires-when `kicad_list_versions` returns `errorCode:"kicad_not_installed"`;-`install_node` when a `browser_*` call returns `errorCode:"node_not_found"`-(Node.js unblocks the Pup bridge).+If KiCad or Node.js is missing on the host, you don't have to stop at a download+link — trigger an unattended winget install:++```bash+adom-desktop desktop_install_kicad '{}'   # winget install KiCad+adom-desktop desktop_install_node  '{}'   # winget install Node.js (unblocks the Pup bridge)+```++(`install_kicad` fires when `kicad_list_versions` returns+`errorCode:"kicad_not_installed"`; `install_node` when a `browser_*` call returns+`errorCode:"node_not_found"`.)  ### KiCad project auto-sync @@ -151,8 +153,8 @@ over a WebSocket to the desktop client(s). **Host shell + files:** ```bash adom-desktop shell_execute '{"command":"<cmd>","timeoutSeconds":60}'-adom-desktop pull_file  '{"filePaths":["<host path>"],"saveTo":"/tmp"}'-adom-desktop send_files '{"filePaths":["/tmp/x"],"saveTo":"<host dir>"}'+adom-desktop pull_file  '{"filePaths":["C:\\path\\file"],"saveTo":"/tmp"}'+adom-desktop send_files '{"filePaths":["/tmp/x"],"saveTo":"C:\\Users\\<you>"}' adom-desktop desktop_list_windows ``` @@ -166,8 +168,8 @@ adom-desktop hd_launch            # start HD detached adom-desktop hd_api '{"method":"POST","path":"/setup/run-all","body":{}}' adom-desktop hd_api '{"method":"GET","path":"/health"}' ```-`hd_api` hits HD's **control API** on its discovered port (fallback **47084**).-See the [[hd-adom-desktop-windows]] companion for the host port-discovery file.+`hd_api` hits HD's **control API**, discovering its real port from+`%APPDATA%\hydrogen-desktop\ports.json` key `control` (fallback **47084**).  **Embedded-mode introspection (AD-served):** ```bash@@ -178,17 +180,19 @@ adom-desktop desktop_embedded_status   # embedded=true/false, enteredVia=launch-  ``` You (AI in the workspace)-  └─ adom-desktop <verb> '<json>'        ← CLI in the workspace+  └─ adom-desktop <verb> '<json>'        ← CLI in the distro        └─ relay  (adom-desktop serve: WS :8765 + HTTP :8766, started in the workspace)-            └─ WebSocket ──► HD's built-in bridge AND/OR the embedded AD on the user's machine+            └─ WebSocket ──► HD's built-in bridge AND/OR the embedded AD on the user's Windows machine                  └─ acts on the OS / KiCad / Fusion / Chrome ```  - In HD the relay is started for you by the **`start-relay`** setup step; HD's-  built-in bridge and the embedded AD both connect to it. The host-side clients-  reach your in-workspace relay — the exact networking depends on the runtime-  (see the `hd-networking` skill, and the [[hd-adom-desktop-windows]] companion-  for the WSL2 loopback-forwarding details).+  built-in bridge and the embedded AD both connect to it. Under WSL2 the relay+  binds `0.0.0.0:8765` in the distro and WSL2 forwards it to the host's+  `localhost:8765` (HTTP on `8766`), which is how the host-side clients reach+  your in-workspace relay (see the `hd-networking` skill). It's reached+  **same-port** under WSL2 — there's no host 47081/47082 remap (that was the old+  Docker model). - **Always verify the bridge before acting on the host:**   ```bash   adom-desktop ping       # → {"status":"connected", ...} means a client is reachable@@ -201,13 +205,11 @@ You (AI in the workspace)  ## What NOT to do -- **Never kill the host AD process** — the host AD is your relay bridge;+- **Never `taskkill /F /IM adom-desktop.exe`** — the host AD is your relay bridge;   killing it severs your control channel (you can't get it back from in here).-  (Windows-specific `taskkill` warnings live in the-  [[hd-adom-desktop-windows]] companion.) - **Never hardcode `:9001` as HD's control API.** `9001` is real — it's AD's   liveness beacon that AD probes to detect HD — but HD's actual control API is-  **47084** (use `hd_api`, which reads the discovered port).+  **47084** (use `hd_api`, which reads `ports.json` → `control`). - **Don't broad-kill `node`** — VS Code Server runs as node; killing it kills the   whole workspace. - Resize screenshots to `<1500px` before reading them, and inject every screenshot@@ -222,7 +224,6 @@ workspace itself (editor, files under `/home/adom/project`, the runtime), that's **HD**. Lead with what you can do, verify with `adom-desktop ping`, then act.  ## Related skills-- [[hd-adom-desktop-windows]] — Windows/WSL2 host specifics (paths, winget installs, loopback forwarding, taskkill) - [hd-embedded-ad](../hd-embedded-ad/SKILL.md) — how HD bundles + embeds AD (tray, lifecycle, standalone↔embedded) - [hd-bridges](../hd-bridges/SKILL.md) — the KiCad / Fusion / Puppeteer bridge ecosystem - [hd-file-transfer](../hd-file-transfer/SKILL.md) — send/pull files, browse + watch the host filesystem@@ -231,4 +232,4 @@ workspace itself (editor, files under `/home/adom/project`, the runtime), that's - [hd-notifications](../hd-notifications/SKILL.md) — desktop toasts; [hd-captions](../hd-captions/SKILL.md) — on-screen caption overlay - [hd-open-url](../hd-open-url/SKILL.md) — the ways to open a URL (Pup, native browser, picker, …) - `pup` — driving Pup browser windows; `adom-desktop` — the full CLI verb reference-- [hd-runtime-mode](../hd-runtime-mode/SKILL.md) — the HD↔AD relationship is identical across runtimes+- [hd-runtime-mode](../hd-runtime-mode/SKILL.md) — the HD↔AD relationship is identical on WSL2 and Docker
skills/hd-api/SKILL.md+69−32
@@ -2,16 +2,16 @@ name: hd-api description: >   Complete reference for Hydrogen Desktop control API endpoints. The control-  API runs on a dynamic port (find it via port discovery). Use these endpoints-  to drive HD programmatically: manage the workspace runtime, control Claude-  Code, manipulate VS Code, manage workspace tabs, run setup steps, trigger+  API runs on a dynamic port (find it in the HD log or via port discovery). Use+  these endpoints to drive HD programmatically: manage the workspace runtime (WSL2 distro or legacy Docker container), control+  Claude Code, manipulate VS Code, manage workspace tabs, run setup steps, trigger   virgin reset, and more. ~159 endpoints. Two self-documenting sources of truth   list them live: GET /_manifest (curated grouped list) and GET /test/help   (the /test/* diagnostics).   Trigger words: HD API, control API, HD endpoint, container exec, claude api,-  iframe eval, workspace tabs, setup run-all, runtime status, reload vscode,-  browser profiles, open url, virgin reset api, diagnostics, ad health,-  test window-tree, ai cursor, setup panel, screenshot mode.+  iframe eval, workspace tabs, setup run-all, docker status, reload vscode,+  browser profiles, open url, virgin reset api, reboot api, diagnostics,+  ad health, test window-tree, ai cursor, setup panel, screenshot mode. ---  # HD Control API Reference@@ -25,9 +25,10 @@ sources of truth you should hit first: | `GET /_manifest` | Curated, grouped, machine-readable list of the highest-value endpoints (path, method, args, description, `visibility`). `hd_api` forwards anything not listed. | `lib.rs:9144` | | `GET /test/help` | Lists the `/test/*` diagnostics (window enumeration, UIA click, dialog classification, cascade reset). Gated behind `HD_TEST_API_ENABLED=1`. | `lib.rs:9723` | -**Base URL:** `http://127.0.0.1:<dynamic>` — the loopback address. The port is-dynamic per launch; read the live URL from `~/.adom/hd-control-url` — see-"Finding the Control Port" below.+**Base URL:** `http://127.0.0.1:<dynamic>` — the same loopback address from inside the+workspace (WSL2 mirrored networking shares loopback with the Windows host) and on the+Windows host. The port is dynamic per launch; read the live URL from+`~/.adom/hd-control-url` — see "Finding the Control Port" below.  ## Finding the Control Port @@ -37,8 +38,11 @@ The control API port is dynamic (default 47084, auto-resolves conflicts). # From HD log adom-desktop hd_log '{"tail":100}' | grep "control=" -# From inside the workspace — USE THIS. HD writes its live control URL to a discovery-# file every launch, so you never hunt for the dynamic port:+# From ports.json+type %APPDATA%\hydrogen-desktop\ports.json++# From inside the WSL2 workspace — USE THIS. HD writes its live control URL to a discovery+# file every launch (mirrored loopback), so you never hunt for the dynamic port: CTRL="$(cat ~/.adom/hd-control-url)"; curl -sf "$CTRL/health" ``` @@ -48,10 +52,6 @@ rewrites it with the live dynamic port every launch. This is the channel for the the live ports map, Claude control, etc. — distinct from `adom-cli` (`ADOM_HYDROGEN_URL` → SSE), which is unchanged for web-hydrogen parity. -> For the host-side ways to discover the port (HD log/`ports.json`) and the-> host runtime endpoints (`/wsl/*`, `/docker/*`, `/system/reboot`), see the-> [[hd-api-windows]] companion skill.- ## Health & Status  | Method | Path | Description |@@ -59,7 +59,7 @@ which is unchanged for web-hydrogen parity. | GET | `/health` | HD alive check — returns `{ok, port, service}` | | GET | `/buildinfo` | Running build git SHA + build metadata (the only trustworthy "did my build ship?" check) | | GET | `/ports` | The 4 editable PortConfig ports (proxy, control, cdp, code_server) |-| GET | `/ports/all` | LIVE full port map — every port HD has bound, with status info |+| GET | `/ports/all` | LIVE full port map — every host + WSL2 port HD has bound, with status + mirrored-mode info |  ## AD-health diagnostics (`/ad/*`) @@ -92,7 +92,7 @@ Open/close/toggle any HD menu, dialog, or panel — the first-class alternative  ## Workspace / Container Management -These endpoints manage the active workspace runtime.+These endpoints manage the active workspace runtime (a WSL2 distro by default, or a Docker container under `HD_RUNTIME=docker`).  | Method | Path | Body | Description | |---|---|---|---|@@ -102,6 +102,7 @@ These endpoints manage the active workspace runtime. | POST | `/container-stop` | — | Stop the active workspace runtime | | POST | `/container-exec` | `{"command":"..."}` | Run command in the workspace as user `adom` | | POST | `/container-delete` | — | Remove the workspace |+| POST | `/volume-delete` | — | Remove project volume (DESTRUCTIVE). **Docker runtime only** — no volume exists under WSL. | | POST | `/image-delete` | — | Remove workspace image | | GET | `/container-images` | — | List available workspace images | | POST | `/container-switch-image` | `{"image":"..."}` | Switch to different image |@@ -112,9 +113,42 @@ These endpoints manage the active workspace runtime. | GET | `/container/disk` | — | Disk usage inside the workspace | | POST | `/container/restart` | — | Alias for `/container-restart` | -> Runtime-specific endpoints — the WSL `/wsl/*` tables, the legacy Docker-> `/docker/*` tables, and `/volume-delete` (Docker-only) — live in the-> [[hd-api-windows]] companion skill.+### WSL runtime endpoints (default runtime)++When HD runs the workspace as a WSL2 distro, it additionally exposes:++| Method | Path | Body | Description |+|---|---|---|---|+| GET | `/wsl/status` | — | WSL distro state (registered, running, code-server reachable) |+| GET | `/workspace/health` | — | Deep workspace health (distro + code-server + host reachability) |+| GET | `/virgin-reset-progress` | — | Live progress of an in-flight virgin reset |+| POST | `/workspace/terminal-profile` | — | Ensure the stable `Adom-Workspace` Windows Terminal profile (idempotent) |+| POST | `/workspace/terminal-profile/remove` | — | Remove the `Adom-Workspace` Windows Terminal profile(s) |+| POST | `/workspace/check-updates` | — | Check upstream for newer code-server + Claude extension; stage them |+| POST | `/workspace/apply-updates` | — | Apply staged code-server/extension updates + reload editor |++> ⛔ `POST /wsl/unregister` is **REFUSED as deprecated** — it was a headless+> destructive reset (deletes `/home/adom/project`). Use the Setup panel's Virgin+> Reset or `POST /setup/panel/run-virgin-reset` instead.++## Docker Desktop (legacy Docker runtime only — `HD_RUNTIME=docker`)++This `/docker/*` table applies only when HD is running the legacy Docker runtime.++| Method | Path | Body | Description |+|---|---|---|---|+| GET | `/docker/status` | — | Docker Desktop running state |+| GET | `/docker/version` | — | Docker engine version |+| GET | `/docker/containers` | — | List all Docker containers |+| GET | `/docker/images` | — | List all Docker images |+| POST | `/docker/start` | — | Launch Docker Desktop + start container |+| POST | `/docker/stop` | — | Stop Docker Desktop |+| POST | `/docker/restart` | — | Restart Docker Desktop |+| POST | `/docker/wait-ready` | — | Block until Docker daemon responds |+| POST | `/docker/install` | — | Install Docker Desktop (downloads ~730 MB) |+| POST | `/docker/uninstall` | — | Uninstall Docker Desktop |+| POST | `/docker/clean-reinstall` | — | Uninstall + reinstall Docker Desktop |+| GET | `/docker/install-progress` | — | Current install step + progress |  ## WebView & VS Code @@ -232,8 +266,8 @@ glides it, and can click. Use for demos or when the user should see where the AI | POST | `/config-reset` | — | Reset HD config |  > ⛔ **REFUSED as deprecated** (headless runs with no visible UI):-> `POST /setup/run-all`, `POST /setup/run-step`, `POST /setup/virgin-reset`.-> They return a refusal pointing at the UI-visible path.+> `POST /setup/run-all`, `POST /setup/run-step`, `POST /setup/virgin-reset`,+> `POST /wsl/unregister`. They return a refusal pointing at the UI-visible path. > To run steps: use `POST /setup/step/<id>` or relaunch HD to auto-run the cascade.  ### Setup panel control@@ -259,6 +293,15 @@ glides it, and can click. Use for demos or when the user should see where the AI | GET | `/workspace/tabs/find?name=X` | — | Find tab by name (404 if not found) | | POST | `/workspace/tabs` | `{tab spec}` | Add a new tab | +## System++| Method | Path | Body | Description |+|---|---|---|---|+| GET | `/system/nonce` | — | Get nonce for authenticated reboot |+| GET | `/system/reboot-state` | — | Check reboot pending state |+| POST | `/system/reboot` | `{"nonce":"..."}` | Reboot Windows (nonce-authenticated) |+| POST | `/system/cancel-reboot` | — | Cancel pending reboot |+ ## App lifecycle & window  | Method | Path | Body | Description |@@ -267,9 +310,6 @@ glides it, and can click. Use for demos or when the user should see where the AI | POST | `/app/relaunch-frontend` | — | Relaunch the HD GUI (kill+respawn) while it is responsive | | POST | `/window/foreground` | — | Bring the HD window to the foreground (unminimize + focus) | -> Host OS reboot (`/system/*`) is platform-specific — see the-> [[hd-api-windows]] companion skill.- ## Diagnostics (`/test/*`)  Window enumeration, UIA clicking, native-dialog classification, and cascade@@ -283,13 +323,10 @@ disabled" otherwise). `GET /test/help` self-lists the whole cluster. | POST | `/test/focus` | `{"window":"..."}` | Focus HD (`self`) or a window by title substring | | POST | `/test/click-uia` | `{...}` | Poll UIAutomation for a Button by Name; Invoke when found | | GET | `/test/setup-steps` | — | Raw setup-steps.json + derived summary (alias: `/test/install-steps`) |-| POST | `/test/dump-state` | `{...}` | Write a diagnostic bundle (logs, install-steps, runtime state, tasklist, window-tree) |+| POST | `/test/dump-state` | `{...}` | Write a diagnostic bundle (logs, install-steps, docker, tasklist, window-tree) | | POST | `/test/reset-cascade` | — | Delete install-steps.json + emit setup-reset event | | POST | `/test/screenshot-hd-window` | `{...}` | Capture HD's own window to a PNG file |--> The `/test/probe-dialogs` endpoint (classifies UAC / WSL2-update / MSI /-> Docker-EULA blocker windows) is Windows-specific — see the-> [[hd-api-windows]] companion.+| GET | `/test/probe-dialogs` | — | Enumerate visible windows, classify against the cascade-blocker catalog (UAC, WSL2 update, MSI installer, Docker EULA, …); returns `kind` + `is_blocking` per window |  ## Key Patterns @@ -311,7 +348,7 @@ POST /container-exec {"command":"ls /home/adom/project"} ```  ### Trigger setup re-run after completion-The trigger file poller STOPS when all steps are done. Use the step API instead:+The trigger file poller STOPS when all steps are done. Use the API instead: ```-POST /setup/step/<id> {"continue_after": true}+POST /setup/run-all ```
skills/hd-captions/SKILL.md+124−61
@@ -1,63 +1,73 @@ --- name: hd-captions description: >-  Paint labeled caption text on the Hydrogen Desktop workspace for demos/walkthroughs —-  captions are CAPTURED BY RECORDINGS so they show up in the finished video. Drive the-  WORKSPACE caption with `adom-cli hydrogen caption` — THE default, identical on-  web-Hydrogen AND HD (text positional; `-d` duration in SECONDS not ms; 30s auto-expire-  by default, 5-min hard cap, newest-wins, `hide` to clear; a raw-HTTP-  `POST .../current/caption` fallback exists for scripts hitting HD's API directly).-  Distinct from toasts (notifications) and TTS (audio). NOTE: a full-DESKTOP overlay-  (over every window, on top of other apps) exists as a platform-specific companion —-  see [[hd-captions-windows]]. Trigger words — caption, on-screen caption, workspace-  caption, hydrogen caption, screen overlay, screen label, callout, annotate the screen,-  step label, put text on screen, overlay text, caption command, adom-cli hydrogen-  caption, walkthrough label, demo callout, status overlay, label the screen, hide-  caption, clear captions, step 3 callout, caption duration, caption seconds, caption-  auto-expire, caption stuck on screen, caption units, caption position, caption size,-  persist caption.+  Paint labeled caption text on screen for demos/walkthroughs — captions are+  CAPTURED BY RECORDINGS so they show up in the finished video. HD has TWO caption+  surfaces: (1) a WORKSPACE caption rendered inside the HD window via+  `adom-cli hydrogen caption` — THE default, identical on web-Hydrogen AND HD+  (text positional; `-d` duration in SECONDS not ms; 30s auto-expire by default, 5-min+  hard cap, newest-wins, `hide` to clear; a raw-HTTP `POST .../current/caption` fallback+  exists for scripts hitting HD's API directly), and+  (2) a full-DESKTOP overlay over ALL windows via `adom-desktop desktop_caption` — HD's+  built-in Win32 always-on-top, click-through overlay (duration in MILLISECONDS — opposite+  unit). Pick by what you're recording: workspace recording → workspace+  caption; whole-screen / other-apps (KiCad, browser) recording → desktop overlay.+  Covers both, the desktop-overlay args (text, id, position top/center/bottom/corners,+  normalized x/y, size/fontSize, duration, action: hide|force-clear) and the id rule+  (same id replaces, different ids coexist). Windows-only for the desktop overlay.+  Distinct from toasts (notifications) and TTS (audio). Trigger words — caption,+  on-screen caption, workspace caption, hydrogen caption, screen overlay, screen+  label, callout, annotate the screen, step label, put text on screen, overlay text,+  always on top text, click-through overlay, desktop caption, caption command,+  adom-cli hydrogen caption, walkthrough label, demo callout, status overlay, label+  the screen, point at the screen, hide caption, clear captions, step 3 callout,+  caption duration, caption seconds, caption auto-expire, caption stuck on screen,+  caption units, caption position, caption size, persist caption. ---  # Hydrogen Desktop — On-Screen Captions -You can **paint labeled caption text on the Hydrogen Desktop workspace** for demos and-walkthroughs — and because captions are real pixels, **they're captured by recordings**,-so they end up in the finished video ("Step 3: run DRC →").+You can **paint labeled caption text on screen** for demos and walkthroughs — and+because captions are real pixels, **they're captured by recordings**, so they end up+in the finished video ("Step 3: approve the UAC dialog →").  > Captions are **visual on-screen narration** — centered status / countdowns / "what > I'm doing," great during demos and recordings. Distinct from: > - **toasts** — corner pop-ups via `POST /ui/toast` (transient notifications, see >   `hd-notifications`); a caption is centered narration, a toast is a corner alert. > - **TTS** *audio* narration (`adom-tts`) — pair a caption with TTS for a narrated walkthrough.-> - the internal **auth-overlay caption** HD draws for login/auth flows — not something->   you trigger for demos. The workspace caption below is the one you drive.+> - the **native Win32 auth-overlay caption** — a separate internal surface HD draws for+>   login/auth flows; not something you trigger for demos. The two surfaces below are the+>   ones you drive.  ## Two caption surfaces — pick by WHAT you're recording -HD has **two** caption surfaces, each captured by a *different* kind of recording:+HD has **two** caption surfaces. Choosing the right one is the key decision, because+each is captured by a *different* kind of recording:  | Surface | Command | Renders | Captured by | Use when | |---|---|---|---|---| | **Workspace caption** | `adom-cli hydrogen caption` | **inside the HD workspace** (webview overlay, web-Hydrogen style) | a recording/screenshot of the **HD window** (panel/workspace) | the demo is **inside HD** — captioning the workspace itself |-| **Desktop overlay** | platform-specific (see [[hd-captions-windows]]) | **over the WHOLE desktop**, above every window | a **full-screen / desktop** recording | the demo shows **other apps** (KiCad, Fusion, a browser) or the whole screen |+| **Desktop overlay** | `adom-desktop desktop_caption` | **over the WHOLE desktop**, above every window (Win32) | a **full-screen / desktop** recording (native `recording --share screen`, AD desktop) | the demo shows **other apps** (KiCad, Fusion, a browser) or the whole screen | -**Match the caption to the recording.** A `screenshot panel` / workspace capture sees the-**webview** content, so it captures the **workspace** caption but NOT a desktop overlay (a-separate OS window). A full-**screen** recording captures the **desktop overlay** (it's-screen pixels). Pick wrong and your caption won't be in the video.+**Match the caption to the recording.** A native `screenshot panel` / workspace+Element-Capture sees the **webview** content, so it captures the **workspace** caption+but NOT the desktop overlay (a separate OS window). A full-**screen** recording+captures the **desktop overlay** (it's screen pixels). Pick wrong and your caption+won't be in the video.  > Quick rule: "caption the Hydrogen workspace" → `adom-cli hydrogen caption`;-> "caption over the whole screen / while I record KiCad / a corner status label" → the-> desktop overlay in the platform companion (the only one with corners, ids, and x/y).+> "caption over the whole screen / while I record KiCad / a corner status label" →+> `adom-desktop desktop_caption` (the only one with corners, ids, and x/y). -## Workspace caption — `adom-cli hydrogen caption` ⭐ THE DEFAULT+## (1) Workspace caption — `adom-cli hydrogen caption` ⭐ THE DEFAULT -**Reach for this FIRST.** It's the *same* command on web Hydrogen and HD (adom-cli routes-through HD's workspace-events server → SSE → the frontend `captionStore`), so it stays-consistent across both — same principle as screenshots. Renders centered **inside the HD-workspace webview**. `show` takes the TEXT as a **positional arg** (NOT `--text`); the only-flags are `-d`/`--duration`, `-p`/`--position`, `-s`/`--size` (no `id`, `x`/`y`, or-`fontSize` — those are desktop-overlay-only). Subcommands: `show` / `hide`.+**Reach for this FIRST.** It's the *same* command on web Hydrogen and HD (adom-cli+routes through HD's workspace-events server → SSE → the frontend `captionStore`), so it+stays consistent across both — John's principle, same as screenshots. Renders centered+**inside the HD workspace webview**. `show` takes the TEXT as a **positional arg** (NOT+`--text`); the only flags are `-d`/`--duration`, `-p`/`--position`, `-s`/`--size` (no+`id`, `x`/`y`, or `fontSize` — those are desktop-overlay-only). Subcommands: `show` / `hide`.  ```bash adom-cli hydrogen caption show "Step 1: open the board" -p center -s large     # 30s auto-expire@@ -66,24 +76,26 @@ adom-cli hydrogen caption hide ```  ### ⚠️⚠️ `-d` / `duration` is in **SECONDS — NOT milliseconds** ⚠️⚠️-THE gotcha. `-d 30` = 30 seconds. `-d 4000` = **66 MINUTES**, not 4 seconds. If you're+THE gotcha. `-d 30` = 30 seconds. `-d 4000` = **66 MINUTES**, not 4 seconds. (This bit+the build thread — `-d 4000` left a caption stuck on screen for over an hour.) If you're thinking in ms you're off by **1000×**. You almost never need a big number — the 30s default already covers "leave it up while I do a thing." (Note: the *desktop overlay* in-the platform companion uses **milliseconds** — the two surfaces differ; don't cross the-units.)--> **Web-Hydrogen vs HD parity:** the **command + the SECONDS unit + `hide` are identical**-> on both (center/large rendering, `-d 20` held visibly). BUT the sane **lifecycle below-> (30s default / 300s cap / persist)** is verified on HD; web Hydrogen may still return the-> *older terse `_hint`* ("auto-hides after the specified duration") and may not enforce the-> 30s-default/300s-cap yet. **So on web Hydrogen, don't assume a fat `-d` self-heals — pass-> a sane duration.**--### Lifecycle (sane, never abandoned)+§2 uses **milliseconds** — the two surfaces differ; don't cross the units.)++> **Web-Hydrogen vs HD parity (checked live 2026-06-14):** the **command + the SECONDS+> unit + `hide` are identical** on both (verified by firing `adom-cli hydrogen caption` in+> a cloud web-Hydrogen workspace — center/large rendered, `-d 20` held visibly). BUT the+> sane **lifecycle below (30s default / 300s cap / persist) is verified on HD v0.1.34+**;+> web Hydrogen still returns the *older terse `_hint`* ("auto-hides after the specified+> duration") and may not enforce the 30s-default/300s-cap yet. **So on web Hydrogen, don't+> assume a fat `-d` self-heals — pass a sane duration.** (Web-Hydrogen backend sync is a+> Colby/carbon item.)++### Lifecycle (HD v0.1.34+, verified live 2026-06-14 — sane, never abandoned) - **No `-d` (or `-d 0`) → auto-expires after 30s.** The right default — you do NOT need   to `hide` it. - **Positive `-d <seconds>` → holds that many seconds, HARD-CAPPED at 300s (5 min).** A-  larger value still clears at 5 min, so a fat-fingered `-d 4000` self-heals.+  larger value still clears at 5 min, so a fat-fingered `-d 4000` now self-heals. - **Newest wins:** showing another caption replaces the current one; `hide` clears immediately. - **No "forever" via adom-cli** — its `-d` is an unsigned int (rejects negatives) by   design. This is a **feature, not a gap**: adom-cli is the same binary on web-Hydrogen and@@ -91,7 +103,8 @@ units.)   captions). A persist-until-hidden escape exists ONLY on the raw HTTP endpoint   (`{"duration":-1}`, below) — rarely needed. - **No `caption status` verb (yet).** There's no way to query "is a caption up / how long-  left" from adom-cli — and with newest-wins + the 30s auto-expire you rarely need to.+  left" from adom-cli — and with newest-wins + the 30s auto-expire you rarely need to. (A+  read-only `caption status` is a possible future verb, not a current one.) - `-p` position: `top` / `center` / `bottom` (NO corners — use the desktop overlay for   those). `-s` size: `small` / `medium` / `large`. - Needs a live workspace/editor session (the server returns 409 if none).@@ -113,23 +126,73 @@ curl -s -X POST "$ADOM_HYDROGEN_URL/api/workspaces/editor/<owner>/<repo>/current # persist until hidden (HTTP-ONLY escape — adom-cli can't send a negative): #   -d '{"text":"Recording…","duration":-1}' ```-Body: `{text, duration (SECONDS), position, size}`; clear with `{hide:true}`.+Body: `{text, duration (SECONDS), position, size}`; clear with `{hide:true}`. Returns the+same `_hint` as adom-cli (verified live).++## (2) Desktop overlay caption — `adom-desktop desktop_caption`++HD's built-in **Win32 always-on-top, click-through overlay** — floats over every+window, doesn't steal focus or intercept clicks (the user works "through" it). The+full-featured surface (ids, corners, x/y, force-clear). **Windows-only** (non-Windows+no-ops).++## Firing a caption++Source: `src-tauri/crates/hd-app/src/caption.rs` (`handle_caption`). The AD CLI verb is+**`desktop_caption`** (the internal message type is `caption`; `adom-desktop status`+lists the `caption` capability). Plain `adom-desktop caption` is NOT a verb — it errors.++```bash+adom-desktop desktop_caption '{"text":"Step 3: approve the UAC dialog →","position":"center","size":"large","duration":6000}'+``` -## Desktop overlay caption (over the whole screen)+### Arguments -For a caption that floats over **every window** (above other apps, the whole desktop) —-with ids, corners, and normalized x/y placement — HD provides a native always-on-top,-click-through desktop overlay. That surface and its arguments are **platform-specific**;-see **[[hd-captions-windows]]**.+| Arg | Type | Meaning |+|---|---|---|+| `text` | string | The caption text. Omit (with no `action`) to hide. |+| `id` | string | Caption identity. **Same id → replaces** that caption; **different ids → coexist.** Defaults to `_default`. |+| `position` | string | `top`, `bottom` (default), `center`, `top-left`, `top-right`, `bottom-left`, `bottom-right`. |+| `x` / `y` | float | **Normalized 0.0–1.0** screen coordinates (clamped). Use for precise placement instead of a named `position`. |+| `size` | string | `large` / `medium` (default) / `small`. |+| `fontSize` | int | Explicit pixel font height (also accepts `font_size`). Overrides `size`. |+| `duration` | int | **Milliseconds** on screen (default 4000), then a short fade-out. ⚠️ **NOTE: this surface is ms — the OPPOSITE of the §1 workspace caption, whose `-d` is SECONDS.** `4000` here = 4s; `4000` there = 66 min. |+| `action` | string | `hide` (dismiss this id, or all if id empty) or `force-clear` (destroy **all** captions regardless of id). |++### The id rule (this is the powerful part)++Captions are keyed by `id`. **Reuse an id to update a caption in place**; **use+different ids to show several at once.** That lets you run, e.g., a persistent+status caption in a corner *and* a moving center callout simultaneously:++```bash+# persistent status in the corner+adom-desktop desktop_caption '{"id":"status","text":"Recording…","position":"top-right","size":"small","duration":60000}'++# step callouts in the center, each replacing the last (same id)+adom-desktop desktop_caption '{"id":"step","text":"Step 1: open the board","position":"center","duration":4000}'+adom-desktop desktop_caption '{"id":"step","text":"Step 2: run DRC","position":"center","duration":4000}'++# clear just the step callout+adom-desktop desktop_caption '{"id":"step","action":"hide"}'++# nuke everything+adom-desktop desktop_caption '{"action":"force-clear"}'+```  ## Patterns -- **Walkthrough / demo callouts** — drop a `center` caption per step. Combine with a-  recording so the callouts end up in the finished video. Pair with TTS for narration.-- **Status corner / point-at-a-thing** — these need named corners or normalized x/y, which-  only the desktop overlay provides; see [[hd-captions-windows]].+- **Walkthrough / demo callouts** — drop a `center` caption per step (same `id` so+  each replaces the last). Combine with a recording (see Related skills) so the+  callouts end up in the finished video. Pair with TTS for narration.+- **Status corner** — a long-`duration` small caption in a corner (`top-right`),+  separate `id`, while you drive the rest of the screen.+- **Point at a thing** — use normalized `x`/`y` to sit a label next to a button or+  dialog you're about to act on.+- **Cleanup** — `action:"hide"` per id when a step is done; `action:"force-clear"`+  to wipe the screen of all captions at the end of a tour.  ## Related skills-- [hd-adom-desktop](../hd-adom-desktop/SKILL.md) — the relay that carries caption verbs to the host+- [hd-recording](../hd-recording/SKILL.md) — captions are captured *into* screen recordings; record a walkthrough with live callouts+- [hd-adom-desktop](../hd-adom-desktop/SKILL.md) — AD carries the `caption` / `desktop_caption` verb to the host; verify the `caption` capability via `adom-desktop status` - `adom-tts` — *audio* narration to pair with on-screen captions (captions are visual-only)-- [[hd-captions-windows]] — the full-desktop always-on-top overlay caption surface
skills/hd-claude-auth/SKILL.md+11−11
@@ -1,6 +1,6 @@ --- name: hd-claude-auth-description: How Claude Code authenticates inside HD — the OAuth flow that opens in your browser via the Browser Picker, where credentials are stored on host vs workspace, how HD backs them up so a workspace rebuild doesn't make you re-auth, the virgin-reset toggle that wipes Claude creds, and the 4-technique auth cascade HD runs if Claude isn't authenticated. READ when troubleshooting "Claude not authenticated", expired Claude tokens, re-authenticating after a virgin reset, or wondering where Claude credentials live. Trigger words — claude auth, claude code login, claude code authentication, claude not authenticated, claude oauth, claude credentials, claude session, claude.ai subscription, replay-claude-credentials.json, claude-auth, claude credential backup, claude re-auth, claude expired, claude.ai subscription button.+description: How Claude Code authenticates inside HD — the OAuth flow that opens in your browser via the Browser Picker, where credentials are stored on host vs container, how HD backs them up so a container rebuild doesn't make you re-auth, the virgin-reset toggle that wipes Claude creds, and the 4-technique auth cascade HD runs if Claude isn't authenticated. READ when troubleshooting "Claude not authenticated", expired Claude tokens, re-authenticating after a virgin reset, or wondering where Claude credentials live. Trigger words — claude auth, claude code login, claude code authentication, claude not authenticated, claude oauth, claude credentials, claude session, claude.ai subscription, replay-claude-credentials.json, claude-auth, claude credential backup, claude re-auth, claude expired, claude.ai subscription button. ---  # HD Claude Auth — how Claude Code signs in@@ -16,14 +16,14 @@ For Adom auth (your hydrogen.adom.inc login), see [hd-adom-auth](../hd-adom-auth 3. HD's Browser Picker intercepts the URL (since it's a `*.claude.ai` link). The "Claude auth" branded variant of the picker appears with the work browser profile pre-selected and a 5-second auto-countdown. 4. The browser opens the Claude OAuth page; you complete sign-in (or it auto-completes if you're already signed in to claude.ai). 5. Claude returns OAuth credentials, which the extension stores at `/home/adom/.claude/.credentials.json` inside the workspace.-6. HD's setup step `claude-auth` notices the new credentials and **backs them up to the host** (in HD's app-data directory, as `replay-claude-credentials.json`) so future workspace rebuilds can replay them. The exact host path is platform-specific — see the platform layer for where it lives on your OS.+6. HD's setup step `claude-auth` notices the new credentials and **backs them up to the host** at `%APPDATA%\hydrogen-desktop\replay-claude-credentials.json` so future workspace rebuilds can replay them.  ## Where Claude credentials live -| Layer | Location | Purpose |-|-------|----------|---------|+| Layer | Path | Purpose |+|-------|------|---------| | Inside workspace (live) | `/home/adom/.claude/.credentials.json` | Active credentials the extension and `claude` CLI both read |-| Host-side backup | `replay-claude-credentials.json` in HD's app-data dir on the host | Backup so a fresh workspace can be re-authenticated without re-OAuth |+| Host-side backup | `%APPDATA%\hydrogen-desktop\replay-claude-credentials.json` | Backup so a fresh workspace can be re-authenticated without re-OAuth | | VS Code secret store (in code-server's user data) | webview-internal, can't be inspected directly | The extension also keeps a secret per panel; this is what dictates the chat UI showing vs the auth button |  **Key insight**: each Claude Code panel instance keeps its own auth state. If one panel says "not authenticated", opening a NEW Claude Code conversation panel often shows the auth button fresh and lets you sign in cleanly.@@ -33,7 +33,7 @@ For Adom auth (your hydrogen.adom.inc login), see [hd-adom-auth](../hd-adom-auth When you virgin-reset and rebuild the workspace (assuming you DON'T check the "Claude credentials" toggle):  1. Workspace deleted + recreated by setup steps-2. Step `claude-auth` runs early — reads the `replay-claude-credentials.json` backup from HD's host app-data dir+2. Step `claude-auth` runs early — reads `replay-claude-credentials.json` from `%APPDATA%` 3. If the file exists AND the `expiresAt` is still in the future → copies it into the new workspace at `/home/adom/.claude/.credentials.json` 4. Claude Code extension reads it on first launch → user stays signed in @@ -46,7 +46,7 @@ If Claude isn't authenticated after setup, HD tries each technique in order unti | # | Technique | What it does | |---|-----------|--------------| | 1 | Detect auth failure | Scans all VS Code webview contexts for the "Claude.ai Subscription" button / "How do you want to log in?" text. Confirms whether the auth UI is reachable. |-| 2 | Open NEW conversation + auto-click auth button | The new-conversation panel re-evaluates auth state and shows the button cleanly. HD clicks it via the webview eval channel. |+| 2 | Open NEW conversation + auto-click auth button | The new-conversation panel re-evaluates auth state and shows the button cleanly. HD clicks it via CDP. | | 3 | Open Claude editor + auto-click auth button | If technique 2 didn't trigger a fresh auth state, opens a Claude editor (different VS Code command) and tries the same click. | | 4 | CLI fallback (`claude auth login`) | Runs `claude auth login` inside the workspace, extracts the OAuth URL from stdout, opens it in your browser via the Browser Picker. You paste the returned code into a VS Code terminal. | @@ -58,7 +58,7 @@ The setup panel's Virgin Reset section has a per-Claude-creds toggle:  | Toggle | What happens to Claude auth | When to use | |--------|----------------------------|-------------|-| **Claude credentials** (default OFF) | Deletes the `replay-claude-credentials.json` backup from the host AND the credentials inside the workspace. **You will need to re-OAuth.** | When Claude is stuck in a broken auth state and you want a true fresh sign-in. |+| **Claude credentials** (default OFF) | Deletes `replay-claude-credentials.json` from host AND the credentials inside the workspace. **You will need to re-OAuth.** | When Claude is stuck in a broken auth state and you want a true fresh sign-in. | | **Workspace** (default ON) | The workspace is rebuilt. If Claude creds toggle is OFF (default), `claude-auth` replays the backup → you stay signed in. | Normal virgin reset for testing. | | **Workspace data** (default ON) | Wipes your `/home/adom/project/` work. Doesn't directly affect Claude creds, but rebuilds the workspace — same as above. | When you want a totally fresh `~/project/`. | @@ -70,17 +70,17 @@ The setup panel's Virgin Reset section has a per-Claude-creds toggle: - A SECOND panel still has stale auth state. Close all Claude Code panels and open one fresh — it'll read the new credentials.  **Credentials backup file exists but Claude says expired**-- Open the `replay-claude-credentials.json` backup (in HD's host app-data dir) and check the `expiresAt` (epoch ms). Compare to current time. If past, you need to re-OAuth. HD's auth cascade will handle this on next setup run.+- Open `%APPDATA%\hydrogen-desktop\replay-claude-credentials.json` and check the `expiresAt` (epoch ms). Compare to current time. If past, you need to re-OAuth. HD's auth cascade will handle this on next setup run.  **`claude auth status` says `loggedIn: true` but the extension says not authenticated** - **Known quirk**: the CLI and the VS Code extension use SEPARATE credential stores. `claude auth status` checks the CLI store; the extension uses VS Code secrets. Trust the extension UI (the "Claude.ai Subscription" button) over the CLI's status output.  **OAuth callback fails / browser shows "connection refused"**-- The callback URL is hitting a local port that HD hasn't forwarded to the host. Check the HD log for `[oauth] Callback port N detected` — HD should auto-start a proxy for it. If not, register the port manually via `adom-cli port-forward register <port> --visibility external`. (How host↔workspace port forwarding works is platform-specific — see the platform layer.)+- The callback URL is hitting a localhost port that HD hasn't bound on Windows. Check the HD log for `[oauth] Callback port N detected` — HD should auto-start a proxy for it. If not, register the port manually via `adom-cli port-forward register <port> --visibility external`.  ## Related skills  - [hd-adom-auth](../hd-adom-auth/SKILL.md) — Adom (hydrogen.adom.inc) login, separate from Claude - [hd-browser-picker](../hd-browser-picker/SKILL.md) — the Browser Picker that routes the Claude OAuth URL, including the branded "Claude auth" variant-- `hd-setup-steps` — the `claude-auth` step and the auth cascade are part of setup+- `hd-setup-steps` — the `claude-auth` step and the auth cascade are part of setup (the runtime-specific hd-setup-steps shows where it falls in the cascade) - `hd-volume` — explains why the host-side backup survives workspace rebuild
skills/hd-claude-management/SKILL.mdadded+214
@@ -0,0 +1,214 @@+---+name: hd-claude-management+description: >+  First-class API for managing the Claude Code conversations inside Hydrogen Desktop:+  list/open/close/switch conversation tabs, read each conversation's full state (title,+  message count, compose box, and the on-disk session GUID), type messages into a SPECIFIC+  conversation (instant or with a human typing animation) and submit them, and turn on+  Remote Control to get a claude.ai cloud URL so the user can view+drive that exact+  conversation from claude.ai or the Claude mobile app. Every conversation is addressed by a+  stable execution-context id (deterministic, background, no foreground/focus needed). Also+  explains how a live conversation is matched to its ~/.claude/projects/*.jsonl log.+  Trigger words: claude tabs, claude conversations, list conversations, open claude tab,+  close claude tab, switch claude tab, new conversation, type into claude, inject prompt,+  remote control, claude.ai url, view on mobile, session id, conversation guid, jsonl,+  claude session, context_id, multi-tab claude, conversation management.+---++# HD Claude Conversation Management++Hydrogen Desktop runs Claude Code as webview tabs inside VS Code. This skill is the+**first-class API** for managing those conversations programmatically — from HD's control+API, from the user's AI inside the WSL2 workspace, or from setup steps.++All endpoints are on the **HD control API** (a dynamic localhost port). From inside the+workspace, examples below use `$HD` for `http://127.0.0.1:<port>` (find the port in the HD+log / port discovery). From an **external** context (a cloud container), call the same+endpoints with the AD verb `adom-desktop hd_api '{"path":"/claude/…","method":"POST","body":{…}}'`+— it auto-discovers the port. Everything here works in the **background** — no window focus,+no foreground, no keystroke stealing.++## The core idea: address conversations by CONTEXT ID, list from the TAB BAR++Each Claude conversation is its own webview **execution context** with a **stable integer id**.+That id — not the tab index, not the title, not visibility — is how you reliably *target* one+conversation (type into it, remote-control it). VS Code keeps multiple webviews "visible" at+once, so visibility/tab-index are NOT reliable addresses; the context id is.++But VS Code also **disposes the webview of a background tab**, so a context id only exists for+*loaded* tabs. That's why `GET /claude/conversations` **merges three sources** into one view:+the **tab bar** (every open conversation + which is active — what you see), the **live webview+contexts** (rich data for loaded tabs), and the **on-disk session logs** (the GUIDs). Each row+carries a `loaded` flag; `loaded:false` means activate the tab first to read its live details.++## GET /claude/conversations — everything in one call++```bash+curl -s $HD/claude/conversations+```+```jsonc+{+  "ok": true,+  "count": 4,+  "conversations": [+    {+      "ordinal": 3,                 // its position in the tab bar+      "active": true,               // the currently-focused tab+      "loaded": true,               // webview is live → rich fields are populated+      "context_id": 7,              // STABLE address for inject/remote-control (null if not loaded)+      "title": "Calculate 10 times 10",   // authoritative title (from the session log when matched)+      "tab_label": "Calculate 10 times 10", // raw tab label (may be ellipsis-truncated)+      "compose_text": "",           // what's typed but not yet sent (null if not loaded)+      "msg_count": 16,              // null if not loaded+      "session_id": "566cec21-…",   // on-disk log GUID (read ~/.claude/projects/*/<id>.jsonl)+      "rc_active": false,           // Remote Control on? (null if not loaded)+      "remote_control_url": null    // claude.ai cloud URL when rc_active+    },+    { "ordinal": 1, "active": false, "loaded": false, "context_id": null,+      "title": "Find the capital of France", "tab_label": "Find the capital of Fran…",+      "compose_text": null, "msg_count": null, "session_id": "b352055b-…", "rc_active": null, "remote_control_url": null }+  ]+}+```+- **Merged view:** every tab is listed (from the tab bar). `loaded:true` rows have live fields+  (`context_id`, `compose_text`, `msg_count`, `rc_active`); `loaded:false` rows are background tabs+  VS Code disposed — **activate them** (`/claude/tabs/activate`) to read those. Even a disposed tab+  resolves its `session_id` when its title matches the on-disk log.+- A conversation is **`Untitled`** with **`session_id: null`** until its first message is submitted —+  then Claude names it and writes the session log.+- `?with_session=false` skips the disk read (faster; omits `session_id`).++`GET /claude/contexts` is the lighter version (just the *loaded* contexts: `context_id` + `compose_text`).++## Open / close / switch tabs++```bash+# Open a fresh conversation (new tab)+curl -s -X POST $HD/claude/new-conversation++# Open the Claude panel if it isn't open+curl -s -X POST $HD/claude/open++# List raw editor tabs (label/active/dirty)+curl -s $HD/claude/tabs++# Close ALL conversation tabs (also removes the leftover empty editor group)+curl -s -X POST $HD/claude/tabs/close-all++# Switch the visible tab by index or label substring (background)+curl -s -X POST $HD/claude/tabs/activate -d '{"index":1}'+curl -s -X POST $HD/claude/tabs/activate -d '{"label":"Eiffel"}'++# Remove a stale EMPTY editor group (the dead blank panel) WITHOUT collapsing a+# real 2-group left/right layout. (merge-groups is a back-compat alias.)+curl -s -X POST $HD/claude/tabs/close-empty-groups+```++## Type a message into a SPECIFIC conversation++`POST /claude/inject` types into the conversation you name with `context_index`. Two speeds:++```bash+# INSTANT paste (fast) — no typing animation. Best for slash commands and scripted input.+curl -s -X POST $HD/claude/inject -d '{"text":"summarize this repo","context_index":16,"typed":false,"submit":true}'++# SLOW human typing animation (the "watch the AI type" effect), then submit.+curl -s -X POST $HD/claude/inject -d '{"text":"hello there","context_index":16,"typed":true,"delay_ms":50,"submit":true}'++# Type but DON'T send (leave it sitting in the compose box):+curl -s -X POST $HD/claude/inject -d '{"text":"draft…","context_index":16,"typed":false,"submit":false}'+```+- `typed`: `true` = char-by-char with ±50% jitter (avg `delay_ms`); `false` = instant paste.+- `submit`: `true` = press Enter; `false` = leave in the box.+- Omit `context_index` ONLY when a single conversation is open. With **more than one** conversation+  open, omitting it can type your text into **several compose boxes at once** (it falls back to a+  visibility heuristic that isn't reliable when the window isn't foreground). When in doubt, pass it.+- Targeting by `context_index` is deterministic — it lands in exactly that tab even when it's+  not the foreground one and even with many tabs open (no fan-out into other tabs). **This is the+  safe default: list `/claude/conversations`, take the row with `active:true` (or the tab you want),+  use its `context_id`, then inject.**++Typical "open a new tab and ask a question":+```bash+curl -s -X POST $HD/claude/new-conversation+CTX=$(curl -s $HD/claude/contexts | jq '.contexts[-1].context_id')+curl -s -X POST $HD/claude/inject -d "{\"text\":\"what does this project do?\",\"context_index\":$CTX,\"typed\":true,\"submit\":true}"+```++## ⭐ Remote Control → view the conversation on claude.ai / mobile++This is the big one. Turn on Remote Control for a conversation and HD returns a **claude.ai+cloud URL**. Open it on claude.ai in any browser or in the Claude **mobile app** to see and+drive that exact conversation in the cloud — not tied to HD. The user can be on their phone+editing the same conversation.++```bash+curl -s -X POST $HD/claude/remote-control -d '{"context_index":7}'+```+```jsonc+{+  "ok": true,+  "rc_active": true,+  "toggled": true,                 // false + already_in_desired_state:true if it was already on+  "context_id": 7,+  "remote_control_url": "https://claude.ai/code/session_014koKPJxmjYpnX2SjRRqrD3"+}+```+- ⚠️ **`/remote-control` is a TOGGLE.** This endpoint **detects** the current state first and only+  toggles when needed — re-calling it on an already-on session is a **no-op** that returns the+  existing URL (it will NOT turn it off; doing that blindly archives the cloud session).+- `{enable:false}` turns Remote Control **off**.+- The `session_…` id in the URL is the **cloud** session id — distinct from the local on-disk+  `session_id` GUID. The cloud URL is the shareable one for claude.ai / mobile.+- `{name}` → `/remote-control <name>` to label the remote session.+- Each conversation's current state is also reported as `rc_active` in `/claude/conversations`.+- **Opening it on the user's machine (external/cloud agent):** get the URL, then open it in their+  Chrome and screenshot to confirm — all via AD verbs (no synthetic keystrokes):+  `desktop_find_window {titleContains:"Claude Code - Google Chrome"}` → `desktop_screenshot_window+  {hwnd}`. To type INTO the claude.ai page, use the native-browser bridge `nbrowser_eval+  {tabId, expression}` (the composer is shadow-DOM; do NOT blind-type with SendInput). See the+  `driving-hd-remotely` guide on the Hydrogen Desktop wiki page.++## How a live conversation maps to its on-disk log (JSONL)++Claude Code stores each conversation as `~/.claude/projects/<cwd>/<uuid>.jsonl` containing+`sessionId`, `aiTitle` (the generated title), and every message. **The session GUID is NOT+exposed in the conversation's webview DOM**, so HD correlates a live conversation to its log by+matching the **first user message** (exact + unique; present in both the DOM and the JSONL).+On a match, `/claude/conversations` fills in `session_id` and uses the log's `aiTitle` as the+authoritative `title`. (Matching on the title alone is unreliable — the rendered title and the+persisted `aiTitle` can differ.)++Read a conversation's full transcript from the workspace:+```bash+cat ~/.claude/projects/*/<session_id>.jsonl+```++## Why this is valuable++- **Multi-conversation orchestration:** open N conversations, drive each independently by+  context id, read each one's state — all from a script or an agent, in the background.+- **Cloud + mobile continuity:** Remote Control hands you a claude.ai URL so a conversation+  started in HD continues on the phone / web. Huge for working away from the desk.+- **Deterministic + safe:** context-id addressing never types into the wrong tab; the empty+  blank panel is cleaned up automatically; a real 2-group left/right layout is preserved.+- **Auditable:** every conversation maps to an on-disk JSONL you can read, diff, or archive.++## Endpoint quick reference++| Endpoint | Method | What it does |+|---|---|---|+| `/claude/conversations` | GET | Full per-conversation data incl. `session_id` (the canonical list) |+| `/claude/contexts` | GET | Light list: `context_id` + `compose_text` |+| `/claude/tabs` | GET | Raw editor tabs (label/active/dirty) |+| `/claude/new-conversation` | POST | Open a fresh conversation tab |+| `/claude/open` | POST | Open the Claude panel if closed |+| `/claude/tabs/close-all` | POST | Close all tabs + remove the leftover empty group |+| `/claude/tabs/activate` | POST | Switch visible tab by `{index}` or `{label}` |+| `/claude/tabs/close-empty-groups` | POST | Remove stale empty editor groups (preserves populated) |+| `/claude/inject` | POST | Type into `{context_index}` — `{typed,submit,delay_ms}` |+| `/claude/remote-control` | POST | Turn on RC for `{context_index}` → returns `remote_control_url` |+| `/claude/cross-eval` | POST | (Diagnostic) run JS across all workbench/webview contexts |++These are the same endpoints HD's own setup steps use to open Claude and inject the first+prompt — so behavior is identical whether a human, setup, or the workspace AI drives them.
skills/hd-desktop-sse/SKILL.md+16−19
@@ -1,28 +1,23 @@ --- name: hd-desktop-sse-description: How HD's local workspace API + SSE works (a.k.a. the workspace API) — replaces Carbon for workspace commands so the workspace's adom-cli controls HD, not cloud Hydrogen. Covers the full pipeline, routing, env vars, field format differences, port discovery, and hard-won lessons. Trigger words — HD SSE, workspace API, local API, adom-cli workspace, add-tab, move-tab, webview tab, EventSource, workspace_updated, ADOM_CARBON_URL, ADOM_HYDROGEN_URL, discovery port.+description: How HD's local workspace API + SSE works (a.k.a. the workspace API) — replaces Carbon for workspace commands so the workspace's adom-cli controls HD, not cloud Hydrogen. The workspace is the WSL2 Adom-Workspace distro by default (or a Docker container under HD_RUNTIME=docker). Covers the full pipeline, routing, env vars, field format differences, and hard-won lessons. Trigger words — HD SSE, workspace API, local API, adom-cli workspace, add-tab, move-tab, webview tab, EventSource, workspace_updated, ADOM_CARBON_URL, ADOM_HYDROGEN_URL. ---  # Hydrogen Desktop — Local Workspace API + SSE -> Platform note: HD runs the same local workspace API on every platform (Windows/WSL2,-> macOS, Linux). For the WSL2-specific networking details (mirrored loopback,-> `%APPDATA%\hydrogen-desktop\ports.json`, the `HD_RUNTIME=docker` runtime, relay-> same-port behavior), see **[[hd-desktop-sse-windows]]**.- ## Architecture  ```-Workspace adom-cli (the local workspace)+Workspace adom-cli (WSL2 Adom-Workspace distro by default, or Docker container)     → http://127.0.0.1:47083 (HD's proxy)     → HD handles workspace commands locally + broadcasts SSE     → HD frontend receives SSE, re-fetches workspace, renders -Cloud adom-cli (unchanged)+Cloud Docker's adom-cli (unchanged)     → carbon.adom.inc → Hydrogen web ``` -HD runs its own workspace API on port 47083 (reverse proxy, default — see PortConfig) so the workspace's adom-cli controls HD's UI, not cloud Hydrogen. No cross-talk between environments. The workspace reaches HD at `127.0.0.1:47083`.+HD runs its own workspace API on port 47083 (reverse proxy, default — see PortConfig) so the workspace's adom-cli controls HD's UI, not cloud Hydrogen. No cross-talk between environments. (Under WSL2 the workspace reaches HD at `127.0.0.1:47083` — mirrored networking shares loopback with the Windows host.)  ## Port 47083 routing (the hd-proxy / reverse-proxy) @@ -33,7 +28,7 @@ All requests hit port 47083 (reverse proxy, default — see PortConfig). The rou | `/api/workspaces/editor/{owner}/{repo}/current/*` | Local workspace API | In-memory | | `/api/panels/webview/*`, `/api/panels/sandbox/*` | Local panel API | SSE broadcast | | `/containers/*` | Local container discovery | Canned response |-| `/proxy/{port}/{path}` | Workspace proxy | TCP forward to the workspace |+| `/proxy/{port}/{path}` | Workspace proxy | TCP forward to the workspace (WSL2 distro) | | Everything else (`/api/*`, etc.) | Carbon proxy | HTTPS to carbon.adom.inc |  The dev file server on port 1420 forwards `/api/*` directly to `handle_request()` (same function, not TCP — supports SSE streaming via BoxBody).@@ -68,7 +63,7 @@ NOT `{"owner": "jlauer12", "repository": "workspace"}` — adom-cli reads `conta  ## Workspace Env Vars -Set when the workspace is created:+Set when the workspace is created (e.g. `create_container()` in `hd-docker/src/lib.rs` under the Docker runtime):  | Var | Value | Why | |---|---|---|@@ -77,7 +72,7 @@ Set when the workspace is created: | `ADOM_HYDROGEN_URL` | `http://127.0.0.1:47083` | Workspace mutations (adom-cli sends these HERE, not to Carbon) | | `ADOM_DESKTOP_MODE` | `local` | Tells adom-cli it's a local environment | -`127.0.0.1` reaches HD on the host from inside the workspace. The canonical code-server port HD exposes on the host is 7380.+Under WSL2, `127.0.0.1` reaches the Windows host directly — mirrored networking shares loopback with the host, so the same `127.0.0.1:<port>` works from inside the distro and on Windows. The canonical code-server port HD exposes on the host is 7380.  **Also set in adom-cli config** (persists across sessions): ```bash@@ -189,16 +184,18 @@ Returns: } ``` -> **Relay ports:** clients discover the relay ports from `~/.adom/cli-relay-ports.json`-> (fallback 8765/8766), not from `/discover`. Relay port mapping/exposure varies by-> platform — see **[[hd-desktop-sse-windows]]**.+> **Relay ports:** under the WSL2 runtime the relay listens **same-port 8765+> (WS) / 8766 (HTTP)** inside the distro and is reached same-port via mirrored+> loopback (or via `/proxy/`). There are **no host 47081/47082 listeners**.+> Clients discover the relay ports from `~/.adom/cli-relay-ports.json` (fallback+> 8765/8766), not from `/discover`.  ### Who uses it  | Client | What it discovers | How | |---|---|---| | adom-desktop relay | Control API port (was hardcoded 9001) | `curl :47080/discover` → use `control` field |-| adom-cli in the workspace | Proxy + Hydrogen URL | Already set via `ADOM_CARBON_URL` env var at workspace creation |+| adom-cli in the workspace (WSL2 distro / Docker) | Proxy + Hydrogen URL | Already set via `ADOM_CARBON_URL` env var at workspace creation | | External tools / diagnostics | Any port | Hit discovery, get the full map | | Cloud Docker (this container) | All HD ports | `curl http://<desktop-ip>:47080/discover` via relay | @@ -226,10 +223,10 @@ std::thread::spawn(move || { | Proxy | 47083 | No | n/a | | Control API | 47084 | No | n/a | | CDP | 47085 | No | n/a |-| Relay WS | (platform-dependent) | No | 8765 |-| Relay HTTP | (platform-dependent) | No | 8766 |+| Relay WS | — (same-port under WSL2) | No | 8765 |+| Relay HTTP | — (same-port under WSL2) | No | 8766 | -On first launch, defaults are written without scanning. Workspace-side ports (8080, 8765, 8766) are always fixed — only host-side ports are dynamic. The `ports.json` location and relay host mapping are platform-specific — see **[[hd-desktop-sse-windows]]**.+Config stored at `%APPDATA%\hydrogen-desktop\ports.json`. On first launch, defaults are written without scanning. Workspace-side ports (8080, 8765, 8766) are always fixed — only host-side ports are dynamic. The relay (8765/8766) is reached **same-port** under WSL2 (mirrored loopback) — no host 47081/47082 mapping; discover it from `~/.adom/cli-relay-ports.json` (fallback 8765/8766).  ## Files 
skills/hd-eda-discovery/SKILL.md+7−13
@@ -28,19 +28,14 @@ detection in the background, then come back with a short, friendly summary + one adom-desktop status                       # relay up? caps include kicad / fusion360? adom-desktop kicad_list_versions '{}'     # KiCad installed (+ which versions) adom-desktop fusion_status '{}'           # Fusion 360 installed? ("installed but not running" = yes)+# No bridge for these — detect by install path / running process:+adom-desktop run_script '{"interpreter":"powershell","scriptB64":"<b64 of:>"}'+#   Get-ChildItem 'C:\Program Files','C:\Program Files (x86)' -Directory -EA 0 |+#     ? { $_.Name -match 'Altium|OrCAD|Cadence|Allegro|EAGLE|DipTrace|Eplan' } | % Name+#   plus: Get-Process | ? { $_.Name -match 'Altium|OrCAD|Capture|Allegro' } | % Name ```--The KiCad/Fusion bridges work the same on every platform. For tools with **no bridge** (Altium,-OrCAD, Cadence/Allegro, EAGLE, DipTrace, Eplan, ...), there's no bridge verb — detect them by-**install path / running process** using `adom-desktop run_script`. The exact probe is-platform-specific:--- **Windows:** scan `C:\Program Files` / `C:\Program Files (x86)` and `Get-Process` via a-  PowerShell `run_script` — see **[[hd-eda-discovery-windows]]** for the ready-to-run probe.-- **macOS:** scan `/Applications` (and `~/Applications`) for the app bundles, plus `pgrep`.-- **Linux:** `which`/`command -v` the CLI binaries and check common install dirs, plus `pgrep`.--(Whatever the platform: treat **empty output as a timeout**, not a negative result.)+(Base64 the PowerShell for `run_script`; use absolute paths, and treat **empty output as a+timeout**, not a negative result.)  ## 2. Branch on what you found @@ -103,6 +98,5 @@ they can **contribute the missing piece** in half an hour.  ## Related skills - [hd-adom-desktop](../hd-adom-desktop/SKILL.md) / [hd-bridges](../hd-bridges/SKILL.md) — the `adom-desktop` relay + KiCad/Fusion bridge verbs (in-distro names; the `adom-desktop-*` skills are the cloud-side equivalents)-- [[hd-eda-discovery-windows]] — the Windows/PowerShell no-bridge install-path + process probe - `pup` — driving fab-vendor upload pages; [hd-open-url](../hd-open-url/SKILL.md) — opening vendor sites - the Adom wiki publish skills — sharing the bridge/app you build with the community
skills/hd-notifications/SKILL.md+50−51
@@ -1,37 +1,33 @@ --- name: hd-notifications description: >-  How Hydrogen Desktop reaches the user OUTSIDE the window — native OS toast-  notifications + taskbar/dock attention — so the AI can proactively tell the user a+  How Hydrogen Desktop reaches the user OUTSIDE the window — native Windows toast+  notifications + taskbar attention — so the AI can proactively tell the user a   long job finished or that it needs them (great for hands-free / away-from-keyboard   work). Covers HD's notify handler (levels info|warning|error|emergency, optional-  <actions> buttons; emergency = a persistent attention request until the user looks)-  and how to fire one with the `notify` desktop command / `adom-desktop notify_user`.-  Also the in-app `/ui/toast` (a message INSIDE the HD window) and Pup's-  browser_alert_window taskbar/dock nudge. The native OS-toast backend is-  platform-specific (see [[hd-notifications-windows]] for the Windows path);-  cross-platform behavior is documented here. Trigger words — notify the user, send a-  notification, desktop notification, toast, os toast, native toast, taskbar flash, dock-  bounce, get the user's attention, alert the user, notify_user, emergency notification,-  urgent alert, notification actions, action buttons, ping the user, job done-  notification, tell me when it's done, request attention, browser_alert_window, in-app-  toast, ui toast, /ui/toast, show a toast in HD, toast inside the window.+  <actions> buttons; emergency = a persistent orange taskbar flash via+  request_user_attention(Critical) until the user looks), how toasts route via a+  PowerShell AUMID so they may show an "Adom" title, and how to fire one with the+  `notify` desktop command / `adom-desktop notify_user`. Also Pup's+  browser_alert_window taskbar flash. Windows-only. Trigger words — notify the+  user, send a notification, desktop notification, toast, windows toast, taskbar+  flash, get the user's attention, alert the user, notify_user, emergency+  notification, urgent alert, notification actions, action buttons, ping the user,+  job done notification, tell me when it's done, flash the taskbar, request+  attention, browser_alert_window, in-app toast, ui toast, /ui/toast, show a toast+  in HD, toast inside the window. ---  # Hydrogen Desktop — Notifications (reaching the user outside the window) -When the user isn't looking at HD — a long build is running, you've finished a job, or-you're **blocked and need them** — you can reach them on the OS level: a native **toast**,-and for urgent cases a **persistent attention request** (a taskbar flash / dock bounce,-depending on platform). This is what makes hands-free / away-from-keyboard work usable:-don't just print a message into a panel nobody's watching — fire a notification.+When the user isn't looking at HD — a long build is running, you've finished a job,+or you're **blocked and need them** — you can reach them on the OS level: a native+Windows **toast**, and for urgent cases a **persistent taskbar flash**. This is what+makes hands-free / away-from-keyboard work usable: don't just print a message into a+panel nobody's watching — fire a notification. -> **Platform note:** the native OS toast is delivered by a per-platform backend. The full-> experience (a rich OS toast plus a persistent attention request) is best on Windows-> (WinRT toasts + taskbar attention — see [[hd-notifications-windows]]); macOS has a more-> limited path (an `osascript`-style notification); Linux has no native toast path. The-> `notify_user` API itself is the same everywhere; what differs is how richly the OS-> surfaces it.+> **Windows-only** for the full experience (WinRT toasts + taskbar attention).+> macOS has a limited `osascript` fallback; Linux has no toast path.  ## Firing a notification @@ -55,29 +51,33 @@ Payload shape (`NotifyPayload`):  | Field | Notes | |---|---|-| `title` | Toast heading. (On some platforms HD prefixes the app identity — see the platform companion.) |+| `title` | Toast heading. If it doesn't already start with "Adom", HD prefixes it → `"Adom: <title>"`. | | `body` | The message. | | `level` | `info` / `warning` / `error` / `emergency`. `warning`/`error`/`emergency` render as **long-duration** toasts; `info` is short. |-| `actions` | Optional array of button labels rendered as buttons in the toast. Empty/omitted = no buttons. |+| `actions` | Optional array of button labels rendered as `<actions>` in the toast template. Empty/omitted = no buttons. | -### Levels — and the `emergency` attention request+### Levels — and the `emergency` taskbar flash -- `info` / `warning` / `error` — a standard toast (warnings and errors stay up longer).-- **`emergency`** — in addition to the toast, HD calls **`request_user_attention(Critical)`**-  on the main window and shows/unminimizes it. This produces a **persistent attention-  request** (a taskbar flash on Windows, a dock bounce on macOS) that **keeps going until-  the user actually interacts with the window/taskbar themselves** — it is *not* cleared by-  a programmatic focus. Reserve `emergency` for "I genuinely cannot proceed without you" —-  it's intentionally hard to ignore.+- `info` / `warning` / `error` — a standard toast (warnings and errors stay up+  longer).+- **`emergency`** — in addition to the toast, HD calls+  **`request_user_attention(Critical)`** on the main window and shows/unminimizes+  it. This produces a **persistent orange taskbar flash that keeps flashing until+  the user actually clicks the taskbar icon themselves** — it is *not* cleared by a+  programmatic focus. Reserve `emergency` for "I genuinely cannot proceed without+  you" — it's intentionally hard to ignore. -> The Windows-specific toast identity/title behavior (the AUMID "Adom" title quirk) and the-> WinRT/orange-taskbar-flash details live in [[hd-notifications-windows]].+### The "Adom" title quirk (AUMID routing)++On Windows, HD's toasts route through a **PowerShell AUMID**. A side effect: toasts+may surface under an **"Adom"** identity/title rather than a per-app one. That's+expected — don't treat an "Adom"-labeled toast as a bug.  ## In-app toast — `POST /ui/toast` (inside the HD window) -The notifications above reach the user **outside** the window (OS toast / taskbar). For a-lightweight message **inside** the HD window — the same toast UI the app uses for its own-success/error messages — fire a control-API toast:+The notifications above reach the user **outside** the window (OS toast / taskbar).+For a lightweight message **inside** the HD window — the same toast UI the app uses+for its own success/error messages — fire a control-API toast:  ```bash # via the control API (or adom-cli hydrogen api, or the API Explorer "Try it")@@ -92,12 +92,12 @@ POST /ui/toast { "message": "Build finished ✅", "type": "success", "duration": | `groupId` + `detail` | Optional: coalesce related toasts into one expandable group. |  It emits the `hd-toast` Tauri event, which the main window renders via the global-`toastStore` (bottom-stacked toasts). **OS toast vs in-app toast:** use a `notify` OS toast-when the user may be **away from / not looking at** HD; use `/ui/toast` for an in-window-status cue while they're working in HD. (HD's native recording uses this for its auto-stop-notice — see [hd-recording](../hd-recording/SKILL.md).)+`toastStore` (bottom-stacked toasts). **OS toast vs in-app toast:** use a `notify`+OS toast when the user may be **away from / not looking at** HD; use `/ui/toast` for+an in-window status cue while they're working in HD. (HD's native recording uses this+for its auto-stop notice — see [hd-recording](../hd-recording/SKILL.md).) -## Pup's taskbar/dock nudge (`browser_alert_window`)+## Pup's taskbar flash (`browser_alert_window`)  For AI-driven browser work, Pup has its own attention nudge: @@ -105,18 +105,18 @@ For AI-driven browser work, Pup has its own attention nudge: adom-desktop browser_alert_window '{"sessionId":"default"}' ``` -It **flashes the taskbar / bounces the dock** for that browser window (and brings the page-to front within Chrome) **without stealing foreground focus** — a gentle "look here." (Use+It **flashes the taskbar** for that browser window (and brings the page to front+within Chrome) **without stealing foreground focus** — a gentle "look here." (Use `browser_focus_window` if you actually want to raise the window.)  ## When you (the AI) should notify proactively -- **Long-job completion** — a build, a batch, a render, a deploy finished. Fire an `info`-  toast so the user can wander off and get pulled back.+- **Long-job completion** — a build, a batch, a render, a deploy finished. Fire an+  `info` toast so the user can wander off and get pulled back. - **You need the user** — an approval, a decision, a credential. Use `warning`, or   `emergency` if you're fully blocked.-- **Hands-free / driving** — pair a notification with audio (TTS) so the user gets both a-  glance-able toast and the spoken answer.+- **Hands-free / driving** — pair a notification with audio (TTS) so the user gets+  both a glance-able toast and the spoken answer.  Don't spam: one notification per meaningful event. Verify the bridge first (`adom-desktop ping`) before claiming you notified them.@@ -124,4 +124,3 @@ Don't spam: one notification per meaningful event. Verify the bridge first ## Related skills - [hd-adom-desktop](../hd-adom-desktop/SKILL.md) — AD is what carries `notify_user` to the host; `ping`/`status` to verify the bridge and the `notify` capability - [hd-bridges](../hd-bridges/SKILL.md) — the full AD capability list (`notify`, …) and Pup's `browser_alert_window`-- [[hd-notifications-windows]] — the Windows toast backend (WinRT, AUMID "Adom" title, orange taskbar flash)
skills/hd-open-url/SKILL.md+12−1
@@ -13,7 +13,10 @@ description: >   open ti.com, open a link, pull up the page, show me the website, view this url,   open in browser, which browser, how do I open, open the datasheet page, open in   a tab, open in pup, open in chrome, headless fetch, ways to open a url, open-  link options, wv, open in wv, open as wv, webview tab, wv tab.+  link options, wv, open in wv, open as wv, webview tab, wv tab, webview,+  show me in webview, open in webview, in a webview, native webview. NEVER+  satisfy a webview request with VS Code's built-in Simple Browser — see+  hd-webview for the exact command. ---  # HD — Opening a URL (your options)@@ -38,6 +41,14 @@ user — DON'T hand them the picker"** below for the rule.  ## "wv" = webview — the shortcut (spread it like `pup`) +## ⛔ NEVER: VS Code's "Simple Browser" is NOT a webview++If the ask is "show me X **in webview**", the ONLY correct destination is option 1+(a native Hydrogen Web View tab, `adom-cli hydrogen webview open-or-refresh`).+**Never** open VS Code's built-in Simple Browser / any editor-internal browser page+— that happened once from a setup prompt (2026-07-16) and it's a banned outcome.+The dedicated `hd-webview` skill has the exact command + verification.+ **`wv` is the short alias for "webview"** — recognize it **everywhere** a user might say "webview" (`open it in wv`, `wv tab`, `shot the wv`, `wv mode`). Treat `wv` and `webview` as identical.
skills/hd-overview/SKILL.md+66−45
@@ -1,69 +1,90 @@ --- name: hd-overview description: >-  Master index for the platform-generic Hydrogen Desktop skills (the-  hd-bootstrap set). Start here to find the right skill for any HD topic.-  These skills are runtime-neutral and apply on every host HD runs on-  (Windows, macOS, Ubuntu); platform layers add their own *-windows (etc.)-  companions. Trigger words: HD skills, hydrogen desktop, what skills, find-  skill, HD help, HD overview, skill index, HD reference.+  Master index for all Hydrogen Desktop skills. Start here to find the right+  skill for any HD topic. Skills are split into a runtime-neutral "shared" set+  plus a runtime-specific set (WSL2 by default, Docker as legacy fallback).+  Trigger words: HD skills, hydrogen desktop, what skills, find skill, HD help,+  HD overview, skill index, HD reference. ---  # Hydrogen Desktop — Skill Index  Hydrogen Desktop (HD) is Adom's standalone Tauri v2 app that runs the full Hydrogen experience locally. One exe manages your workspace, VS Code,-Claude Code, the bridges, and the Adom Wiki — zero cloud dependency. HD runs-on Windows, macOS, and Ubuntu.+Claude Code, the bridges, and the Adom Wiki — zero cloud dependency. -This index lists the **platform-generic** HD skills (the `hd-bootstrap` set).-Every fact in these skills holds regardless of host OS. Where a topic has-host-specific mechanics (e.g. how the workspace is hosted, host networking,-host-side recording), the platform layer adds a companion skill — on Windows-those are the **`hd-windows-bootstrap`** `*-windows` skills (and equivalents-for other platforms). The generic skill cross-references its companion.+## ⚠️ First: know your runtime — **`hd-runtime-mode`** -## The generic HD skills (hd-bootstrap)+HD hosts your workspace one of two ways: a **WSL2 Ubuntu distro `Adom-Workspace`**+(the default) or a **Docker container** (legacy, `HD_RUNTIME=docker`). Almost every+fact below — container vs distro, files, ports, stats, setup steps — depends on+which is active. **Read `hd-runtime-mode` first** to confirm your runtime, then use+the matching runtime-specific skill. HD only installs the skills for the active+runtime, so in a given workspace you'll usually have exactly the right set.++## Shared skills (runtime-neutral — always installed)  | Skill | What it covers | |---|---|+| **hd-runtime-mode** | WSL2 vs Docker runtime: how to tell which you're in and what differs. Read first. |+| **hd-golden-image** | Your workspace is a pre-baked golden WSL2 image — gallia, the CLIs, claude, code-server, settings, and these skills are baked in (not installed by setup steps); how updates work. **Lightweight by design: tools like ffmpeg/imagemagick aren't baked — install on demand (`sudo apt-get install`) rather than refusing.** |+| **hd-skill-loop** | (Maintainers) The loop to fix a wrong/stale HD skill: verify vs the live HD, fix it live, write it back to the repo, bake it into the next image. |+| **hd-who-am-i** | Answer "who am I / what can I do here" — identity, resources, environment intro. | | **hd-adom-auth** | Adom login/logout, session token, profile menu, how auth feeds setup. |-| **hd-adom-desktop** | What HD and Adom Desktop (AD) are and how they work together — AD is your hands on the user's real OS (files, shell, OS screenshots, app launch, bridges). |-| **hd-adom-menu** | The upper-left Adom logo menu (Settings, Ports, API Explorer, DevTools, Setup/Virgin Reset) + About dialog + version readout. |-| **hd-api** | Control API reference. Runtime-neutral endpoints. |-| **hd-bridges** | Built-in KiCad/Fusion/Puppeteer bridges + extensible wiki catalog (e.g. Blender) + AD capability list. |-| **hd-captions** | Paint labeled text on the user's screen — an always-on-top caption overlay for demos / step callouts. |-| **hd-capture-share** | The screen-share + "AI wants access" approval + countdown the AI triggers to capture the editor; tab/screen scopes, Webview/Pup window mode. | | **hd-claude-auth** | How Claude Code signs in: OAuth via Browser Picker, credential backup, the `claude-auth` step. |-| **hd-container** | Context for Claude running inside the workspace: relay, direct connect, bridge commands, env vars. |-| **hd-container-stats** | The title-bar CPU/RAM "Container" indicator and how its stats are gathered. |+| **hd-api** | Control API reference (`127.0.0.1:47084`). Runtime-neutral endpoints + runtime-specific notes. | | **hd-desktop-sse** | Local workspace API + SSE — how adom-cli inside the workspace controls HD (replaces Carbon locally). |-| **hd-eda-discovery** | EDA tool discovery / setup flow. |-| **hd-eval** | Inject JS into any HD surface (shell/workbench/wiki/Claude) via /eval-in — add-ons, overlays, highlights, drive UI. |-| **hd-instapcb** | InstaPCB integration in HD. | | **hd-monitor** | Real-time SSE event stream + Monitor-tool patterns for watching workspace mutations. |-| **hd-notifications** | Reach the user outside the window — native OS toasts + emergency taskbar flash via `notify_user`. |-| **hd-open-url** | The decision guide for "open a website" — the ways (webview tab, HD window, Pup, native browser, picker, headless curl) and when to pick each. |-| **hd-overview** | This index. |-| **hd-permissions** | Why mic/camera/clipboard/notifications "just work" in HD — webview permissions are auto-granted, so webview apps see no Allow prompts. |+| **hd-ui** | HD's UI: menus, dialogs, panels, CDP-driven navigation, brand/CSS conventions. |+| **hd-open-url** | The decision guide for "open a website" — the six ways (webview tab, HD window, Pup, native browser, picker, headless curl) and when to pick each. |+| **hd-browser-picker** | URL interception — every link routes through the Browser Profile Dialog. |+| **hd-permissions** | Why mic/camera/clipboard/notifications "just work" in HD — WebView2 permissions are auto-granted, so webview apps see no Allow prompts. |+| **hd-tab-icons** | Webview tab icon system — `displayIcon`, icon resolution, SVG data URLs. | | **hd-profile-menu** | The avatar dropdown: profile/repos/molecules links and logout. |+| **hd-adom-desktop** | What HD and Adom Desktop (AD) are and how they work together — AD is your hands on the user's real OS (files, shell, OS screenshots, app launch, bridges). |+| **hd-bridges** | Built-in KiCad/Fusion/Puppeteer bridges + extensible wiki catalog (e.g. Blender) + AD capability list. |+| **hd-eval** | Inject JS into any HD surface (shell/workbench/wiki/Claude) via /eval-in — add-ons, overlays, highlights, drive UI. |+| **hd-adom-menu** | The upper-left Adom logo menu (Settings, Ports, API Explorer, DevTools, Setup/Virgin Reset) + About dialog + version readout. |+| **hd-settings** | HD's Settings dialog + the full preferences tree (theme, vim mode, 3D control style, launch-on-boot, AD window behavior). |+| **hd-file-transfer** | Move files both ways between the WSL2 workspace and the Windows PC. |+| **hd-embedded-ad** | HD ↔ Adom Desktop embedded mode: the tray, why AD is hidden, the footer pill. | | **hd-self-screenshot** | How the AI screenshots HD panels + any host window (window control, multi-monitor), injects to shotlog, runs visual self-checks. |-| **hd-self-update** | How HD updates itself. |-| **hd-settings** | HD's Settings dialog + the full preferences tree (theme, vim mode, 3D control style, launch-on-login, AD window behavior). |+| **hd-capture-share** | The screen-share + "AI wants access" approval + countdown the AI triggers to capture the editor; tab/screen scopes, Webview/Pup window mode. |+| **hd-recording** | Record the screen/mic — the in-app `.webm` recorder (→ `recordings/`) and AD desktop recording, with the tab-vs-desktop footgun. |+| **hd-notifications** | Reach the user outside the window — native Windows toasts + emergency taskbar flash via `notify_user`. |+| **hd-captions** | Paint labeled text on the user's screen — a Win32 always-on-top caption overlay for demos / step callouts. |+| **hd-welcome** | The static welcome page shown after setup completes. |+| **hd-skill-catalog** | The catalog of skills your Claude has in this workspace. |+| **hd-overview** | This index. |++## Runtime-specific skills (you get the WSL2 *or* the Docker variant)++These topics exist in two parallel implementations — `wsl2/` (default) and+`docker/` (legacy) — with the same skill names. Trust the one for your active+runtime (see `hd-runtime-mode`).++| Skill | What it covers |+|---|---|+| **hd-container** | Context for Claude running inside the workspace: relay, direct connect, bridge commands, env vars. |+| **hd-topology** | The three-layer architecture and how to reach the workspace (WSL2: `wsl -d Adom-Workspace`; Docker: `docker exec`). |+| **hd-networking** | Port architecture, host access (`127.0.0.1` / mirrored networking), code-server proxy. Canonical port behavior. |+| **hd-ports** | Forwarding workspace services to Windows (WSL2 auto-forward vs Docker `-p` + `/proxy/`). |+| **hd-port-watcher** | The dynamic port-forward daemon for extension OAuth callbacks. |+| **hd-volume** | Where your files live, what persists, how to copy out, what a reset wipes. |+| **hd-container-stats** | The title-bar CPU/RAM "Container" indicator and how its stats are gathered. | | **hd-setup** | The setup panel, Run All, Rollback, Virgin Reset. | | **hd-setup-steps** | What each setup step did to prepare your workspace. |-| **hd-tab-icons** | Webview tab icon system — `displayIcon`, icon resolution, SVG data URLs. |-| **hd-ui** | HD's UI: menus, dialogs, panels, CDP-driven navigation, brand/CSS conventions. |-| **hd-welcome** | The static welcome page shown after setup completes. |-| **hd-who-am-i** | Answer "who am I / what can I do here" — identity, resources, environment intro. |-| **hd-workspace-monitoring** | Workspace + code-server health monitoring, floaty states, the 15s poll, auto-start. |-| **hd-workspace-updater** | The workspace-tooling updater daemon. | -## Platform layers+### WSL2-only+| Skill | What it covers |+|---|---|+| **hd-workspace-lifecycle** | WSL distro lifecycle: import/export/terminate/unregister, code-server as an HD-owned child, the never-global-WSL rule. |+| **hd-workspace-monitoring** | Distro + code-server health monitoring, floaty states, the 15s poll, auto-start. | -Platform-specific mechanics live in a platform layer that ships alongside this-set and adds `*-windows`-style companion skills (e.g. `hd-container-windows`,-`hd-container-stats-windows`, `hd-networking`, `hd-volume`,-`hd-workspace-lifecycle`). When a generic skill above has a host-specific detail,-it cross-references its companion. On a given host you'll have the generic set-plus that host's platform layer.+### Docker-only (legacy `HD_RUNTIME=docker`)+| Skill | What it covers |+|---|---|+| **hd-docker-desktop** | Silently install/upgrade/start/monitor Docker Desktop as invisible infrastructure. |+| **hd-docker-lifecycle** | Docker Desktop + container lifecycle: WSL2 recovery, restart/stop rules, health checks. |+| **hd-docker-monitoring** | Frontend monitoring of the Docker container and Docker Desktop. |
skills/hd-permissions/SKILL.md+54−47
@@ -1,69 +1,76 @@ --- name: hd-permissions description: >-  Hydrogen Desktop AUTO-GRANTS every webview permission — microphone, camera,-  clipboard-read, geolocation, notifications, sensors — so inside HD a webview app NEVER-  shows a "this site wants to use your microphone/camera/clipboard/location" prompt. READ-  THIS before building or debugging a webview app that uses getUserMedia / clipboard /-  geolocation: do NOT tell the user to click "Allow" — there is no prompt to click; it's-  suppressed by design. Distinguish this browser-permission auto-grant from the SEPARATE-  in-app screen-share / mic consent the AI itself requests (that one IS user-approved — see-  hd-capture-share). HD's webview engine is platform-specific; the per-engine-  implementation detail (e.g. WebView2 on Windows) lives in the platform companion (see-  [[hd-permissions-windows]]). Trigger words — permission, permissions, webview permission,-  allow microphone, allow camera, allow clipboard, clipboard read, getUserMedia, mic-  permission, camera permission, geolocation permission, notifications permission, sensors-  permission, site wants to use, permission prompt, click allow, no permission prompt,-  auto-grant, auto granted, why no prompt, permission denied webview.+  Hydrogen Desktop AUTO-GRANTS every WebView2 permission — microphone, camera,+  clipboard-read, geolocation, notifications, sensors — so inside HD a webview+  app NEVER shows a "this site wants to use your microphone/camera/clipboard/+  location" prompt. READ THIS before building or debugging a webview app that+  uses getUserMedia / clipboard / geolocation: do NOT tell the user to click+  "Allow" — there is no prompt to click; it's suppressed by design. Distinguish+  this browser-permission auto-grant from the SEPARATE in-app screen-share / mic+  consent the AI itself requests (that one IS user-approved — see hd-capture-+  share). Trigger words — permission, permissions, webview2 permission, allow+  microphone, allow camera, allow clipboard, clipboard read, getUserMedia, mic+  permission, camera permission, geolocation permission, notifications+  permission, sensors permission, site wants to use, permission prompt, click+  allow, no permission prompt, auto-grant, auto granted, why no prompt,+  permission denied webview. --- -# HD auto-grants every webview permission+# HD auto-grants every WebView2 permission -Hydrogen Desktop's webview registers a permission handler that returns **ALLOW for every-permission kind** — microphone, camera, clipboard-read, geolocation, notifications,-sensors, etc. So **inside HD the user never sees a "this site wants to use your microphone /-camera / clipboard / location" dialog.** Webview apps that call `getUserMedia`, read the-clipboard, or ask for geolocation simply *work*, with no prompt.+Hydrogen Desktop's webview (Windows / WebView2) registers a+`PermissionRequested` handler that returns **ALLOW for every permission kind** —+microphone, camera, clipboard-read, geolocation, notifications, sensors, etc. So+**inside HD the user never sees a "this site wants to use your microphone /+camera / clipboard / location" dialog.** Webview apps that call `getUserMedia`,+read the clipboard, or ask for geolocation simply *work*, with no prompt. -Every request is unconditionally allowed. In the HD log you'll see lines like `[perm]-auto-granted permission kind …` and, at startup, `[perm] Registered PermissionRequested-auto-grant handler`.+Evidence: `hd-app/src/lib.rs` (~lines 326-349): -> **Platform note:** HD uses a different webview engine per platform (e.g. WebView2 on-> Windows, WebKit on mac/Linux). The auto-grant policy is the same everywhere — every-> permission is allowed up front — but the exact engine API is platform-specific. The-> Windows/WebView2 implementation and its code evidence are in [[hd-permissions-windows]].+```rust+// PermissionRequested: auto-grant EVERY permission kind (clipboard+// read, mic, camera, geolocation, notifications, sensors, …) so the+// user never sees a WebView2 "site wants to" dialog.+…+args.SetState(COREWEBVIEW2_PERMISSION_STATE_ALLOW)?;+hd_log::hd_log!("[perm] auto-granted permission kind {:?}", kind);+```++Every request is unconditionally set to `COREWEBVIEW2_PERMISSION_STATE_ALLOW`. In+the HD log you'll see lines like `[perm] auto-granted permission kind …` and, at+startup, `[perm] Registered PermissionRequested auto-grant handler`.  ## Why HD does this -HD is the user's **trusted desktop app** — they've already chosen to run it. Intermediate-per-site Web permission prompts (especially the clipboard-paste dialog) are pure friction-with no added safety here, since there's no untrusted third-party browsing context: the-surfaces are HD's own panels and the user's own webview apps. So HD grants them all up-front.+HD is the user's **trusted desktop app** — they've already chosen to run it.+Intermediate per-site Web permission prompts (especially the clipboard-paste+dialog) are pure friction with no added safety here, since there's no untrusted+third-party browsing context: the surfaces are HD's own panels and the user's own+webview apps. So HD grants them all up front.  ## What this means for you when building webview apps -- **Don't instruct the user to "click Allow."** There is no prompt — telling them to look-  for one is wrong and confusing. `getUserMedia({ audio: true })`, clipboard reads,-  geolocation, notifications all resolve without a dialog.+- **Don't instruct the user to "click Allow."** There is no prompt — telling them+  to look for one is wrong and confusing. `getUserMedia({ audio: true })`,+  clipboard reads, geolocation, notifications all resolve without a dialog. - If a webview app *isn't* getting mic/camera data, the cause is **not** a denied-  permission prompt (HD never denies). Look elsewhere: no device present, the page served-  over a non-secure context, a code bug, or the OS-level privacy toggle for the camera/mic-  being off for the app entirely.-- This is behavior baked into HD's webview host — it's not something the web page or the-  user configures.+  permission prompt (HD never denies). Look elsewhere: no device present, the+  page served over a non-secure context, a code bug, or the OS-level Windows+  privacy toggle for the camera/mic being off for the app entirely.+- This is WebView2/Windows-specific behavior baked into HD's webview host — it's+  not something the web page or the user configures.  ## NOT the same as in-app screen-share / mic consent -This auto-grant is **only** the low-level webview browser-permission layer. It is separate-from the **screen-share / microphone consent the AI itself requests** when it wants to-capture the user's screen or mic for a session — that flow **is** explicitly user-approved-(the user sees and accepts an in-app consent UI). Don't conflate them: webview site-permissions are silently allowed; the AI's capture/share request is a real, user-facing-approval. See `hd-capture-share`.+This auto-grant is **only** the low-level WebView2 browser-permission layer.+It is separate from the **screen-share / microphone consent the AI itself+requests** when it wants to capture the user's screen or mic for a session — that+flow **is** explicitly user-approved (the user sees and accepts an in-app consent+UI). Don't conflate them: WebView2 site permissions are silently allowed; the AI's+capture/share request is a real, user-facing approval. See `hd-capture-share`.  ## Related skills - `hd-capture-share` — the SEPARATE, user-approved screen-share / mic consent the AI requests - [hd-open-url](../hd-open-url/SKILL.md) — opening URLs/webview apps inside HD (where these permissions apply)-- [[hd-permissions-windows]] — the WebView2 (Windows) implementation + lib.rs evidence+- [hd-browser-picker](../hd-browser-picker/SKILL.md) — routing URLs to webviews vs native browsers vs Pup
skills/hd-pup/SKILL.mdadded+57
@@ -0,0 +1,57 @@+---+name: hd-pup+description: >+  PUP — what "pup" means in Hydrogen Desktop and exactly how to open one. When+  the user says "show me in pup", "open it in pup", "pup window", "in pup", or+  asks to demo/drive ANY page "in pup", it means a real, AI-drivable Chrome/Edge+  window opened by Adom Desktop's Puppeteer bridge (auto-installed with HD) on+  THIS machine — never a webview (see hd-webview), never the user's personal+  signed-in browser (that's nbrowser). CRITICAL HD DIFFERENCE: in HD, localhost+  URLs are the NORM for pup (everything binds localhost on the same machine) —+  the cloud-container rule "pup can't see localhost" is INVERTED here. Trigger+  words — pup, open in pup, show me in pup, in pup, pup window, puppeteer,+  pup browser, drive a browser, show the page in pup.+---++# hd-pup — "pup" is a real drivable browser window on this machine++**pup** = Adom Desktop's Puppeteer bridge driving a fresh, isolated Chrome (or+Edge) process. HD embeds Adom Desktop and auto-installs the bridge, so pup is+always available — no setup questions, just check readiness and go.++## ⚠️ THE LOCALHOST RULE IS INVERTED IN HD (do not import cloud instincts)++- **Web Hydrogen (cloud container):** pup runs on the *user's desktop*, so the+  container's `localhost` is unreachable — the bridge sanity-checks localhost+  URLs because they're almost always a mistake, and pages get slug/proxy URLs+  (`vscode_proxy_uri` style) instead.+- **Hydrogen Desktop (here):** the workspace, HD, and pup all live on the SAME+  machine. **~95% of pup URLs are `http://localhost:<port>` and that is+  CORRECT.** Never rewrite a localhost URL to a slug/proxy URL, and never+  refuse it — HD binds its web servers to localhost by design.++## ✅ How to open a page in pup (from the workspace)++```bash+adom-desktop browser_readiness '{}'          # is the bridge ready? which browser?+adom-desktop browser_open_window '{"url":"http://localhost:<port>/...","sessionId":"<task-name>"}'+adom-desktop browser_screenshot '{"sessionId":"<task-name>"}'   # verify what's on screen+```++- Reuse ONE window per task via a stable `sessionId` — open tabs in it rather+  than spawning window after window.+- pup opens in the background by default; pass `foreground:true` only when the+  user should see it appear right now.+- Verify by screenshot, not by assumption: if `browser_screenshot` doesn't show+  your page, it isn't open.++## ⛔ Never confuse the three browser surfaces++| Ask | Surface | Skill |+|---|---|---|+| "show me in **webview**" | native Hydrogen Web View tab | `hd-webview` |+| "show me in **pup**" / drive it | isolated Puppeteer Chrome (this skill) | `pup` for deep driving |+| use **my** logins / my real browser | user's signed-in Chrome/Edge | nbrowser / adom-browser-extension |++For deep pup driving (tabs, sessions, recording, eval), the full `pup` skill+applies — this skill exists so the word "pup" always routes correctly in HD.
skills/hd-self-screenshot/SKILL.md+103−51
@@ -9,21 +9,23 @@ description: >   panel", "screenshot the editor", "screenshot my whole screen / the desktop",   "show me what HD looks like", or verifying a UI change (ralph loop). Use this   even for "my whole screen / my desktop / my monitor" — that's the `screen`-  scope. You do NOT need any image resizer. For a SPECIFIC element/region (a CPU-  meter, a menu, a dialog, a toolbar) or an inline-b64 PNG, use the canonical-  `POST /screenshot` control endpoint with a CSS `selector` (it ALWAYS region-clips-  to that element) — and combine it with the UI command bus (`hd-ui`: `ui/invoke`-  to open a menu/dialog, then `/screenshot` its selector). Identical across web-  Hydrogen and HD. Trigger words — screenshot HD, screenshot the welcome page,-  screenshot the webview, screenshot a panel, screenshot a tab, screenshot the-  workspace, screenshot the editor, screenshot my screen, screenshot the whole-  screen, screenshot the desktop, capture my monitor, full screen capture,+  scope, NOT adom-desktop. Do NOT curl host.docker.internal, do NOT use+  adom-desktop's OS screenshot for anything inside HD (or for the screen), and you+  do NOT need any image resizer. For a SPECIFIC element/region (a CPU meter, a menu,+  a dialog, a toolbar) or an inline-b64 PNG, use the canonical `POST /screenshot`+  control endpoint with a CSS `selector` (it ALWAYS region-clips to that element) —+  and combine it with the UI command bus (`hd-ui`: `ui/invoke` to open a menu/dialog,+  then `/screenshot` its selector). Trigger words — screenshot HD, screenshot the+  welcome page, screenshot the webview, screenshot a panel, screenshot a tab,+  screenshot the workspace, screenshot the editor, screenshot my screen, screenshot+  the whole screen, screenshot the desktop, capture my monitor, full screen capture,   screenshot everything on screen, what does HD look like, adom-cli hydrogen   screenshot, capture panel, capture workspace, capture screen, screenshot a region,   clip to selector, screenshot an element, screenshot a menu, screenshot a dialog,   region screenshot, b64 screenshot, POST /screenshot, /shot, screenshot without flash,-  no-flash screenshot, which screenshot tool, verify visually, ralph loop, shotlog,-  image resizer, resize screenshot.+  no-flash screenshot, hd_shot, hd_screenshot, screenshot KiCad, screenshot another app,+  screenshot a non-HD window, desktop_screenshot_window, desktop_screenshot_screen, which+  screenshot tool, verify visually, ralph loop, shotlog, image resizer, resize screenshot. ---  # HD — Screenshot a panel / webview / the workspace / the screen@@ -31,12 +33,14 @@ description: > The built-in way to screenshot anything inside HD is the **`adom-cli hydrogen screenshot`** command — the *same* `adom-cli` you already use. It captures the real rendered surface, drops a PNG into the container's `screenshots/` folder,-and prints the path. Just `Read` that path. **No image resizer needed.**+and prints the path. Just `Read` that path. **No `host.docker.internal`, no+ImageMagick.** (`adom-desktop`'s host verbs DO have a place — other apps, no-flash+grabs, the whole desktop — see the ladder; just not as the default for HD content.)  ## Which screenshot tool? — the priority ladder -What you're capturing (and whether you want the teal flash) picks the tool. Default to-HD-native:+You have HD-native capture AND AD's host verbs. **What** you're capturing (and whether+you want the teal flash) picks the tool. Default to HD-native:  1. **HD content — a panel, the workspace, the editor, a webview, the screen    (the 99% case): `adom-cli hydrogen screenshot panel|workspace|screen`. THIS IS THE@@ -51,27 +55,52 @@ HD-native:    - **The one time you switch to CDP for an ordinary shot:** during another thread's      recording the `adom-cli` SSE path returns `capture_busy` — then fall to `POST /screenshot`      (CDP), which coexists (see "During a recording" below). That's a fallback, not the default.+2. **HD content, NO flash** (clean shot, or HD's CDP/SSE isn't mounted): `adom-desktop hd_shot+   '{"region":"full|titlebar|setup-panel|…"}'` (named HD-window regions) or `adom-desktop+   hd_screenshot` (the whole HD window). Host-side, deliberately **no teal flash**.+3. **A specific NON-HD app window** (KiCad, Fusion 360, a native dialog — **or an HD Tauri browser+   window, which is less-tested**): `adom-desktop desktop_list_windows` → `desktop_screenshot_window+   '{"hwnd":N}'`. OS PrintWindow of one window; coexists with a recording. See `hd-bridges`.+4. **Your app in a Pup browser window** (AI-driven Chrome — hero images, clean app shots):+   **`adom-desktop browser_screenshot '{"sessionId":"…"}'`** (the `pup` skill). Full-page, no HD+   chrome, no flash — separate Chrome, so it coexists with an HD recording.+5. **The whole physical desktop** (every app, taskbar): `adom-cli hydrogen screenshot screen` (HD+   scope) OR `adom-desktop desktop_screenshot_screen` (AD host GDI). Both **coexist with a recording**+   (independent of HD's WGC/DXGI recorder — corrected 2026-06-14; `ad_screen` can be intermittent+   under heavy load).  ## During a recording (multi-thread) — pick a coexisting method, never blind-retry -Adom users run **multiple AI threads on one HD**, so another thread may be recording the-screen while you capture. **Only the `adom-cli` SSE path (`screenshot panel/workspace/screen`)-is affected** — the CDP path coexists. HD makes this deterministic:+Adom users run **multiple AI threads on one HD**, so another thread may be recording the screen+while you capture. **Only the `adom-cli` SSE path (`screenshot panel/workspace/screen`) is affected**+— everything else coexists. HD makes this deterministic: -- **Pre-flight `GET /capture/availability`** → reports the recording state plus, per method,-  reliability + whether it coexists with a recording, a `recommended` method, and a `_hint`.-  Check it **only when a recording might be running.**-  - **`recommended` is STATE-DEPENDENT and agrees with the default:** when+- **Pre-flight `GET /capture/availability`** → `{recording:{active,source}, methods:{cdp, ad_window,+  ad_screen, pup, sse} each w/ reliability + coexists_with_recording, recommended, _sharing_note,+  _hint}`. Check it **only when a recording might be running.**+  - **`recommended` is STATE-DEPENDENT (HD v0.1.40+) and agrees with the default:** when     `recording.active === false` it returns **`"sse"`** (≡ `adom-cli hydrogen screenshot`, the-    web-Hydrogen-consistent default); when `recording.active === true` it returns **`"cdp"`**-    (the SSE path would `capture_busy`, so CDP is correct). So you can follow `recommended`-    directly — it will never push you off `adom-cli` while idle. Your everyday default remains-    `adom-cli`; CDP is the during-a-recording fallback.+    web-Hydrogen-consistent default, rung #1); when `recording.active === true` it returns+    **`"cdp"`** (the SSE path would `capture_busy`, so CDP is correct). So you can follow+    `recommended` directly — it will never push you off `adom-cli` while idle. (Verified live+    2026-06-14: idle → `recommended:"sse"`.) Your everyday default remains `adom-cli`; CDP is the+    during-a-recording fallback.+  - **`_sharing_note`:** HD-native capture uses CDP, so there is **no real screen-share to+    detect** (any "sharing" field would be a meaningless `false`) — the truthful signal is the note+    + the recording status, not a sharing flag. The display-hold / screensaver-block footgun is a+    **web-Hydrogen-only** problem (its `getDisplayMedia` holds `ES_DISPLAY_REQUIRED`); if you hit a+    pinned display, the fix is **`adom-cli hydrogen sharing stop`**, not anything HD-side. See+    [hd-screen-lock](../hd-screen-lock/SKILL.md). - **`capture_busy`:** the SSE path (`PATCH /current/screenshot`, i.e. `adom-cli screenshot   panel/workspace`) returns, the moment a recording is active, `{ok:false, error:"capture_busy",-  retry_after_ms, alternatives:[{method:"cdp"}], _hint}` — never an empty body. **On-  `capture_busy`: read `alternatives` and SWITCH — do NOT blindly retry the SSE path.**-- Authoritative recording state: `GET /recording/native/status`. See `hd-recording`.+  retry_after_ms, alternatives:[{method:"cdp"},{ad_window},{ad_screen},{pup}], _hint}` — never an+  empty body. **On `capture_busy`: read `alternatives` and SWITCH — do NOT blindly retry the SSE path.**+- **Coexistence matrix (verified live):** `POST /screenshot` (CDP) ✅ *best during a recording* ·+  `desktop_screenshot_window` ✅ · `desktop_screenshot_screen` ✅ (medium) · `pup browser_screenshot`+  ✅ · `adom-cli screenshot panel/workspace/screen` ⚠️ → `capture_busy`.+- Authoritative recording state: `GET /recording/native/status`. See `hd-recording`, `hd-screen-lock`.++**Quick map:** in-HD → #1 (or #2 for no-flash) · other app → #3 · whole desktop → #4.  ## Pick the scope — panel / workspace / screen @@ -82,8 +111,9 @@ is affected** — the CDP path coexists. HD makes this deterministic: | The whole **screen** — desktop, taskbar, OTHER apps | `adom-cli hydrogen screenshot screen` | `screen` |  **"My whole screen / my desktop / my monitor / everything"** → `adom-cli hydrogen-screenshot screen`. The HD `screen` scope captures the real desktop and saves the PNG into-your container, same as the others.+screenshot screen`. Do **NOT** reach for `adom-desktop` here — that's only for one+SPECIFIC non-HD window (KiCad, Fusion). The HD `screen` scope captures the real+desktop and saves the PNG into your container, same as the others (verified live).  ## Do this — it saves a PNG and prints the path; then Read it @@ -112,8 +142,8 @@ the webview tab you find by its `--tab-id`. ### What it returns — a saved path; just Read it The command saves the PNG into the container's `screenshots/` folder and prints the path. **Read it — done.** No decoding, no resizer, no second tool. The printed path-is **relative to `~/project`** (matches the cloud contract); the `_hint` gives the full-path:+is **relative to `~/project`** (HD v0.1.27+ matches the cloud contract); the `_hint`+gives the full path:  ``` screenshots/2026-06-13T20-04-43.png@@ -122,11 +152,16 @@ _hint: Screenshot saved to ~/project/screenshots/<ts>.png. Read the file to view → `Read ~/project/screenshots/<ts>.png` (prepend `~/project/` to the line-1 path, or just use the full path from the `_hint`). +(Legacy/edge case: an older HD build could return a doubled `~/project/~/project/`+prefix, or inline JSON with `"dataUrl"` + `"uploadFailed": true` — both fixed in+v0.1.27. If you ever see the `dataUrl` shape, base64-decode it to a .png and Read it;+don't build the capture around it.)+ ### If a capture errors, retry once A COLD capture can occasionally fail with a proxy URL containing a literal `{{port}}` (e.g. `…/proxy/{{port}}/: error sending request`) — a known **adom-cli** cold-start race (the proxy port isn't substituted yet). Just **run the same command again**; the-warm retry succeeds.+warm retry succeeds. Don't switch tools or reach for adom-desktop over this.  ## Sharing must be active (it usually is; here's the gate) @@ -143,28 +178,36 @@ adom-cli hydrogen sharing request --share screen  # adds the 'screen' scope The `screen` scope is for the whole desktop; `panel`/`workspace` come from tab sharing. See `hd-capture-share` for the sharing/approval UX. -**Release SCREEN sharing when you're done.** A `screen` share (getDisplayMedia) holds the-display **awake** — leaving it active blocks the user's screensaver. After a one-off-`screen` capture, run `adom-cli hydrogen sharing stop` (and close any Pup windows you-opened). Tab `panel`/`workspace` sharing doesn't hold the display, so this only matters-once you've requested the `screen` scope.+**Release SCREEN sharing when you're done.** A `screen` share (getDisplayMedia) holds+the display **awake** — leaving it active blocks the user's screensaver. After a+one-off `screen` capture, run `adom-cli hydrogen sharing stop` (and close any Pup+windows you opened). Tab `panel`/`workspace` sharing doesn't hold the display, so this+only matters once you've requested the `screen` scope.  ## Why this works the same in HD as it does for web Hydrogen  `adom-cli` is **one binary** used by both web Hydrogen and HD — you can test these commands anywhere. The difference is purely *where the work runs*: HD intercepts what adom-cli talks to. `adom-cli hydrogen <cmd>` hits `ADOM_HYDROGEN_URL`, which-in HD points at **HD's local proxy**. HD's proxy pulls out the **local hydrogen/SSE-commands** (screenshot, webview, caption, notify, recording…) and runs them against-the HD frontend over SSE, while **carbon/cloud calls pass straight through** to the-cloud. For a screenshot: `PATCH /current/screenshot` → HD broadcasts an SSE-`screenshot_request` → the frontend Element-Captures the panel → uploads it into-**this container's** `screenshots/` folder → the CLI returns the saved path. So the-command, and the returned path, behave the same — the bytes just land in your local-container.+in HD points at **HD's local proxy** (`http://127.0.0.1:<proxy>`). HD's proxy+pulls out the **local hydrogen/SSE commands** (screenshot, webview, caption,+notify, recording…) and runs them against the HD frontend over SSE, while+**carbon/cloud calls pass straight through** to the cloud. For a screenshot:+`PATCH /current/screenshot` → HD broadcasts an SSE `screenshot_request` → the+frontend Element-Captures the panel → uploads it into **this container's**+`screenshots/` folder → the CLI returns the saved path. So the command, and the+returned path, behave the same — the bytes just land in your local container.  ## What NOT to do (these are the traps) +- **Don't curl `host.docker.internal`.** That's a Docker-ism HD does not use. HD's+  host services are reached at `http://127.0.0.1:<port>` (WSL2 mirrored+  networking); the live control URL is in `~/.adom/hd-control-url`. But for+  screenshots you don't need any of that — use the CLI above.+- **Don't use `adom-desktop desktop_screenshot_*` for an HD panel/webview.** That+  grabs the whole Windows window/desktop, not the panel — it's the wrong tool for+  anything inside HD. Use it only for **non-HD** apps (KiCad, Fusion, a native+  window — see `hd-bridges`). - **You do NOT need an image resizer.** `adom-cli hydrogen screenshot` produces a   normal PNG and the `Read` tool reads PNGs directly. (Don't reach for ImageMagick   `convert` or Pillow — neither is guaranteed in the golden image, and you don't@@ -197,18 +240,21 @@ A `selector` clips to the **first matching element** in that surface — grab JU meter, a menu, a dialog, a toolbar instead of the whole window (verified live: `{selector:".resource-bars"}` → 192×61, vs `{target:"full"}` → the whole window). -**Screenshot a tab by its display NAME — incl. a BACKGROUND tab.**+**Screenshot a tab by its display NAME — incl. a BACKGROUND tab (fixed in HD v0.1.42).** `POST /screenshot {target:"<tab name>"}` resolves the name → the workspace panel, **activates that tab** (so a *background* tab actually paints — a webview is an OOPIF and can't be CDP-shot while hidden), captures the shell cropped to that panel, then **restores the previously-active tab**. So in a pane stacked `VS Code | ScreenA | ScreenB` (ScreenB showing), `{target:"ScreenA"}`-returns ScreenA's pixels and leaves ScreenB active. The `adom-cli` SSE path-(`screenshot panel --name ScreenA`) also activates + restores. This is the right call for-"shot tab #2 while #4 is showing."+returns ScreenA's pixels and leaves ScreenB active. **Verified live 2026-06-14:** CDP *and* the+`adom-cli` SSE path (`screenshot panel --name ScreenA`) both returned the background tab's content+(example.com, not the active httpbin tab) and restored the prior tab — `target:"<name>"` was+NO-PNG before v0.1.42. (The `adom-cli` SSE path has always activated; v0.1.42 brings the CDP+`/screenshot` by-name path to parity.) This is the right call for "shot tab #2 while #4 is showing."  **The teal zap:** every HD-driven capture flashes a teal (`#00b8b0`) highlight on the captured **region** (just the panel/menu/region; full-window flash only for-`target:full`). Teal = HD-driven. Pass `silent:true` to suppress it.+`target:full`). Teal = HD-driven. (The `adom-desktop` host verbs `hd_shot`/`hd_screenshot`+deliberately do NOT flash — different tool.) Pass `silent:true` to suppress it.  ### Screenshot a menu / dialog / panel — open it, then clip to it The killer combo with the UI command bus (see **`hd-ui`**): **open a surface →@@ -230,7 +276,13 @@ Verify a UI change: make the change → (rebuild if needed) → repeat. Log shots for the user with `shotlog inject -c hd-ui -d "<desc>" <path>` (shotlog resizes internally — another reason you don't need `convert`). +## Host window control (for NON-HD windows only)+`adom-desktop desktop_list_windows` → `desktop_set_window_state {hwnd,state}` →+`desktop_bring_to_front {hwnd}` → then `desktop_screenshot_window`. Windows-only.+ ## Related skills - [hd-capture-share](../hd-capture-share/SKILL.md) — the sharing/approval UX behind `screenshot`+- [hd-desktop-sse](../hd-desktop-sse/SKILL.md) — the adom-cli → HD-proxy → SSE interception model - [hd-recording](../hd-recording/SKILL.md) · [hd-captions](../hd-captions/SKILL.md) — sibling `adom-cli hydrogen` AV verbs+- [hd-bridges](../hd-bridges/SKILL.md) — `desktop_screenshot_*` for NON-HD apps - `shotlog` — the screenshot log viewer/injector
skills/hd-self-update/SKILL.md+1−1
@@ -1,6 +1,6 @@ --- name: hd-self-update-description: How the AI keeps the Hydrogen Desktop APP itself (the Windows/macOS frontend, not the workspace) up to date — AI-first, consent-based. Use when asked "is there an HD update", "update Hydrogen Desktop", "is my HD current", "what version of HD am I on", "update the app", "new HD version". Trigger words: HD update, update hydrogen desktop, app update, is HD current, HD version, new version of HD, relaunch to update, self-update.+description: "How the AI keeps the Hydrogen Desktop APP itself (the Windows/macOS frontend, not the workspace) up to date — AI-first, consent-based. Use when asked \"is there an HD update\", \"update Hydrogen Desktop\", \"is my HD current\", \"what version of HD am I on\", \"update the app\", \"new HD version\". Trigger words: HD update, update hydrogen desktop, app update, is HD current, HD version, new version of HD, relaunch to update, self-update." ---  # HD Self-Update — the AI updates the app for you (consent-based)
skills/hd-settings/SKILL.md+8−8
@@ -2,19 +2,19 @@ name: hd-settings description: >   Hydrogen Desktop's Settings dialog and the full preference tree the user can-  change — theme, vim mode, launch-on-login, console-on-startup, 3D control style,+  change — theme, vim mode, launch-on-boot, console-on-startup, 3D control style,   font, line numbers, schematic nudge, the embedded Adom Desktop options, and   more. READ THIS when the user asks "how do I turn on vim mode", "change the-  theme", "make HD launch at startup", "stop Adom Desktop's window popping up",+  theme", "make HD launch on boot", "stop Adom Desktop's window popping up",   "switch to blender/solidworks orbit controls", "hide line numbers", "show the   console on startup", "make the UI compact", or "where are the settings". Opened   from the Adom logo menu → Settings. Trigger words — settings, preferences,   settings dialog, options, config, theme, dark mode, light mode, high contrast,   compact ui, developer mode, vim mode, vim emulation, line numbers, code font,-  editor font, launch on login, launch on startup, launch on boot, show console,-  console on startup, 3d controls, control style, fusion solidworks blender orbit,-  schematic nudge, auto approve, foreground hd, adom desktop window, turn on, turn-  off, change setting, how do I configure.+  editor font, launch on boot, start with windows, show console, console on+  startup, 3d controls, control style, fusion solidworks blender orbit, schematic+  nudge, auto approve, foreground hd, adom desktop window, turn on, turn off,+  change setting, how do I configure. ---  # HD Settings — the preference tree@@ -50,7 +50,7 @@ override. Keys are dotted (`section.subsection.name`). | Key | Default | What it does | |---|---|---| | `desktop.show_console_on_startup` | `false` | Show the debug console window when HD starts (→ "show the console on startup") |-| `desktop.launch_on_boot` | `true` | Auto-launch HD on login / at startup (→ "make HD launch at startup" / "stop HD launching on login" = set false) |+| `desktop.launch_on_boot` | `true` | Auto-launch HD when Windows starts (→ "make HD launch on boot" / "stop HD starting with Windows" = set false) |  ### adom_desktop  *(the embedded Adom Desktop / AD that HD runs)* When HD is running it takes over AD, so AD's options live here. See@@ -97,7 +97,7 @@ extension-specific settings).  - **"Turn on vim mode"** → `code.vim_emulation_mode` = true - **"Change the theme / dark mode / high contrast"** → `general.appearance.theme`-- **"Make HD launch on login / at startup"** / "don't launch on login" → `desktop.launch_on_boot`+- **"Make HD launch on boot"** / "don't start with Windows" → `desktop.launch_on_boot` - **"Stop Adom Desktop's window popping up"** → `adom_desktop.show_window_on_launch` = false - **"Blender / SolidWorks orbit controls"** → `3d.control_style` - **"Hide line numbers / change code font"** → `code.line_numbers.enabled` / `code.appearance.font.family`
skills/hd-skill-catalog/SKILL.md+2
@@ -45,6 +45,8 @@ which runtime you're in. | `hd-ui` | HD's menus, dialogs, panels, programmatic UI control via CDP, CSS selectors. | | `hd-open-url` | The decision guide for "open a website": the six ways to open a URL (webview tab, HD window, Pup, native browser, picker, headless curl) and when to pick each. | | `hd-browser-picker` | Every URL HD opens routes through a 5-layer interception into a picker dialog (AI-friendly 5s countdown). |+| `hd-wiki-review` | After editing any wiki.adom.inc page, load it in pup so the user can review the rendered result (don't just report the commit). |+| `hd-claude-management` | First-class API for the Claude conversation tabs: list/open/close/switch, read per-conversation state + on-disk session GUID, type into a SPECIFIC conversation (instant/animated) + submit, and turn on Remote Control for a claude.ai/mobile cloud URL. Address by stable context id. | | `hd-permissions` | Why mic/camera/clipboard/notifications "just work" — HD auto-grants WebView2 permissions, so webview apps see no Allow prompts. | | `hd-adom-desktop` | What HD and Adom Desktop (AD) are + how they work together — AD is your reach onto the user's real OS (create files/folders, run shell, OS screenshots, launch apps, browsers, KiCad/Fusion). | | `hd-bridges` | Built-in KiCad/Fusion/Puppeteer bridges + extensible wiki catalog (e.g. Blender) + full AD capability list (usb, caption, record…). |
skills/hd-tab-icons/SKILL.md+3−3
@@ -37,7 +37,7 @@ only they load an HTML page that can ship its own `<link rel="icon">`.  Other panel types — Schematic Editor, 3D Editor, KiCad panel,-Desktop Demo, Movie Maker, etc. —+Desktop Demo, Movie Maker, Adom Viewer native panel, etc. — have their icons assigned by Hydrogen's internal panel registry keyed off `panelType`, not by anything the tab adder passes in. If your tab isn't a webview and its icon is wrong, **this skill@@ -68,7 +68,7 @@ favicon, not `mdi:rocket-launch`.  ## Brand rule: icons must be monochrome `#e6edf3` -Per the Adom `brand` skill, **all Adom icons must be monochrome+Per `gallia/skills/brand/SKILL.md`, **all Adom icons must be monochrome white (`#e6edf3`)** — no colored icons, no multi-color, no brand-palette colors in icons. This applies to tab icons too. @@ -226,7 +226,7 @@ both as soon as it loads.** | Icon | Typical use | |---|---| | `mdi:chip` | chips, ICs, boards, PCB/tscircuit tools |-| `mdi:eye` | viewers |+| `mdi:eye` | viewers (AV) | | `mdi:bug` | bug-filing tools | | `mdi:chart-line` | visualizers | | `mdi:monitor-cellphone` | demo/desktop tools |
skills/hd-ui/SKILL.md+34−28
@@ -33,7 +33,7 @@ HD's window has these regions (top to bottom, left to right): - Panes are split and resizable  ### Setup Panel (bottom)-- Collapsible panel showing the setup-cascade steps+- Collapsible panel showing the setup-cascade steps (16 steps under the WSL2 runtime) - See `hd-setup` skill for details  ## Menus@@ -52,17 +52,17 @@ The main menu, opened by clicking the Adom logo at the top-left. Items are group - **Zoom** — webview zoom controls (− %  +) with persistence across launches - **Fullscreen** — toggle fullscreen - **Console** — show/hide the HD debug console window-- **Developer Tools** — open the webview developer tools+- **Developer Tools** — open WebView2 DevTools - **Dev Toolbar** — show/hide the Adom Dev Toolbar window (eval-in / shot / Claude control endpoints); bus id `dev-toolbar.toggle`  > The Bridges section / "Bridge Manager" item was removed (it was a no-op with no backing panel). For the bridge panel itself, see `hd-bridges`.  **Workspace / runtime section** (section label shows live status badge: `RUNNING`, `STOPPED`, etc.)-- **Restart** — restarts the workspace (terminates and re-ensures code-server). The exact mechanism is runtime-specific.-- **Stop** — stops the workspace. The exact mechanism is runtime-specific.+- **Restart** — restarts the workspace; under WSL2 this terminates the `Adom-Workspace` distro and re-ensures code-server, under the Docker runtime it's `docker restart <container>`.+- **Stop** — stops the workspace; under WSL2 this terminates the `Adom-Workspace` distro, under the Docker runtime it's `docker stop <container>`.  **ADMIN**-- **Setup Steps** — opens the setup panel (the setup cascade for the active runtime); see hd-setup-steps+- **Setup Steps** — opens the setup panel (the setup cascade for the active runtime; 16 steps under WSL2); see hd-setup-steps - **Virgin Reset** — opens the virgin reset section of the setup panel; see hd-volume for what each toggle deletes - **Browser Picker Manager** — configure per-domain default browser/profile prefs; see hd-browser-picker @@ -100,9 +100,9 @@ API — no CDP, no `.click()`, no selector guessing.** This is how you operate H user says "open the Ports dialog", "open About", "show settings", etc.  **Get the control URL from the discovery file** `~/.adom/hd-control-url` (HD rewrites it with-the live, dynamic control port every launch; it's the host loopback, reachable from the-workspace). Read it from a file, not an env var — your Bash tool runs non-interactive shells-that don't source `.bashrc`/`profile.d`:+the live, dynamic control port every launch; it's the host loopback, shared with the distro by+WSL2 mirrored networking). Read it from a file, not an env var — your Bash tool runs+non-interactive shells that don't source `.bashrc`/`profile.d`:  ```bash CTRL="$(cat ~/.adom/hd-control-url)"@@ -162,37 +162,43 @@ b64/silent) is in **[hd-self-screenshot](../hd-self-screenshot/SKILL.md)**. ## Legacy: raw CDP clicking (deprecated fallback — the command bus above is canonical)  ⚠ The command bus (`/ui/actions` → `/ui/invoke`) is the canonical way to drive HD's UI. Before-it existed, UI was driven by CDP `.click()` on CSS selectors via the HD CDP eval channel. This-is brittle (selectors drift; multiple `localhost:1420` CDP targets) and the selectors below may-be stale. Reach for CDP ONLY for an element not yet on the bus — and the better fix is to-register it. Eval JS against the CDP endpoint (its port comes from `/discover` as `cdp`).+it existed, UI was driven by CDP `.click()` on CSS selectors via hd-cdp.js. This is brittle+(selectors drift; multiple `localhost:1420` CDP targets) and the selectors below may be stale.+Reach for CDP ONLY for an element not yet on the bus — and the better fix is to register it.  ### Find and click menu items-```js-// Open Adom menu-document.querySelector('.logo-button')?.click()--// Find a menu item by text-var items = document.querySelectorAll('.dropdown-link,.menu-item');-var target = Array.from(items).find(function(e){return e.textContent.includes('Ports')});-if (target) target.click()+```bash+# Open Adom menu+echo document.querySelector('.logo-button')?.click() | node C:\Users\john\hd-cdp.js++# Find a menu item by text+echo var items=document.querySelectorAll('.dropdown-link,.menu-item');+var target=Array.from(items).find(function(e){return e.textContent.includes('Ports')});+if(target)target.click() | node C:\Users\john\hd-cdp.js ```  ### Click setup panel buttons-```js-document.querySelector('.run-all').click()                 // Run All-document.querySelector('.virgin-reset-btn')?.click()       // Virgin Reset dropdown-document.querySelector('.virgin-go')?.click()              // Wipe Selected (execute virgin reset)-document.querySelector('.close-btn,.setup-close')?.click() // Close setup panel+```bash+# Run All+echo document.querySelector('.run-all').click() | node C:\Users\john\hd-cdp.js++# Virgin Reset dropdown+echo document.querySelector('.virgin-reset-btn')?.click() | node C:\Users\john\hd-cdp.js++# Wipe Selected (execute virgin reset)+echo document.querySelector('.virgin-go')?.click() | node C:\Users\john\hd-cdp.js++# Close setup panel+echo document.querySelector('.close-btn,.setup-close')?.click() | node C:\Users\john\hd-cdp.js ```  ### Query step states-```js-JSON.stringify(Array.from(document.querySelectorAll('.step-row')).map(+```bash+echo JSON.stringify(Array.from(document.querySelectorAll('.step-row')).map( function(e,i){   var icon=e.querySelector('.step-icon');   return{n:i+1, s:icon?.textContent?.trim()}-}))+})) | node C:\Users\john\hd-cdp.js ```  ## CSS Selectors for Key Elements
skills/hd-webview/SKILL.mdadded+55
@@ -0,0 +1,55 @@+---+name: hd-webview+description: >+  WEBVIEW — what the word "webview" means in Hydrogen Desktop and exactly how to+  open one. When the user says "show me in webview", "open it in webview", "in a+  webview", "webview panel", "wv", or asks to show ANY app/page/tool "in webview",+  it ALWAYS means a native Hydrogen workspace Web View tab opened via+  `adom-cli hydrogen webview open-or-refresh` — NEVER VS Code's built-in Simple+  Browser, never an editor-internal browser, never an iframe hack. Read this the+  moment the word webview (or wv) appears. Trigger words — webview, wv, show me+  in webview, open in webview, in a webview, webview tab, webview panel, native+  webview, show in webview, launch in webview, webview app.+---++# hd-webview — "webview" means a native Hydrogen Web View tab. Period.++When a user (or a setup prompt) says **"show me X in webview"**, they mean a+**native Hydrogen Desktop Web View tab** — a first-class panel in the HD+workspace, next to their editor. Nothing else qualifies.++## ⛔ NEVER (the 2026-07-16 incident — do not repeat)++- **NEVER open VS Code's built-in "Simple Browser"** (or any editor-internal+  browser page) to satisfy a webview request. A setup-thread AI did this once —+  the user called it "an awful outcome that can never happen again." The Simple+  Browser is not the HD webview: it's cramped, it isn't a workspace tab, and it+  breaks every downstream flow (screenshots, captions, panel routing).+- Don't fall back silently to pup or a native browser either — those are+  *different, deliberate* destinations (see `hd-open-url` for the decision+  guide). "webview" is not ambiguous; it names exactly one thing.++## ✅ The exact command (idempotent — safe to re-run)++```bash+# open (or refresh, if a tab with this name already exists) a Web View tab:+adom-cli hydrogen webview open-or-refresh --name "<Tab Name>" --url "<url>" --panel-id <id>++# ⚠️ --panel-id is REQUIRED to CREATE a new tab (without it: "Tab 'X' not found+#    and --panel-id not provided"). Get a panel id first:+adom-cli hydrogen workspace get        # or: adom-cli hydrogen workspace tabs+# Re-running with the same --name once the tab exists just navigates/refreshes+# (no --panel-id needed). The --name is your stable handle.+```++Local Adom apps (parts search, chip-fetcher, adom-tsci previews, wiki pages)+are all shown this way: start/locate the app's local URL, then+`open-or-refresh` it into a named tab.++## Verify you actually did it++The tab must appear in `adom-cli hydrogen workspace tabs` with your `--name`.+If it isn't there, you did NOT open a webview — go again.++For the broader "which surface should this URL open in?" decision (webview vs+pup vs native browser vs headless fetch), see **hd-open-url**.
skills/hd-welcome/SKILL.md+8−8
@@ -24,15 +24,16 @@ It's served locally at `http://localhost:1420/welcome.html` by HD's dev file ser  ## When it appears -- Automatically as the final setup step — the `open-welcome` gate (the last step of the-  setup cascade for the active runtime).+- Automatically as the final setup step. On the WSL2 runtime (default) that is+  the `open-welcome` gate (step 16 of 16); on the legacy Docker runtime it's+  the last of the 24 steps. - Can be opened manually via the API  ## How to open it -### From inside the workspace (the standard way)+### From inside the Docker container (the standard way) -This is how the setup steps do it, and how any AI inside the workspace should:+This is how the setup steps do it, and how any AI inside the container should:  ```bash adom-cli hydrogen webview open-or-refresh \@@ -41,9 +42,8 @@ adom-cli hydrogen webview open-or-refresh \   --panel-id desktop-pane-right ``` -`localhost:1420` is HD's dev file server running on the host (where HD itself runs),-NOT anything inside the workspace. HD's webview renders the URL against the host, so the-page resolves on whatever platform HD is running on.+The URL is rendered by HD's WebView2 on Windows, so `localhost:1420` resolves+to HD's dev file server on Windows, NOT to anything inside the container.  ### From outside (via HD control API) @@ -67,7 +67,7 @@ curl -X POST http://127.0.0.1:47083/api/workspaces/editor/{owner}/{repo}/current ## IMPORTANT: This is NOT  - NOT the adom.inc homepage (https://adom.inc)-- NOT the Adom wiki (https://wiki.adom.inc)+- NOT the wiki (https://git-wiki-*.adom.cloud) - NOT the VS Code welcome tab inside code-server  It is a LOCAL static page at `http://localhost:1420/welcome.html`, bundled
skills/hd-who-am-i/SKILL.md+2−2
@@ -49,7 +49,7 @@ Tell them they have access to a full electronics prototyping ecosystem. Specific Adapt this to whatever the user's data is. Don't bullet-dump everything — write it as a warm welcome paragraph followed by capabilities. Use markdown.  ```markdown-You're **{user.formatted_name}**, signed in to Adom as **{user.name}** ({user.email}). You're running in **Hydrogen Desktop**, Adom's local AI dev environment, on your Windows machine. The workspace itself is Ubuntu 24.04 with code-server, the `claude` CLI, and the full Adom skill ecosystem (adompkg + HD skills) already loaded.+You're **{user.formatted_name}**, signed in to Adom as **{user.name}** ({user.email}). You're running in **Hydrogen Desktop**, Adom's local AI dev environment, on your Windows machine. The workspace itself is Ubuntu 24.04 with code-server, the `claude` CLI, and the full Adom skill ecosystem (gallia + HD skills) already loaded.  A few quick orientation notes: - Your **Linux username here is `adom`** (not `{user.name}`) — that's intentional, every Adom workspace uses `adom` for consistency. Your Adom identity (`{user.name}`) is what shows up across the Adom ecosystem.@@ -81,7 +81,7 @@ Ask me to do any of those, or just ask "what's the best way to start a new PCB p  - **Don't just bullet-dump every capability** — group them, lead with the personalized intro, end with an invitation. - **Pull real numbers** from `adom-cli` — generic "you have some repos" feels worse than "you have 4 repos."-- **Don't list internal jargon** — say "Adom's autorouter", not "the autorouter/v2 skill".+- **Don't list internal jargon** — say "Adom's autorouter", not "the gallia/autorouter/v2 skill". - **Mention the Linux username quirk early** — it WILL confuse users on first `whoami`. - **If a data fetch fails** (e.g. adom-cli not yet configured), gracefully say "I can't read your Adom session right now, but here's what HD can do once you're signed in" and pivot to capabilities only. 
skills/hd-wiki-review/SKILL.mdadded+48
@@ -0,0 +1,48 @@+---+name: hd-wiki-review+description: >+  After editing ANY wiki.adom.inc page (an adom-wiki push/publish, a README/doc/hero change),+  immediately LOAD that page in pup so the user can see and double-check the rendered result —+  don't just report the commit hash and move on. Covers how to open the page in pup on the+  user's machine, refresh it, and post a screenshot to the shotlog for review.+  Trigger words: wiki update, adom-wiki push, adom-wiki publish, wiki page, show wiki in pup,+  review wiki, verify wiki page, load wiki page, wiki hero, wiki readme, double-check wiki.+---++# Show every wiki edit in pup for review++Whenever you change a wiki.adom.inc page — `adom-wiki repo push`, `adom-wiki pkg publish`, or+any edit to a page's README / docs / hero — **open that page in pup right away** so the user+can eyeball the rendered result. A successful push is not proof the page looks right; the user+wants to verify it. Never stop at "pushed, commit abc123."++## Do this after every wiki change++```bash+# 1. Push / publish the page (the change itself).+adom-wiki repo push <slug> -m "…" --files README.md docs/foo.md+#    (or: adom-wiki pkg publish --org adom)++# 2. Immediately load the page in pup on the user's machine so they can review it.+adom-desktop browser_open_window '{"sessionId":"wiki-review","profile":"wiki-review","url":"https://wiki.adom.inc/<owner>/<slug>"}'+#    Already open from a prior review? Refresh + cache-bust instead of opening a duplicate:+#    adom-desktop browser_navigate '{"sessionId":"wiki-review","url":"https://wiki.adom.inc/<owner>/<slug>?cb=2"}'++# 3. Screenshot it and post to the shotlog with a one-line description, then hand the user the URL.+```++## Rules++- **Always the real `https://wiki.adom.inc/...` URL** — never a `localhost:<port>` (pup/webviews+  can't reach those).+- **Proactive, not offered** — load it without being asked; the whole point is the user reviews+  every wiki change as it happens.+- **Wiki ops go through the `adom-wiki` CLI**, not raw API calls.+- Keep related content on ONE page (e.g. all Hydrogen Desktop docs live on the `hydrogen-desktop`+  page) — don't spray a new wiki page per small doc.++## Why++The user runs the same setup as every Adom user and validates the shared experience by eye.+Loading each wiki edit in pup closes the loop: they confirm the page renders correctly (hero,+screenshots, links, formatting) instead of trusting a silent push.
skills/hd-workspace-updater/SKILL.md+1−1
@@ -1,6 +1,6 @@ --- name: hd-workspace-updater-description: How Hydrogen Desktop keeps THIS workspace's Adom tooling up to date, and how an Adom employee ships a skill / extension / CLI to EVERY Adom workspace automatically. Use when asked "how do I get the latest skills or tooling from Adom", "how are updates delivered here", "what's the reload banner", "how do I make a skill that distributes to all Adom users", "how do I publish tooling to every workspace". Trigger words: workspace updater, adom-workspace-updater, latest skills, get updates, how do updates work, auto update, distribute a skill, publish to all users, ship to every workspace, reload banner.+description: "How Hydrogen Desktop keeps THIS workspace's Adom tooling up to date, and how an Adom employee ships a skill / extension / CLI to EVERY Adom workspace automatically. Use when asked \"how do I get the latest skills or tooling from Adom\", \"how are updates delivered here\", \"what's the reload banner\", \"how do I make a skill that distributes to all Adom users\", \"how do I publish tooling to every workspace\". Trigger words: workspace updater, adom-workspace-updater, latest skills, get updates, how do updates work, auto update, distribute a skill, publish to all users, ship to every workspace, reload banner." ---  # How this workspace stays up to date — and how to ship to every workspace