---
name: hydrogen-workspace-lifecycle
description: Workspace machine (`Adom-Workspace`) lifecycle management for Adom Hydrogen on macOS. Import/export/remove/terminate, code-server-as-HD-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.
---

# 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 HD-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.

## 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/hd-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/hd-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 …`.

## 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
