From d6debd476215cc5cf04bcde87b50b3e089c52dc7 Mon Sep 17 00:00:00 2001 From: iris Date: Tue, 23 Jun 2026 12:00:09 +0200 Subject: [PATCH 1/7] docs(conventions): reframe stale 'the manager' as the root/bootstrap agent MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The manager is no longer a structural role — root-ness is purely topological (an agent with no parent). Reframe the naming + socket lines that presented 'the manager' as a fixed coordinating agent, while keeping the manager-flavour socket/protocol identifiers (those still name live code). --- docs/conventions.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/conventions.md b/docs/conventions.md index 2894bdba..9c0daca4 100644 --- a/docs/conventions.md +++ b/docs/conventions.md @@ -7,10 +7,10 @@ exist because something already went wrong without them. - Containers are length-bounded by `nixos-container` (≤ 11 chars). - Sub-agents are `h-` with `` ≤ 9 chars. -- The manager is `ruth` (fixed name). +- One agent is the bootstrap/root container, with a fixed name (`ruth` today). - `MAX_AGENT_NAME` in `lifecycle.rs` enforces the cap. - Per-agent web UI port = `WEB_PORT_BASE + FNV1a(name) % WEB_PORT_RANGE` - (8100..8999) for every agent including the manager; dashboard + (8100..8999) for every agent including the bootstrap/root container; dashboard `cfg.dashboardPort` (default 7000). ## Hive identity (label + domain + display names) @@ -56,8 +56,8 @@ peer's name when the caller knows it's hive-local. There are no auth tokens on the per-agent unix sockets. The socket *path* identifies the principal; perms come from "who has the bind-mount." A sub-agent only sees its own `/run/hive/mcp.sock`; the -manager has access to its privileged socket; hive-c0re owns the host -admin socket. +root agent additionally has access to its privileged (manager-flavour) +socket; hive-c0re owns the host admin socket. ### Wake injection From adb76f3cdf292a2ff57844b79fd02158c2398fa3 Mon Sep 17 00:00:00 2001 From: iris Date: Tue, 23 Jun 2026 12:01:40 +0200 Subject: [PATCH 2/7] docs(persistence): reframe stale 'the manager' as the root agent Config-repo editor, meta RO-mount, non-destroyable container, and the topology.json example now refer to the root agent / bootstrap container rather than 'the manager'. The /run/hyperhive/manager/mcp.sock path is a real runtime path, kept (clarified as the root agent's manager-flavour socket). --- docs/persistence.md | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/docs/persistence.md b/docs/persistence.md index 233fedfa..7c7496c3 100644 --- a/docs/persistence.md +++ b/docs/persistence.md @@ -180,16 +180,16 @@ Survives destroy/recreate, gone on `--purge`. Under `/var/lib/hyperhive/agents//`: -- `config/` — the proposed nix repo (manager-editable). Bind-mounted +- `config/` — the proposed nix repo (root-agent-editable). Bind-mounted **read-only** to `/agents//config` inside the sub-agent's own container so the agent can inspect what defines it and request - precise changes from the manager; RW into the manager via the + precise changes from the root agent; RW into the root agent via the `/agents` tree bind. - `claude/` — claude OAuth credentials, bind-mounted RW to `/home//.claude` inside the container. - `state/` — durable notes and `hyperhive-harness.json`. Bind-mounted to `/agents//state` inside the container (uniform for - sub-agents + manager). The `$HYPERHIVE_STATE_DIR` env var exposes + all agents — sub-agents + root). The `$HYPERHIVE_STATE_DIR` env var exposes the same path to in-container scripts. Notable files written here by the harness: - `hyperhive-status` — single-line free-text status string written @@ -237,8 +237,8 @@ sibling's. Under `/var/lib/hyperhive/applied//` — the hive-c0re-only applied repo. Tracks `flake.nix` (module-only boilerplate; never edited after first spawn) + `agent.nix` (the actual config; the -manager's edits land here via the approval flow) + any other -files the manager committed. `.git/` carries the proposal / +root agent's edits land here via the approval flow) + any other +files committed via the approval flow. `.git/` carries the proposal / approved / building / deployed / failed / denied tag history. Under `/var/lib/hyperhive/meta/` — the swarm-wide deploy flake plus @@ -251,7 +251,7 @@ Contents: canonical "what's deployed where." The git log is the deploy audit trail (one commit per successful deploy or hyperhive bump). - `topology.json` — parent/child agent graph - (`{ "alice": "manager", "bob": "alice", "manager": null }`). + (`{ "alice": "root", "bob": "alice", "root": null }`). Written by `topology::set_parent`; read by the dashboard, the renderer, and `` / `` recipient resolution. - `tool-groups.json` — per-agent MCP tool group grants @@ -263,7 +263,7 @@ Contents: `capabilities::set_caps`; injected as `HIVE_CAPABILITIES` env var. Absent agents have no extra capabilities. -Manager has the meta dir RO-mounted at `/meta/`. +The root agent has the meta dir RO-mounted at `/meta/`. Marker file `/var/lib/hyperhive/.meta-migration-done` is written by the startup migration after every container has @@ -285,8 +285,8 @@ step would re-fire). claude creds, /state/ notes, and the harness dir are all gone. No undo. -The manager is non-destroyable from both paths (declarative -container; would fight with the host's NixOS config). +The root/bootstrap container is non-destroyable from both paths +(declarative container; would fight with the host's NixOS config). ### btrfs subvolumes for `/var/lib/hyperhive/agents/` @@ -323,7 +323,8 @@ Without that, every restart wipes bind sources and existing containers can't be started. - `/run/hyperhive/host.sock` — admin socket (host-side CLI). -- `/run/hyperhive/manager/mcp.sock` — manager-privileged socket. +- `/run/hyperhive/manager/mcp.sock` — the root agent's privileged + (manager-flavour) socket. - `/run/hyperhive/agents//mcp.sock` — per-sub-agent socket (bind-mounted into the container as `/run/hive/mcp.sock`). From ec5c7d49c4e91a8356ed2699573ce9fd004f8f49 Mon Sep 17 00:00:00 2001 From: iris Date: Tue, 23 Jun 2026 12:02:57 +0200 Subject: [PATCH 3/7] docs: reframe stale 'the manager' as the root/bootstrap container (infra + web-ui) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Port-range, network-isolation, state-dir, web-UI-port, priv allowlist, and rebuild-source mentions now refer to the root/bootstrap container rather than 'the manager' — no structural manager exists (root-ness is topological). Real artifact names (the manager.nix template toplevel, /run/hyperhive/manager/mcp.sock) are left as-is. --- docs/coordinator.md | 4 ++-- docs/gateway.md | 6 +++--- docs/gotchas.md | 4 ++-- docs/network.md | 6 +++--- docs/security.md | 2 +- docs/web-ui.md | 4 ++-- 6 files changed, 13 insertions(+), 13 deletions(-) diff --git a/docs/coordinator.md b/docs/coordinator.md index e915b0a4..9dadde45 100644 --- a/docs/coordinator.md +++ b/docs/coordinator.md @@ -38,7 +38,7 @@ somewhere." | `MetaUpdate` | `nix flake update` on the meta flake. The worker runs the lock bump itself, then enqueues a cascade of `Rebuild` entries with `parent_id` set to the meta-update's id. | | `Spawn` | First-deploy of a new agent (approval-driven). Same serialisation as `Rebuild` from the operator's POV. | | `Destroy` | For future use (`destroy --purge` does real I/O). Variant exists so the wire shape doesn't change later; not currently routed through the queue. | -| `Restart` | Stop + start a container without touching config (~5-10s). Routed through the queue so it serialises against in-flight rebuilds for the same agent — prevents a restart racing a rebuild mid-flight. Sources: dashboard ↺ button, manager `restart` MCP tool. | +| `Restart` | Stop + start a container without touching config (~5-10s). Routed through the queue so it serialises against in-flight rebuilds for the same agent — prevents a restart racing a rebuild mid-flight. Sources: dashboard ↺ button, the `restart` MCP tool. | | `PermChange` | Write a tool-group or capability change to the shared JSON file (`tool-groups.json` / `capabilities.json`), then rebuild the agent so the updated `HIVE_TOOL_GROUPS` / `HIVE_CAPABILITIES` env var takes effect. Serialising the file write through the queue prevents concurrent dashboard batch-apply actions from racing on the shared file. After a successful file write, emits `CapabilitiesChanged` or `ToolGroupsChanged` SSE snapshot so the P3RM1SS10NS tab updates live. | | `GracefulStop` | Quiesce then stop a container (the `?graceful=1` path on `/kill/`). Signals the harness (its next `Recv` returns `GracefulStop` — the inbound fence — so it runs one stop-checkpoint turn to flush durable `/state`, then exits), waits for it to drain (bounded by a 3-min timeout → hard-stop fallback), then runs the normal container-stop teardown. Queued so it can't race an in-flight rebuild for the same agent. | @@ -55,7 +55,7 @@ since the current run started). | Source | Meaning | |--------|---------| -| `Manual` | Operator clicked rebuild / update-all / meta-update on the dashboard, or any other direct human action (CLI, manager tool). | +| `Manual` | Operator clicked rebuild / update-all / meta-update on the dashboard, or any other direct human action (CLI, an agent MCP tool). | | `AutoUpdate` | Legacy startup-sweep source (flat, no parent). Replaced by `StartupSweep` for new boots. | | `StartupSweep` | Child of a `StartupSweep` parent entry; boot-time per-agent rebuild with the sweep as the visual group header. | | `Approval` | Triggered by an operator-approved `ApprovalKind::{Spawn, ApplyCommit}`. | diff --git a/docs/gateway.md b/docs/gateway.md index d223b110..14b08c36 100644 --- a/docs/gateway.md +++ b/docs/gateway.md @@ -269,9 +269,9 @@ firewall-open would defeat the single-front-door story. `httpsPort` — the gateway always terminates TLS (self-signed floor), so both are always served. -The manager hashes into the same port range as sub-agents (no -"manager pinned at 8000" special case), so one range opening covers -every container. +The root/bootstrap container hashes into the same port range as +sub-agents (no special case), so one range opening covers every +container. The dashboard port (`cfg.dashboardPort`, default 7000) is *not* listed in either case — it binds `127.0.0.1` only, so a firewall diff --git a/docs/gotchas.md b/docs/gotchas.md index bfbf8305..bce915c7 100644 --- a/docs/gotchas.md +++ b/docs/gotchas.md @@ -96,7 +96,7 @@ across `destroy`/recreate (`--purge` wipes them). ## Persistent notes dir per agent `/var/lib/hyperhive/agents//state/` bind-mounts to -`/agents//state` (RW; uniform for sub-agents + manager). +`/agents//state` (RW; uniform for all agents — sub-agents + root). The harness exposes the same path via `$HYPERHIVE_STATE_DIR`. System prompts tell agents to keep durable knowledge here (`notes.md`, anything else). The harness also @@ -112,7 +112,7 @@ unlucky. Operator resolves a collision by renaming the offending agent (different hash → different port) and rebuilding. No state file, no probing, no port-allocation drift — the value is reproducible from just the name. Every agent — including the -manager — hashes into 8100..8999 via the same FNV-1a; dashboard +root/bootstrap container — hashes into 8100..8999 via the same FNV-1a; dashboard at `cfg.dashboardPort` (default 7000). ## Restart races on TCP bind diff --git a/docs/network.md b/docs/network.md index 0f3d9330..f40e9308 100644 --- a/docs/network.md +++ b/docs/network.md @@ -130,7 +130,7 @@ address arithmetic. `lifecycle::set_nspawn_flags` when creating or updating containers. Each agent gets a deterministic IP derived from its name so the address is reproducible across destroy/recreate. This applies uniformly to all -containers including the manager — no special case. +containers including the root/bootstrap container — no special case. `HOST_ADDRESS` is the bridge gateway IP (the address part of `HIVE_NETWORK_SUBNET`, via `lifecycle::bridge_gateway_ip` — taken verbatim @@ -163,9 +163,9 @@ wiring is runtime: an instant no-op in shared-netns mode (the marker is absent, so `ConditionPathExists` skips it). -**Why isolation is safe for the manager**: all hive-c0re communication goes +**Why isolation is safe for the root agent**: all hive-c0re communication goes through unix domain sockets (`/run/hive/mcp.sock` for agent requests, -`/run/hive/priv.sock` for privileged ops, per-agent manager sockets). +`/run/hive/priv.sock` for privileged ops, per-agent privileged sockets). These are bind-mounted into containers via the nspawn conf. UDS paths traverse the VFS, not the network stack, so `PRIVATE_NETWORK=1` does not affect them. diff --git a/docs/security.md b/docs/security.md index cebfb621..14fd6d44 100644 --- a/docs/security.md +++ b/docs/security.md @@ -110,7 +110,7 @@ known operations; there is no arbitrary command pass-through: **Container allowlist** — every request is validated against an allowlist before any operation: only names matching `h-` (the -standard agent prefix), the manager container, or the known sibling +standard agent prefix), the root/bootstrap container, or the known sibling service containers (`hive-gateway`, `hive-forge`, `hive-matrix`, `hive-ci`) are accepted. Arbitrary container names are rejected. diff --git a/docs/web-ui.md b/docs/web-ui.md index ed52f3d3..4231fda6 100644 --- a/docs/web-ui.md +++ b/docs/web-ui.md @@ -1,8 +1,8 @@ # Web UI Two web surfaces share the same skeleton: the dashboard (port 7000) -and the per-agent UIs (every container — including the manager — -hashes into :8100-8999 via `lifecycle::agent_web_port`'s FNV-1a). +and the per-agent UIs (every container — including the root/bootstrap +container — hashes into :8100-8999 via `lifecycle::agent_web_port`'s FNV-1a). Both are SPAs — `GET /` returns a static shell, `/api/state` returns JSON, JS renders. No full-page reloads. From c24ca4dfe1ddc815e7a6cca13762a8021d417d62 Mon Sep 17 00:00:00 2001 From: iris Date: Tue, 23 Jun 2026 12:04:45 +0200 Subject: [PATCH 4/7] docs(dashboard): reframe stale 'the manager' as the root/submitting agent Schedule columns, tool-group/capability defaults, terminal addressing (@root), destroy/move guards, and approval-resolution notes now refer to the root agent (or the submitting agent, for approval flows) rather than 'the manager'. Also fixed the stale 'moving the manager' move-refusal example (the root agent is reparentable) to a cycle example. --- docs/web-ui/dashboard.md | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/docs/web-ui/dashboard.md b/docs/web-ui/dashboard.md index 1a6b2362..3d34ba73 100644 --- a/docs/web-ui/dashboard.md +++ b/docs/web-ui/dashboard.md @@ -144,7 +144,7 @@ lock graph with a `visited` set — `follows` aliases and rev-less nodes are skipped. A `select all / select none` control sits above the tree. Checking inputs + submitting bumps the lock in `/meta/` and rebuilds the selected agents in -sequence; each outcome reaches the manager as a `rebuilt` +sequence; each outcome reaches the root agent as a `rebuilt` system event. `POST /meta-update`. While a lock-bump ripple runs, the panel shows a pulsing "⏳ meta-update running" banner and the update button is disabled (snapshot field `meta_update_running`, @@ -305,7 +305,7 @@ The current capabilities are: | Name | Effect | |------|--------| -| `manage_root_agent` | allows the `set_status` / lifecycle tools on the root manager | +| `manage_root_agent` | allows the `set_status` / lifecycle tools on the root agent | | `read_host_journal` | unlocks `get_host_journal` to read journald from inside a container | | `query_agent_state` | allows `get_loose_ends(agent: "")` calls targeting other agents | @@ -319,7 +319,7 @@ agents in the assignment map have no extra capabilities. **T00L GR0UPS** — per-agent tool-group permissions. Tool groups are named buckets of MCP tools; each agent starts with a role default -(agents: `messaging`, `meta`, `inbox`, `execution`; manager: all +(sub-agents: `messaging`, `meta`, `inbox`, `execution`; root agent: all groups). Checking / unchecking stages which groups are active for the agent; the page-level **save all** button (below) commits it. Columns come from `GET /api/tool-groups`. A rebuild is queued so @@ -367,7 +367,7 @@ share enough conceptual ground to live together. scheduled prompts. **Single-table layout**: each schedule is one ``; columns are `# | src | next | every | owner | body | …agents… | actions`. -Agent columns are dynamic — `operator` + `manager` + every +Agent columns are dynamic — `operator` + `root` + every live container + any extra name that appears as a target on some schedule but isn't a current container (same `buildTargetChips` membership rule the new/edit forms use, @@ -583,7 +583,7 @@ stream sits a terminal-style compose box: `@name` picks the recipient (sticky via localStorage; auto-complete from the live container list, Tab/Enter to confirm; `@*` broadcasts). `POST /api/op-send` drops `{from:"operator", to, body}` into the broker; the resulting SSE frame -re-renders the terminal row. Manager is addressed as `@root`. +re-renders the terminal row. The root agent is addressed as `@root`. ## H0M3 page (`/`) @@ -925,12 +925,12 @@ frosted-mauve bar slides up from the bottom of the viewport - `■ ST0P` — running agents only - `▶ ST4RT` — stopped agents only - `↻ R3BU1LD` — always available - - `DESTR0Y` / `PURG3` — sub-agents only (disabled if manager selected) + - `DESTR0Y` / `PURG3` — sub-agents only (disabled if the root/bootstrap container selected) - `⇡ M0V3 → ROOT` — promote selected agents to top-level (parent = null); disabled when all selected are already at root. Backend `topology::set_parent` refuses moves it can't satisfy - (e.g. moving the manager) and the refusal surfaces in the - failure roll-up. + (e.g. a move that would create a cycle) and the refusal surfaces + in the failure roll-up. - `⇢ M0V3 → [select]` — inline picker available for any selection size. The dropdown lists every container that isn't IN the selection itself nor a descendant of any selected agent @@ -958,14 +958,14 @@ renderApprovals`) with three stacked sections: so a stale approval stands out; the `.stale` class flips precisely at the 3600s boundary rather than at the next `renderApprovals` call. -- **what-changed body** — the manager's description, then +- **what-changed body** — the submitting agent's description, then drill-in triggers: `↳ view diff` opens the diff in the side panel; `↳ commit on forge ↗` deep-links the proposal commit into `agent-configs/` (shown only when `forge_present`). Spawn approvals show a one-line "container will be created" note instead. - **decision actions** — `◆ APPR0VE` and `DENY`. Deny pops a - `prompt()` for an optional reason carried to the manager as + `prompt()` for an optional reason carried to the submitting agent as `HelperEvent::ApprovalResolved.note`. The diff panel has a 3-way base toggle — **vs applied** (the @@ -1012,7 +1012,7 @@ that's a browser-level decision, not ours. updates derived approvals state from the event. - `POST /api/deny/{id}` (`note=`, optional) — deny a pending approval with an optional operator-supplied reason. The reason - travels to the manager as `HelperEvent::ApprovalResolved.note` + travels to the submitting agent as `HelperEvent::ApprovalResolved.note` and also rides on the dashboard's `ApprovalResolved` event. Dashboard prompts via the themed `themedPrompt()` dialog on click — a resizable `