docs: extract 3 substantive harness-base.nix prose blocks (#718, first pass)
iris's #718 scope: move substantive design context from `#` comment blocks in `nix/` to corresponding `docs/` files, leave short references in code. iris handed it back to me on #10114 since nix/ is my lane + #775 established the pattern. First pass — three highest-density blocks in harness-base.nix: 1. **First-boot agent-user migration** (~70 lines → `~20 lines code + short ref` in the activation script). Substantive prose moves to new `docs/persistence.md::First-boot agent-user migration (post-#658)` section explaining the 4 steps the script performs + the eventual removability of the marker-guarded body. 2. **nix-daemon `sandbox-fallback = true`** (10-line block → 5-line ref). New `docs/gotchas.md::Containerized nix-daemon needs sandbox-fallback = true` section covers the user-namespaces rationale + nixpkgs-default override. 3. **Matrix daemon + token-arrival trigger** (~50 lines across two systemd units → ~10 lines code + short refs). New `docs/persistence.md::Matrix per-agent daemon + token-arrival trigger` covers the socket-path rationale, the runtime-dir ownership story, and the first-boot ordering pattern. Net: harness-base.nix -84 lines, docs +74 lines. Substantive design context moves to durable docs; in-code refs follow iris's pattern from her #712 batches (`see docs/<file>::<section>`). Follow-ups: hive-c0re.nix, hive-forge.nix, hive-matrix.nix (already trimmed via #775 but a couple of remaining blocks could go), and the smaller files in #718's scope table. Shipping this first to get the pattern reviewed before larger batches. Verified: `nix eval` on agent-base toplevel still resolves.
This commit is contained in:
parent
3f84b6492a
commit
309879dba0
3 changed files with 96 additions and 84 deletions
|
|
@ -227,3 +227,14 @@ hive-forge lint assignments # per-assignee open item count
|
|||
Credentials come from `$HYPERHIVE_STATE_DIR/forge-token`; default
|
||||
repo from `$HIVE_FORGE_REPO`, overridden per-invocation by the
|
||||
global `-r/--repo` flag.
|
||||
|
||||
## Containerized nix-daemon needs `sandbox-fallback = true`
|
||||
|
||||
Agent containers bind-mount the host's nix-daemon socket. nspawn
|
||||
containers don't get user-namespaces by default, so `nix build`
|
||||
invocations *inside* the container can't set up the build sandbox
|
||||
and fail outright if the host daemon's
|
||||
`nix.settings.sandbox-fallback` is `false` (nixpkgs default).
|
||||
`nix/templates/harness-base.nix` does `lib.mkForce true` so builds
|
||||
fall back to unsandboxed local builds rather than failing. Security
|
||||
implications: `docs/security.md`.
|
||||
|
|
|
|||
|
|
@ -198,3 +198,66 @@ On startup, `Coordinator::register_agent` drops any prior socket
|
|||
task before rebinding — idempotent so a hive-c0re restart followed
|
||||
by `rebuild alice` recreates the agent's socket without a clean
|
||||
reinstall.
|
||||
|
||||
## First-boot agent-user migration (post-#658)
|
||||
|
||||
Pre-#658 the harness ran as root inside the container. #658 dropped
|
||||
to a per-agent unix user (`hyperhive.user.name`, defaults to the
|
||||
agent's logical label so each container has a uniquely-named user).
|
||||
The transition needs a one-time data shuffle so existing operators
|
||||
who deployed pre-#658 don't lose their claude session.
|
||||
|
||||
`system.activationScripts.hive-agent-user-migrate` (in
|
||||
`nix/templates/harness-base.nix`) runs on every activation,
|
||||
marker-guarded so the substantive moves only happen once per
|
||||
container lifetime:
|
||||
|
||||
1. **`${homeDir}` exists with the right ownership** — covers the
|
||||
very first boot before `useradd`'s `createHome` has had a
|
||||
chance to chown. Also re-applies on every rebuild in case the
|
||||
meta-flake's per-agent name evolves (rare).
|
||||
2. **Migrate any leftover `/root/.claude` content into
|
||||
`${homeDir}/.claude`** — pre-#658 `claude` wrote to root's
|
||||
empty home; the bind mount didn't exist yet. Marker
|
||||
(`/var/lib/hive-agent-user-migrated`) guards single-shot.
|
||||
`cp -an` (no-clobber) so any pre-existing files at the new
|
||||
location win — never blow over data already there.
|
||||
3. **Chown the bind-mounted state dir** (`/agents/*/state`)
|
||||
recursively so the new agent user can read/write it. Wildcard
|
||||
matches the single agent that container sees; `-h` skips
|
||||
symlinks the agent might have planted.
|
||||
4. **Chown the `~/.claude/` bind-mount** recursively. Pre-#658
|
||||
`claude` wrote `.credentials.json` 0600 root:root; post-#658
|
||||
the harness reads `~/.claude/` as the agent user to decide
|
||||
Online vs NeedsLogin in `login::has_session`. Without the
|
||||
chown the existing credentials get silently treated as "no
|
||||
session" and the operator re-prompts every boot.
|
||||
|
||||
The activation script will eventually become unnecessary once no
|
||||
operators have pre-#658 state dirs left to migrate; drop the body
|
||||
+ marker check at that point.
|
||||
|
||||
## Matrix per-agent daemon + token-arrival trigger
|
||||
|
||||
`hive-matrix-daemon` is a long-running matrix-sdk Client + sync
|
||||
process per agent. Holds the unix socket the stdio
|
||||
`hive-matrix-mcp` bridge talks to, emits hyperhive wake signals
|
||||
on incoming room events via `/run/hive/mcp.sock`. Conditional on
|
||||
`hyperhive.matrix.enable` (which both the daemon AND the
|
||||
auto-injected `extraMcpServers.matrix` entry read).
|
||||
|
||||
Socket path lives inside the systemd-managed runtime dir
|
||||
(`RuntimeDirectory = "hive-matrix"` → `/run/hive-matrix/`, owned by
|
||||
the agent user) so the daemon can bind without needing root over
|
||||
`/run/` itself. Both daemon + bridge agree on the path via the
|
||||
`HIVE_MATRIX_SOCKET` env var.
|
||||
|
||||
**First-boot ordering**: hive-c0re provisions the matrix token AFTER
|
||||
agent containers come up. Without the path-trigger sibling
|
||||
(`systemd.paths.hive-matrix-daemon`, `PathExistsGlob =
|
||||
/agents/*/state/matrix-token`), the daemon would exit 0 quietly the
|
||||
first time it ran and the MCP would have no backend until the next
|
||||
restart. The `.path` unit makes the appearance of the token re-fire
|
||||
the service so the daemon comes alive in the same boot cycle as
|
||||
provisioning. `matrix-avatar-sync.path` uses the same pattern for
|
||||
the icon-upload oneshot (#571).
|
||||
|
|
|
|||
Loading…
Reference in a new issue