bootstrap
Adom Hydrogen (macOS / Lima)
Public Made by Adomby adom
The macOS platform layer for Adom Hydrogen.
← Commit history
Publish 0.1.30
10 files changed
+77−166
package.json+1−1page.json+1−1skills/hydrogen-api-key-mac/SKILL.md−1skills/hydrogen-container/SKILL.md+1−1skills/hydrogen-networking/SKILL.md+2−2skills/hydrogen-ports/SKILL.md+10−9skills/hydrogen-recording-mac/SKILL.md+4−3skills/hydrogen-self-screenshot-mac/SKILL.md+26−73skills/hydrogen-volume/SKILL.md+7−15skills/hydrogen-workspace-lifecycle/SKILL.md+25−60package.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.29",+ "version": "0.1.30", "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.29",+ "version": "0.1.30", "license": "proprietary", "visibility": "public", "metadata": {
skills/hydrogen-api-key-mac/SKILL.md−1@@ -100,4 +100,3 @@ endpoint is deprecated and hard-refused. - `hydrogen-api-mac` — `~/.adom/hydrogen-control-url` discovery + the `adom-host` gateway (why `127.0.0.1` doesn't reach Hydrogen from the machine).-- `hydrogen-setup-steps` — where `inject-api-key` sits in the install cascade.
skills/hydrogen-container/SKILL.md+1−1@@ -20,7 +20,7 @@ on the user's Mac, hosted in the `hydrogen-builder` Lima VM. | 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` |+| 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; refresh/repair any of it with `adom-wiki pkg install adom/hydrogen-mac-bootstrap` | Confirm live with `cat /etc/os-release`, `uname -m`, `/usr/lib/code-server/bin/code-server --version`.
skills/hydrogen-networking/SKILL.md+2−2@@ -29,7 +29,7 @@ The two corollaries that drive everything below: - **Bind `0.0.0.0`, not `127.0.0.1`.** A `127.0.0.1`-only listener inside the machine is NOT exposed to the Mac — the Mac can't see it. A workspace service that binds loopback-only is invisible to the host until you route it explicitly- (see `hydrogen-port-watcher`).+ (see `hydrogen-ports`). - **There are NO Docker port mappings.** code-server binds `0.0.0.0:7380` inside the machine and is therefore reachable at `localhost:7380` on the Mac automatically. Same for a dev server on `0.0.0.0:5173` → `localhost:5173`.@@ -160,7 +160,7 @@ limactl shell hydrogen-builder -- sudo nsenter -t <leader> -a -S 1001 -G 1001 -- 1. **NEVER bind `127.0.0.1`-only** for a service that must be reachable from the Mac. macOS won't expose it (vz does NOT mirror loopback). Bind `0.0.0.0`,- or register it with the port-forward registry (see `hydrogen-port-watcher`).+ or register it with the port-forward registry (see `hydrogen-ports`). 2. **NEVER use `host.docker.internal` for machine→host** communication — it's a Docker-ism Hydrogen doesn't use; inside the machine it resolves to the wrong interface. Reach the host via the `adom-host` gateway (vz does NOT mirror loopback, so
skills/hydrogen-ports/SKILL.md+10−9@@ -62,16 +62,19 @@ proxy URL for everything else. Lima's port exposure handles the common case. You still need the registry — Hydrogen's port-forward registry, serviced by the port-watcher daemon (see-`hydrogen-port-watcher`) — when:+Hydrogen) — when: - The service binds **`127.0.0.1` only** and you can't change it (some OAuth callback servers, some native tools). Lima won't expose loopback-only listeners; the registry creates a real host proxy that reaches them through code-server.-- Lima's port exposure is **lagging or broken** for a port (a real Hydrogen- failure mode: "code-server alive in the machine but the Mac can't reach- 127.0.0.1:7380"). The registry gives a reliable host-side proxy that doesn't- depend on Lima's port exposure.+- Lima's port exposure is **lagging or broken** for a port. The registry+ gives a reliable host-side proxy that doesn't depend on it.++**OAuth callbacks mostly just work:** Hydrogen watches for new listeners in+the machine and auto-forwards short-lived callback ports (Codex/Copilot-style+`127.0.0.1`-only servers included). If a callback still fails with connection+refused, register the port explicitly (below) and retry the flow. Decision order: 1. **Bind `0.0.0.0`** → exposed by Lima, done.@@ -188,15 +191,13 @@ of truth every consumer reads. **"`localhost:7380` shows nothing / code-server unreachable from the Mac"** - code-server is alive in the machine but Lima's port exposure wedged (a real Hydrogen-logged failure mode). The port-forward registry / port-watcher- daemon installs a host-side proxy to recover this — see `hydrogen-port-watcher`.- Or restart Hydrogen to re-establish the forward.+ registry installs a host-side proxy to recover this — register the port.+ Or have the user restart Hydrogen to re-establish the forward. ## Related skills - `hydrogen-networking` — the broader picture: `0.0.0.0` Lima exposure, hostnames, proxy architecture, relay vs direct connect, the `adom-host` gateway, NEVER do these-- `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 ## Bridge ports are dynamic
skills/hydrogen-recording-mac/SKILL.md+4−3@@ -20,8 +20,9 @@ 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.+ `recordings/`. Holds a display wake-lock while running — the screen+ won't sleep until you stop it. (Display pinned awake later?+ `pmset -g assertions` names the holder; stop that capture.) 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** —@@ -38,5 +39,5 @@ recording story here. 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 —+recording app (Adom Bridge — see `hydrogen-permissions-mac`). Without the grant the capture "succeeds" but comes back black — if a desktop recording is blank, check that grant first.
skills/hydrogen-self-screenshot-mac/SKILL.md+26−73@@ -1,87 +1,40 @@ --- name: hydrogen-self-screenshot-mac description: >- macOS platform companion to hydrogen-self-screenshot — the Apple-specific half of Hydrogen- screenshotting its own window, PLUS the token-efficient capture flow (`shot` — one- call, prints a PNG path, never floods context with base64). The tool ladder, the- `POST /screenshot` CDP endpoint, selector region-clips, the sharing gate, and the- during-a-recording contention matrix live in hydrogen-self-screenshot (adom/hydrogen-bootstrap);- THIS skill carries the `shot` helper doctrine and the macOS capture internals: the- `screencapture` CLI / CoreGraphics window path, the CDP `Page.captureScreenshot`- content grab, how the per-panel selector crop resolves the rect via `dom.measure`- (WKWebView has no CDP) and crops with the image crate, and the Screen Recording TCC- grant. Trigger- words — screenshot hydrogen mac, shot helper, token efficient screenshot, screencapture- cli, coregraphics screenshot, wkwebview no cdp, dom.measure crop,- page.capturescreenshot mac, screen recording permission screenshot, tcc screenshot- grant.+ Token-efficient screenshots of the Hydrogen workspace on macOS: the `shot`+ wrapper (one Bash call → PNG path → Read; never base64 in context), panel /+ workspace / screen targets, selector crops, and the Screen Recording grant+ gotcha for blank captures. Trigger words — screenshot hydrogen mac, shot+ helper, token efficient screenshot, screenshot blank mac, capture panel. --- -# hydrogen-self-screenshot (macOS) — screencapture / CoreGraphics + the CDP content path+# Screenshots on macOS — use `shot` -This is the **macOS half** of `hydrogen-self-screenshot`. The default flow — `adom-cli-hydrogen screenshot panel|workspace|screen` saving a PNG into the container's-`screenshots/` to `Read`, the `POST /screenshot {target,selector,b64,silent}` CDP-power-path, the sharing gate, and the multi-thread `capture_busy` / coexistence matrix-— is cross-platform and lives in the generic **hydrogen-self-screenshot** skill. Read that-first; this skill documents the token-efficient capture flow and what's Apple-specific-about how the bytes are grabbed.--## ⭐ ALWAYS capture with `shot` — 2 tool calls, ~20 bytes of output--**Never run `adom-cli hydrogen screenshot ...` bare.** It prints the capture as a-~300 KB base64 `dataUrl` JSON on stdout — that's ~85k tokens of noise in your context-per capture, plus a second decode step you'd have to improvise. This bootstrap installs-a wrapper that does the whole thing in one call and prints ONLY the PNG path:+**Never run `adom-cli hydrogen screenshot ...` bare** — it prints ~300 KB of+base64 into your context. This workspace installs a wrapper that prints ONLY+a PNG path: ```bash-shot # whole workspace (all panels) → /tmp/shot-workspace-<ts>.png-shot screen # entire screen (desktop, other apps)+shot # whole workspace (all panels)+shot screen # entire desktop (other apps too) shot panel --name "KiCad" # one panel's content-shot workspace --reason "verify the flow viewer rendered" # flags pass through+shot workspace --reason "verify the flow viewer rendered" ``` -Then **Read** the printed path — the Read tool attaches images efficiently. Total flow:-one Bash call + one Read. That's the floor; don't add steps.--- If no image comes back, `shot` exits 1 and prints the CLI's own JSON to stderr —- usually the **sharing gate** (capture needs the user's sharing approval; pass- `--reason "…"` so the approval dialog says why). Read the error, don't blind-retry.-- `SHOT_OUT=/path/out.png shot ...` overrides the output path if you need a stable name.-- If `shot` is missing (pre-0.1.3 workspace), re-converge: `adom-wiki pkg install- adom/hydrogen-mac-bootstrap` — or inline the same pipe:- `adom-cli hydrogen screenshot workspace 2>/dev/null | python3 -c "import sys,json,base64;d=json.load(sys.stdin);open('/tmp/ws.png','wb').write(base64.b64decode(d['dataUrl'].split(',',1)[1]));print('/tmp/ws.png')"`--## How Hydrogen grabs its own window on macOS--- **Whole-window / desktop:** Hydrogen uses the macOS **`screencapture` CLI** (and- CoreGraphics window capture) to grab the Hydrogen window or the full screen — the macOS- analog of the Windows `PrintWindow`/`BitBlt` path.-- **Webview / panel content:** the canonical content grab is **CDP- `Page.captureScreenshot`** (the `/capture/viewport` · `/shot` path) — a one-shot,- wake-lock-free capture of the rendered surface. This is the same `POST /screenshot`- endpoint as everywhere; on macOS it backs the `target`/panel content capture.--## ⭐ The per-panel selector crop — `dom.measure`, not CDP--On Windows the `selector` region-clip can lean on CDP against the webview. On macOS the-Hydrogen shell uses **WKWebView, which exposes no CDP** to drive the page directly. So a-per-panel / per-selector crop resolves the rect a different way:--1. Resolve the element's rectangle via the **`dom.measure` ui-action RPC** (the- UI-command bus measures the selector in the live DOM and returns its bounds).-2. Capture the content area (CDP `Page.captureScreenshot` / `screencapture`).-3. **Crop the captured image to that rect with the Rust `image` crate.**--So `{selector:".resource-bars"}` still clips to just that element — but the rect comes-from `dom.measure` and the crop is server-side in Rust, because WKWebView can't be-CDP-shot to a selector the way a Chromium webview can.+Then **Read** the printed path. Total flow: one Bash call + one Read — that's+the floor, don't add steps. -## macOS gotcha — the Screen Recording TCC grant+- Selector crops work: pass `--selector ".resource-bars"` style flags through+ — the crop lands server-side.+- On failure `shot` exits 1 and prints the CLI's own JSON to stderr — usually+ the sharing gate (pass `--reason "…"` so the approval dialog says why).+ Read the error; don't blind-retry.+- `SHOT_OUT=/path/out.png shot ...` pins the output path.+- If `shot` is missing, re-converge:+ `adom-wiki pkg install adom/hydrogen-mac-bootstrap`. -The OS-level capture (`screencapture` / CoreGraphics) is gated by macOS **TCC: System-Settings → Privacy & Security → Screen Recording** must allow Adom Hydrogen. Without-that grant a window/screen capture comes back **black or empty** even though the call-"succeeds." If screenshots are blank, check the Screen Recording grant first — it's the-same grant the desktop recording paths need ([hydrogen-recording-mac]).+## Blank/black capture? → the Screen Recording grant +OS-level screen capture is gated by **System Settings → Privacy & Security →+Screen Recording** (granted to Adom Bridge — see `hydrogen-permissions-mac`).+Without it, captures "succeed" but come back black. Check that grant first.
skills/hydrogen-volume/SKILL.md+7−15@@ -26,7 +26,7 @@ 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/` | 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/extensions/` | Re-created by the converge (slim image: the cascade installs extensions from the wiki/marketplace pin chain) | See Hydrogen | | `~/.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 |@@ -34,21 +34,13 @@ There is **no named volume to delete separately** — the project files and the **Rule of thumb:** if you want it to survive a workspace rebuild, put it under `/home/adom/project/`. -## What survives each virgin-reset choice+## What survives a reset -When you open Virgin Reset (Hydrogen setup panel), the checkbox toggles control which artifacts get deleted:--| Toggle ON means: | Result |-|------------------|--------|-| Install step state | `setup-steps-macos.json` deleted; next setup re-runs everything. Your project files unaffected. |-| Workspace machine | **`machinectl remove Adom-Workspace`. This wipes the ENTIRE machine including `/home/adom/project/`. This is the destructive option.** No reboot needed; the wipe is immediate. |-| Workspace image | Deletes the cached `adom-golden.tar.gz`, so setup re-downloads it on next run. Your machine (and your code, if still registered) is unaffected. |-| Adom session token | Re-login required next time. Project files unaffected. |-| Claude credentials | Claude Code requires re-auth. Project files unaffected. |--**The only toggle that destroys your work is "Workspace machine" (the `machinectl remove`).** All others are safe for your code. (Note: the "image" reset just deletes the cached `adom-golden.tar.gz` — NOT a 390MB Docker image like the legacy runtime.)--⚠️ The reset only ever targets `Adom-Workspace`. It NEVER touches the Lima VM itself or any other machine registered on the host.+The only Hydrogen operation that destroys your work is the **workspace-machine+wipe** (container delete / the "Workspace machine" toggle in a virgin reset) —+it removes the machine including `/home/adom/project`. Every other reset+option (step state, cached image, tokens, webview state) leaves your files+untouched. Before anything destructive, copy work out (below) or ask the user. ## Accessing workspace files from the Mac
skills/hydrogen-workspace-lifecycle/SKILL.md+25−60@@ -1,73 +1,38 @@ --- name: hydrogen-workspace-lifecycle-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.+description: Safety rules for anything that touches the Mac host or the workspace machine's lifecycle from inside an Adom Hydrogen container — above all, NEVER run a global teardown (limactl/machinectl) on the host, and what to tell the user when the workspace feels broken. Trigger words — restart workspace, machinectl, limactl, workspace broken, workspace unhealthy, fix workspace, teardown. --- -# Hydrogen Workspace Lifecycle (macOS)+# Workspace lifecycle — the rules from inside -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.+Your machine is managed by Adom Hydrogen on the user's Mac (a systemd-nspawn+machine inside the `hydrogen-builder` Lima VM). You don't manage its+lifecycle — Hydrogen does. Two things you DO need: -## ABSOLUTE RULE — never a global teardown+## 1. If you touch the host, 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.+You can reach the Mac via `adom-bridge shell_execute`. If a task ever leads+you toward host-side VM/machine commands, the hard rules: -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.+- ❌ never stop/delete the `hydrogen-builder` Lima VM (kills every machine in+ it, including things Hydrogen doesn't own)+- ❌ never `machinectl terminate/remove` any machine you don't positively know+ is Hydrogen's, and never as a "cleanup"+- ❌ never blanket-kill machinectl/nsenter processes+- ❌ never remove your OWN machine from inside — you'd be sawing off the+ branch you're sitting on, and destroying `/home/adom/project` -## code-server runs under systemd — it self-heals+The user may run other Lima VMs and machines (Docker-for-Mac included). A+"helpful" teardown looks like Hydrogen broke their computer. -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.+## 2. When the workspace feels broken, hand it to the user -## Lifecycle semantics+Editor dead, host unreachable, everything timing out after the laptop slept:+the fix lives in Hydrogen, not in here. Tell the user plainly: -- **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).+> Open the Adom menu in Hydrogen and click **Restart Workspace** — that+> rebuilds the connection cleanly. -## 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--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` — 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+Then re-verify your side (`adom-cli carbon user get`,+`curl "$(cat ~/.adom/hydrogen-control-url)/health"`). For a dead Adom token+specifically, see `hydrogen-api-key-mac`.