split claude.md into docs/ — per-topic, human-readable
claude.md was eating 400 lines of subsystem detail that's useful
when you're working on that subsystem and noise the rest of the
time. split into:
- docs/conventions.md naming, identity, async forms, commit style
- docs/gotchas.md nspawn / nixos-container quirks
- docs/web-ui.md dashboard + per-agent layouts and endpoints
- docs/turn-loop.md claude invocation, wake prompt, mcp surface
- docs/approvals.md approval flow, manager policy, helper events
- docs/persistence.md sqlite dbs, retention, state dir layout
claude.md is now the entry point — file map, reading paths
("pick the doc that matches your task"), quick reminders that
fit on one screen, and a small scratchpad section for in-flight
context. references the docs; the docs don't reference claude.md.
no content was lost — the docs/ files cover everything the old
claude.md did, plus things i wrote up better while extracting.
This commit is contained in:
parent
c27111ac32
commit
8b10731aa4
7 changed files with 708 additions and 396 deletions
144
docs/approvals.md
Normal file
144
docs/approvals.md
Normal file
|
|
@ -0,0 +1,144 @@
|
|||
# Approvals + manager + helper events
|
||||
|
||||
The approval queue is hyperhive's pivot: nothing that changes the
|
||||
shape of an agent (its config, whether it exists) happens without an
|
||||
operator click. The manager (`hm1nd`) is the policy gate in front of
|
||||
that queue; helper events are how it stays informed about what
|
||||
happens after a decision lands.
|
||||
|
||||
## End-to-end approval flow
|
||||
|
||||
1. Manager edits `/agents/<name>/config/agent.nix` (bind-mounted
|
||||
from the host's per-agent `proposed` repo) and commits.
|
||||
2. Manager submits the commit sha via `request_apply_commit(agent,
|
||||
commit_ref)`.
|
||||
3. Operator sees the diff on the dashboard, clicks ◆ APPR0VE (or
|
||||
`hive-c0re approve <id>` on the CLI).
|
||||
4. hive-c0re reads the file at that sha from `proposed`, applies
|
||||
into `applied`, commits there, runs `nixos-container update`.
|
||||
5. `HelperEvent::ApprovalResolved` lands in the manager's inbox.
|
||||
|
||||
`Spawn` approvals follow the same shape but skip the commit-diff
|
||||
step — the operator just sees the name. On approve, hive-c0re
|
||||
creates the container in a background task while the dashboard
|
||||
shows a spinner.
|
||||
|
||||
## Two repos per agent
|
||||
|
||||
```
|
||||
/var/lib/hyperhive/agents/<name>/config/ proposed
|
||||
└── agent.nix # the only file the
|
||||
# manager can change
|
||||
# (initial commit by
|
||||
# hive-c0re on first
|
||||
# spawn, never touched
|
||||
# again).
|
||||
|
||||
/var/lib/hyperhive/applied/<name>/ applied — hive-c0re-only
|
||||
├── flake.nix # auto-generated
|
||||
└── agent.nix # overwritten by approve
|
||||
# from the proposed commit
|
||||
```
|
||||
|
||||
The container's `--flake` ref is `<applied_dir>#default`. The flake
|
||||
extends `hyperhive.nixosConfigurations.{agent-base|manager}` with
|
||||
`./agent.nix` plus an inline module setting
|
||||
`programs.git.config.user` (committer identity = the agent's name)
|
||||
and `systemd.services.<harness>.environment` (`HIVE_PORT`,
|
||||
`HIVE_LABEL`, `HIVE_DASHBOARD_PORT`).
|
||||
|
||||
## Manager (`hm1nd`) is hive-c0re-managed
|
||||
|
||||
The manager container runs through the **same lifecycle as
|
||||
sub-agents**. On `hive-c0re serve` startup, if `hm1nd` is missing,
|
||||
hive-c0re creates it. The manager's flake lives at
|
||||
`/var/lib/hyperhive/applied/hm1nd/`; its proposed config at
|
||||
`/var/lib/hyperhive/agents/hm1nd/config/`. Manager can edit its own
|
||||
`agent.nix` (visible inside the container at `/agents/hm1nd/config/`)
|
||||
and submit `request_apply_commit("hm1nd", <sha>)` for operator
|
||||
approval.
|
||||
|
||||
Differences from sub-agents:
|
||||
|
||||
- `flake.nix` extends `hyperhive.nixosConfigurations.manager`
|
||||
(vs `agent-base`).
|
||||
- Container name is `hm1nd` (no `h-` prefix).
|
||||
- Fixed web UI port (`MANAGER_PORT = 8000`).
|
||||
- `set_nspawn_flags` adds an extra bind:
|
||||
`/var/lib/hyperhive/agents` → `/agents` (RW), so the manager can
|
||||
edit per-agent proposed repos.
|
||||
- First-deploy spawn bypasses the approval queue (manager is
|
||||
required infrastructure).
|
||||
- Per-agent socket lives at `/run/hyperhive/manager/`, owned by
|
||||
`manager_server::start`.
|
||||
|
||||
**Migration note** (for older hosts): drop any `containers.hm1nd =
|
||||
{ ... }` block from your host NixOS config. hyperhive creates and
|
||||
updates the manager itself.
|
||||
|
||||
## Manager policy
|
||||
|
||||
From `hive-ag3nt/prompts/manager.md`: the manager does NOT
|
||||
rubber-stamp sub-agent config requests. It verifies (role match,
|
||||
package legitimacy, cheaper alternative, blast radius) before
|
||||
committing and calling `request_apply_commit`.
|
||||
|
||||
For ambiguous cases or anything that needs human signal, the
|
||||
manager calls `ask_operator(question, options?, multi?)` — queues
|
||||
the question on the dashboard and returns the id immediately. The
|
||||
operator's answer arrives later as
|
||||
`HelperEvent::OperatorAnswered` in the manager inbox. Storage is
|
||||
`hive-c0re::operator_questions` (sqlite); the answer flow is:
|
||||
|
||||
```
|
||||
POST /answer-question/{id}
|
||||
→ OperatorQuestions::answer
|
||||
→ notify_manager(OperatorAnswered { id, question, answer })
|
||||
```
|
||||
|
||||
## Helper events to the manager
|
||||
|
||||
`Coordinator::notify_manager(&HelperEvent)` enqueues an inbox
|
||||
message from sender `system` with the event JSON in the body. The
|
||||
manager harness no longer short-circuits these — they drive a
|
||||
regular claude turn so the manager can react. Variants
|
||||
(`hive_sh4re::HelperEvent`):
|
||||
|
||||
- `ApprovalResolved { id, agent, commit_ref, status, note }` —
|
||||
fired by `actions::approve` + `actions::deny` whenever an
|
||||
approval transitions to its terminal state.
|
||||
- `Spawned { agent, ok, note }` — `actions::approve` (Spawn-kind)
|
||||
+ admin `HostRequest::Spawn`.
|
||||
- `Rebuilt { agent, ok, note }` — `auto_update::rebuild_agent`
|
||||
(covers startup scan + manual `/rebuild` from dashboard) +
|
||||
`actions::approve` (ApplyCommit).
|
||||
- `Killed { agent }` — admin `HostRequest::Kill` + dashboard
|
||||
`/kill` + manager `Kill` MCP tool.
|
||||
- `Destroyed { agent }` — `actions::destroy`.
|
||||
- `OperatorAnswered { id, question, answer }` — dashboard
|
||||
`/answer-question/{id}` after the operator submits the answer
|
||||
form.
|
||||
|
||||
To add a new event: new `HelperEvent` variant + call sites + update
|
||||
`prompts/manager.md` so the manager knows the new shape.
|
||||
|
||||
## Auto-update on startup
|
||||
|
||||
`hive-c0re serve` runs `auto_update::run` in a background task right
|
||||
after opening the coordinator. It enumerates managed containers and
|
||||
rebuilds any whose recorded hyperhive rev differs from the current
|
||||
one — sub-agents and manager go through the same `lifecycle::rebuild`
|
||||
path.
|
||||
|
||||
"Rev" = canonical filesystem path of `cfg.hyperhiveFlake`. Marker
|
||||
file: `/var/lib/hyperhive/applied/.<name>.hyperhive-rev`. If the
|
||||
flake input has no canonical path (e.g. a `github:` URL),
|
||||
auto-update is a no-op — rebuild manually.
|
||||
|
||||
The dashboard surfaces pending updates per agent: a clickable
|
||||
"needs update ↻" badge appears whenever the marker differs from
|
||||
current rev. The badge POSTs `/rebuild/<name>`, calling the same
|
||||
`auto_update::rebuild_agent` path so manual triggers and the
|
||||
startup scan can't drift. When at least one container is stale, a
|
||||
top-level `↻ UPD4TE 4LL` button appears that loops over every
|
||||
stale container.
|
||||
Loading…
Add table
Add a link
Reference in a new issue