bootstrap
Adom Hydrogen (macOS / Lima)
Public Made by Adomby adom
The macOS platform layer for Adom Hydrogen.
← Commit history
Publish 0.1.29
17 files changed
+368−773
package.json+1−1page.json+1−1skills/hydrogen-captions-mac/SKILL.md+15−49skills/hydrogen-container/SKILL.md+45−105skills/hydrogen-eda-install/SKILL.md+2−2skills/hydrogen-networking/SKILL.md+11−12skills/hydrogen-open-url-mac/SKILL.md+27−50skills/hydrogen-permissions-mac/SKILL.md+38−57skills/hydrogen-port-watcher/SKILL.md+8−9skills/hydrogen-ports/SKILL.md+15−16skills/hydrogen-recording-mac/SKILL.md+37−66skills/hydrogen-screen-lock-mac/SKILL.md−6skills/hydrogen-self-screenshot-mac/SKILL.md−5skills/hydrogen-setup-steps/SKILL.md+55−74skills/hydrogen-volume/SKILL.md+18−20skills/hydrogen-workspace-lifecycle/SKILL.md+63−163skills/hydrogen-workspace-monitoring/SKILL.md+32−137package.json+1−1@@ -4,7 +4,7 @@ "type": "bootstrap", "title": "Adom Hydrogen (macOS / Lima)", "brief": "The macOS platform layer for Adom Hydrogen.",- "version": "0.1.28",+ "version": "0.1.29", "description": "The macOS platform layer for Adom Hydrogen, where the workspace runs in a Lima Ubuntu VM hosting the Adom-Workspace systemd-nspawn machine. Depends on adom/hydrogen-bootstrap (the platform-generic Hydrogen layer) and adds everything specific to the Lima/nspawn runtime: the container/networking/ports/setup/topology/volume/workspace-lifecycle hydrogen-* skills (the macOS-runtime bucket), the in-machine workspace-updater daemon, and the macOS code-server workbench seed. Sibling layers adom/hydrogen-windows-bootstrap (WSL2) and adom/hydrogen-ubuntu-bootstrap depend on the same adom/hydrogen-bootstrap. This is the package the golden Lima image installs.", "org": "adom", "tags": [
page.json+1−1@@ -4,7 +4,7 @@ "slug": "hydrogen-mac-bootstrap", "title": "Adom Hydrogen (macOS / Lima)", "brief": "The macOS platform layer for Adom Hydrogen.",- "version": "0.1.28",+ "version": "0.1.29", "license": "proprietary", "visibility": "public", "metadata": {
skills/hydrogen-captions-mac/SKILL.md+15−49@@ -1,56 +1,22 @@ --- name: hydrogen-captions-mac description: >- macOS platform companion to hydrogen-captions — the Apple-specific note on Hydrogen's on-screen- captions. The two caption surfaces, the SECONDS-vs-MILLISECONDS unit trap, ids,- positions, and the adom-cli / HTTP commands all live in hydrogen-captions- (adom/hydrogen-bootstrap) and are platform-neutral; THIS skill carries only the one macOS- difference: the full-DESKTOP overlay (adom-desktop desktop_caption) is a Win32- click-through window and is NOT implemented on macOS yet (the non-Windows build is a- stub). The workspace caption (adom-cli hydrogen caption) works the same on macOS. Trigger words — caption macos, desktop_caption macos,- desktop overlay mac, screen overlay mac, caption not showing mac, click-through caption mac.+ macOS note on Hydrogen's on-screen captions: the WORKSPACE caption (adom-cli+ hydrogen caption) is the supported surface here and behaves exactly as the+ generic hydrogen-captions skill documents. The desktop_caption verb is not a+ macOS surface — never plan a mac demo around it. Trigger words — caption+ macos, caption not showing mac, workspace caption. --- -# hydrogen-captions (macOS) — only the desktop overlay differs+# hydrogen-captions (macOS) -This is the **macOS half** of `hydrogen-captions`, and it is deliberately short: **almost-nothing about captions is macOS-specific.** The two surfaces, the units (workspace =-SECONDS, desktop overlay = MILLISECONDS), positions/ids/sizes, the `adom-cli hydrogen-caption` command and the raw-HTTP `.../current/caption` fallback all live in the generic-**hydrogen-captions** skill and behave identically here — read that first. There is exactly-**one** macOS-distinct fact, below.+The two facts a mac session needs: -## (1) Workspace caption — fully platform-neutral on macOS--`adom-cli hydrogen caption show/hide` renders **inside the Hydrogen workspace webview** via the-workspace-events server → SSE → the frontend `captionStore`. That path has no host-native-code, so it works on macOS exactly as documented in hydrogen-captions (same SECONDS unit, 30s-default / 300s cap, newest-wins, the HTTP fallback). **This is your default on a Mac.**--## (2) ⚠️ Desktop overlay — NOT implemented on macOS--`adom-desktop desktop_caption` (the always-on-top, click-through, whole-screen overlay)-is **Windows-only**. The implementation in `src-tauri/crates/hd-app/src/caption.rs` is a-Win32 layered-window stack (`WS_EX_LAYERED | WS_EX_TOPMOST | WS_EX_TRANSPARENT` popups,-`EnumWindows`-keyed by id) gated entirely behind `#[cfg(windows)]`. The non-Windows-`show_caption_window` is a **stub** that logs *"Caption overlay is only supported on-Windows"* and returns `created=false`. So on macOS:--- `adom-desktop desktop_caption` will fail to actually paint a desktop overlay (the- command returns, but `visible:false` / no window appears). **Do NOT rely on it for a- full-screen recording on macOS** — there is no native overlay layer yet.-- For a whole-desktop / other-app (KiCad, Fusion, browser) recording on macOS, there is- currently **no on-screen caption** equivalent. Caption the **Hydrogen workspace** instead- (surface 1), or narrate via TTS — don't claim a desktop overlay you can't render.--This is an honest gap, not a different mechanism: Hydrogen has **no macOS-native desktop-caption overlay** at this time. (The `caption` capability that `adom-desktop status`-advertises reflects the Windows host overlay; treat it as Windows-only until a macOS-overlay ships.)--## Not applicable on macOS--The Win32 always-on-top click-through layered-window implementation — `caption.rs`'s-`#[cfg(windows)]` `show_caption_window` / `destroy_captions`, the `AdomCaptionOverlay`-window class, and the id-as-window-title routing that backs `adom-desktop-desktop_caption` — is the **Windows** delivery;.+1. **Use the workspace caption.** `adom-cli hydrogen caption show/hide` renders+ inside the Hydrogen workspace (workspace-events → SSE → `captionStore`) and+ works exactly as the generic **hydrogen-captions** skill documents — same+ SECONDS unit, defaults, ids, and HTTP fallback. This is the caption surface+ on a Mac.+2. **Do not use `desktop_caption` here.** That verb has no macOS surface — for+ a whole-desktop recording, caption the workspace (surface 1) or narrate+ with TTS instead.
skills/hydrogen-container/SKILL.md+45−105@@ -1,131 +1,71 @@ --- name: hydrogen-container-description: Context for Claude Code running inside a Adom Hydrogen workspace machine. Documents the exact OS (Ubuntu 24.04, code-server 4.112.0, the Adom-Workspace machine), explains how setup differs from Adom cloud containers (setup-steps), what bridges are available, and how to use the relay. Trigger on startup, adom-cli errors, bridge commands, screenshot requests, container-platform questions, code-server / VS Code extension issues, or when the AI needs concrete facts about its environment instead of guessing.+description: Context for the AI running inside an Adom Hydrogen macOS workspace machine. Exact facts about the environment (Ubuntu 24.04 arm64 Rosetta-hybrid, code-server, the nspawn machine + Lima VM), how tooling got here (slim image + wiki converge), the bridge CLI, and how this differs from Adom cloud containers. Trigger on startup, adom-cli errors, bridge commands, container-platform questions, or whenever you need concrete environment facts instead of guessing. --- -# Adom Hydrogen Workspace (Machine)+# Adom Hydrogen Workspace (macOS machine) -Machine-runtime version (default). Legacy Docker container runtime (`HD_RUNTIME=docker`) is in the docker/ bucket.+You are running inside a **systemd-nspawn machine** managed by Adom Hydrogen+on the user's Mac, hosted in the `hydrogen-builder` Lima VM. -You are running inside the **`Adom-Workspace` machine** managed by Adom Hydrogen (Hydrogen). Hydrogen is the flagship Adom desktop app — it manages your workspace machine, bridges to desktop apps, and provides VS Code + Claude Code.--## The workspace — exact facts (don't guess)+## Exact facts (don't guess) | Field | Value | |-------|-------|-| Machine name | `Adom-Workspace` (fixed — there is no random container suffix) |-| Imported from | golden image `adom-golden.tar.gz` (full pre-baked image) via `machinectl import-tar` |-| Base | Ubuntu 24.04 |-| Architecture | `aarch64` (arm64) — the macOS golden image is a **Rosetta-hybrid**: native arm64 code-server / node / claude, with the x86-64 Adom CLIs run **translated under Rosetta** inside the Lima VM. So `uname -m` returns `aarch64` and `node`'s `process.arch` is `arm64`, but `adom-*` x86-64 binaries still run (via Rosetta) |-| code-server | 4.112.0 (pinned via setup step) |-| code-server binary | `/usr/lib/code-server/bin/code-server` |-| Extensions dir | `~/.local/share/code-server/extensions/` |-| Settings | `~/.local/share/code-server/User/settings.json` |-| Machine default user | `adom` (UID 1001; under systemd-nspawn the default user comes from the machine config / nsenter `-S 1001 -G 1001`) — in-machine exec via `limactl shell hd-builder -- sudo nsenter -t <leader> -a -S 1001 -G 1001 -- bash -lc '<cmd>'`; root variant drops `-S 1001 -G 1001` |+| Machine name | `Adom-Workspace` for the default container; additional containers are named `Adom-Workspace…-cN` (Hydrogen supports several containers per account — check `machinectl` truth via Hydrogen if it matters) |+| Base | Ubuntu 24.04, `aarch64` — a **Rosetta-hybrid**: native arm64 code-server/node, x86-64 Adom CLIs run translated under Rosetta (`uname -m` = aarch64; `adom-*` binaries still work) |+| Imported from | the pinned golden image (`hydrogen-lima-image` release) or Hydrogen's configured snapshot, via `machinectl import-tar` |+| code-server | `/usr/lib/code-server/bin/code-server`, run under its systemd unit `code-server@adom` (Restart=always), bound `0.0.0.0:<container's port>` (default container: 7380) | | Work user | `adom` (UID 1001, passwordless sudo, home `/home/adom`) |-| Workspace | `/home/adom/project` (lives directly in the machine's ext4 filesystem) |-| Pre-installed | Node 18 + npm, Python 3.12, git, gh, curl, wget, jq, build-essential, cmake, pkg-config, libssl-dev |-| Code-server runs as | `code-server --bind-addr 0.0.0.0:7380 --auth none --disable-telemetry /home/adom/project` (binds 0.0.0.0:7380; Lima exposes it to the Mac at `localhost:7380`) |-| Runtime source | `adom-hydrogen/src-tauri/crates/hd-app/src/runtime/macos.rs` (selector `runtime/mod.rs::select_runtime()`) |--If you ever need to confirm: `cat /etc/os-release`, `uname -m` (expect `aarch64` on Apple Silicon), `/usr/lib/code-server/bin/code-server --version`. Don't speculate about alpine — it's Ubuntu 24.04, same distro as the cloud container (the cloud is amd64; this macOS port is arm64 + Rosetta for the x86-64 Adom CLIs).--## Setup is via Hydrogen's setup-steps--Hydrogen provisions this machine through its own **setup-steps** flow (Rust code in `adom-hydrogen/src-tauri/crates/hd-app/src/setup_steps_macos.rs`, with the runtime mechanics in `adom-hydrogen/src-tauri/crates/hd-app/src/runtime/macos.rs`), shown as the "Install Tools" panel in the Hydrogen UI. It is a **different code path** than cloud containers, which provision via the adompkg/wiki-package bootstrap (`adom/hydrogen-bootstrap`).--The machine cascade is **18 steps** (state file `setup-steps-macos.json`) vs the legacy Docker flow's 24. Most tooling is NOT installed by a step — it's BAKED into `adom-golden.tar.gz` at image-build time (the 8 Adom CLIs, the claude CLI + Code extension, code-server, VS Code settings, and all `hd-*` skills). The Docker `pull-image` / `create-container` / `start-container` steps are collapsed into a single step 1, `ensure-workspace`, which runs `machinectl import-tar` of `adom-golden.tar.gz` if the machine isn't already present. The relay is started by the `start-relay` step. See `hydrogen-golden-image`.--When debugging install issues here, the source of truth is `setup_steps_macos.rs` (and `runtime/macos.rs`) — its step IDs (`ensure-workspace`, `install-adom-vscode`, `set-env-vars`, `inject-api-key`, `start-relay`, `claude-auth`, etc.) map 1:1 to what ran on this machine. There is NO `install-claude-ext` / `install-claude-cli` / `write-vscode-settings` step anymore — those are baked. (For the legacy Docker `setup_steps.rs` flow see the docker/ bucket.)--## VS Code extension caveats+| Workspace | `/home/adom/project` — plain ext4 inside the machine, no Docker volume |+| Editor extensions | installed under `~/.local/share/code-server/extensions/`; the `claude` and `codex` CLIs on PATH are SHIMS to the binaries bundled inside their extensions |+| Marketplace | code-server resolves Open VSX by default; **extension auto-update is OFF by design** — Hydrogen owns extension updates through its controlled pin chain. Do not switch it on. |+| Tooling provenance | the golden image is SLIM (static layer only); every `hydrogen-*` skill, adom-vscode, and editor config was converge-installed from the Adom Wiki (`adom/hydrogen-mac-bootstrap` chain) — see `hydrogen-setup-steps` | -- The Claude Code extension and `code-server` settings (including `extensions.autoUpdate: true` / `extensions.autoCheckUpdates: true`) are BAKED into the golden image — there is no `write-vscode-settings` or `install-claude-ext` setup step. Auto-update **must** stay on so every installed extension auto-updates from the marketplace; the image bakes it on. Do not regress this.-- Bare `code-server --install-extension <id>` (no version pin) historically resolves to the **universal** target-platform build. For some extensions (notably `anthropic.claude-code` after 2.1.89), Anthropic stopped shipping universal builds — so bare install permanently sticks at 2.1.89 even when newer `linux-x64` builds exist. The golden-image bake installs the latest `linux-x64` build pinned, so the workspace ships current. It also heals orphan `extensions.json` entries (entries pointing to deleted dirs cause a permanent "Invalid extensions detected" banner).-- Marketplace: code-server uses **Open VSX** (open-vsx.org), not Microsoft Marketplace. No `EXTENSIONS_GALLERY` env override is set; `product.json` has no gallery URL — it falls through to Open VSX defaults.+Confirm live with `cat /etc/os-release`, `uname -m`,+`/usr/lib/code-server/bin/code-server --version`. ## adom-cli is authenticated -Hydrogen auto-injects the user's session token on every launch. To verify:-```bash-adom-cli carbon user get-```-If this returns user data, all adom-cli commands work (containers, repos, orgs, wiki, etc.). If it fails, the user needs to log in via Hydrogen's login page.--## Relay server is running--The adom-desktop relay runs on ports 8765 (WebSocket) / 8766 (HTTP) inside this machine. The `start-relay` setup step launches it.+Hydrogen injects the user's session token (`/var/run/adom/api-key`) at setup,+on every auth completion, and on every launch. Verify:+`timeout 15 adom-cli carbon user get`. If it 401s, see `hydrogen-api-key-mac`. -Check health: `curl -sf http://127.0.0.1:8766/health`-Check desktop connection: `adom-desktop ping`+## The bridge CLI is `adom-bridge` -The macOS host control API is reachable from inside the machine via the `adom-host` gateway alias — vz does NOT mirror loopback, so 127.0.0.1 inside the machine is NOT the Mac. The port is dynamic per launch, so read the live URL from `~/.adom/hydrogen-control-url`: `BASE="$(cat ~/.adom/hydrogen-control-url)"; curl "$BASE/health"`.--## Available bridge commands (when desktop is connected)--### Screenshots (zero dialogs, instant)-```bash-adom-desktop desktop_screenshot_screen # full screen capture-adom-desktop desktop_screenshot_screen '{"maxWidth":1500}' # resized for Claude vision-adom-desktop desktop_screenshot_window '{"hwnd": N}' # capture specific window-adom-desktop desktop_list_windows # list all windows with HWNDs-```-Default to `maxWidth: 1500, format: "png"` for UI screenshots. Use `"jpeg"` for natural photos, `"webp"` for smaller files.--### Browser automation (Puppeteer)-```bash-adom-desktop browser_open_window '{"url": "https://..."}'-adom-desktop browser_screenshot '{"sessionId": "default"}'-adom-desktop browser_eval '{"js": "document.title"}'-adom-desktop browser_navigate '{"url": "..."}'-```--### KiCad bridge-```bash-adom-desktop kicad_open_board '{"path": "/Users/<you>/path/to/board.kicad_pcb"}'-adom-desktop kicad_screenshot_all-adom-desktop kicad_run_drc '{"path": "..."}'-adom-desktop kicad_window_info-```--### Fusion 360 bridge-```bash-adom-desktop fusion_start-adom-desktop fusion_import_step '{"path": "..."}'-adom-desktop fusion_export_step '{"path": "..."}'-```--### File transfer-```bash-adom-desktop send_files '{"files": [{"path": "/home/adom/file.txt"}]}'-adom-desktop pull_file '{"remotePath": "/Users/<you>/file.txt", "localPath": "/tmp/file.txt"}'-```+The desktop-bridge CLI inside this machine is **`adom-bridge`**. (There is no+`adom-desktop` binary here — that's the retired old name; substitute+`adom-bridge` in any example that still uses it.) The relay it serves runs on this container's relay+ports; check health from in here with the port from+`~/.adom/cli-relay-ports.json`, or just use the verbs: -### Desktop interaction ```bash-adom-desktop notify_user '{"message": "Build complete", "duration_ms": 3000}'-adom-desktop desktop_open_url '{"url": "https://..."}'-adom-desktop desktop_open_folder '{"path": "/Users/<you>/project"}'+adom-bridge ping # desktop connection round-trip+adom-bridge status # capabilities + bridges+adom-bridge desktop_screenshot_screen '{"maxWidth":1500}'+adom-bridge kicad_open_board '{"path":"/Users/<you>/board.kicad_pcb"}'+adom-bridge fusion_start+adom-bridge send_files '{"filePaths":["/home/adom/project/file.txt"],"targetApp":"general","destinationFolder":"."}'+adom-bridge notify_user '{"message":"Build complete"}' ``` -## What's different from Adom cloud containers+## Reaching Hydrogen (the host) -| Feature | Adom Cloud | Hydrogen Local (machine) |-|---------|-----------|-----------------|-| Workspace provisioning | Adom platform API | `machinectl import-tar` of `adom-golden.tar.gz` inside the Lima VM on the user's Mac |-| Relay connection | wss:// through Cloudflare | ws://localhost:8765 (direct, no TLS) |-| Bridge latency | ~50-100ms (internet round-trip) | <1ms (localhost) |-| VSCODE_PROXY_URI | Coder proxy URL | http://localhost:7380/proxy/{{port}}/ |-| Socket.IO (collab) | Connected to iron.adom.inc | Disabled (single-user) |-| Service containers | Adjacent containers | Remote via Adom cloud |+vz does NOT mirror loopback — from in here, `127.0.0.1` is the machine, not+the Mac. Hydrogen's host services bind `0.0.0.0` and are reached via the+`adom-host` gateway; the live control URL is in+`~/.adom/hydrogen-control-url`. See `hydrogen-networking` / `hydrogen-api-mac`. -## Environment variables+## vs Adom cloud containers -- `ADOM_DESKTOP_MODE=local` — indicates Hydrogen local mode-- `HD_RUNTIME=macos` — indicates the machine runtime (default); `docker` selects the legacy container runtime-- `VSCODE_PROXY_URI=http://localhost:7380/proxy/{{port}}/` — code-server's proxy+| | Adom Cloud | Hydrogen local (this machine) |+|---|-----------|-------------------------------|+| Provisioning | Adom platform API | golden image / snapshot import on the user's Mac |+| Relay | wss:// through Cloudflare | localhost inside the machine (no TLS) |+| Bridge latency | ~50–100 ms | <1 ms | ## Related skills -- `hydrogen-topology` — the three-tier topology; tier 3 is this workspace machine-- `hydrogen-volume` — where your files live, what persists, and how to back up / copy out the machine+- `hydrogen-volume` — what persists, backups, moving files in/out+- `hydrogen-workspace-lifecycle` — start/stop/restart rules and scoping+- `hydrogen-networking` — the port model
skills/hydrogen-eda-install/SKILL.md+2−2@@ -30,7 +30,7 @@ whole point of Adom is that the AI has hands: **offer the install, then run it.* ## KiCad — unattended install (you can do this fully yourself) ```bash-adom-desktop desktop_install_kicad '{}'+adom-bridge desktop_install_kicad '{}' ``` - Downloads the latest official KiCad release and installs it (macOS: DMG →@@ -50,7 +50,7 @@ Autodesk account). But don't just paste a link either: 1. Tell the user: "Fusion 360 needs Autodesk's own installer and your Autodesk sign-in — I'll download it and open it for you." 2. Open the official download for them:- `adom-desktop desktop_open_url '{"url":"https://www.autodesk.com/products/fusion-360/appstream"}'`+ `adom-bridge desktop_open_url '{"url":"https://www.autodesk.com/products/fusion-360/appstream"}'` (or drive the download in a browser surface you control and open the downloaded installer). 3. While they install, keep the thread alive: tell them what you'll show once
skills/hydrogen-networking/SKILL.md+11−12@@ -13,13 +13,12 @@ description: > # Adom Hydrogen — Networking & Port Architecture -> This is the machine-runtime version (default). For the legacy Docker container-> runtime (`HD_RUNTIME=docker`) see the docker/ bucket.+> runtime (the retired Docker runtime. ## Core Principle: expose `0.0.0.0` listeners to the Mac The Hydrogen workspace is the `Adom-Workspace` machine (a systemd-nspawn machine booted-inside the `hd-builder` Lima VM), not a Docker container. The Apple `vz` VM does+inside the `hydrogen-builder` Lima VM), not a Docker container. The Apple `vz` VM does **NOT** mirror loopback between host and machine. Instead, Lima exposes the machine's listeners to the Mac: **any service that binds `0.0.0.0:<port>` inside the workspace machine is reachable at@@ -55,7 +54,7 @@ native TCP listeners on the Mac — not inside the workspace machine. | Port | Service | Notes | |------|---------|-------| | 1420 | Dev file server | Dev mode only, serves `build/` |-| 8770 | adom-desktop direct connect | Owned by Adom Bridge, NOT Hydrogen |+| 8770 | adom-bridge direct connect | Owned by Adom Bridge, NOT Hydrogen | | 47080 | Hydrogen discovery server | | | 47083 | Hydrogen reverse proxy | Proxies to code-server | | 47084 | Hydrogen control API | Health, setup, eval, CDP, `/workspace/status`, `/port-forward` |@@ -113,12 +112,12 @@ Direct connect → `http://127.0.0.1:8770/health` ## Relay Architecture -The relay (`adom-desktop serve`) runs inside the machine on ports 8765+The relay (`adom-bridge serve`) runs inside the machine on ports 8765 (WebSocket) and 8766 (HTTP). It binds `0.0.0.0`, so it is reachable both via Lima's port exposure (`localhost:8765` / `localhost:8766` on the Mac) and via the code-server proxy. The proxy path is preferred for connection stability: -1. **adom-desktop on the Mac** connects as a WS client via the+1. **adom-bridge on the Mac** connects as a WS client via the code-server proxy: `ws://127.0.0.1:7380/proxy/8765/` 2. **Registration** happens via `server_add` on the direct connect API (port 8770):@@ -132,7 +131,7 @@ code-server proxy. The proxy path is preferred for connection stability: 3. **Health checks** use the proxy path: `http://127.0.0.1:7380/proxy/8766/health` -This matches cloud containers where adom-desktop connects via+This matches cloud containers where adom-bridge connects via `wss://<slug>.adom.cloud/proxy/8765/`. ## VSCODE_PROXY_URI@@ -148,13 +147,13 @@ available, falling back to `http://127.0.0.1:{code_server}/proxy/{port}/`. ## In-machine command form -The workspace is the `Adom-Workspace` machine inside the `hd-builder` Lima VM, so+The workspace is the `Adom-Workspace` machine inside the `hydrogen-builder` Lima VM, so you reach it by entering its namespaces via `nsenter`, NEVER `docker exec` (`<leader>` is the machine's leader PID): ```bash-limactl shell hd-builder -- sudo nsenter -t <leader> -a -S 1001 -G 1001 -- bash -lc '<cmd>'+limactl shell hydrogen-builder -- sudo nsenter -t <leader> -a -S 1001 -G 1001 -- bash -lc '<cmd>' # or the simpler form for a single command:-limactl shell hd-builder -- sudo nsenter -t <leader> -a -S 1001 -G 1001 -- <cmd>+limactl shell hydrogen-builder -- sudo nsenter -t <leader> -a -S 1001 -G 1001 -- <cmd> ``` ## NEVER Do These@@ -173,10 +172,10 @@ limactl shell hd-builder -- sudo nsenter -t <leader> -a -S 1001 -G 1001 -- <cmd> maps `adom-host` to the gateway. No firewall allow needed. 4. **NEVER `docker exec` / `docker cp` against the workspace.** It's the `Adom-Workspace` machine; enter it via- `limactl shell hd-builder -- sudo nsenter -t <leader> -a -S 1001 -G 1001 --`.+ `limactl shell hydrogen-builder -- sudo nsenter -t <leader> -a -S 1001 -G 1001 --`. 5. **NEVER hardcode port numbers** in machine code. Read from env vars (`ADOM_CARBON_URL`, `ADOM_HYDROGEN_URL`) or discover via the direct connect API.-6. **NEVER assume adom-desktop direct connect (8770) is owned by Hydrogen.**+6. **NEVER assume adom-bridge direct connect (8770) is owned by Hydrogen.** It's owned by Adom Bridge. Hydrogen's direct-api thread binds to 8770 as a fallback but Adom Bridge takes priority when both are running.
skills/hydrogen-open-url-mac/SKILL.md+27−50@@ -1,60 +1,37 @@ --- name: hydrogen-open-url-mac description: >- macOS platform companion to hydrogen-open-url — the Apple-specific half of "open a URL- in a native browser". The six ways to open a URL (Hydrogen webview tab, Hydrogen window,- Pup, native browser, the Browser Picker, headless curl), the decide-for-the-user- rule, the /open-url + /open-in-profile + prefs API all live in hydrogen-open-url- (adom/hydrogen-bootstrap); THIS skill carries only the macOS native-browser mechanics:- launching via LaunchServices (`open` / `open -a "<App Name>"` / `--new-window`- fresh windows), macOS browser-profile dirs, and the control-URL discovery file- (~/.adom/hydrogen-control-url). Trigger words — open url macos, open -a, native browser mac, Safari Chrome- Arc Edge, fresh window mac, browser profiles mac, hydrogen-control-url.+ macOS mechanics for opening a URL in a native browser from Adom Hydrogen:+ LaunchServices (`open` / `open -a "<App Name>"`), forcing a truly fresh+ window for auth flows, and the control-URL discovery file+ (~/.adom/hydrogen-control-url). The decision framework (webview tab vs+ window vs pup vs native, decide-for-the-user) lives in hydrogen-open-url+ (adom/hydrogen-bootstrap). Trigger words — open url macos, open -a, native+ browser mac, fresh window mac, Safari Chrome Arc Edge. --- -# hydrogen-open-url (macOS) — opening URLs in native macOS browsers+# hydrogen-open-url (macOS) — LaunchServices, not .exe paths -This is the **macOS half** of `hydrogen-open-url`. The decision framework — the six ways to-open a URL, "decide for the user — DON'T hand them the picker", the-`/open-url` · `/open-in-profile` · `/browser-picker/prefs` API, the fresh-window-rationale for auth flows — is host-agnostic and lives in the generic **hydrogen-open-url**-skill. Read that first; this skill only covers how the **native-browser path (#4)**-launches on a Mac.+The generic **hydrogen-open-url** skill owns the decision framework (when a+webview tab, an Hydrogen window, pup, or a native browser is right — and that+YOU decide, never handing the user a chooser). This skill is only the macOS+launch mechanics for the native-browser path. -## Control-URL discovery — `~/.adom/hydrogen-control-url`+## Control-URL discovery -Same as the generic skill: read the live base URL from `~/.adom/hydrogen-control-url`-(`BASE="$(cat ~/.adom/hydrogen-control-url)"`) — never hard-code the port. On macOS that file-resolves to the **`adom-host` gateway** from inside the workspace machine, because the-Apple `vz` VM does NOT mirror host loopback (`127.0.0.1` inside the machine is NOT the-Mac, and Hydrogen's host services bind `0.0.0.0`). See `hydrogen-api-mac` for the gateway detail.+Read the live control base from `~/.adom/hydrogen-control-url`+(`BASE="$(cat ~/.adom/hydrogen-control-url)"`) — never hard-code a port. From+inside the workspace machine it points at the `adom-host` gateway (vz does not+mirror loopback — see hydrogen-api-mac). -## Native browsers launch via LaunchServices (`open` / `open -a`)+## Native browsers launch via LaunchServices -The `/open-in-profile` and direct native-browser paths drive macOS browsers through-LaunchServices, not by resolving an `.exe`:--- **Default / shell-open:** `open <url>` (LaunchServices picks the user's default- browser) — `open_in_browser_profile` / `screenshot.rs`.-- **Named browser:** `open -a "<App Name>" <url>`. `screenshot.rs` maps- `chrome→"Google Chrome"`, `edge→"Microsoft Edge"`, `firefox→"Firefox"`,- `brave→"Brave Browser"`; **Safari** and **Arc** are likewise app-name targets. Using- the app *name* (not a path) handles user-relocated installs uniformly.-- **Fresh window (`fresh:true`):** to force a brand-new window/process Hydrogen resolves a- concrete browser binary and passes `--new-window` (Chromium) / `-new-window` (Firefox)- before the URL — `open -a … <url>` alone opens a tab, not a window (`lib.rs`- fresh-window branch). A freshly-launched window auto-foregrounds, so this is the path- for **Claude/Adom auth pages the user must complete** (the generic skill defaults the- fresh toggle ON for those).--## macOS browser-profile dirs--`GET /browser-profiles` enumerates the user's installed browsers + profiles so-`/open-in-profile {browser, profileDir}` can target the **work** profile (where saved-logins live). On macOS those profiles live under the app's Application Support dir-(e.g. `~/Library/Application Support/Google/Chrome/<Profile>`,-`…/Microsoft Edge/<Profile>`). Discover them via the endpoint rather than assuming a-path or browser — don't hard-code `chrome`/`edge`.--On macOS the native-browser path is LaunchServices (`open` / `open -a`) with app-name-targets, never a resolved executable path.+- **Default browser:** `open <url>`.+- **Named browser:** `open -a "<App Name>" <url>` — app names, not paths:+ "Google Chrome", "Microsoft Edge", "Firefox", "Brave Browser", "Safari",+ "Arc". App-name targets survive user-relocated installs.+- **Fresh window (auth flows):** `open -a … <url>` opens a TAB in an existing+ window. To force a brand-new window Hydrogen resolves the browser binary and+ passes `--new-window` (Chromium) / `-new-window` (Firefox) before the URL.+ A fresh window auto-foregrounds — the right behavior for Claude/Adom auth+ pages the user must complete.
skills/hydrogen-permissions-mac/SKILL.md+38−57@@ -1,70 +1,51 @@ --- name: hydrogen-permissions-mac description: >- macOS platform companion to hydrogen-permissions — the Apple-specific half of the- permission story. The generic skill (adom/hydrogen-bootstrap) covers Hydrogen's webview- auto-grant: inside Hydrogen a webview app NEVER sees a "site wants to use your- microphone/camera/clipboard/location" prompt. THIS skill carries only what's- macOS-specific: the OS-level TCC privacy model (Screen Recording, Accessibility,- Automation, Camera, Microphone) granted under System Settings → Privacy &- Security, how Hydrogen preflights/requests them (CGPreflightScreenCaptureAccess,- AXIsProcessTrustedWithOptions), and that some need a relaunch / a stable signing- identity to stick.- Trigger words — macos permissions, TCC, screen recording permission, accessibility- permission, automation permission, privacy and security, AXIsProcessTrusted,- CGPreflightScreenCaptureAccess, grant accessibility, relaunch to take effect.+ macOS platform companion to hydrogen-permissions — the TCC (Privacy &+ Security) layer under Hydrogen's webview auto-grant, and the ONE doctrine+ that governs it here: Adom Hydrogen itself NEVER prompts for or appears in+ the TCC lists — Adom Bridge is the machine's TCC identity (Screen Recording,+ Accessibility, Automation). Hydrogen's status commands are read-only+ preflights. Trigger words — macos permissions, TCC, screen recording+ permission, accessibility permission, privacy and security, grant+ accessibility, permissions deck. --- -# hydrogen-permissions (macOS) — the TCC privacy gates+# hydrogen-permissions (macOS) — TCC, and who owns it -This is the **macOS half** of `hydrogen-permissions`. The cross-platform contract — Hydrogen's-**webview auto-grant** (mic/camera/clipboard/geolocation/notifications/sensors all-ALLOW, so no in-page "site wants to use…" prompt) — is identical on every host and-lives in the generic **hydrogen-permissions** skill. Read that first; this skill only covers-the macOS **OS-level** gates that sit *separately* underneath that auto-grant.+The generic **hydrogen-permissions** skill covers the webview auto-grant+(mic/camera/clipboard/etc. never show an in-page prompt). Underneath that,+macOS gates *processes* with TCC (System Settings → Privacy & Security). Two+layers — don't conflate them: if an in-page capture fails with no prompt in+sight, the OS layer is where to look. -## Two different layers — don't conflate them+## The doctrine: Bridge is the TCC identity, not Hydrogen -- **In-webview permissions** (mic/camera/clipboard/etc.): on macOS Hydrogen's webview is- **WKWebView**, which grants in-page media capture with no per-site prompt — the- auto-grant behavior described in the generic skill. This is the generic skill's- territory.-- **OS-level TCC permissions:** macOS still gates Hydrogen's *process* with the system-wide- TCC (Transparency, Consent & Control) model. These are real system prompts and live- under **System Settings → Privacy & Security**. The webview auto-grant does NOT bypass- them — if Hydrogen's process is denied Camera/Mic/Screen Recording at the OS, the in-page- capture still fails (look here, not at a "denied prompt", per the generic skill).+**Adom Hydrogen never prompts for TCC permissions and must not appear in the+Privacy & Security lists.** Screen Recording, Accessibility, and Automation+are granted to **Adom Bridge**, and the permissions deck in Hydrogen's+first-run flow walks the user through granting them to Bridge. Consequences: -## The TCC gates Hydrogen touches (and how it preflights them)+- Hydrogen's `macos_accessibility_status` / `macos_screen_recording_status`+ are **read-only preflights** — they accept a `prompt` argument for API+ compatibility and ignore it. They never fire a system dialog and never+ register Hydrogen in a TCC pane.+- Anything that needs a TCC-gated capability (desktop screenshots, desktop+ recording, synthesized input) runs through **Bridge**, under Bridge's+ grants. If such an operation comes back black/empty, check Bridge's rows in+ Privacy & Security — not Hydrogen's.+- TCC grants bind to the app's code signature; Bridge ships signed ++ notarized so grants persist across updates. -Hydrogen requests/preflights these natively (`mac_input.rs`, exposed as Tauri commands in-`lib.rs`):+## Deep links -| TCC permission | What Hydrogen uses it for | How Hydrogen checks/requests |-|---|---|---|-| **Accessibility** | synthesize keystrokes / `AXPress` into another app (press Return on Safari's claude.ai Authorize page) to auto-approve OAuth | `AXIsProcessTrustedWithOptions` via `accessibility_trusted(prompt)` → `macos_accessibility_status` |-| **Screen Recording** | screenshot the consent window for the OCR-approve flow | `CGPreflightScreenCaptureAccess` (non-prompting) / `CGRequestScreenCaptureAccess` via `screen_capture_trusted(prompt)` → `macos_screen_recording_status` |-| **Automation** ("control System Events") | the AppleScript/System-Events button-press that approves OAuth | `prime_automation` / `prime_browser_automation` → `macos_prime_automation`, `macos_prime_browser_automation` |-| **Camera / Microphone** | the first time Hydrogen's process actually uses the device | one-time system TCC prompt; toggles must be ON for **Adom Hydrogen** under Privacy & Security |+The exact panes can be opened directly, e.g.+`open "x-apple.systempreferences:com.apple.preference.security?Privacy_ScreenCapture"`+(and the Accessibility / Automation equivalents) — useful when walking the+user to a specific grant. -Preflight (`CGPreflight…`, `AXIsProcessTrusted…` with `prompt=false`) is-**non-prompting** — it reports current state. Passing `prompt=true` shows the system-dialog the first time and adds Hydrogen to the relevant Privacy & Security list. Hydrogen frontloads-Accessibility (and the Automation consent) in the **pre-login gate** rather than-mid-cascade (`setup_steps_macos.rs`), and can deep-link the user to the exact pane via-`open x-apple.systempreferences:com.apple.preference.security?Privacy_Accessibility`-(and the Screen Recording / Automation equivalents).+## Graceful degradation -## Gotchas--- **Some grants need a relaunch.** Screen Recording in particular: after the user toggles- it on, macOS may not honor it for the already-running process — Hydrogen's gate has a- "stale" path that **relaunches Adom Hydrogen** (`lib.rs` relaunch command) so the- new grant takes effect.-- **The grant is bound to the app's code signature.** An adhoc / un-notarized rebuild is- seen as a "new app" and the Accessibility grant is dropped (`mac_input.rs` signing- note). A stable Developer ID + notarization is needed for the grant to persist across- builds — relevant when a dev build keeps re-prompting.-- **Graceful degradation:** if Accessibility / Screen Recording are off, Hydrogen still opens- the sign-in page and starts the flow — the user just approves the browser page- themselves (no auto-press). It does not hard-block on these (`setup_steps_macos.rs`).+Auth and setup never hard-block on TCC: with grants missing, flows fall back+to the user clicking through themselves (e.g. approving the browser sign-in+page manually). Offer the grant path; don't stall the task on it.
skills/hydrogen-port-watcher/SKILL.md+8−9@@ -13,8 +13,7 @@ description: > # Hydrogen Port Watcher — Dynamic Port Forwarding -> This is the machine-runtime version (default). For the legacy Docker container-> runtime (`HD_RUNTIME=docker`) see the docker/ bucket.+> runtime (the retired Docker runtime. ## Why the daemon is still here on the machine @@ -125,16 +124,16 @@ listener lives. The control port is dynamic per launch; the live control URL ## Installation The watcher is a bash script (`port-watcher.sh`) deployed into the machine-during setup steps. Installation uses `limactl shell hd-builder` + `nsenter`+during setup steps. Installation uses `limactl shell hydrogen-builder` + `nsenter` into the machine, NOT `docker cp`/`docker exec`: ```bash # Stage the script into the Lima VM, then install it into the machine via nsenter.-limactl copy port-watcher.sh hd-builder:/tmp/port-watcher.sh-limactl shell hd-builder -- sudo nsenter -t <leader> -a -- bash -lc \+limactl copy port-watcher.sh hydrogen-builder:/tmp/port-watcher.sh+limactl shell hydrogen-builder -- sudo nsenter -t <leader> -a -- bash -lc \ 'cp /tmp/port-watcher.sh /usr/local/bin/port-watcher.sh && chmod +x /usr/local/bin/port-watcher.sh' # Launch detached inside the machine (as the adom user)-limactl shell hd-builder -- sudo nsenter -t <leader> -a -S 1001 -G 1001 -- bash -lc \+limactl shell hydrogen-builder -- sudo nsenter -t <leader> -a -S 1001 -G 1001 -- bash -lc \ 'nohup bash /usr/local/bin/port-watcher.sh >/tmp/port-watcher.log 2>&1 &' ``` @@ -233,15 +232,15 @@ typically pick a different random port on retry. Hydrogen logs the conflict. ## Debugging -All debugging runs inside the machine via `limactl shell hd-builder -- sudo+All debugging runs inside the machine via `limactl shell hydrogen-builder -- sudo nsenter -t <leader> -a -S 1001 -G 1001 -- ...`, NEVER `docker exec`: ```bash # Check what ports the watcher sees-limactl shell hd-builder -- sudo nsenter -t <leader> -a -S 1001 -G 1001 -- bash -lc "cat /proc/net/tcp | awk '\$4 == \"0A\" { split(\$2, a, \":\"); printf \"%d\\n\", strtonum(\"0x\" a[2]) }' | sort -n"+limactl shell hydrogen-builder -- sudo nsenter -t <leader> -a -S 1001 -G 1001 -- bash -lc "cat /proc/net/tcp | awk '\$4 == \"0A\" { split(\$2, a, \":\"); printf \"%d\\n\", strtonum(\"0x\" a[2]) }' | sort -n" # Check the watcher's own log-limactl shell hd-builder -- sudo nsenter -t <leader> -a -S 1001 -G 1001 -- cat /tmp/port-watcher.log+limactl shell hydrogen-builder -- sudo nsenter -t <leader> -a -S 1001 -G 1001 -- cat /tmp/port-watcher.log # Check what Hydrogen has forwarded (from the Mac host) curl -sf http://127.0.0.1:47084/port-forward
skills/hydrogen-ports/SKILL.md+15−16@@ -5,15 +5,16 @@ description: How Hydrogen does port forwarding between your workspace machine an # Hydrogen Ports — forwarding workspace services to your Mac -> This is the machine-runtime version (default). For the legacy Docker container-> runtime (`HD_RUNTIME=docker`) see the docker/ bucket.+> runtime (the retired Docker runtime. The Hydrogen workspace is the `Adom-Workspace` machine (a systemd-nspawn machine booted inside the `hydrogen-builder` Lima VM), not a Docker container. There is **no Docker `-p` port mapping** — Lima exposes the machine's listeners to the Mac for you. Any service that binds `0.0.0.0:<port>` inside the machine is reachable at-`localhost:<sameport>` on the Mac automatically. code-server itself binds-`0.0.0.0:7380`, so `localhost:7380` on the Mac just works. For browser-facing+`localhost:<sameport>` on the Mac automatically. code-server binds+`0.0.0.0:<the container's port>` — 7380 for the default container; additional+containers use their own ports (Hydrogen tracks them per container) — so that+same port just works on the Mac. For browser-facing HTTP/WS, code-server's `/proxy/<port>/` URL pattern is still preferred and still exposes any internal port. For the cases Lima's exposure can't cover (`127.0.0.1`-only listeners, or when exposure is flaky), Hydrogen's port-forward@@ -136,9 +137,9 @@ Defaults (you can override via ports.json): | Reverse proxy (`proxy`) | 47083 | | Hydrogen control API (`control`) | 47084 | | WebView2 CDP (`cdp`) | 47085 |-| KiCad bridge | **dynamic** (adom-desktop picks at bridge launch) |-| Fusion bridge | **dynamic** (adom-desktop picks at bridge launch) |-| Puppeteer bridge | **dynamic** (adom-desktop picks at bridge launch) |+| KiCad bridge | **dynamic** (adom-bridge picks at bridge launch) |+| Fusion bridge | **dynamic** (adom-bridge picks at bridge launch) |+| Puppeteer bridge | **dynamic** (adom-bridge picks at bridge launch) | **Conflict resolution is NOT "next sequential port."** On startup `PortConfig::resolve_available()` checks `proxy`, `control`, and `cdp`; if a@@ -197,28 +198,26 @@ of truth every consumer reads. - `hydrogen-port-watcher` — the retained daemon that registers `127.0.0.1`-only listeners and covers Lima port-exposure gaps - `hydrogen-container` — what's inside the workspace reachable on which port-- `hydrogen-desktop-sse` — the workspace API which runs on these ports-- `hydrogen-browser-picker` — what happens when you click a port-mappings URL ## Bridge ports are dynamic KiCad, Fusion 360, Puppeteer, and any 3rd-party bridges no longer have known-fixed ports. When a bridge launches, **adom-desktop picks an available port at+fixed ports. When a bridge launches, **adom-bridge picks an available port at runtime** and registers it. To find a running bridge's current port, query-adom-desktop:+the bridge CLI: ```bash-adom-desktop status+adom-bridge status # Look at desktop.apps.<bridge>.bridgePort ``` -Or use the bridge directly via adom-desktop CLI — you don't need the port at all:+Or use the bridge directly via adom-bridge CLI — you don't need the port at all: ```bash-adom-desktop kicad_open_board '{"path":"..."}' # adom-desktop routes to the right port-adom-desktop browser_eval '{"js":"..."}'+adom-bridge kicad_open_board '{"path":"..."}' # adom-bridge routes to the right port+adom-bridge browser_eval '{"js":"..."}' ``` This means **old code or skill examples that hardcoded fixed bridge ports-(8771 / 8773 / 8851) are stale.** Use the adom-desktop CLI or `status` lookup+(8771 / 8773 / 8851) are stale.** Use the adom-bridge CLI or `status` lookup instead.
skills/hydrogen-recording-mac/SKILL.md+37−66@@ -1,71 +1,42 @@ --- name: hydrogen-recording-mac description: >- macOS platform companion to hydrogen-recording — the Apple-specific half of recording- screen + window video from Adom Hydrogen. The recorder ladder, codec choice,- the max-duration cap, audio-only narration, and the "● Recording" indicator live- in hydrogen-recording (adom/hydrogen-bootstrap); THIS skill carries only what's true on macOS:- Hydrogen's native recorder is NOT available here (it's #![cfg(windows)]), so recording- goes through the in-app getDisplayMedia recorder, pup per-tab, or the Adom Bridge desktop- relay — and the Screen Recording TCC grant gates the desktop paths. Trigger words — record macos,- screen recording mac, record kicad mac, native recording windows-only,- screencapturekit, avfoundation, getdisplaymedia mac, screen recording permission,- tcc grant recording, desktop_record_start macos.+ How to record video from Adom Hydrogen on macOS: the in-app getDisplayMedia+ recorder (records the Hydrogen workspace to a .webm in recordings/), pup+ per-tab screencasts, and the Adom Bridge whole-desktop recorder — plus the+ Screen Recording TCC grant that gates desktop capture. The recorder ladder,+ codecs, caps, and the "● Recording" indicator live in hydrogen-recording+ (adom/hydrogen-bootstrap). Trigger words — record macos, screen recording+ mac, record kicad mac, getdisplaymedia mac, desktop_record_start macos,+ recording blank mac, screen recording permission. --- -# hydrogen-recording (macOS) — no native recorder; use getDisplayMedia / pup / Adom Bridge--This is the **macOS half** of `hydrogen-recording`. The recorder priority ladder, codec-tradeoffs (h264 vs h265), the `maxSeconds` cap + `reason`, audio-only narration-(`adom-cli hydrogen audio`), and the "● Recording" badge are cross-platform and live in-the generic **hydrogen-recording** skill — read that first. This skill only documents what's-Apple-specific.--## ⭐ There is no native macOS recorder (be honest about this)--Hydrogen's native recorder — `crates/hd-control/src/recorder.rs` — is **`#![cfg(windows)]`**.-On macOS it is **not compiled in**:--- `POST /recording/native/start` returns `{ok:false, error:"native recording is- Windows-only"}`, and `GET /recording/native/sources` has nothing to enumerate.-- `adom-cli hydrogen recording start --share …` routes to that endpoint, so it **fails- on macOS** — it does not produce a file.-- **Per-window recording ("record kicad" scoped to one window) does not exist on- macOS** — that capability is native-Hydrogen-only, hence Windows-only.--A ScreenCaptureKit / AVFoundation native recorder is the obvious macOS analog of the-Windows WGC/DXGI path, but **it is not yet built.** Do not claim Hydrogen has a-ScreenCaptureKit recorder.--## The macOS recording paths (what actually works here)--Per the source ladder, on macOS skip the native rungs and use:--1. **In-app `getDisplayMedia` recorder** — the Recording dropdown in the editor toolbar- (`EditorNav.svelte` + `recordingStore.ts`/`audioCaptureStore.ts`). Records the Hydrogen- workspace (and/or mic) → a single `.webm` uploaded to the workspace `recordings/`.- This is the in-Hydrogen path. **It DOES assert a display wake-lock** while running (see- [hydrogen-screen-lock-mac]) — release it by stopping the recording.-2. **pup per-tab — `adom-desktop browser_record_start {sessionId}`** — a clean CDP- screencast of one Chrome tab, no wake-lock, coexists with everything.-3. **Adom Bridge host desktop — `adom-desktop desktop_record_start {confirmDesktopNotTabRecording:true}`**- — the whole-desktop fallback on macOS. Whole-desktop ONLY (no per-window), Chrome- `getDisplayMedia` → holds the wake-lock, writes a `.webm` into Adom Bridge's bridges-cache- (NOT `~/project/recordings/`). **Verify the cap first:** `adom-desktop status` must- list the `record` capability.--## macOS gotcha — the Screen Recording TCC grant--The desktop-scoped paths (Adom Bridge `desktop_record_start`, and any `getDisplayMedia` capture-of the screen) are gated by macOS **TCC: System Settings → Privacy & Security → Screen-Recording** must allow the recording app. Without that grant the capture is black /-empty even though the call "succeeds." If a desktop recording comes back blank, check-the Screen Recording grant first.--## Not applicable on macOS--The native WGC/DXGI recorder — `Windows.Graphics.Capture` per-window + DXGI Desktop-Duplication full-screen → Media Foundation hardware H.264/H.265 → mp4 in-`~/project/recordings/`, the `/recording/native/*` endpoints, `adom-cli hydrogen-recording start --share`, and per-window `{source:"window:X"}` scoping (no picker, no-"you're sharing" banner, no wake-lock) — are all Windows-only;. None of that machinery exists on macOS.+# hydrogen-recording (macOS) — the three paths that work here++The generic **hydrogen-recording** skill has the ladder, codecs, `maxSeconds`+cap, audio-only narration, and the "● Recording" badge — read it first. On a+Mac, pick from these:++1. **In-app recorder** — the Recording dropdown in the editor toolbar+ (`recordingStore`/`audioCaptureStore`). Records the Hydrogen workspace+ (and/or mic) via `getDisplayMedia` → one `.webm` uploaded to the workspace+ `recordings/`. Holds a display wake-lock while running+ ([hydrogen-screen-lock-mac]) — released when you stop it.+2. **pup per-tab** — `adom-bridge browser_record_start {sessionId}`: a clean+ CDP screencast of one Chrome tab. No wake-lock; coexists with everything.+3. **Adom Bridge whole-desktop** —+ `adom-bridge desktop_record_start {confirmDesktopNotTabRecording:true}`.+ Whole desktop only; writes a `.webm` into Bridge's bridges-cache (NOT+ `~/project/recordings/`). Check `adom-bridge status` lists the `record`+ capability first.++Skip any `/recording/native/*` route or `--share` flag you see in older+material — those are not macOS surfaces; the three paths above are the+recording story here.++## The one macOS gotcha — the Screen Recording TCC grant++Desktop-scoped capture (path 3, and any `getDisplayMedia` of the screen) is+gated by **System Settings → Privacy & Security → Screen Recording** for the+recording app. Without the grant the capture "succeeds" but comes back black —+if a desktop recording is blank, check that grant first.
skills/hydrogen-screen-lock-mac/SKILL.md−6@@ -52,9 +52,3 @@ pmset -g assertions # look for a PreventUserIdleDisplaySleep holder `caffeinate -d`); if you see it in `pmset -g assertions`, something invoked it on purpose — it is not Hydrogen. -## Not applicable on macOS--The Windows wake-lock mechanics — `SetThreadExecutionState(ES_DISPLAY_REQUIRED)` as the-lock primitive, and diagnosing the holder with `powercfg /requests` (the elevated-`DISPLAY:` section) — do not exist on macOS. Here it's the IOKit-`IOPMAssertion` + `pmset -g assertions`, full stop.
skills/hydrogen-self-screenshot-mac/SKILL.md−5@@ -85,8 +85,3 @@ that grant a window/screen capture comes back **black or empty** even though the "succeeds." If screenshots are blank, check the Screen Recording grant first — it's the same grant the desktop recording paths need ([hydrogen-recording-mac]). -## Not applicable on macOS--The Win32 capture primitives — **`PrintWindow`** (per-window, works for backgrounded-windows) and **`BitBlt`** — are the Windows self-screenshot mechanics;. On macOS it's `screencapture`/CoreGraphics + CDP-`Page.captureScreenshot`, with `dom.measure`-driven cropping for selectors.
skills/hydrogen-setup-steps/SKILL.md+55−74@@ -1,94 +1,75 @@ --- name: hydrogen-setup-steps-description: What Hydrogen's setup steps did to prepare your workspace — the 18-step install sequence that imports the Adom-Workspace golden image, injects your Adom session, wires up the relay, and walks the Claude auth gate. Use this skill when the user asks "what did setup do", "why is X installed", "re-run a setup step", "what's a virgin reset", or "why did step N fail". Trigger words — setup steps, install steps, setup panel, virgin reset, re-run step, Run All, what did setup do, why is X installed, setup failed, install-tools, hydrogen setup, claude code extension install, hydrogen workspace ready.+description: What Hydrogen's setup cascade did to prepare this macOS workspace — the 19-step sequence that provisions the Lima VM, imports the golden image, converge-installs the tooling layer from the Adom Wiki, and verifies the whole stack end-to-end. Use when the user asks "what did setup do", "why is X installed", "re-run a setup step", "what's a virgin reset", or "why did step N fail". Trigger words — setup steps, install steps, setup panel, virgin reset, re-run step, Run All, what did setup do, setup failed, hydrogen setup. --- -# Hydrogen Setup Steps — what was done to prepare your workspace+# Hydrogen Setup Steps (macOS) -Machine-runtime version (default). The legacy 24-step Docker cascade-(`HD_RUNTIME=docker`) is in the docker/ bucket.+On first launch (or after a virgin reset) Hydrogen runs a 19-step cascade that+turns a blank Mac into a fully-tooled Adom workspace. The golden image is+SLIM — it bakes only the static layer (Ubuntu, code-server, the editor+extensions with their bundled CLIs as shims, the Adom CLIs). The tooling+layer — every `hydrogen-*` skill, adom-vscode, editor settings — is+converge-installed fresh from the Adom Wiki. Executed by+`setup_steps_macos.rs` (`step_defs_macos()`): halt-on-failure,+resume-not-restart, per-step 3× auto-retry. -When you first launched Adom Hydrogen (or after a virgin reset), Hydrogen ran a ~19-step install sequence to turn a blank workspace into a fully-tooled Adom workspace — the `Adom-Workspace` machine. The golden image is SLIM: it bakes only the STATIC layer (Ubuntu, code-server, the Adom CLIs). The tooling layer — the `hydrogen-*` skills, the adom-vscode + Claude Code extensions, editor settings — is converge-installed fresh from the Adom Wiki by the cascade (`install-hydrogen-skills`, `install-adom-vscode`, `install-claude-ext`, `configure-vscode`), and the `claude` CLI is a shim to the binary bundled inside the Claude Code extension (golden v21). Setup imports the image, runs those converges, injects your Adom session, and wires up the relay. This skill explains what each step did so you can help the user understand their environment, re-run failed steps, or wipe and rebuild. See `hydrogen-golden-image` for the baked-image model.--The cascade is executed by `setup_steps_macos.rs` (`step_defs_macos()` / `run_all_macos()`). `run_all_macos` is halt-on-failure, resume-not-restart, with per-step 3× auto-retry. In-machine work runs via `limactl shell hydrogen-builder -- sudo nsenter -t <leader> -a -S 1001 -G 1001 -- bash -lc '<cmd>'` (the machine's DEFAULT user is `adom`, UID 1001, home `/home/adom`; under systemd-nspawn the default user comes from the machine config / nsenter `-S 1001 -G 1001`; root variant drops `-S 1001 -G 1001`). There is NO `docker exec` and NO Docker image anywhere in this flow.--## The 18 steps (in order)+## The steps (current, in order) | # | Step | Purpose | |---|------|---------|-| 1 | ensure-workspace | Ensure the Lima VM `hydrogen-builder` is up (provision it if missing — no host reboot needed on macOS), `machinectl import-tar Adom-Workspace` from the golden image `adom-golden-v21-arm64.tar.gz` (full pre-baked image from the `adom-inc/hydrogen-lima-image` GitHub release), create the `adom` user, start code-server, verify code-server reachable from the Mac on 7380. SUBSUMES the old Docker pull-image / create-container / start-container steps. |-| 2 | wait-codeserver | Host TCP probe of the code-server port (default 7380), 120s |-| 3 | install-adom-vscode | "Activate editor extensions" — installs NOTHING (binary + extension are baked); waits for Adom sign-in, reloads the editor iframe, and proves the :8821 editor-control API answers |-| 4 | set-env-vars | Set `ADOM_CARBON_URL`, `ADOM_HYDROGEN_URL`, `ADOM_HD_CONTROL_URL`, `VSCODE_PROXY_URI`, `ADOM_DESKTOP_MODE` |-| 5 | inject-api-key | Write the Adom session token into the machine at `/var/run/adom/api-key` (mode 644) so adom-cli works |-| 6 | configure-vscode | settings.json / trusted-domains / activity-bar are BAKED; re-asserts theme + workbench backstops idempotently, and applies the per-session layout via :8821 |-| 7 | ensure-adom-desktop | Verify the Adom Bridge companion app is running on the Mac (the relay's desktop bridge) |-| 8 | start-relay | Start the adom-desktop relay inside the workspace (ports 8765 WS / 8766 HTTP) |-| 9 | test-direct-connect | Prove the fast container→desktop command path |-| 10 | test-relay | Register the relay with Adom Bridge for file streaming (file transfer + shell exec) |-| 11 | test-adom-cli | GATE: carbon path + hydrogen-proxy reachability via adom-cli (6 retries) |-| 12 | claude-auth | The single human gate — restore Claude creds or drive the in-editor Claude.ai sign-in via the native browser Browser Picker; runs LAST before the payoff steps |-| 13 | ensure-sse | GATE: confirm the editor browser SSE session is connected so Welcome's webview-open doesn't 409 |-| 14 | verify-workspace | GATE: battery confirming the proxy holds a real layout |-| 15 | welcome | Open Claude Code, authenticate if needed, send the first prompt |-| 16 | open-welcome | GATE: open welcome.html in Hydrogen's right pane; hard-fails if the Welcome tab doesn't appear |-| 17 | eda-discovery | Opt-in payoff: opens a SECOND fresh Claude conversation and human-types a prompt to run `hydrogen-eda-discovery` — quietly detects your EDA tools (KiCad, Fusion 360, Altium, OrCAD/Cadence) and reports what it found. Never blocks setup. |-| 18 | instapcb-quote | Opt-in payoff: opens a THIRD fresh Claude conversation and human-types a prompt to run `hydrogen-instapcb` — finds your uploaded InstaPCB quotes + the quoting engine, then offers to wire the live KiCad→quote loop. Never blocks setup. |--### Steps that NO LONGER EXIST (baked into the golden image)--These OLD step names are gone. If a user asks "what installed the Claude extension / my skills / VS Code settings", the answer is: **the live cascade converge-installed them from the Adom Wiki** (`install-hydrogen-skills` → skills + adom-vscode, `install-claude-ext` → the pinned Claude Code extension, `configure-vscode` → settings). Only the static OS/editor layer is baked. See `hydrogen-golden-image`.+| 1 | ensure-workspace | Lima VM `hydrogen-builder` up (provision if missing), import the machine (configured snapshot when it matches the pinned golden version, else the golden tarball), boot, start code-server on the container's port, verify host reachability |+| 2 | ensure-adom-bridge | The Adom Bridge companion app present + running on the Mac |+| 3 | wait-codeserver | Host TCP probe of the container's code-server port |+| 4 | install-hydrogen-skills | THE tooling converge: bundled native arm64 adom-wiki CLI into the machine, then `adom-wiki pkg install adom/hydrogen-mac-bootstrap` (+ chain) with install scripts re-run |+| 5 | install-adom-vscode | Waits for Adom sign-in, reloads the editor, proves the :8821 editor-control API answers (extension actually ACTIVATED) |+| 6 | set-env-vars | ADOM_CARBON_URL / ADOM_HYDROGEN_URL / control URL / VSCODE_PROXY_URI into the machine (4-channel delivery) |+| 7 | inject-api-key | Adom session token → `/var/run/adom/api-key` (tmpfs — re-injected on every auth completion + launch) |+| 8 | configure-vscode | Theme, trusted domains, layout — idempotent re-assert + per-session layout via :8821 |+| 9 | install-claude-ext | Ensures the Claude Code extension via Hydrogen's controlled install→restart→reload chain (marketplace auto-update stays OFF) |+| 10 | ensure-bridge-runtimes | Node/Python runtimes for the tool bridges (pinned downloads if the system lacks them, no admin prompt) |+| 11 | start-relay | The adom-bridge relay inside the workspace, on the container's relay ports |+| 12 | test-direct-connect | Fast workspace→desktop command path proven |+| 13 | test-relay | Relay registered with Adom Bridge for file streaming |+| 14 | test-adom-cli | GATE: adom-cli reaches Adom on both route classes (carbon + hydrogen-proxy) |+| 15 | ensure-sse | GATE: the editor's live SSE link is connected |+| 16 | verify-workspace | GATE: the proxy holds a real pushed layout |+| 17 | welcome | Tidies the editor layout for the first conversation |+| 18 | verify-setup | GATE: end-to-end re-verification (machine, code-server, :8821, session) |+| 19 | open-welcome | GATE: welcome.html actually opens in the right pane |++**Multi-container note:** the cascade converges the ACTIVE container's+machine. Additional containers (see the profile menu) import the configured+snapshot — tooling preinstalled — and only re-run the mechanical subset. ## Common user questions -**"Why is X installed in my workspace?"** → If X is an Adom CLI it is baked into the golden image; the Claude Code extension, VS Code settings, and every `hydrogen-*` skill were **converge-installed by the setup cascade from the Adom Wiki** (slim-image model). The `claude` CLI is a shim to the extension-bundled binary. The setup panel (Hydrogen UI → bottom) lists every step with its current status.+**"Why is X installed?"** → Adom CLIs are baked in the golden image; skills,+extensions, and settings were converge-installed from the wiki (step 4/9). The+`claude` and `codex` CLIs are shims to the binaries bundled inside their+editor extensions. -**"Setup failed at step N"** → The setup panel shows the error. Most common failures: step 1 (Lima VM `hydrogen-builder` not available / failed to provision, or the `adom-golden-v21-arm64.tar.gz` download), step 11 (test-adom-cli — carbon/hydrogen-proxy not reachable yet), step 12 (Claude credentials expired). Each step has a retry button (and the cascade already retried it 3×).+**"Setup failed at step N"** → the setup panel shows the error; each step has+a retry button (after the automatic 3×). Most common: step 1 (VM provisioning+/ image download) and step 14 (network to carbon). -**"Re-run a single step"** → In the setup panel, click the step row and use the Re-run action. Or via API: `POST http://127.0.0.1:47084/setup/step/<id>` (optional body `{"continue_after":true}` to keep going after it).--**"Re-run all steps"** → Click "Run All" in the setup panel; it resumes from the first not-done step. (The old headless `POST /setup/run-all` is now REFUSED.)+**"Re-run a step"** → setup panel → step row → Re-run, or+`POST $CTRL/setup/step/<id>` (optional `{"continue_after":true}`). ## Virgin reset -Virgin reset wipes parts of your workspace so setup can rebuild them cleanly. The ONLY programmatic trigger is `POST /setup/panel/run-virgin-reset`. Toggle which artifacts to delete (option keys in parentheses):--| Toggle (key) | What gets wiped | When to use |-|--------|----------------|-------------|-| Install step state (`install_state`) | Marks all steps as pending (`setup-steps-macos.json`) so they re-run | Always (default on) |-| Workspace machine (`container`) | PRISTINE `machinectl remove Adom-Workspace` + reimport — deletes the machine AND everything in it, including `/home/adom/project` | Always (default on); your work in `/home/adom/project` is GONE |-| Machine tarball (`tarball`, legacy `image`) | Deletes the cached `adom-golden-v21-arm64.tar.gz` (full-image re-download) | Rarely — only if the tarball is corrupted |-| Webview storage (`webview_storage`) | Queued wipe, flushed at next Hydrogen launch (restart_required) | Rarely |-| VS Code state (`vscode_state`) | Queued wipe, flushed at next Hydrogen launch (restart_required) | Rarely |-| Adom session token (`adom_token`) | Deletes `hydrogen-session.txt`; forces re-login | Rarely |-| Claude credentials (`claude_token`) | Deletes the host-side Claude creds backup; forces Claude re-auth | When Claude auth is stuck |--`confirmed_destructive` must be set. After toggling, hit "Wipe Selected", then "Run All" to rebuild. The machine reset backs up Claude creds first UNLESS `claude_token` is checked; the `webview_storage` / `vscode_state` wipes are queued and flushed at the next Hydrogen launch (restart_required), not immediate.--CRITICAL: the machine reset ONLY ever runs `machinectl remove Adom-Workspace` (+ reimport). It never runs a global teardown — stopping/deleting the `hydrogen-builder` Lima VM itself or running global `machinectl` teardown (those would kill the user's other Lima VMs / `machinectl` machines, including Docker-for-Mac's own VM), and it performs NO Docker actions and NO reboot for the wipe.--## Setup panel APIs (useful for AI automation)--| Endpoint | What it does |-|----------|--------------|-| `GET /setup/state` | Current state — `never-run`, `in-progress`, `complete`, or `error` |-| `POST /setup/step/<id>` | Re-run a single named step (optional `{"continue_after":true}`) |-| `POST /setup/panel/run-virgin-reset` | Trigger virgin reset with the supplied toggle options |-| `POST /setup/panel/show` | Open the setup panel from anywhere |--All on Hydrogen's control API at `http://127.0.0.1:47084`.--**DEPRECATED — now REFUSED, do not use:** `POST /workspace/unregister`, `POST /setup/virgin-reset`, `POST /setup/run-all`, `POST /setup/run-step`. Use `POST /setup/panel/run-virgin-reset` and `POST /setup/step/<id>` instead.--## Setup state file--Setup writes its state to `~/Library/Application Support/adom-hydrogen/setup-steps-macos.json` (one entry per step with `status: pending|running|done|failed`, output text, percent complete). Hydrogen reads this on launch to decide whether the setup panel auto-opens. (The legacy Docker runtime uses `setup-steps.json`.)+The ONLY programmatic trigger is `POST /setup/panel/run-virgin-reset` with+`confirmed_destructive:true` and the toggle keys: `install_state` (step state),+`container` (DESTRUCTIVE — `machinectl remove` of the active container's+machine + reimport; `/home/adom/project` in it is gone), `tarball` (cached+golden re-download), `webview_storage` / `vscode_state` (queued, flushed next+launch), `adom_token`, `claude_token`. The reset scopes to Hydrogen's own+machine only — never the Lima VM or other machines. Deprecated + refused:+`POST /setup/run-all`, `/setup/run-step`, `/setup/virgin-reset`,+`/workspace/unregister`. ## Related skills -- `hydrogen-golden-image` — the baked-image model: what's pre-installed in `adom-golden-v21-arm64.tar.gz` vs. what setup does-- `hydrogen-container` — the workspace machine and runtime that setup configures-- `hydrogen-networking` — how the machine reaches the host (via the `adom-host` gateway alias; live control URL in `~/.adom/hydrogen-control-url`) and how ports forward-- `hydrogen-browser-picker` — used by step 12 (claude-auth) for the Claude auth OAuth flow-- `hydrogen-adom-auth` — how the Adom session token (step 5) gets injected-- `hydrogen-volume` — where your files live in the machine and what survives a virgin reset (or doesn't)+- `hydrogen-container` — the workspace machine this cascade produces+- `hydrogen-networking` — adom-host gateway + port model+- `hydrogen-api-key-mac` — recovering step 7's token later
skills/hydrogen-volume/SKILL.md+18−20@@ -5,18 +5,18 @@ description: How Hydrogen's machine workspace storage is laid out — what's per # Hydrogen Workspace Storage — what persists, what doesn't -Machine-runtime version (default). Legacy Docker container runtime (`HD_RUNTIME=docker`) is in the docker/ bucket.+Machine-runtime version (default). Legacy Docker container runtime (the retired Docker runtime. -Your work lives on the `Adom-Workspace` machine's filesystem at `/home/adom/project` — a systemd-nspawn machine rootfs under the `hd-builder` Lima VM (e.g. `/var/lib/machines/Adom-Workspace`). There is **no Docker named volume** — `/home/adom/project` sits directly in the machine's own ext4 filesystem. ALL your work belongs under that path. It persists for as long as the machine stays registered.+Your work lives on the `Adom-Workspace` machine's filesystem at `/home/adom/project` — a systemd-nspawn machine rootfs under the `hydrogen-builder` Lima VM (e.g. `/var/lib/machines/Adom-Workspace`). There is **no Docker named volume** — `/home/adom/project` sits directly in the machine's own ext4 filesystem. ALL your work belongs under that path. It persists for as long as the machine stays registered. ## The filesystem | Property | Value | |----------|-------|-| Machine name | `Adom-Workspace` (fixed) |+| Machine name | `Adom-Workspace` for the default container (additional containers get their own machine names) | | Your work path | `/home/adom/project` (plain directory in the machine's ext4 fs) |-| Backing store | The machine's rootfs directory inside the Lima VM (`hd-builder`), e.g. `/var/lib/machines/Adom-Workspace/` on the VM disk |-| On-disk location (Mac) | N/A on macOS — it lives inside the `hd-builder` Lima VM's disk image, not directly on the Mac. Reach it via the relay or `limactl shell hd-builder` + nsenter (see below) |+| Backing store | The machine's rootfs directory inside the Lima VM (`hydrogen-builder`), e.g. `/var/lib/machines/Adom-Workspace/` on the VM disk |+| On-disk location (Mac) | N/A on macOS — it lives inside the `hydrogen-builder` Lima VM's disk image, not directly on the Mac. Reach it via the relay or `limactl shell hydrogen-builder` + nsenter (see below) | | Persistence | Survives workspace restart, Hydrogen restart, and Mac reboot. Persists as long as the machine stays **registered** (`machinectl`). | There is **no named volume to delete separately** — the project files and the OS image are one and the same ext4 filesystem. The only thing that wipes `/home/adom/project` is removing the machine.@@ -26,9 +26,9 @@ There is **no named volume to delete separately** — the project files and the | Path inside the machine | Persists across a tarball re-import? | Notes | |------------------------|---------------------------------------|-------| | `/home/adom/project/` | **Yes** — Hydrogen exports `/home/adom` before re-importing the golden image on a version bump, then restores it | This is your code. Put everything important here. |-| `~/.local/share/code-server/extensions/` | **Yes** within the machine — BAKED into the golden image, restored on tarball re-import | Not a setup step; baked at image-build time |-| `~/.local/share/code-server/User/settings.json` | **Yes** within the machine — BAKED into the golden image | Not a setup step; baked at image-build time |-| `~/.claude/` (skills, credentials) | Skills are BAKED into the golden image (restored on re-import); credentials are restored by the `claude-auth` setup step from a host-side backup | Hydrogen skills are baked FLAT into `~/.claude/skills/<name>/` |+| `~/.local/share/code-server/extensions/` | Re-created by the converge (slim image: the cascade installs extensions from the wiki/marketplace pin chain) | See `hydrogen-setup-steps` |+| `~/.local/share/code-server/User/settings.json` | Re-asserted by the converge (`configure-vscode`) | |+| `~/.claude/` (skills, credentials) | Skills are converge-installed from the Adom Wiki; Claude credentials restore from a host-side backup | Skills live FLAT at `~/.claude/skills/<name>/` | | `/tmp/` | **No** | Ephemeral | | `/etc/`, `/usr/`, system stuff | Lives in the same ext4 fs, but is overwritten on a tarball version bump | Treat as part of the workspace image | @@ -54,21 +54,21 @@ When you open Virgin Reset (Hydrogen setup panel), the checkbox toggles control There is **no Finder share** into the machine. Reach your files via the relay or by shelling into the Lima VM. -### 1. `limactl shell hd-builder` + nsenter + cp+### 1. `limactl shell hydrogen-builder` + nsenter + cp ```bash # Drop into the Lima VM, enter the machine namespace as the adom user, and operate on files-limactl shell hd-builder -- sudo nsenter -t <leader> -a -S 1001 -G 1001 -- bash -lc \+limactl shell hydrogen-builder -- sudo nsenter -t <leader> -a -S 1001 -G 1001 -- bash -lc \ 'ls -la /home/adom/project' ``` Use `limactl copy` to move files between the Mac and the VM disk, then `nsenter` + `cp` to land them in the machine's `/home/adom/project`. -### 2. `adom-desktop send_files` / `pull_file` (from inside the workspace, via the relay)+### 2. `adom-bridge send_files` / `pull_file` (from inside the workspace, via the relay) ```bash # Send a workspace file to your Mac desktop's Downloads folder-adom-desktop send_files '{"filePaths":["/home/adom/project/myfile.txt"],"targetApp":"general","destinationFolder":"."}'+adom-bridge send_files '{"filePaths":["/home/adom/project/myfile.txt"],"targetApp":"general","destinationFolder":"."}' # Pull a Mac file into the workspace's /tmp-adom-desktop pull_file '{"filePaths":["/Users/<you>/Downloads/myfile.txt"],"saveTo":"/tmp"}'+adom-bridge pull_file '{"filePaths":["/Users/<you>/Downloads/myfile.txt"],"saveTo":"/tmp"}' ``` ### 3. Open the workspace's `/home/adom/project/` in VS Code's File Explorer@@ -76,20 +76,20 @@ Just use the built-in code-server tree — the project folder is what's open, so ## Backing up your workspace -Persistence and backup for the machine is `machinectl export-tar` / `machinectl import-tar` (run inside the `hd-builder` Lima VM) — NOT a Docker volume tar. Before a destructive operation (the workspace-machine virgin-reset / `machinectl remove`):+Persistence and backup for the machine is `machinectl export-tar` / `machinectl import-tar` (run inside the `hydrogen-builder` Lima VM) — NOT a Docker volume tar. Before a destructive operation (the workspace-machine virgin-reset / `machinectl remove`): ```bash # Export the whole machine to a tarball inside the Lima VM-limactl shell hd-builder -- sudo machinectl export-tar Adom-Workspace /tmp/adom-workspace-backup.tar+limactl shell hydrogen-builder -- sudo machinectl export-tar Adom-Workspace /tmp/adom-workspace-backup.tar # (then limactl copy /tmp/adom-workspace-backup.tar back to the Mac if you want it off-VM) # Restore it later (re-register the machine from the backup)-limactl shell hd-builder -- sudo machinectl import-tar /tmp/adom-workspace-backup.tar Adom-Workspace+limactl shell hydrogen-builder -- sudo machinectl import-tar /tmp/adom-workspace-backup.tar Adom-Workspace ``` This is exactly the mechanism Hydrogen's own tarball-migration uses: on a tarball version bump it `machinectl export-tar`s `/home/adom` first, then re-imports the new base and restores your work. -Or, for just a few files, copy them out first via the relay or `limactl shell hd-builder` + nsenter + cp.+Or, for just a few files, copy them out first via the relay or `limactl shell hydrogen-builder` + nsenter + cp. ## Why a machine filesystem (no named volume, no bind mount)? @@ -98,10 +98,8 @@ Hydrogen keeps your work directly inside the `Adom-Workspace` ext4 filesystem ra - Avoids line-ending and permission issues that bind mounts of host paths often have - Lets Hydrogen wipe + re-import the base image (on a tarball bump) without losing your code — it `machinectl export-tar`s `/home/adom` first -There is no Finder share into the machine on macOS — use the relay (`adom-desktop send_files`/`pull_file`) or `limactl shell hd-builder` + nsenter + cp to move files in and out.+There is no Finder share into the machine on macOS — use the relay (`adom-bridge send_files`/`pull_file`) or `limactl shell hydrogen-builder` + nsenter + cp to move files in and out. ## Related skills - `hydrogen-container` — the `Adom-Workspace` machine whose filesystem holds your work-- `hydrogen-topology` — the three-tier topology; tier 3 is this Adom-Workspace machine-- `hydrogen-golden-image` — what's baked into `adom-golden.tar.gz` (extensions, settings, skills) vs. what setup does
skills/hydrogen-workspace-lifecycle/SKILL.md+63−163@@ -1,173 +1,73 @@ --- name: hydrogen-workspace-lifecycle-description: Workspace machine (`Adom-Workspace`) lifecycle management for Adom Hydrogen on macOS. Import/export/remove/terminate, code-server-as-Hydrogen-child, the resume reality-check, recovery after sleep/hibernate, and every hard-won rule about what NOT to do — above all, NEVER run a global teardown; touch ONLY Adom-Workspace so the user's other Lima VMs / machines stay safe. MUST READ before any workspace operation. Trigger words — machine, workspace, Adom-Workspace, restart workspace, terminate machine, remove, machinectl import-tar, machinectl remove, code-server, workspace broken, workspace unhealthy, machine hung, fix workspace, /workspace/status.+description: Workspace machine lifecycle for Adom Hydrogen on macOS — boot/stop/restart semantics, per-container systemd units, code-server under its own unit, recovery after sleep, and the hard scoping rules (NEVER a global teardown; touch only Hydrogen's own machines). MUST READ before any workspace operation. Trigger words — machine, workspace, Adom-Workspace, restart workspace, terminate machine, machinectl, code-server, workspace broken, workspace unhealthy, fix workspace. --- -# Adom Hydrogen — Workspace Machine Lifecycle--> This is the machine-runtime version (default). The legacy Docker equivalent-> (`HD_RUNTIME=docker`) is in the docker/ bucket.--Under the machine runtime the workspace is the **`Adom-Workspace` machine** (Ubuntu, a-systemd-nspawn machine imported with `machinectl import-tar`), running locally inside-Hydrogen's `hd-builder` Lima VM on the user's Mac. `/home/adom/project` lives inside the-machine — there is no Docker volume.--## ABSOLUTE RULE — NEVER do a global teardown--**Operate ONLY on `Adom-Workspace`. Never run any global teardown that hits the shared-Lima VM or other machines.**--Forbidden, no exceptions:-- ❌ stopping or deleting the `hd-builder` Lima VM itself (kills every machine inside it)-- ❌ `machinectl terminate` on any machine other than `Adom-Workspace`-- ❌ blanket killing of `machinectl` / nsenter processes-- ❌ restarting / re-provisioning the `hd-builder` Lima VM-- ❌ `machinectl remove` on anything but `Adom-Workspace`-- ❌ global `machinectl` teardown--**Why this matters:** the user may run other Lima VMs or `machinectl` machines, and-Docker-for-Mac keeps its own VM. Any global teardown — stopping/deleting the shared-`hd-builder` VM or wiping other machines — would knock those out. It's harmless to Hydrogen's-own `Adom-Workspace`, but it looks to the user like Hydrogen broke their other VMs / Docker —-terrible first-run UX. So every Hydrogen operation must be scoped to `Adom-Workspace` and-nothing else.--Allowed, scoped operations:-- ✅ `machinectl terminate Adom-Workspace` (this is what "Restart" does)-- ✅ `machinectl remove Adom-Workspace` (destructive wipe, this machine only)-- ✅ `machinectl import-tar Adom-Workspace <tarball>` (fresh import)-- ✅ `limactl shell hd-builder -- sudo nsenter -t <leader> -a -S 1001 -G 1001 -- bash -lc '<cmd>'` (exec inside the machine)--## In-machine exec — NEVER `docker exec`--To run a command inside the workspace:-```bash-limactl shell hd-builder -- sudo nsenter -t <leader> -a -S 1001 -G 1001 -- bash -lc '<cmd>'-# or, root variant (drop -S/-G):-limactl shell hd-builder -- sudo nsenter -t <leader> -a -- bash -lc 'su - adom -c "..."'-```-`<leader>` is the machine's leader PID. There is no `docker exec` under this runtime,-and no Docker container to exec into.--## Workspace Lifecycle--### Import (fresh setup)-`setup_and_start` → `MacosVmRuntime::setup_and_start` → `fresh_import`:-download `adom-golden.tar.gz` (the full pre-baked golden image, downloaded-anonymously from the `adom-inc/hd-lima-image` GitHub release, SHA256-verified)-then `machinectl import-tar Adom-Workspace adom-golden.tar.gz`, then start code-server.-Log proof: `[golden-tarball] downloaded … SHA256 OK` → `[setup] machine setup_and_start completed`-and `machinectl list` shows `Adom-Workspace` running.--### code-server is an HYDROGEN-OWNED CHILD process-code-server (`CODE_SERVER_CHILD` in `runtime/macos.rs`) runs as a child of Hydrogen, deliberately-tied to Hydrogen's lifetime — **NOT a detached `nohup`** (a detached process dies when the-machine tears down the session anyway). Consequence: every Hydrogen restart (rebuild / crash /-relaunch) orphans the old code-server, so a fresh Hydrogen can come up with the machine-running but the editor DEAD ("Starting AI Environment" forever) even when setup is-otherwise complete.--Fix (already in Hydrogen): Hydrogen **re-ensures code-server on every launch**-(`[macos-startup] re-ensured code-server on launch`). And the resume reality-check in-`run_all_machine` requires code-server reachable on the host port **7380** — not just-"machine present" — before it trusts the workspace as ready.--### Restart-"Restart Workspace" = `machinectl terminate Adom-Workspace` + re-ensure code-server.-NOT `docker restart`. This is the fix for a workspace that's gone unreachable after-laptop sleep/hibernate.--### Stop-`machinectl terminate Adom-Workspace`. The machine stays present (and your project files-persist); it just isn't running.--### Export / backup-`machinectl export-tar Adom-Workspace <file>.tar` snapshots the machine to a tarball.-Re-import with `machinectl import-tar Adom-Workspace <file>.tar`. (Scoped to this machine,-so safe.)--### Remove (DESTRUCTIVE wipe)-`machinectl remove Adom-Workspace` — deletes the machine AND everything in it, including-`/home/adom/project`. This is the only destructive wipe, and it names ONLY-`Adom-Workspace`. Never remove any other machine.+# Hydrogen Workspace Lifecycle (macOS)++The workspace is a systemd-nspawn machine inside the `hydrogen-builder` Lima+VM. Hydrogen may manage SEVERAL such machines (one per container in the+profile menu; the default is `Adom-Workspace`). Each machine boots under its+OWN transient unit, and each serves its own code-server port.++## ABSOLUTE RULE — never a global teardown++Operate ONLY on Hydrogen's own machines. Forbidden, no exceptions: stopping or+deleting the `hydrogen-builder` Lima VM; `machinectl terminate/remove` on any+machine Hydrogen doesn't own; blanket-killing machinectl/nsenter processes;+re-provisioning the VM. The user may have other Lima VMs and machines+(Docker-for-Mac included) — a "cleanup" that touches them looks like Hydrogen+broke their computer.++Allowed, scoped: `machinectl stop/terminate <machine>`, `machinectl remove+<machine>` (destructive, that machine only), `machinectl import-tar`,+and in-machine exec via+`limactl shell hydrogen-builder -- sudo nsenter -t <leader> -a -S 1001 -G 1001 -- bash -lc '<cmd>'`.+There is no `docker exec` in this runtime.++## code-server runs under systemd — it self-heals++code-server runs under the machine's **`code-server@adom` unit** with+`Restart=always` (RestartSec=4) and a converged drop-in pinning+`--bind-addr 0.0.0.0:<the container's port>`. A crash comes back in ~4s+whether Hydrogen is running or not; the editor pane's health watcher reloads+itself on recovery. Hydrogen also re-ensures the unit (and adopts any raw+orphan process holding the port) on every launch and every boot.++## Lifecycle semantics++- **Boot** — Hydrogen boots the machine under its per-container unit+ (`systemd-run … systemd-nspawn --boot`), serialized per machine; different+ machines can boot and run concurrently.+- **Restart Workspace** (menu) — synchronous stop (stop → terminate → unit+ kill escalation, waiting out the unit) then re-boot + code-server ensure.+ This is the fix for a workspace gone unreachable after laptop sleep.+- **Stop** — the machine deregisters; its files persist. Closing a container's+ window stops that container; quitting Hydrogen stops every machine, then the+ VM (per the user's quit choice).+- **Remove** (destructive) — `machinectl remove <machine>` deletes the machine+ and everything in it including `/home/adom/project`. Only via the+ confirm-gated flows (container delete, virgin reset).++## Diagnosing++- Editor stuck "Starting AI Environment" → is the machine registered+ (`machinectl list`)? Is code-server answering on the container's port from+ the Mac? Restart Workspace covers the common wedge.+- The real health line in Hydrogen's log is `[macos] Workspace unhealthy …`;+ the authoritative runtime line is `[app] Active workspace runtime: MacosMachine`.+- Recovery order: check the VM (`limactl list` — never stop it) → check the+ machine → Restart Workspace → last resort, remove + re-import (destructive). ## Control API -The Hydrogen control API is on loopback **`http://127.0.0.1:<dynamic>`** (NOT 9001). The-port is dynamic per launch — read the live URL from `~/.adom/hydrogen-control-url`. From-inside the machine, reach the host via the `adom-host` gateway alias (vz does NOT-mirror loopback, so 127.0.0.1 inside the machine is NOT the Mac).--| Endpoint | What it does |-|---|---|-| `GET /workspace/status` | Reports the machine state — present? running? code-server reachable on :7380? |-| `POST /workspace/unregister` | Destructive: `machinectl remove Adom-Workspace` (this machine only) |-| `GET /container-stats` | Live CPU/RAM/disk from the `workspace_stats()` probe (see hydrogen-container-stats) |--```bash-BASE="$(cat ~/.adom/hydrogen-control-url)" # http://127.0.0.1:<dynamic>--# Workspace status (from inside the machine, via the adom-host gateway)-curl -s "$BASE/workspace/status"--# Destructive wipe of ONLY Adom-Workspace-curl -s -X POST "$BASE/workspace/unregister"-```--## Diagnosing Workspace Problems--### "Workspace unhealthy" / editor stuck on "Starting AI Environment"-- **Cause**: code-server child was orphaned by an Hydrogen restart, or the machine went- unreachable after sleep.-- **Check**: `[macos] Workspace unhealthy …` in the Hydrogen log (the real signal). NOTE: a- `[docker] Container runtime unhealthy …` line under the machine runtime is **benign- noise** — a leftover heartbeat with no container bound. Ignore it; look at the- `[machine]` line.-- **Fix**: Restart Workspace (Adom menu) = `machinectl terminate Adom-Workspace` + re-ensure- code-server. Verify code-server answers on :7380.--### Machine running but editor dead-- **Cause**: code-server (Hydrogen's child) isn't up even though `machinectl list` shows running.-- **Fix**: relaunch Hydrogen (it re-ensures code-server on launch), or Restart Workspace.- Confirm via the resume reality-check — code-server reachable on :7380, not just- "machine present."--### Lima VM not available at all-- **Cause**: the `hd-builder` Lima VM isn't up / hasn't been provisioned.-- **Fix**: the "Lima VM not available" floaty → "Run Setup Steps" walks the user through- provisioning it. See [hydrogen-workspace-monitoring](../hydrogen-workspace-monitoring/SKILL.md).--## Recovery Checklist--When the workspace is broken, follow this order:--1. **Check the Lima VM itself**: `limactl list` / `limactl shell hd-builder -- systemctl status`- (NOT stopping or deleting `hd-builder`).-2. **Check the machine**: `machinectl list` — is `Adom-Workspace` listed and running?-3. **If running but editor dead**: code-server child orphaned → Restart Workspace- (`machinectl terminate Adom-Workspace` + re-ensure code-server), or relaunch Hydrogen.-4. **Verify code-server**: it must answer on host :7380 (the resume reality-check).-5. **Last resort (destructive)**: `machinectl remove Adom-Workspace` then re-import via- `setup_and_start` — wipes the machine and re-imports `adom-golden.tar.gz`.-6. **NEVER** reach for a global teardown to "fix" things — stopping/deleting the- `hd-builder` VM or running global `machinectl` teardown breaks the user's other- Lima VMs / machines, doesn't help your machine, and angers the user.--## What NOT To Do (learned the hard way)--- Do NOT stop or delete the `hd-builder` Lima VM — global, kills every machine in it,- breaks the user's other Lima VMs / Docker-for-Mac's VM.-- Do NOT `machinectl terminate` or `machinectl remove` any machine except `Adom-Workspace`.-- Do NOT blanket-kill `machinectl` / nsenter processes — same blast radius as tearing- down the VM.-- Do NOT use `docker exec` / `docker restart` — there is no container in this runtime.-- Do NOT trust "machine present" as healthy — require code-server reachable on :7380.-- Do NOT treat `[docker] … unhealthy` in the log as a real failure under the machine- runtime — it's benign; the real signal is `[macos] Workspace unhealthy …`.+Base URL from `~/.adom/hydrogen-control-url` (adom-host gateway from inside a+machine). `GET /workspace/status` and `GET /workspace/health` report the+FOCUSED window's container. `POST /workspace/unregister` is deprecated and+refused — destructive resets go through the setup panel's virgin reset. ## Related skills -- [hydrogen-workspace-monitoring](../hydrogen-workspace-monitoring/SKILL.md) — the 15s poll, floaty states, lifecycle dialog, auto-start-- [hydrogen-container-stats](../hydrogen-container-stats/SKILL.md) — title-bar CPU/RAM bars + `workspace_stats()` probe-- [hydrogen-networking](../hydrogen-networking/SKILL.md) — port 7380 code-server, control port 47084, host reachability via the `adom-host` gateway+- `hydrogen-workspace-monitoring` — how Hydrogen's UI watches this state+- `hydrogen-container` — what's inside the machine+- `hydrogen-setup-steps` — how a machine gets built in the first place
skills/hydrogen-workspace-monitoring/SKILL.md+32−137@@ -1,153 +1,48 @@ --- name: hydrogen-workspace-monitoring description: >- How Adom Hydrogen monitors and manages the local workspace machine- (`Adom-Workspace`) and code-server. Covers the 15s workspace state poll, the- two health levels (Lima VM up, machine running + code-server reachable), the- floaty states (Lima VM not available, machine stopped), auto-start via setup_and_start,- auto-reload of the VS Code iframe, and the lifecycle dialog system. Read BEFORE- touching PanelVisualStudioCode.svelte, ContainerLifecycleDialog.svelte, or any- workspace state handling code. Trigger words: workspace stopped, lima vm not available,- workspace monitoring, machine poll, workspace floaty, start workspace, code-server- reachable, lifecycle dialog, workspace state, Adom-Workspace running.+ How Adom Hydrogen's UI monitors the local workspace on macOS: the editor+ panel's health polling, the two health levels (Lima VM up; machine running ++ code-server reachable on the container's port), the in-panel floaty states+ with their Start/Setup actions, and the lifecycle dialog that streams+ start/stop/restart output. Trigger words — workspace stopped, lima vm not+ available, workspace monitoring, start workspace, code-server reachable,+ lifecycle dialog, workspace state. --- -# Hydrogen Workspace Monitoring+# Hydrogen Workspace Monitoring (macOS) -> This is the machine-runtime version (default). The legacy Docker equivalent-> (`HD_RUNTIME=docker`) is in the docker/ bucket.+Two health levels, probed through the runtime layer: -## Architecture+1. **Lima VM up** — is `hydrogen-builder` responding?+2. **Workspace healthy** — is the container's machine registered AND running+ AND code-server actually answering on that container's port from the Mac?+ ("Machine present" is never trusted as healthy — a machine can run with a+ dead editor.) -Under the machine runtime the workspace is the **`Adom-Workspace` machine** (a-systemd-nspawn machine imported via `machinectl import-tar`), not a Docker container.-Hydrogen monitors workspace health at two levels:+The VS Code panel polls workspace state and reacts; `/workspace/health` on the+control API is the same probe for programmatic callers (it reports the FOCUSED+window's container). -1. **Lima VM up** — is the `hd-builder` Lima VM itself up and responding on this Mac?-2. **Workspace healthy** — is `Adom-Workspace` present AND running AND is- code-server reachable on host port **7380**?+## Floaty states (inside the VS Code panel, draggable — never full-app modals) -The second level is a real reachability check, not just "is the machine present."-A resume reality-check (after sleep, or after an Hydrogen rebuild/relaunch) requires-code-server to actually answer before Hydrogen trusts the workspace as healthy — a machine-can be running while code-server is dead.+- **Lima VM not available** (red) → "Run Setup Steps" walks provisioning.+- **Workspace stopped / not ready** (red) → "Start Workspace" runs+ `setup_and_start`; the lifecycle dialog streams progress; when code-server+ answers again the editor iframe auto-reloads. -The VS Code panel (`PanelVisualStudioCode.svelte`) polls workspace state every 15s-and shows appropriate UI for each state. These frontend components survive unchanged-from the Docker era; they now front the machine runtime via the runtime trait.+There is no daemon middle-state (nothing like Docker Desktop to launch): the+VM is up or it isn't; the workspace is healthy or it isn't. -## Workspace State Poll+## The lifecycle dialog -`PanelVisualStudioCode.svelte` calls `get_container_status` (Tauri command) every 15s.-The command dispatches through the runtime trait to the machine impl. Returns a status-struct shaped like:-```rust-pub struct ContainerStatus {- pub docker_available: bool, // under the machine runtime: is the Lima VM hd-builder up?- pub image_pulled: bool, // is the Adom-Workspace tarball/machine present?- pub container_exists: bool, // is the machine present (running or stopped)?- pub container_running: bool, // is it running AND code-server reachable on :7380?- pub container_id: Option<String>,- pub error: Option<String>,-}-```-The field names are inherited from the Docker era; under the machine runtime they map-onto the two health levels above (Lima VM availability, then machine-present →-machine-running + code-server-reachable).--## Floaty States--All floaties appear INSIDE the VS Code panel only — not as full-app modals.-They are draggable (grab header to move). The rest of the app (wiki tab, menu, etc.)-remains fully interactive. The old Docker floaties ("Docker Desktop not installed/-running") become Lima-VM / machine states under this runtime.--### 1. Lima VM Not Available (red dot)-- **When**: the `hd-builder` Lima VM itself is not up / not responding (level-1 health fails)-- **Message**: "The Hydrogen utility VM (hd-builder) is required but not available."-- **Action**: "Run Setup Steps" button → dispatches `hd-show-setup` event (which walks- the user through provisioning the Lima VM)-- **Color**: Red dot in header--### 2. Workspace Stopped / Not Ready (red dot)-- **When**: the Lima VM is up but `Adom-Workspace` isn't running, or it's running but- code-server isn't reachable on :7380 (`container_running == false`)-- **Message**: "The Adom workspace is not running."-- **Action**: "Start Workspace" button → calls `setup_and_start` Tauri command-- **Lifecycle dialog**: Shows the draggable lifecycle dialog with live setup output-- **Auto-reload**: After the machine + code-server come up, waits for code-server- health, then reloads the VS Code iframe--There is no separate "daemon not running" middle state like Docker had — the machine-runtime has no always-on daemon to launch. Either the Lima VM is up or it isn't-(state 1), and the workspace is either healthy or it isn't (state 2).--## Auto-Start via `setup_and_start`--The "Start Workspace" path calls Tauri `setup_and_start`, which (in machine mode)-delegates to `MacosVmRuntime::setup_and_start`:-- If the machine isn't present yet, `fresh_import` = download the golden- `adom-golden.tar.gz` (from the `adom-inc/hd-lima-image` release) + `machinectl- import-tar Adom-Workspace` + start code-server.-- If the machine is present but code-server is down, it just (re-)starts code-server.--Importantly, code-server runs as an **Hydrogen-owned child process** (not a detached-`nohup`) — it dies with Hydrogen. So Hydrogen also **re-ensures code-server on every launch**-(look for `[macos-startup] re-ensured code-server on launch` in the log). Without that,-a freshly relaunched Hydrogen would show the machine running but the editor stuck on-"Starting AI Environment" forever, because the previous Hydrogen's code-server child was-orphaned. See [hydrogen-workspace-lifecycle](../hydrogen-workspace-lifecycle/SKILL.md) for the-full lifecycle detail.--## Lifecycle Dialog--`ContainerLifecycleDialog.svelte` — a draggable floating card (no background blur)-that shows live command output for start/stop/restart operations on the machine.--### Events-Listens for `hd-container-lifecycle` CustomEvents on `window`:-- `action: 'restart' | 'stop' | 'start'` — opens dialog, starts spinner-- `action: 'step', step: string` — appends a log line-- `action: 'done'` — stops spinner, shows Close button, auto-reloads VS Code-- `action: 'stopped'` — stops spinner (for stop-only operations)-- `action: 'error', message: string` — shows error state--### Title-Dynamic based on `actionType`:-- Restarting: "Workspace Restarting..." → "Restart Complete"-- Stopping: "Stopping Workspace..." → "Workspace Stopped"-- Starting: "Starting Workspace..." → "Workspace Started"-- On error: "Restart/Stop/Start Failed"--### VS Code Auto-Reload-After the `done` event, the dialog polls code-server health (`/proxy/8080/`) every 5s-for up to 2 minutes. When healthy, it reloads all iframes whose src points at-`localhost:7380` (the host-side code-server port), then shows "VS Code iframe reloaded"-and stops.--## Tauri Commands--| Command | What it does (machine mode) |-|---|---|-| `get_container_status` | Returns workspace status — Lima VM up, machine present, running + code-server reachable |-| `setup_and_start` | `MacosVmRuntime::setup_and_start` — `fresh_import` (import machine) + start code-server, up to 10 min timeout |-| `stop_container` | Stops the workspace (`machinectl terminate Adom-Workspace`) |-| `toggle_console` | Show/hide the debug console window |-| `is_console_visible` | Returns true if console window exists |--There is no `launch_docker_desktop` equivalent under the machine runtime — there's no daemon to start.--## Menu Items (Adom Menu → Workspace Section)-- **Restart Workspace** — `machinectl terminate Adom-Workspace` + re-ensure code-server; emits lifecycle events, shows dialog-- **Stop Workspace** — terminates the machine; emits lifecycle events, shows dialog, triggers stopped floaty-- **Start Workspace** — available when stopped (from floaty button or menu)--## Settings (Desktop section in Settings dialog)-- `desktop.show_console_on_startup` — boolean, default false-- `desktop.launch_on_boot` — boolean, default true (auto-start Hydrogen when the Mac logs in)+`ContainerLifecycleDialog.svelte` — a draggable card showing live output for+start/stop/restart, driven by `hydrogen-container-lifecycle` window events+(`restart|stop|start`, `step`, `done`, `stopped`, `error`). After `done` it+polls code-server health and reloads the editor iframe when it answers. ## Related skills -- [hydrogen-workspace-lifecycle](../hydrogen-workspace-lifecycle/SKILL.md) — import/export/remove/terminate, the never-do-a-global-teardown rule, control endpoints-- [hydrogen-container-stats](../hydrogen-container-stats/SKILL.md) — the title-bar CPU/RAM bars and `workspace_stats()` probe-- [hydrogen-networking](../hydrogen-networking/SKILL.md) — port 7380 code-server, control port 47084+- `hydrogen-workspace-lifecycle` — what the start/stop/restart actions+ actually do, and the scoping rules+- `hydrogen-networking` — why reachability is probed the way it is