docs(nh3-dev): add Mac Pro migration plan; retire vestigial volva/heid daemons

- migration-plan.md: workstation-only migration of nh3-dev's dev env to
  the M2 Ultra Mac Pro Rack (on-subnet, sidecars stay on Linux).
- nh3-dev README: drop volva from live sidecars + add retired note.
  volva.service/heid.service removed by infra-ops at heid's request
  (re-architected daemon->CC-orchestrator; volva.service was crash-looping).
This commit is contained in:
2026-06-07 21:45:17 -07:00
parent 5349da567c
commit 6e2f80e18e
2 changed files with 106 additions and 2 deletions
+101
View File
@@ -0,0 +1,101 @@
# nh3-dev → Mac Pro Rackmount migration plan
**Status:** planning — not started. Picked up later.
**Date framed:** 2026-06-07
**Audit snapshot:** 2026-06-07 (the unsaved-work table goes stale fast — re-run before acting).
---
## Locked decisions (operator, 2026-06-07)
| Fork | Decision | Consequence |
|---|---|---|
| **Chipset** | Apple Silicon (2023 Mac Pro Rack, **M2 Ultra, ARM64**) | Docker images need arm64 variants; x86-only binaries need Rosetta 2. macOS, not Linux. |
| **Scope** | **Workstation only** | Move *Hat 1* (dev env). Leave *Hat 2* (fleet sidecars) on the existing Linux VM. |
| **Network** | **Racked in NH3, on the 10.100 subnet** | Direct fleet reach; no WireGuard needed. Gets a **new** IP — `10.100.10.50` stays with the sidecars. |
### The governing insight
`nh3-dev` currently wears **two hats on one box**, and only one follows you to the Mac:
- **Hat 1 — your dev environment** (moves to the Mac): ~40 repos under `~/development`, all of `~/.claude` (skills, agents, auto-memory, settings — **1.8 GB**), `~/.ssh` (incl. `infra-ops_ed25519`), `.zshrc → dotfiles/`, `.gitconfig`, `.cargo`, `.config`, toolchain.
- **Hat 2 — load-bearing fleet sidecars** (STAY on Linux, untouched): `althing-forseti` (file-based agent message-bus curator), the ttyd seats (`ttyd-ro`/`ttyd-rw`/`ttyd-caddy`), **mead-hall** `:5173`, **NH3 egress SOCKS5 proxy** `socks5h://10.100.10.50:1080`, NFS mounts to nh3-nas.
- *(2026-06-08: `volva.service` + `heid.service` removed — vestigial daemons from before Heid/Volva became CC-session orchestrators; not part of Hat 2. One fewer service in the split.)*
Keeping Hat 2 on the existing VM (a) avoids porting Linux systemd/dante/Docker services to macOS launchd/Colima, and (b) un-tangles a latent bug: today a dev-box reboot kills fleet egress. After the split, the Mac reboots freely and nothing else notices. `10.100.10.50` stays bound to the sidecars.
---
## ⚠️ Phase 0 — Safety net (data-loss clock; do FIRST)
**Why this matters:** a "clean re-clone" on the Mac would silently drop unsaved work in ~15 repos. The correct cutover is **`rsync` the working trees wholesale**, not re-clone. Push everything pushable first as belt-and-suspenders.
### Unsaved-work audit (snapshot 2026-06-07 — RE-RUN before acting)
| Category | Repos | Risk on naive re-clone |
|---|---|---|
| **Local-only (no upstream branch)** | `bloom_music`, `comfy-dev`, `csm-expressiva`, `eitri-smithy`, `iris-friday`, `mead-hall` | May exist ONLY on this box → re-clone impossible. Must be copied. |
| **Unpushed commits** | `eshpfi-management` (**+14**), `heid` (+4), `brokkr-smithy`, `bifrost`, `chatterbox-fast`, `nevermore`, `ratatoskr`, `skaldsong`, `task-board`, `vastai-app` (each +1) | Lost on re-clone. |
| **Uncommitted working changes** | `vastai-app` (**21**), `voice-library` (16), `vor` (7), `heid`/`eitri-smithy` (6), `Worldtree`/`dvalin-smithy`/`task-board` (4)… | Never committed → lost on re-clone. |
| **Stashes** | `skaldsong` (1), `Worldtree` (1) | Stashes don't travel through remotes at all. |
Re-run the audit:
```bash
cd ~/development
for d in */; do d=${d%/}; [ -d "$d/.git" ] || continue; cd "$d"
dirty=$(git status --porcelain 2>/dev/null | grep -c .)
stash=$(git stash list 2>/dev/null | wc -l | tr -d ' ')
if git rev-parse '@{u}' >/dev/null 2>&1; then
n=$(git rev-list '@{u}..HEAD' --count 2>/dev/null); [ "$n" != "0" ] && state="ahead-$n" || state=""
else state="NO-UPSTREAM"; fi
{ [ "$dirty" != "0" ] || [ "$stash" != "0" ] || [ -n "$state" ]; } && printf '%-34s dirty=%-3s stash=%-2s %s\n' "$d" "$dirty" "$stash" "$state"
cd ..; done
```
### Phase 0 actions
- [ ] Push every repo with a remote + unpushed commits.
- [ ] For the 6 "no-upstream" repos: confirm whether a remote exists at all (`git remote -v`). Truly local-only → copy is the ONLY path; flag them.
- [ ] Do NOT auto-commit dirty trees — `rsync` carries them verbatim; pushing is just the redundant backup.
- [ ] Confirm `nh3-dev` will keep running headless after cutover (Hat 2 lives on).
---
## Phase 1 — Provision the Mac (Homebrew baseline)
- [ ] Xcode Command Line Tools + Homebrew.
- [ ] `brew install`: `uv`, `node`, `rustup`, `git`, `gh`, `tea`, `zellij`, `ripgrep`, `fd`, `jq`, `rsync`. Install Claude Code.
- [ ] zsh is already the macOS default — but prune Linux-isms from `.zshrc` (`apt`, `/etc/profile.d` sourcing, `PLAYWRIGHT_BROWSERS_PATH=/opt/ms-playwright`).
## Phase 2 — Re-home data (rsync over the 10.100 link)
- [ ] `rsync` (trees + dirty state): `~/development`, `~/.claude` (1.8 GB), `~/.ssh`, `~/.config`, `~/.gitconfig`, `~/.cargo`, `dotfiles/`.
- [ ] `chmod 600 ~/.ssh/*` after copy (rsync can mangle perms; macOS ssh is strict).
## Phase 3 — Repath for macOS ⚠️ (the silent breaker)
- [ ] **macOS home is `/Users/lkraven`, not `/home/lkraven`.** Sweep all of `~/.claude` + dotfiles for `/home/lkraven` and rewrite → `$HOME` / `/Users/lkraven`.
- Already-known hits in `~/.claude/settings.json`: the `statusline-command.sh` path and the `althing/plugin` path.
- `grep -rn '/home/lkraven' ~/.claude ~/dotfiles` to find the rest.
- [ ] Reinstall MCP/plugins (`task-board` from gitea `vh/task-board`, `althing`) and re-point absolute paths.
- [ ] ARM64 reality:
- Docker (if needed locally) → OrbStack/Colima + **arm64 images**.
- Playwright → `npx playwright install chromium` (arm64 supported; no `/opt/ms-playwright` shared trick needed on a single-user box).
- Python wheels are almost all arm64-mac now — only flag x86-only wheels (→ Rosetta 2).
## Phase 4 — Fleet citizenship for the new box
- [ ] Assign a **new** IP on 10.100 (NOT `10.100.10.50` — that's the sidecars'). Add to `~/.ssh/config`, fleet DNS, and `scripts/add-host.sh` if tracking here.
- [ ] WireGuard: **not needed** (no WG tunnel terminates on this box; Irvine reach was never a Hat-1 concern).
- [ ] Stand up a backup for the Mac (Time Machine, or a new restic client → `rest-server-nh3`). The risk table is the argument for not skipping this — real local-only state travels with you.
---
## Small decisions left (with recommendations)
- **NFS `/mnt/smithy` + `/mnt/backup` on the Mac?** → Recommend `/mnt/smithy` **yes** (R14/smithy workflows use it), `/mnt/backup` **no**. *(macOS NFS works, but the Synology export must list the Mac's new IP; macOS prefers autofs over fstab.)*
- **iPad/web seat into the Mac's dev session?** → Recommend **defer**. *(ttyd seats stay pointed at the Linux zellij session; a Mac seat is a fresh launchd port — only if you still drive from iPad.)*
- **Hostname** → Avoid `nh3-dev2` confusion; pick role-clear, e.g. `nh3-mac` / `nh3-workbench`.
---
## `/elitk` takeaway
Treat this as "set up a new workbench and copy my stuff over the network," **not** "move the server." Push everything first, then copy the folders wholesale (don't re-clone — you'd lose unsaved work in ~15 repos), fix the `/home/``/Users/` paths, and leave the little fleet-utility box humming untouched in the rack.
**Next action when resumed:** run Phase 0 (push pushable repos; confirm which of the 6 no-upstream repos are truly local-only). It's the only step with a data-loss clock; everything else waits on the hardware.
+5 -2
View File
@@ -20,8 +20,6 @@ local Bash already executes here — no SSH-to-self needed for non-privileged wo
behind Caddy; OSC52 clipboard shim). User systemd services under `~/.config`.
- **mead-hall** — Bifrost tool-provider sidecar (`:5173`), CI-deployed from
`vh/mead-hall`.
- **volva** — Codex peer agent on the althing bus (single-turn oracle, systemd
daemon).
- **bloom_music dev** — `~/development/bloom_music`; its `web/` test harness uses
Playwright headless Chromium for OSMD browser-geometry assertions.
@@ -47,3 +45,8 @@ Available to **every user/project** on this box — no per-home `playwright inst
(`scripts/refresh-server-info.sh nh3-dev`).
- Not in the colo Docker-stack topology — no `/opt/docker/compose` deploy target;
workloads are systemd services + dev checkouts.
- **Retired (2026-06-08):** `volva.service` + `heid.service` user systemd units
removed. Heid/Volva were re-architected from Python systemd daemons (`volva run`
/ `heid run` pollers) into Claude Code session orchestrators (heid commit
`12aa5a9`); the `~/development/volva` dir + venvs are gone. `volva.service` had
been crash-looping `203/EXEC`. Cleanup done by infra-ops at heid's request.