bootstrap
Adom Hydrogen (Windows / WSL2)
Public Made by Adomby adom
The Windows (WSL2) platform layer for Hydrogen.
← Commit history
Publish 0.3.29
46 files changed
+968−2
package.json+1−1page.json+1−1skills/hydrogen-adom-auth-windows/._SKILL.mdskills/hydrogen-adom-bridge-triage/._SKILL.mdskills/hydrogen-adom-bridge-triage/SKILL.md+241skills/hydrogen-ai-threads-api/._SKILL.mdskills/hydrogen-ai-threads/._SKILL.mdskills/hydrogen-annotate/._SKILL.mdskills/hydrogen-annotate/SKILL.md+109skills/hydrogen-api-windows/._SKILL.mdskills/hydrogen-api-windows/SKILL.md+102skills/hydrogen-bridges/._SKILL.mdskills/hydrogen-browser-picker/._SKILL.mdskills/hydrogen-captions-windows/._SKILL.mdskills/hydrogen-container-stats-windows/._SKILL.mdskills/hydrogen-container-windows/._SKILL.mdskills/hydrogen-demo-recording/._SKILL.mdskills/hydrogen-desktop-sse-windows/._SKILL.mdskills/hydrogen-dock-windows/._SKILL.mdskills/hydrogen-dock-windows/SKILL.md+40skills/hydrogen-editor-state/._SKILL.mdskills/hydrogen-editor-state/SKILL.md+52skills/hydrogen-embedded-bridge/._SKILL.mdskills/hydrogen-file-transfer/._SKILL.mdskills/hydrogen-golden-image/._SKILL.mdskills/hydrogen-lightbulb/._SKILL.mdskills/hydrogen-lightbulb/SKILL.md+74skills/hydrogen-notifications-windows/._SKILL.mdskills/hydrogen-permissions-windows/._SKILL.mdskills/hydrogen-project-workspaces/._SKILL.mdskills/hydrogen-project-workspaces/SKILL.md+53skills/hydrogen-recording/._SKILL.mdskills/hydrogen-runtime-mode/._SKILL.mdskills/hydrogen-screen-lock/._SKILL.mdskills/hydrogen-setup-steps-windows/._SKILL.mdskills/hydrogen-setup-windows/._SKILL.mdskills/hydrogen-skill-catalog/._SKILL.mdskills/hydrogen-skill-catalog/SKILL.md+8skills/hydrogen-skill-loop-windows/._SKILL.mdskills/hydrogen-wake-repair/._SKILL.mdskills/hydrogen-webview-windows/._SKILL.mdskills/hydrogen-webview-windows/SKILL.md+22skills/hydrogen-widget/._SKILL.mdskills/hydrogen-widget/SKILL.md+265skills/hydrogen-workspace-monitoring-windows/._SKILL.mdskills/hydrogen-wslg/._SKILL.mdpackage.json+1−1@@ -4,7 +4,7 @@ "type": "bootstrap", "title": "Adom Hydrogen (Windows / WSL2)", "brief": "The Windows (WSL2) platform layer for Hydrogen.",- "version": "0.3.28",+ "version": "0.3.29", "description": "The Windows platform layer for Hydrogen, where the workspace runs in a WSL2 Ubuntu distro. Depends on adom/hydrogen-bootstrap (the platform-generic layer, which bundles the generic hydrogen-* skills) and adds everything specific to the WSL2 runtime: the WSL2/networking/lifecycle hydrogen-* skills (BUNDLED here by design, John+Kyle 2026-07-16) and the WSL2 code-server workbench seed. Sibling adom/hydrogen-mac-bootstrap carries the parallel mac skills. This is the package the golden WSL2 image installs.", "org": "adom", "tags": [
page.json+1−1@@ -4,7 +4,7 @@ "slug": "hydrogen-windows-bootstrap", "title": "Adom Hydrogen (Windows / WSL2)", "brief": "The Windows (WSL2) platform layer for Hydrogen.",- "version": "0.3.28",+ "version": "0.3.29", "author": { "name": "John Lauer", "email": "[email protected]"
skills/hydrogen-adom-auth-windows/._SKILL.mdadded⋯ 1 unchanged line ⋯
skills/hydrogen-adom-bridge-triage/._SKILL.mdadded⋯ 1 unchanged line ⋯
skills/hydrogen-adom-bridge-triage/SKILL.mdadded+241@@ -0,0 +1,241 @@+---+name: hydrogen-adom-bridge-triage+description: >+ Triage Adom Bridge (ab) when it will not connect from a Hydrogen workspace —+ especially the case where ab CRASHES ON BOOT because a bad release shipped,+ which looks identical to "not installed" / "not signed in" from the container+ side. Teaches the cheapest-first diagnostic ladder (read ab's crash.log BEFORE+ touching any config), the two out-of-band channels that work while ab is dead+ (Hydrogen's control API and WSL2 interop), how to compare the installed build+ against the wiki and install the fix, and the config changes you must NOT make+ while guessing. Read this when `adom-bridge ping` says no desktop client is+ connected, when the user says the app "never actually starts", when it starts+ and vanishes, or when hydrogen-doctor's adom-bridge / adom-bridge-direct check+ fails. Trigger words: adom bridge won't start, ab won't connect, bridge not+ connected, no desktop client connected, ab never starts, ab starts then+ disappears, bridge offline, ab crash loop, ab crashing on boot, bad ab release,+ connectedClients 0, adom-bridge-direct failed, bridge keeps dying, ab tray+ missing.+---++Parent skill: **hydrogen-adom-bridge** (works with **hydrogen-doctor**, **hydrogen-key-values**, **adom-bridge**)++# Triage: Adom Bridge won't connect++`ping` returning **"No desktop client connected"** tells you only that the+desktop half is absent. It does **not** tell you whether ab is uninstalled,+signed out, misconfigured, or **installed and crash-looping**. Those need+opposite fixes, and the last one is invisible from the container unless you+go looking for it.++> **The failure that motivated this skill.** ab 2.0.91 panicked on startup,+> died in under a second, and was respawned by Hydrogen's supervisor every+> ~30-60s — 367 times over ~3 hours. From the container it looked exactly like+> "the user never installed it." The user's own words were *"when I launch it+> from the Windows menu it never actually starts."* The fix was one version+> newer on the wiki. Time wasted before reading `crash.log`: most of the session.++## The ladder — cheapest first, and read crash.log EARLY++### 1. Which half is broken? (container-side, free)++```bash+curl -sf http://127.0.0.1:8766/health # connectedClients, usingDefaultToken+adom-bridge --ai-thread "<your thread>" ping+adom-bridge --ai-thread "<your thread>" targets+```++`connectedClients: 0` with a healthy relay ⇒ the container is fine; **every+remaining step is about the desktop**. Do not start reconfiguring the container.++### 2. Ask Hydrogen — it can see the host while ab is dead++Hydrogen's control API (`127.0.0.1:47084`, port from+`~/.adom/hydrogen-ports.json`) is reachable from the workspace and does **not**+depend on ab:++```bash+curl -s http://127.0.0.1:47084/diagnostics/all | python3 -m json.tool+```++Look for the `adom-bridge-direct` check. Its failure text names the cause and+carries a `fix` field. Note it probes ab's direct API, so read the port caveat+in **Gotchas** below before trusting a "silent range" message.++### 3. **Read ab's crash log. Do this before touching any config.**++This is the step that collapses a long session into two minutes.++| What | Windows path | From a WSL2 workspace |+|---|---|---|+| Crash log | `%LOCALAPPDATA%\Adom Bridge\crash.log` | `/mnt/c/Users/<user>/AppData/Local/Adom Bridge/crash.log` |+| Install dir | `%LOCALAPPDATA%\Adom Bridge\` | same, without `crash.log` |+| Direct-API port | `%USERPROFILE%\.adom\direct-api-port` | `/mnt/c/Users/<user>/.adom/direct-api-port` |+| Embedded marker | `%LOCALAPPDATA%\Adom Bridge\embedded.json` | same |+| Server list | `%USERPROFILE%\.adom\config.json` | `/mnt/c/Users/<user>/.adom/config.json` |++```bash+C="/mnt/c/Users/<user>/AppData/Local/Adom Bridge/crash.log"+ls -l "$C" # mtime is the whole story+tail -40 "$C"+```++**Read the mtime first.** A `crash.log` modified *seconds or minutes ago* means+ab is crash-looping **right now** — it is installed, it is being launched, and+it is dying. That single fact rules out the entire "not installed / not signed+in / wrong URL" branch you were about to explore.++A crash loop looks like one repeating panic with a marching clock:++```+[2026-08-31 19:44:04] PANIC: panicked at src\carbon_runtime.rs:113:5:+there is no reactor running, must be called from the context of a Tokio 1.x runtime+[2026-08-31 19:44:55] PANIC: panicked at src\carbon_runtime.rs:113:5:+...+```++Useful shape checks:++```bash+grep -c "PANIC" "$C" # how bad+grep -n "PANIC" "$C" | head -3 # when it STARTED+grep -v "carbon_runtime\|no reactor running" "$C" | tail # other panic classes+```++A panic in a path under `src\...` is **ab's own code** — i.e. a shipped+regression, not a broken machine. A panic inside `.cargo\registry\...` is a+dependency/host-environment issue and usually a different story.++### 4. Compare the installed build against the wiki++```bash+"/mnt/c/Users/<user>/AppData/Local/Adom Bridge/adom-bridge-cli.exe" --version+adom-wiki release list adom/adom-bridge # newest version + assets+```++A `-dirty` suffix in the installed version means it was built locally, not+installed from a signed wiki release — common on a developer's own machine and+a strong hint that it is ahead of, or diverged from, anything published.++If the installed build is older than the wiki's newest **and** `crash.log`+shows a repeating panic, **the newer release is the fix**. Go to step 5.++### 5. Install the newer release++```bash+adom-wiki release download adom/adom-bridge <version> # verifies integrity+sha256sum ./Adom.Bridge_<version>_windows_x64-setup.exe # confirm independently++cp ./Adom.Bridge_<version>_windows_x64-setup.exe /mnt/c/Users/<user>/AppData/Local/Temp/+cd /mnt/c/Users/<user>/AppData/Local/Temp+/mnt/c/Windows/System32/taskkill.exe /F /IM adom-bridge.exe # release the mmap lock+./Adom.Bridge_<version>_windows_x64-setup.exe /S /NOLAUNCH+tr -d '\r' < ./adom-bridge-install.log | tail -20 # [START]...[DONE]+```++**Use `/NOLAUNCH` when Hydrogen manages ab** (the usual case in a Hydrogen+workspace — see the `hd-managed` marker in the install dir). Hydrogen's+supervisor spawns ab itself with `--embedded --start-hidden --relay-url+... --session-token ...`; let it, or you get a standalone instance that the+single-instance logic then fights.++### 6. Verify — three independent signals, not one++```bash+sleep 45 # let the supervisor respawn+/mnt/c/Windows/System32/tasklist.exe /FI "IMAGENAME eq adom-bridge.exe"+curl -sf http://127.0.0.1:24680/health # {"service":"adom-bridge","pid":...}+adom-bridge --ai-thread "<thread>" targets # name, os, version+ls -l "$C" # crash.log mtime must STOP advancing+```++The crash.log mtime going quiet is the one that proves you fixed the loop+rather than catching ab between crashes. Give it more than one crash interval+before declaring success.++## The out-of-band channels (why you are not blind)++When ab is dead you have not lost the host — you have lost one route to it.++1. **Hydrogen's control API** — `127.0.0.1:47084`, always up if Hydrogen is+ running. Diagnostics, ports, container state. See `hydrogen-api`.+2. **WSL2 interop (Windows hosts)** — a Hydrogen Windows workspace is a WSL2+ distro, so `/mnt/c` is the real Windows filesystem and Windows `.exe`s are+ directly executable from the workspace:++ ```bash+ ls /mnt/c/Users # is it mounted?+ cat /proc/sys/fs/binfmt_misc/WSLInterop # "enabled"?+ /mnt/c/Windows/System32/tasklist.exe # proof it works+ ```++ This is how you read crash logs, check versions, and run an installer+ **without ab**. On macOS/Linux Hydrogen hosts this section does not apply;+ use the platform bootstrap's equivalent and the control API.++## Do NOT do these while guessing++Every one of these was tried during the incident above. None helped, and the+first two left changes that had to be reverted.++| Don't | Why |+|---|---|+| `register_container` when Hydrogen already manages ab | Creates a **second** connection to the same workspace relay alongside the managed `hydrogen` entry — a duplicate path the user sees in the Connections list. It also writes **three** cloud keys, not one. Check for the managed entry / the `hd-managed` marker first. |+| Rotate the relay auth token | For a cloud container the auth model is the **Adom account**, not a relay token — `setup_desktop` deliberately emits `auth_token: ""`. Rotating adds a mismatch failure mode to a system that is already broken, and the relay's `usingDefaultToken` warning assumes a directly-exposed port, which a proxied container relay is not. |+| Conclude "not installed" / "not signed in" from `ping` alone | Indistinguishable from a crash loop without reading `crash.log`. |+| Restart the relay, re-register, re-sign-in as a first move | All container-side; none of them touch a desktop process that is panicking. |++## Reverting a mistaken `register_container`++If you (or a previous agent) registered a container that should not exist,+removing it locally is **not enough** — ab re-reads the cloud profile at boot,+at sign-in, and hourly, so a local-only removal comes back. Remove both:++```bash+TOK=$(cat /var/run/adom/api-key)++# 1. cloud profile (the authoritative copy)+curl -s -X PATCH https://carbon.adom.inc/user/hydrogen/settings \+ -H "Authorization: Bearer $TOK" -H 'Content-Type: application/json' \+ -d '{"key":"bridge.container.<id>","value":null}'++# 2. ab's local list+adom-bridge --ai-thread "<thread>" \+ server_remove '{"name":"<name>","reason":"<why>"}'+```++`register_container` writes **`bridge.container.<id>`, `bridge.last_slug`, and+`bridge.enabled`**. `bridge.last_slug` will be left pointing at the entry you+just deleted; null it too. Its previous value is **not recoverable** — which is+the real argument for not calling `register_container` speculatively.++Verify with `server_list` and by re-reading `hydrogen_preferences.settings`+(see `hydrogen-key-values`). Removing a relay entry you are *talking through*+severs your own transport (adom/adom-bridge#387) — check `ping`'s `transport`+field first; if it says `direct-http` you are on the loopback API and a relay+entry removal cannot cut you off.++## Gotchas that cost time++- **ab's direct API is on `24680`** (stable since ab 2.0.27); `47200-47209` is+ legacy. A diagnostic that probes only the legacy range can report ab+ unreachable when it is merely elsewhere. `%USERPROFILE%\.adom\direct-api-port`+ is authoritative (written at bind, removed on clean shutdown), so a *stale*+ file plus a silent port is itself a crash signal.+- The 2.0.92 installer reserves `24680-24689` via `netsh excludedportrange`+ (best-effort, needs elevation) to stop Windows HNS grabbing the range.+- **Caller identity is mandatory.** Verbs refuse with+ `errorCode: caller_identity_required` unless you pass+ `--ai-thread "<a name the user would recognize>"`. Gated verbs additionally+ need a per-call `reason`. See `adom-bridge-caller-identity`.+- `embedded.json` with `entered_via: "launch-flag"` plus a dead Hydrogen makes+ ab exit by design ("no hanging chad"). Pre-1.8.74 builds did not delete the+ stale marker, leaving ab unlaunchable — a different crash-on-boot cause with+ the same symptom, so confirm which one `crash.log` actually shows.++## When it is genuinely not a crash++If `crash.log` is old and quiet and no ab process exists, you are in ordinary+setup territory: installed? signed in? does the workspace's connection appear+in the Connections list? Then follow `adom-bridge` / `adom-bridge-auth`. The+point of this skill is to make you *prove* that before you go there.
skills/hydrogen-ai-threads-api/._SKILL.mdadded⋯ 1 unchanged line ⋯
skills/hydrogen-ai-threads/._SKILL.mdadded⋯ 1 unchanged line ⋯
skills/hydrogen-annotate/._SKILL.mdadded⋯ 1 unchanged line ⋯
skills/hydrogen-annotate/SKILL.mdadded+109@@ -0,0 +1,109 @@+---+name: hydrogen-annotate+version: 1.1.0+description: >+ Annotate in Hydrogen Desktop: the pencil in the Title Bar (left of the bell), or Win+Alt+A from+ any app, lets the human draw on top of the whole screen, any app (KiCad, a browser, a jump list,+ Hydrogen), with a red circle, an arrow, a box, a text note or a plain snip, and puts the+ marked-up area on the clipboard as a PNG, ready to paste into an AI thread. Covers the tools, Auto versus Multi capture, the keys, what the AI can do (POST+ /annotate opens the overlay for the human; the AI itself takes screenshots with+ POST /screenshot, not with annotate), and how to read what the user pasted. Trigger words:+ annotate, annotation, draw on the screen, red circle, circle it, mark it up, markup,+ pencil icon, pencil in the title bar, snip, snip a region, paste a screenshot into the chat,+ /annotate, annotate overlay, arrow on the screenshot, box on the screenshot, win+alt+a,+ annotate shortcut, annotate hotkey setting, annotate the desktop, draw over kicad, desktop annotate.+---++# Annotate: draw on the screen, paste it into your AI thread++## On the whole desktop (Hydrogen 1.0.612+)++Annotate draws **on top of any app, on the monitor the pointer is on**, and never gets in the way:++- Start it from anywhere with **Win+Alt+A**, or click the pencil. Settings > Hydrogen > Annotate+ turns the shortcut off, and says so when another program already holds it. (Win+Shift+A and+ Win+Shift+M belong to Windows; Alt+Shift+A is VS Code's Toggle Block Comment.)+- **Hold Ctrl and drag to draw.** Everything else, every click, the wheel, hovering and every key+ except Enter and Esc, still goes to your apps. So you can right-click a taskbar icon, and with+ its jump list open, Ctrl+drag a circle around the item: the jump list stays open.+- **Enter** copies, **Esc** cancels. Nothing is captured before Enter (in the default Multi);+ one-shot Auto captures when you let go of the mouse.+- The toolbar is its own small window, dragged by its grip, and it never takes the focus. It has+ Pen, Arrow, Box, Snip, six colours, Auto/Multi, Undo, Clear, Done, and **Drag draws**, which+ draws with a plain drag instead of Ctrl+drag (clicks then draw instead of reaching your apps).+- The capture is the area around the drawing with the drawing on it, on the clipboard as PNG (and+ as a bitmap), saved in `%APPDATA%\hydrogen-desktop\annotations`. A small card at the+ bottom-right shows it (Copy again, Show file); it never takes focus and leaves after 8 seconds.++The shortcut is per machine: `GET /annotate/hotkey` reads it, `POST /annotate/hotkey+{"enabled": false}` turns it off.++The pencil in Hydrogen's **Title Bar**, left of the bell and right of the CPU/RAM meter, is+**Annotate**. It puts a drawing canvas over the whole Hydrogen window (the editor, the wiki,+every panel; they are all under the same canvas), with the same toolbar pup uses. The human+draws, and the area around the drawing is captured and written to the clipboard as a PNG.+The point is the next step: paste it into an AI thread and say "this one".++## What the human sees++| Tool | What it does |+|---|---|+| Pen | Draw freehand. With Auto on, the capture fires the moment the mouse is released. |+| Arrow | Drag from tail to tip; the arrowhead lands where the mouse is released. |+| Box | Frame a region with a rectangle, corner to corner. |+| Text | Click where the note starts, type, press Enter. |+| Snip | Capture exactly a region, like Win+Shift+S: drag a marquee, it is copied on release, no strokes. |++Colours: red, blue, yellow on the bar, more one click deeper. Two capture modes:++- **Auto** (default): one shot. Draw one thing, lift the mouse, and it is captured, copied,+ and annotate mode closes. This is the "red circle" case.+- **Multi**: compose. Draw several shapes; nothing is captured until Done. The colour+ advances after each shape so every shape is distinct.++The capture is the composited window with the drawing on it, cropped tight around everything+drawn. A toast confirms it: "Captured 640×320, on your clipboard. Paste it into an AI thread."++Keys: **Enter** = Done (capture and close), **Esc** = leave without capturing, **Ctrl+Z** = undo+the last shape. Undo and Clear are on the bar too.++## What the AI does with it++**You do not need annotate to see the screen.** To look at Hydrogen yourself, take a+screenshot: `POST /screenshot` on the control API (the `hydrogen-self-screenshot` skill), or+`adom-bridge desktop_screenshot_window`. Annotate exists for the **human** to point at+something.++When the user pastes an annotated PNG into your thread, treat the drawing as the pointer: the+circled, boxed or arrowed thing is what they mean, and a text note is their comment. Read the+image before answering.++You can open the overlay for the human when that is the fastest way to get an answer ("circle+the part you mean"):++```bash+adom-bridge --target <desktop> hd_api '{"method":"POST","path":"/annotate","body":{"tool":"pen","mode":"auto"}}'+```++`tool` is pen | arrow | box | text | snip (default pen), `mode` is auto | multi, `scope` is+desktop (the default since 1.0.611: the whole monitor, any app) or window (inside Hydrogen only),+`close: true` dismisses the overlay. The response says whether the window took it+(`ok`). Then say what you want them to mark and wait; the result lands on **their**+clipboard, not in your context, so ask them to paste it. Do not open the overlay while they are+typing or during a demo recording without saying so first; it covers the whole window until Esc.++## Where it lives++- The pencil: `src/lib/components/editor/EditorNav.svelte` (button next to the meters).+- The overlay and toolbar: `src/lib/components/AnnotateOverlay.svelte`, driven by+ `src/lib/stores/annotate.ts` (`startAnnotate(tool, mode)`, `closeAnnotate()`).+- The route: `POST /annotate` in `src-tauri/crates/hydrogen-control/src/lib.rs`.+- The capture itself is `POST /screenshot` with `target=full`, cropped in the overlay.+- Desktop mode: `src-tauri/crates/hydrogen-app/src/desktop_annotate.rs` (the overlay and preview+ windows, the capture, the clipboard, the hotkeys), the `annotate-desktop` route with+ `src/lib/components/annotate/DesktopOverlay.svelte` and `DesktopPreview.svelte`, and the shared+ tools in `src/lib/annotate/draw.ts`.++Related: `hydrogen-self-screenshot` (the AI's own screenshots), `hydrogen-captions` (text+overlays the AI puts on screen for narration; not for marking things up), `hydrogen-pup`+(pup's annotate, the same toolbar in the browser window).
skills/hydrogen-api-windows/._SKILL.mdadded⋯ 1 unchanged line ⋯
skills/hydrogen-api-windows/SKILL.md+102@@ -102,3 +102,105 @@ HD's webview is **WebView2** on Windows; `/cdp-eval`, `/cdp-info`, and | 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 | (Gated behind `HD_TEST_API_ENABLED=1`, like the rest of `/test/*`.)++## Moved from the generic hydrogen-api (Windows-only, 2026-10-21)++These endpoints exist only in the Windows Hydrogen; the macOS app does not serve them.++## ab-health diagnostics (`/ab/*`)++(Canonical since 1.0.47; the old `/ad/*` spellings still answer as aliases.)++These verify the **adom-bridge / relay / embedded-ab** half of Hydrogen is alive (the+bridge that connects this cloud container to Hydrogen). All GET, all return `{ok, ...}`.++| Method | Path | Description |+|---|---|---|+| GET | `/ab/health` | Overall embedded-ab health roll-up |+| GET | `/ab/process` | Is the adom-bridge process running |+| GET | `/ab/embedded` | Embedded-ab module status |+| GET | `/ab/workspace-direct` | ⭐ The **converged** check — direct path to the workspace relay (use this one) |+| GET | `/ab/relay` | Relay (WS/HTTP) reachability |+| GET | `/ab/liveness-beacon` | Liveness beacon freshness |+| GET | `/ab/direct-api` | Direct-API reachability |+| GET | `/ab/discovery-file` | Discovery file present + parseable |++### Workspace / WSL endpoints++| 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 |++### Windows-only route groups++**Adom Bridge** (19)++- `GET /ab/direct-api`+- `GET /ab/discovery-file`+- `GET /ab/embedded`+- `GET /ab/health`+- `GET /ab/liveness-beacon`+- `GET /ab/permissions`+- `POST /ab/permissions/request`+- `POST /ab/permissions/revoke`+- `GET /ab/process`+- `GET /ab/relay`+- `GET /ab/settings`+- `POST /ab/settings`+- `POST /ab/show`+- `POST /ab/toast-ack`+- `POST /ab/verb`+- `GET /ab/workspace-direct`+- `POST /direct/command`+- `GET /direct/health`+- `GET /direct/status`++**Dock** (6)++- `GET /dock/apps`+- `POST /dock/close`+- `POST /dock/launch`+- `POST /dock/refresh`+- `POST /dock/reset`+- `POST /dock/result`++**Editor State Machine (ESM)** (4)++- `POST /editor/audit-prompt`+- `POST /editor/bars`+- `POST /editor/normalize`+- `GET /editor/state`++**Hydrogen Browser Window** (9)++- `GET /hbw/chrome`+- `POST /hbw/chrome-toggle`+- `POST /hbw/close`+- `POST /hbw/nav`+- `POST /hbw/open`+- `GET /hbw/state`+- `GET /hbw/tip`+- `GET /hbw/tip-state`+- `POST /hbw/tooltip`++**Settings** (2)++- `GET /settings/external-changes`+- `POST /settings/rebroadcast`++**Widgets** (7)++- `GET /widgets`+- `POST /widgets/close`+- `POST /widgets/menu`+- `POST /widgets/navigate`+- `POST /widgets/open`+- `POST /widgets/refresh`+- `GET /widgets/status`+
skills/hydrogen-bridges/._SKILL.mdadded⋯ 1 unchanged line ⋯
skills/hydrogen-browser-picker/._SKILL.mdadded⋯ 1 unchanged line ⋯
skills/hydrogen-captions-windows/._SKILL.mdadded⋯ 1 unchanged line ⋯
skills/hydrogen-container-stats-windows/._SKILL.mdadded⋯ 1 unchanged line ⋯
skills/hydrogen-container-windows/._SKILL.mdadded⋯ 1 unchanged line ⋯
skills/hydrogen-demo-recording/._SKILL.mdadded⋯ 1 unchanged line ⋯
skills/hydrogen-desktop-sse-windows/._SKILL.mdadded⋯ 1 unchanged line ⋯
skills/hydrogen-dock-windows/._SKILL.mdadded⋯ 1 unchanged line ⋯
skills/hydrogen-dock-windows/SKILL.mdadded+40@@ -0,0 +1,40 @@+---+name: hydrogen-dock-windows+description: >+ Windows-only dock control: drive the dock from an AI thread through the control API (GET /dock/apps, POST /dock/launch, /dock/close, /dock/refresh, /dock/reset) — the ralph loop and back-to-defaults. Trigger words — dock launch, /dock/apps, relaunch dock app, dock reset, ralph loop.+---++# hydrogen-dock-windows — Windows companion to hydrogen-dock++Read **hydrogen-dock** (platform-generic) first. The parts below exist only in the Windows Hydrogen;+the macOS app does not have them.++## Driving the dock from an AI thread (the ralph loop)++You do not click. ah's control API (see the hydrogen-api skill for the base URL and+`hd_api`) presses the dock for you and hands back what happened, so the loop is:+change the app in the container, launch it through the API, read the transcript, look+at the dashboard, repeat. Every response carries `_hints` saying what to do next.++| call | what it does |+|---|---|+| `GET /dock/apps` | every app: `id`, `wiki_repo`, `name`, `mode`, `running`, `launching`, `tab_open` (from the layout, the truth after a reload), `url`, `health`, `last_launch` summary |+| `POST /dock/launch {id, relaunch?, timeoutSec?}` | presses the button. `relaunch` defaults to true: close the tab, recreate it, run the steps again. Waits for the launch to finish (default 240 s) and returns `ok`, `url`, `reason`, `status`, `elapsed_ms`, `tab_open` and `console`, the same transcript the user sees in the loading screen: every status phase, every command and its container stdout/stderr, the failing step verbatim |+| `POST /dock/close {id}` | removes the app's webview tab and forgets its running state. Does not stop the app's container process; the next launch's serve retires it, or stop it with `/workspace/exec` |+| `POST /dock/refresh {full?}` | re-reads the curated apps.json now (with `full:true` also every display, manifest path and hero); call it after publishing a new apps.json or dockbar.json instead of waiting for the 6-hour poll |++`id` is the dock id (`kicad`, `nb`, `codex`), the wiki repo (`adom/nb-bridge`) or its slug.++```bash++## Back to the defaults (1.0.222)++Right-click the rail > **Reset to defaults (what every Adom user sees)**, click it again to+confirm, or `POST /dock/reset`. It drops the PERSONAL layer only: apps you added locally, pins,+the draft manifest URL override, the rail's width and collapsed state, the reveal flags and the+caches, then reloads the curated list from the wiki. The behaviour toggles in Settings > Dock Bar+(arm delay, alt-pin, collapse on launch...) are settings, not additions, and stay. The API answer+lists what was cleared and the curated app count:++```bash+curl -sX POST "$BASE/dock/reset"
skills/hydrogen-editor-state/._SKILL.mdadded⋯ 1 unchanged line ⋯
skills/hydrogen-editor-state/SKILL.mdadded+52@@ -0,0 +1,52 @@+---+name: hydrogen-editor-state+description: The Editor State Machine (ESM) — HOW to know the true state of the VS Code editor and the Claude Code conversations inside Hydrogen, and the HARD typing invariants. Use BEFORE typing into a Claude conversation, driving setup-step threads, diagnosing "state unknown", empty split panels, tab spam, prompts landing in the wrong conversation, or any Claude tab/webview confusion. Trigger words — editor state, /editor/state, claude tab state, conversation state, which tab is active, empty editor group, split panel, double-type, typed into two boxes, prompt in wrong conversation, census, safe to type, stray text, disk verified, msg_count wrong, workbench unknown.+---++# hydrogen-editor-state — the Editor State Machine++ONE authoritative read: `GET /editor/state` on Hydrogen's control API. Everything below is what it+returns and the rules for acting on it. Full design: docs/EDITOR-STATE-MACHINE.md (hd repo).++## The layered truth (never blend layers)++| Layer | Question | Source | Trust |+|---|---|---|---|+| L0 `lifecycle` | starting / editor-up / ready | port probes (7380, :8821, CDP) | absolute |+| L1 `layout`+`conversations` | groups, widths, empty panels, tab census, focused tab | workbench DOM + tab bar | high (VS Code chrome is stable) |+| L2 `extension` | what commands can I invoke | the extension's contributed-command registry + fingerprint | absolute (it IS the API) |+| L3 `conversations_disk` | turns, first prompt, generating, delivered | the jsonl transcripts | absolute — works for DISPOSED background tabs |+| L4 `census` | compose boxes + submit buttons visible NOW | DOM probes across ALL contexts | only under the invariants below |++## The HARD invariants (John 2026-07-17 — non-negotiable)++1. **Never type unless `census.safe_to_type == true`** (exactly 1 visible input across ALL+ webview contexts — not just the focused one).+2. **Freshness oracle is the TITLE**: `title == 'Untitled'` = never submitted. NEVER use+ `msg_count` for freshness — it counts welcome-screen DOM nodes (reads 5 on a pristine tab).+3. **After a submit, run the stray-text audit**: `POST /editor/audit-prompt {prefix}` must+ return `contexts_containing: 0`. 1+ = the prompt is ALSO sitting in another conversation's+ box (double-type) — clear it, fail loudly, never ignore.+4. **Delivery is proven on DISK, not in the DOM**: the prompt must be the first user turn of+ exactly ONE `~/.claude/projects/*/*.jsonl`. 0 = not delivered; 2+ = double-send.+5. **Background tabs are unreadable** (VS Code disposes their webviews): `loaded:false`,+ null ctx/compose. To read one, activate it first (`/claude/tabs/activate {index:<ordinal>}`+ — by ORDINAL, never by label: every Claude tab is labeled 'Claude Code').+6. **`normalize_needed: true` → `POST /editor/normalize`** before showing the user anything+ (an empty split group steals 50% of their editor; populated 2-group layouts are preserved).+7. **Prefer registered commands over DOM clicks**: `extension.commands` lists them+ (claude-vscode.newConversation, .focus, .editor.open, ...). Run via the in-distro+ `:8821/command` API. Commands survive extension updates; selectors don't.+8. **Extension drift**: `extension.fingerprint` changes when Claude Code updates — re-verify+ your assumptions (anchors, commands) before trusting flows after a fingerprint change.++## Quick recipes++- Am I safe to type? `GET /editor/state` → `census.safe_to_type`.+- Did my prompt double-type? `POST /editor/audit-prompt {"prefix":"<first words>"}` → want 0 after submit.+- Which conversation is generating? `conversations_disk[*].generating` (disk truth, any tab).+- Fix a half-width Claude tab / dead empty panel? `POST /editor/normalize`.+- Bars: `layout.bars` reports activity / primary sidebar / secondary (auxiliary) bar / bottom+ panel visibility. A Claude conversation living in the SECONDARY bar is a second compose box+ (census=2). Close bars deterministically: `POST /editor/bars {"primary":"close","secondary":"close"}`+ (read -> toggle-on-mismatch -> verify; never a blind toggle).
skills/hydrogen-embedded-bridge/._SKILL.mdadded⋯ 1 unchanged line ⋯
skills/hydrogen-file-transfer/._SKILL.mdadded⋯ 1 unchanged line ⋯
skills/hydrogen-golden-image/._SKILL.mdadded⋯ 1 unchanged line ⋯
skills/hydrogen-lightbulb/._SKILL.mdadded⋯ 1 unchanged line ⋯
skills/hydrogen-lightbulb/SKILL.mdadded+74@@ -0,0 +1,74 @@+---+name: hydrogen-lightbulb+description: >+ The LIGHTBULB menu (sample prompts) in Hydrogen's title bar — the 💡+ button just right of the Adom logo (top-left, 0.1.265+; it lived by the CPU/RAM+ badges before). Each item opens a FRESH Claude AI thread and+ types a curated demo prompt for the user (parts search, KiCad/Fusion, pup,+ native browser, adom-tsci, shotlog, webviews, hands-free, "Speak Adom"+ shorthand training). Covers: how items run, the samples-menu.open/close AI+ commands, GET /claude/sample-prompts, and sample-prompts.json — the overlay+ file that adds or rewords prompts WITHOUT a new Hydrogen release. Trigger words:+ lightbulb, light bulb menu, sample prompts, samples menu, demo prompts, sample+ threads, speak adom, add a sample prompt, sample-prompts.json.+---++# hydrogen-lightbulb — the sample-prompts (💡) menu++The **lightbulb button** just right of the Adom logo in Hydrogen's title bar (moved there+0.1.265 — the AI work happens on the left where VS Code lives) opens a menu of curated sample+prompts. Picking one opens a **new Claude conversation** in the editor and+human-types the prompt (open → ready → type → verify → submit, all verified) —+the user just watches it run. It exists to teach by DOING: each prompt+demonstrates a capability end to end.++**Hidden by default since 1.0.142** (`Settings > Hydrogen > Behavior > Show Lightbulb`,+default off): the menu earns its keep while learning Hydrogen and is header noise after+that. Turning the setting on shows the button immediately, no restart. The+`samples-menu.open` / `samples-menu.close` AI commands stay registered even while the+button is hidden.++## Current lineup (0.1.260+)++Full tour (everything at once) · Adom parts search · KiCad · Fusion 360 ·+Altium · pup (AI-driven browser) · Native Chrome/Edge · Google Workspace ·+chip-fetcher · adom-tsci (build a board) · shotlog · Webview panels ·+Hands-free (TTS) · **Speak Adom (wv, pup, nb...)** — teaches the popular Adom+shorthand with a cheat sheet in a wv and a quick quiz.++## Drive it as an AI++```bash+# open/close the menu (registered UI actions):+POST /ui/invoke {"id": "samples-menu.open"} # and "samples-menu.close"++# list what the menu shows (id, label, blurb):+GET /claude/sample-prompts+```++## Where the list comes from (three layers, later wins)++1. **Compiled defaults** in the Hydrogen build (offline fallback).+2. **The wiki list** (0.1.263+): `lightbulb-prompts/prompts.json` on the Hydrogen wiki+ page — the fleet-wide lineup, updated INDEPENDENTLY of Hydrogen releases. Hydrogen checks+ it on every menu open (debounced 15 min) plus every 4 hours during business+ hours (Mon-Fri 7am-7pm local); a changed list pops into an open menu live.+ Cache: `%APPDATA%\hydrogen-desktop\sample-prompts-remote.json`. Docs + PR+ guide: the [Lightbulb Prompts sub-readme](https://wiki.adom.inc/adom/hydrogen-desktop/files/lightbulb-prompts/README.md).+3. **The user's local file** `%APPDATA%\hydrogen-desktop\sample-prompts.json` —+ personal overrides, always wins:++```json+[{"id":"thread-my-demo","label":"My demo","blurb":"one line","prompt":"the full prompt text"}]+```++- A **new id** appends a menu item; a **matching id** overrides a lower layer+ (label/blurb, and the prompt body if non-empty).+- Any `thread-*` id routes to the runner automatically — no code change needed.+- Bad JSON (local or wiki) is logged and ignored — the menu never breaks.+- To contribute a prompt for EVERYONE: PR `lightbulb-prompts/prompts.json` in the+ hydrogen-desktop repo (see the sub-readme above for the rules).++Prompts are written in the user's casual first-person voice, as ONE flat+paragraph (a typed newline would submit early). Never edit John's compiled+prompt bodies without permission; add new ids instead.
skills/hydrogen-notifications-windows/._SKILL.mdadded⋯ 1 unchanged line ⋯
skills/hydrogen-permissions-windows/._SKILL.mdadded⋯ 1 unchanged line ⋯
skills/hydrogen-project-workspaces/._SKILL.mdadded⋯ 1 unchanged line ⋯
skills/hydrogen-project-workspaces/SKILL.mdadded+53@@ -0,0 +1,53 @@+---+name: hydrogen-project-workspaces+description: The Project workspaces menu in Hydrogen Desktop (the icon right of the Adom logo) and its control API, the desktop side of shared workspaces (hydrogen/workspace.json benches a project ships). Read this when a user says - project workspaces, shared workspace, apply a bench, unload a bench, workspace.json, hydrogen/workspace.json, save as project workspace, the layout a project ships, this project ships a workspace, apply / not now card, workspace offer, the icon next to the Adom logo, /workspaces/apply, /workspaces/benches, ztest-bench, bench placeholder, connect adom bridge for a bench, open the same layout as Colby. For the file format, the WORKSPACE_* hints and adom-cli export/apply use the wiki-workspaces skill; for the pane API (tabs, splits, moves) use adom-workspace-control; this skill covers only what Hydrogen Desktop adds.+---++# hydrogen-project-workspaces: the desktop side of shared workspaces++A project can ship its Hydrogen layout as `hydrogen/workspace.json` (or `hydrogen/workspaces/<name>.json`) in its page repo. The platform pieces are shared with Hydrogen Cloud and documented in the **wiki-workspaces** skill (file, hints, `adom-cli hydrogen workspace export|apply|teardown`) and **adom-workspace-control** (the pane routes). Hydrogen Desktop (ah) adds a menu, a one-time offer, placeholder tabs that know the bridge state, and a control API for all of it. Use the API; never click for the user.++## The menu++Right of the Adom logo. Benches grouped by project, labelled "project / name", from the checkout (`~/project` root and one clone folder down) plus the cloud mirror (`mirror`, and `legacy` when keyed by repo instead of project). Rows have Apply, Unload and a copy-the-command button; below: "Replace existing tabs on Apply" and "Save as project workspace". Apply/Unload/Save run adom-cli in the WSL2 workspace with the output in a launch console tab (closes itself on success, stays with the reason on failure).++## Control API (ah, port 47084 by default; GET /ports for the real one)++| Route | Body | Notes |+|---|---|---|+| `GET /workspaces/benches` | | `benches[]` with identity, project, name, path, dir, source, legacy, tabs, panels, requires, applied, apply_command, unload_sources. |+| `POST /workspaces/refresh` | | rescan checkout + mirror |+| `POST /workspaces/apply` | `{identity|project|path|name, merge?, dryRun?, timeoutSec?}` | replace by default (the bench is built from scratch, the VS Code pane kept, displaced tabs restored by unload; `merge: true` adds the bench next to what is open); returns `ok`, `summary`, `envelope` (the CLI JSON), `console` |+| `POST /workspaces/unload` | same selectors | tries identity, then the relative and absolute path adom-cli may have recorded |+| `POST /workspaces/save` | `{dir, out?, project?}` | `adom-cli hydrogen workspace export --out <out>` in `dir`; `project` when the folder has no page.json |+| `POST /workspaces/offer` | `{action: "apply"|"dismiss"}` | answers the one-time card |+| `POST /workspaces/menu` | `{open: bool}` | UI-bus: `project-workspaces.open` / `.close` |+| `POST /workspaces/demo` | | the "Show me how it works" walkthrough (ab demo panel `pw-tour`, captions, narration); returns at once |+| `GET /workspaces/status` | | running, walkthrough, last (with transcript), offer, applied this session |+| `POST /ab/verb` | `{command, args?, timeoutMs?}` | any Adom Bridge verb on this machine (ab's own gates still apply) |++A name given to apply/unload resolves to the applied bench first, then a checkout bench, then a mirror copy (a legacy mirror entry can share a name with a checkout bench).++## Rules the desktop follows++- A checkout bench is applied as the local file from its project folder (what the user is editing); a mirror-only entry with a project uses the wiki ref. Identity is `project#hydrogen/...` (path inside the project), the key adom-cli and the cloud use.+- The project for a files-only wiki clone comes from the wiki (page.json has the slug, not the owner).+- The offer card shows once per bench per machine (preference key `workspace.offered.<owner>.<repo>`, the cloud's key), one per app start, and self-dismisses after a minute as Not now. Never auto-apply.+- Placeholder tabs ("X (not available)" / "(not started)", or `panelState.placeholder`) show the Adom Bridge state (GET /ab/health) with Connect and Re-apply; re-apply is idempotent in merge mode.+- The workspace API on the proxy (47083) serves the cloud's granular routes plus `GET /api/panels/catalog`, `POST .../current/apply` (replace mode, keeps the VS Code leaf), and forwards `.../shared[/...]` to Hydrogen Cloud with the desktop session. Every tree mutation bumps a revision; a `PUT /current` whose `_rev` is behind gets 409, so an external apply cannot be erased by the browser's echo.+- `POST /splits` seeds the new pane with the placeholder tab adom-cli sends (`panelType`, `displayName`, `position`, `ratio`); adom-cli deletes it as tabIndex 0 after adding the bench's tabs.+- No 3D panel on the desktop: a `3d-viewer` tab renders as "not available on Hydrogen Desktop".+- `hydrogen://edit?workspace=<ref|identity|path>` is a registered scheme (installer + every start): a second launch forwards the link to the running ah, which applies the bench once the list loads. Test it with `Start-Process "hydrogen://edit?workspace=kcknox/ztest-bench-lite"` on the box.+- The VS Code pane is never created, removed or replaced by any of this.++## Testing a change (the ralph loop)++```bash+cd ~/project && adom-wiki repo clone kcknox/ztest-bench-lite # 3 tabs; -kicad has 6 with app launches; ztest-bench has 7+curl -s -X POST :47084/workspaces/refresh | jq '.benches[].identity'+curl -s -X POST :47084/workspaces/apply -H 'content-type: application/json' -d '{"identity":"kcknox/ztest-bench-lite#hydrogen/workspace.json"}' | jq '{ok,summary}'+curl -s :47084/workspace/tabs | jq '[.tabs[].name]' # 3D and Hydrogen present, VS Code untouched+curl -s -X POST :47084/workspaces/unload -H 'content-type: application/json' -d '{"identity":"kcknox/ztest-bench-lite#hydrogen/workspace.json"}' | jq '{ok,summary}'+```++Symptoms: "no recorded apply" from the CLI means the source spelling differs from what apply recorded (the unload route already tries identity, relative and absolute path); an empty mirror in the menu with entries visible to curl means the forward stripped gzip (fixed 1.0.371, the proxy asks for identity encoding); a tab created by apply vanishing within a second means a stale browser write got through (the revision check refuses it since 1.0.364).
skills/hydrogen-recording/._SKILL.mdadded⋯ 1 unchanged line ⋯
skills/hydrogen-runtime-mode/._SKILL.mdadded⋯ 1 unchanged line ⋯
skills/hydrogen-screen-lock/._SKILL.mdadded⋯ 1 unchanged line ⋯
skills/hydrogen-setup-steps-windows/._SKILL.mdadded⋯ 1 unchanged line ⋯
skills/hydrogen-setup-windows/._SKILL.mdadded⋯ 1 unchanged line ⋯
skills/hydrogen-skill-catalog/._SKILL.mdadded⋯ 1 unchanged line ⋯
skills/hydrogen-skill-catalog/SKILL.md+8@@ -78,6 +78,14 @@ The bootstraps deploy both buckets: `shared/` rides adom/hydrogen-bootstrap and | `hydrogen-workspace-lifecycle` | Starting, stopping, restarting and repairing the `Adom-Workspace` distro. | | `hydrogen-workspace-monitoring` | Frontend monitoring of the workspace distro's health. | | `hydrogen-wake-repair` | Recovering the workspace after the laptop sleeps or wakes. |+| `hydrogen-annotate` | Annotate: the Title Bar pencil / Win+Alt+A screen overlay — draw, snip, share the capture with the AI. |+| `hydrogen-editor-state` | The Editor State Machine — the true VS Code / Claude conversation state and the hard typing invariants (`/editor/*`). |+| `hydrogen-lightbulb` | The 💡 sample-prompts menu in the title bar and sample-prompts.json. |+| `hydrogen-project-workspaces` | The Project workspaces menu (benches from `hydrogen/workspace.json`) and its `/workspaces/*` API. |+| `hydrogen-widget` | Title Bar widgets (Claude/Codex/Antigravity usage, clock, your own): build, list, open, drive. |+| `hydrogen-webview-windows` | hbw, Hydrogen's standalone browser window (`/hbw/open`). |+| `hydrogen-dock-windows` | Driving the dock from an AI thread (`/dock/*`) and resetting it to the defaults. |+| `hydrogen-adom-bridge-triage` | Adom Bridge won't connect: the crash.log-first ladder, comparing and reinstalling the Windows build, WSL2 interop. | ## What's NOT in your workspace — internal dev skills
skills/hydrogen-skill-loop-windows/._SKILL.mdadded⋯ 1 unchanged line ⋯
skills/hydrogen-wake-repair/._SKILL.mdadded⋯ 1 unchanged line ⋯
skills/hydrogen-webview-windows/._SKILL.mdadded⋯ 1 unchanged line ⋯
skills/hydrogen-webview-windows/SKILL.mdadded+22@@ -0,0 +1,22 @@+---+name: hydrogen-webview-windows+description: >+ Windows-only webview surface: hbw, Hydrogen's standalone built-in browser window (POST /hbw/open). Trigger words — hbw, hydrogen browser window, standalone browser window, /hbw/open.+---++# hydrogen-webview-windows — Windows companion to hydrogen-webview++Read **hydrogen-webview** (platform-generic) first. The parts below exist only in the Windows Hydrogen;+the macOS app does not have them.++## hbw — Hydrogen's standalone browser window (the fourth surface)++Under Hydrogen there is one more surface: **hbw**, Hydrogen's standalone built-in+Tauri browser window (picker label "Hydrogen Browser Window", destination id+`webview-window`, window label `hbw-*`). It is a separate OS window Hydrogen manages+directly — bigger than a pane tab, still not a real browser. Open one first-class via+`POST /hbw/open {"url": ...}` on Hydrogen's control API (0.1.113+), or pick "Hydrogen Browser+Window" in the Browser Picker. The surface shortlist: **wv** (this skill's webview+panel; Hydrogen's pane tab inside Hydrogen), **extwv** (the real-browser pane tab for embed-blocked+sites, above), **pup**, **nb** (the user's native browser via abe), **hbw**. VS+Code's Simple Browser is NEVER one of them.
skills/hydrogen-widget/._SKILL.mdadded⋯ 1 unchanged line ⋯
skills/hydrogen-widget/SKILL.mdadded+265@@ -0,0 +1,265 @@+---+name: hydrogen-widget+description: "Build, list, open and drive Hydrogen Widgets: small live panels in Hydrogen Desktop's Title Bar (Claude usage, Codex usage, a clock, or your own), each served by a binary inside the workspace and mounted in a sandboxed slot. Covers the hydrogen-widget.json facet a wiki repo carries (alone, or next to its dock manifest and project workspace), the per-widget page the pulldown links to, the launch contract (HYDROGEN_WIDGET_ID / _PORT / _SLOT / HYDROGEN_PROXY_PORT, the health URL, the explicit takeover, stop-first relaunch), the tall and compact layouts, vendor marks, private repos (read with the user's session), the curated list on adom/hydrogen-bootstrap, the Hydrogen Widgets pulldown, and the control API (GET /widgets, POST /widgets/open|close|navigate|refresh|menu, GET /widgets/status) so an AI can do all of it with no mouse. Trigger words: hydrogen widget, hydrogen-widget, title bar widget, widgets pulldown, widget slot, claude usage widget, codex usage widget, tokens left widget, usage meter in the title bar, hydrogen-widget.json, /widgets/open, make a widget, add a widget to hydrogen, private widget, widget SDK."+version: 1.5.7+---++# hydrogen-widget: small live panels in Hydrogen Desktop's Title Bar++The bar across the top of the Hydrogen window is the **Title Bar**: the Adom menu, the+widgets, the CPU/RAM/GPU meter, the bell, your avatar and the window controls. Its short form+(the chevron at the top edge) is the **compact Title Bar**. A **Hydrogen Widget** is a page+that lives in a slot of that bar, left of the meter, served by a binary that runs **inside the+workspace** (the WSL2 distro on the desktop), the way a dock app serves its dashboard. Hydrogen+mounts it in a sandboxed iframe. The user opens and closes widgets from the **Hydrogen+Widgets** pulldown (the puzzle-piece icon); an AI does the same through the control API. Open+widgets are remembered per user and come back on the next start.++The name has a prefix on purpose: wiki-widget is the component-page widget, and future+surfaces (kicad-widget, fusion-widget) get their own. This skill is only about the Title Bar.++## The three that ship++| id | what it shows | source of the numbers | repo |+|---|---|---|---|+| `claude-usage` | 5-hour session, weekly, and every weekly limit scoped to a model on your plan (Fable, Opus, ...), as percent used, in the provider's severity colour | the Claude Code sign-in in `~/.claude/.credentials.json`, asked at `api.anthropic.com/api/oauth/usage`; the `limits` list in that answer is what Claude Code's `/usage` panel draws | a facet of adom/adom-vscode |+| `codex-usage` | the plan's rate-limit window as percent used, plus a secondary window when the plan has one | the Codex sign-in in `~/.codex/auth.json`, asked at `chatgpt.com/backend-api/wham/usage` (what `/status` shows) | a facet of adom/adom-vscode |+| `clock` | the time and date, stacked when tall, inline when compact; the one to copy | the workspace clock | a facet of adom/hydrogen-bootstrap |++Neither usage call runs a model, so neither costs quota. They ask at most once every three+minutes per provider, pause while the window is hidden, back off on errors (doubling to 15+minutes), and re-read the sign-in file only when it changes.++## Drive it from an AI (no mouse)++All on Hydrogen's control API (`$ADOM_HD_CONTROL_URL` inside the workspace, `ports.json` on+the host). Nothing in the pulldown needs a click.++```+GET /widgets # the list: id, name, wiki_repo, source, open, status, url+POST /widgets/refresh # re-read the curated list and the checkout+POST /widgets/open {"id":"claude-usage"} # mount, install, stop any old instance, launch, hand the slot over+POST /widgets/close {"id":"claude-usage"} # unmount and stop it+POST /widgets/navigate {"id":"...","url":"..."} # point an open slot at a URL yourself+POST /widgets/menu {"open":true} # show or hide the pulldown+GET /widgets/status # open ids, each status (closed|installing|starting|live|failed), menu state+```++UI bus: `widgets.menu.open` and `widgets.menu.close` (POST /ui/invoke {id}).++`POST /widgets/open` returns when the widget's page answers (`ok:true, url`) or when the+install, launch or health wait failed (`ok:false, error`); the slot stays mounted with the+reason so the user can see it, and `/widgets/close` removes it. The launch log is+`~/.adom/widgets/<id>.log` in the workspace.++## What happens on open, exactly++1. The slot mounts with a compact placeholder (a ring and a status line, sized by the slot).+2. `adom-wiki pkg install <install>` runs in the workspace, every open, so publishing a new+ version of your package is enough to update the widget.+ When Hydrogen restores widgets at start it installs only what is missing (the launch+ command's binary is looked up first) and runs installs one at a time; an open from the+ pulldown or the API always installs, so a new package version lands then.+3. Any previous instance is stopped first (`launch.stop`, else a `pkill` on the command's first+ word), so a new version actually gets the port. The slot's frame is remounted on the+ placeholder for the same reason: a stale page never stays put.+4. `launch.command` runs in its own session (`setsid -f nohup ...`, so an editor reload or an+ extension host restart cannot take it down) as the workspace user, from the repo folder when the widget+ came from the checkout, with `HYDROGEN_WIDGET_ID`, `HYDROGEN_WIDGET_PORT`,+ `HYDROGEN_WIDGET_SLOT` and `HYDROGEN_PROXY_PORT` in its environment plus the workspace env+ every login shell has (`ADOM_HD_CONTROL_URL`, `ADOM_HYDROGEN_URL`).+5. Hydrogen asks for `http://127.0.0.1:<port>/<health.url>` from inside the workspace until it+ answers 2xx or 3xx, up to `health.timeout_seconds`, then navigates the slot to+ `http://<port>.localhost:<proxy>/` (its subdomain port proxy). The probe runs in the+ workspace on purpose: the proxy's own error page while the distro boots is not an answer.+ Before any of this, if the workspace is not running yet (a full quit and relaunch boots the+ distro for a minute or more), the slot says "Waiting for the workspace" and waits, up to+ ten minutes; nothing is installed or launched until it is up.+6. Your page owns the slot from then on: poll your own JSON, redraw, push whatever you want.+ Explicit takeover, when you want the slot before health is up or want another page:+ `POST $ADOM_HD_CONTROL_URL/widgets/navigate {"id": $HYDROGEN_WIDGET_ID, "url": "..."}`.++## Make one: the facet++Put a `hydrogen-widget.json` at the root of a wiki repo. It can sit next to a dock manifest+and a `hydrogen/workspace.json`, or be the whole repo. One widget:++```json+{+ "hydrogen_widget": "1.0.0",+ "id": "clock",+ "name": "Clock",+ "icon": "mdi:clock-outline",+ "brief": "The time and date, the smallest widget there is.",+ "width": 110,+ "width_tall": 84,+ "install": "adom/hydrogen-bootstrap",+ "launch": { "command": "hydrogen-widget-clock", "port": 8933 },+ "health": { "url": "/", "timeout_seconds": 60 },+ "docs": "widgets/README.md"+}+```++Several in one repo: `{"widgets": [ {...}, {...} ]}`. Each entry has its own `id`, name, mark,+launch command and port; they share the repo's package (`install`) and page (`docs`). The curated+list names a Hydrogen Widget by repo plus id, so each is its own row in the pulldown and opens and+closes on its own. adom/adom-vscode ships Claude usage and Codex usage this way because both read+an AI sign-in that lives next to the editor extension; a repo with one thing to show ships one.++| field | meaning |+|---|---|+| `id` | unique, lowercase, stable; the curated list and the control API address it |+| `name`, `brief` | the pulldown row and its hover text; `brief` is also the body of the hover card when the widget shows no live view there, so write it for a person |+| `icon` | an iconify name for the row (`mdi:clock-outline`), or `vendor:claude` / `vendor:codex` for the vendor marks the AI launch bar paints, so a person can tell whose numbers a widget shows |+| `launch.port` | the port your page serves on inside the workspace. Pick one far from where apps land: not the 8000s (dashboards, dev servers, the KiCad dashboard's 8931), not the ephemeral range (32768 and up). The shipped widgets sit at 27011 to 27013; take 27020 and up for yours. A widget is a side panel and must never cost an app its port (John 2026-09-15). |+| `width` | slot width in px in the compact Title Bar (one horizontal row); clamped to 48..320 |+| `width_tall` | slot width in the full Title Bar, where your page stacks its rows; defaults to 60 percent of `width` |+| `install` | the adom-wiki package that provides the command; defaults to the repo itself |+| `launch.command` | run in the workspace as the workspace user, backgrounded; `launch.stop` optional |+| `launch.port` | the port the page listens on, 127.0.0.1 inside the workspace |+| `health.url` | path Hydrogen polls until it answers (default `/`); `timeout_seconds` default 60 |+| `about` | one or two sentences on how it works, shown under Details on the hover card ("Reads the Claude Code sign-in ... asks the usage endpoint ... no quota is spent") |+| `refresh` | how often it asks anything, shown under Details on the hover card ("the provider at most once every 3 minutes; pauses while hidden; backs off on errors") |+| `docs` | the widget's own page: a repo file path (`widgets/README.md`) or a full URL. The pulldown row links to it. Defaults to `<repo>/files/widgets/README.md` |++### The widget's own page (what the pulldown row opens)++Every widget should ship a page a person can read before opening it. The convention is+`widgets/README.md` in the repo (the default `docs`), with: a picture of the widget in the full+and the compact Title Bar, what it shows and where the numbers come from, how often it asks+anything, the list of files in the repo that make it a widget, and a link back to this skill. The+two shipped examples: adom/adom-vscode `widgets/README.md` and adom/hydrogen-bootstrap+`widgets/README.md`.++### The page in the slot: two layouts, chosen by height++The slot is 38 px tall in the full Title Bar (like the meter) and 20 px in the compact one.+Size your page by its height, never in fixed px: `@media (min-height: 34px)` stack rows+(label, bar, value) to use the room; `@media (max-height: 33px)` one horizontal row with+`clamp()` font sizes. Transparent background, no scrollbars. The shipped helper does this;+copy it.++### The hover card (a tooltip that lives outside the iframe)++A tooltip inside your page cannot reach past the slot's edge, so Hydrogen draws the card:+hover the slot and, after a moment, a card appears under it in the host, in the style of the+tab cards. It is for the person looking at the widget, so it leads with what the widget shows:+the name and mark, then the widget's own live view when it asks for one (see "A bigger view on+hover" below), otherwise its `brief`. A status line under the name appears only while the+widget is not live (Installing, Starting, Waiting for the workspace, Could not start: reason).++Everything about how it runs sits under **Details** at the foot of the card, folded by default:+`brief` (when a live view took its place), `about`, `refresh`, the port and the log path, the+page URL, the repo, and four links: the widget's page (`docs`), the wiki repo, this SDK, and+Close widget. Opening Details pins the card, so those links are live as soon as they show.+Moving onto the card keeps it; a click on the card (or its pin) pins it; Escape or a click+outside closes a pinned card. Your page needs nothing for this beyond the manifest fields, so+write `brief` for a person ("how much of your limits you have used; hover for when they+reset"), and put the mechanics in `about` and `refresh`. An AI shows the same card with+`POST /widgets/card {"id": "...", "pinned": true}` and hides it with `{"id": "...", "open": false}`.++### Resizing: who tells the page++Nobody has to. The slot is an iframe; when the Title Bar goes compact or tall, Hydrogen resizes+the slot and the iframe's own `window` gets a normal `resize` event, and any height media+queries re-evaluate by themselves. Hydrogen posts no message on resize. So a page must:++- size itself by its own `innerHeight`/`innerWidth` (or the height media queries above), never+ by fixed pixel widths;+- give every column a natural width and let one flexible column absorb the rest+ (`grid-template-columns: auto minmax(14px, 1fr) auto`), so a value is never clipped when the+ slot is narrow; trim long labels with an ellipsis instead;+- re-render on `resize` if its render depends on the size (the shipped helper keeps the last+ data and re-renders after 80 ms of quiet, no refetch).++The page decides its own width per layout: after every render and resize, measure your content+and post `window.parent.postMessage({hdWidget: {width: <px>}}, '*')`; Hydrogen sizes the slot to+it (clamped 48..320) and knows which slot from the frame that sent it. The manifest's `width`+(compact) and `width_tall` (full) are only the first guess before your page has measured. So a+tall layout can be narrow (rows stacked) and the compact one wide (one row), which is what the+shipped helper does. Measure on a hidden copy of your content laid out at `width: max-content`+(clone the root, remove ids, `position:absolute; left:-10000px; height:100vh; width:max-content;+visibility:hidden`, read its width, remove it): the live boxes stretch to the slot, so measuring+them only ever grows the slot (the clock once asked for 361 px that way). The helper's+`postWidth()` is that code; keep it when you copy the helper. For pictures of your widget the+helper serves `/preview?h=38` and `/preview?h=20`: its page in a frame of that height that follows+the width the page asks for, so a browser screenshot of `#w` at a high device scale is a crisp+docs image (`?w=` pins the frame instead). The shipped widgets are+the reference: adom/adom-vscode `widgets/bin/hydrogen-widget-lib.py` is the page and layout,+`hydrogen-widget-claude-usage` and `hydrogen-widget-codex-usage` the data feeds, and+adom/hydrogen-bootstrap `bin/hydrogen-widget-clock` the smallest one.++### Who draws what: your two canvases++Your widget has two canvases and draws everything inside them: the **slot** in the Title Bar and,+if you ask for one, the **card** view on hover. Hydrogen draws only what surrounds them: the slot's+edge, its height (38 or 20 px) and its close button, and the card's frame, header (your `name` and+`icon`), pin and Details (your `about`, `refresh`, `docs`, plus the port and log). Anything inside a+canvas changes when you publish your package, with no Hydrogen release. The table and the diagram:+the Hydrogen Widgets page, `widgets/README.md` on adom/hydrogen, section "Who draws what".++### A bigger view on hover (optional; Hydrogen 1.0.609+ gives the card its own frame)++Ask for a live view in the hover card by adding `expand` to the same message:+`window.parent.postMessage({hdWidget: {width: 265, expand: {width: 560, height: 400}}}, '*')`.+When the card opens, Hydrogen loads a **second copy of your page** in the card at that size (width+clamped 280..720, height 120..600, at most 45% of the window height), or the page at `expand.path`+(`{width, height, path: "/card"}`, a path on your own origin) if you want a separate one. Your slot+keeps showing your page the whole time. Rules:++- keep `width` the compact title-bar width; never send the expanded width as `width`;+- switch layouts on height (`@media (min-height: 100px)` shows the big view), not on a message:+ the card copy is simply a taller frame of the same page;+- the card copy is a fresh page each time the card opens: keep state you need on your server;+- send `expand: null` to withdraw, and omit it to keep the plain card (your `brief` as text);+- the request is dropped whenever the slot frame loads, so post it again on your `load` event;+- only the slot frame's `width` and `expand` count; the card frame may only send+ `{hdWidget: {collapse: true}}` (forward Escape with it, since keys do not leave an iframe).++Before 1.0.609 Hydrogen moved the slot's own frame into the card, leaving the slot empty with a+"Expanded below" stand-in; pages written for that work unchanged, because they already pick the big+layout by height. Adom AI Flow and the usage widgets are the references.+Details: `docs/hydrogen-widget-expansion.md` in the Hydrogen source.++### Listing it++- **Your checkout**: any repo under `~/project` (one clone folder down too) with a+ `hydrogen-widget.json` appears in the pulldown as "(checkout)", no publish needed.+- **Everyone**: publish the repo (with the binary in its package), then file an issue on the+ adom/hydrogen-bootstrap page titled `List widget: <owner>/<repo>` with a one-line description+ and a picture of the slot (its `/preview?h=38`). That page's maintainers add+ `{ "id", "wiki_repo", "order" }` to `widgets/widgets.json`, the curated list Hydrogen reads,+ and the widget appears in every user's pulldown at their next refresh. From a workspace:+ `adom-wiki issue create adom/hydrogen-bootstrap --title "List widget: <owner>/<repo>" --body "..."`.+ The list only orders and names repos; every other fact comes from the repo's own manifest,+ which the curated list Hydrogen reads. The list only orders and names repos; every other fact comes+ from the repo's own manifest.+- **Just you, or your team (private)**: keep the repo private on the wiki (`adom-wiki page+ create --private`, `adom-wiki page share` for teammates). Hydrogen reads the curated list and+ every manifest **with the signed-in user's session**, so a private repo's widget lists and+ installs for the people the page is shared with and nobody else. Private widgets are not in+ the curated list; they come from your checkout, or from your own `widgets.json` if you fork+ the bootstrap for your org.++### A binary in fifty lines++The shipped widgets are Python 3 scripts (already in every workspace), one file each plus a+shared helper: an `http.server` that answers `GET /` with the page, `GET /data.json` with fresh+numbers (cached per interval, refreshed only when asked after the interval, exponential backoff+on errors), and `GET /health`. Copy `hydrogen-widget-clock` and `hydrogen-widget-lib.py` from+adom/hydrogen-bootstrap `bin/`, change `data()` and the render expression, add a+`hydrogen-widget.json`, a `widgets/README.md` and an `install.sh` line that symlinks your script+into `~/.local/bin`. That is the whole SDK.++## Ralph test++```+curl -s -X POST $ADOM_HD_CONTROL_URL/widgets/open -H 'content-type: application/json' -d '{"id":"clock"}'+curl -s $ADOM_HD_CONTROL_URL/widgets/status+curl -s http://27013.localhost:$(python3 -c "import json;print(json.load(open('/home/adom/.adom/ports.json'))['proxy'])")/data.json+```++Then look: a screenshot of the Hydrogen window shows the slot left of the meter, the chevron+makes the Title Bar compact and the slot follows, and `/widgets/close` makes it go away.++
skills/hydrogen-workspace-monitoring-windows/._SKILL.mdadded⋯ 1 unchanged line ⋯
skills/hydrogen-wslg/._SKILL.mdadded⋯ 1 unchanged line ⋯