Compare commits

...
Author SHA1 Message Date
iris
fae2025247 docs(approvals): update helper-events routing to reflect shipped behavior
notify_manager (always-root) has been replaced by notify_submitter
(routes to the approval submitter, with root fallback for legacy rows).
Update three locations:

- Step 6 of end-to-end flow: "root agent's inbox" →
  "submitting agent's inbox"; explain notify_submitter + submitter column.
- InitConfig paragraph: remove limitation note; "to the root agent's inbox
  (current limitation...)" → "to the submitting agent's inbox via notify_submitter".
- Section header + prose: "Helper events to the root agent" →
  "Helper events to the submitting agent"; rewrite lead paragraph around
  notify_submitter semantics (approvals.submitter column, legacy fallback).
2026-06-23 22:45:43 +02:00
iris
60403fd27c docs(approvals): drop tracker-tag refs; add topology.rs pointer for role
Remove three bare #NNN tracker-tag references in docs/approvals.md
(hive-rules: no #NNN in code/comments/docs):

- Step 6 of end-to-end flow: "tracked in #1953" → "a known limitation
  under active development"
- InitConfig paragraph: same rewrite
- Helper events section: same rewrite

Also add a code pointer for `can_manage_top_level_agents`: the role is
defined as ROLE_CAN_MANAGE_TOP_LEVEL_AGENTS in hive-c0re/src/topology.rs,
now noted inline so reviewers can verify the name is real.
2026-06-23 22:45:43 +02:00
iris
136102cd27 docs(approvals): reframe stale 'the manager' as the root agent
The last docs/ piece of the manager-cleanup. The manager is no longer a
structural role — root-ness is purely topological. Reframe:
- title 'Approvals + manager + helper events' -> 'Approvals + helper events'
- section headers: 'Manager view of applied'/'Manager policy'/'Manager
  (ruth) is hive-c0re-managed'/'Helper events to the manager' ->
  root-agent / root-bootstrap-container equivalents
- body prose: 'the manager (ruth)' -> 'the root agent' (or 'the submitter'
  in the approval-flow steps)
- authority semantics: 'manager-only' -> approvals are submitted by an
  agent with the approvals tool group, for its direct children
- dropped the stale 'the manager refuses to destroy itself' line (the
  bootstrap container is now destroyable + transient; recreated on startup)

Kept the genuine code/protocol identifiers (nixosConfigurations.manager,
manager_server, role:manager prompt block, notify_manager, the
/run/hyperhive/manager/ socket path) — renaming those would diverge from
the source (de-hardcoding is its own backend cleanup).
2026-06-23 22:45:43 +02:00

View file

@ -11,9 +11,12 @@ informed about what happens after a decision lands.
## End-to-end approval flow ## End-to-end approval flow
1. The submitting agent (the child's parent, holding the `approvals` 1. The submitting agent (the child's parent, holding the `approvals`
tool group) edits files under the child's `/agents/<name>/config/` tool group) edits files in the child's proposed config repo
(any tracked path, but `agent.nix` is the contract entry point) and (any tracked path, but `agent.nix` is the contract entry point)
commits with its own git identity. and commits with its own git identity. The parent's container has
the child's proposed config repo bind-mounted read-write at
`/agents/<name>/config/` (topology-driven via `set_nspawn_flags`;
the agent's *own* config at `/agents/<self>/config/` is read-only).
2. The submitting agent submits the commit sha via `request_apply_commit(agent, 2. The submitting agent submits the commit sha via `request_apply_commit(agent,
commit_ref)`. `commit_ref` must be a commit **sha** (7-40 hex commit_ref)`. `commit_ref` must be a commit **sha** (7-40 hex
chars, short or full) — a branch or tag name is rejected so the chars, short or full) — a branch or tag name is rejected so the
@ -63,11 +66,11 @@ informed about what happens after a decision lands.
failure, main stays put and the working tree resets back to failure, main stays put and the working tree resets back to
the previous deployed commit. the previous deployed commit.
6. `HelperEvent::ApprovalResolved` (and `Rebuilt` for the 6. `HelperEvent::ApprovalResolved` (and `Rebuilt` for the
ApplyCommit kind) land in the root agent's inbox, carrying both ApplyCommit kind) land in the **submitting agent's** inbox, carrying
the canonical sha and the terminal tag. (Helper events currently route both the canonical sha and the terminal tag. Helper events route to
to the root agent via `notify_manager` regardless of which agent the submitting agent via `notify_submitter` (the approval row carries
submitted the approval; routing them to the submitting agent is tracked a `submitter` column recording which agent called `request_apply_commit`
in #1953.) or `request_init_config`).
### Withdrawing a pending approval ### Withdrawing a pending approval
@ -88,7 +91,8 @@ without it has nothing of its own to withdraw.
`InitConfig` approvals are the first step in a two-step spawn `InitConfig` approvals are the first step in a two-step spawn
flow. On approve, hive-c0re seeds the proposed config repo with flow. On approve, hive-c0re seeds the proposed config repo with
a default `agent.nix` template and sends `HelperEvent::ConfigReady { agent }` a default `agent.nix` template and sends `HelperEvent::ConfigReady { agent }`
to the root agent. The submitting agent then reviews, to the submitting agent's inbox via `notify_submitter`. The submitting
agent then reviews,
edits, and commits the template before calling `request_apply_commit` edits, and commits the template before calling `request_apply_commit`
to proceed to an `ApplyCommit` approval. The first `ApplyCommit` to proceed to an `ApplyCommit` approval. The first `ApplyCommit`
creates the container; subsequent ones rebuild it with new config. creates the container; subsequent ones rebuild it with new config.
@ -400,26 +404,33 @@ The dashboard deep-links into this org — a `config repo` link
per container row and a `commit on forge` link per approval per container row and a `commit on forge` link per approval
card. See `docs/web-ui.md`. card. See `docs/web-ui.md`.
### Root-agent view of applied + meta ### Submitting agent's view of config repos
The root agent container gets three host-side bind mounts via Every parent agent's container has its **direct children's** proposed
`set_nspawn_flags`: config repos bind-mounted read-write (topology-driven: `lifecycle.rs`
calls `bind_child_agent_dirs` for each entry in
`topology::children_of(agent_name)`). An agent with the `approvals`
tool group can therefore edit, commit, and submit changes for any of
its direct children directly inside its container at `/agents/<child>/config/`.
- `/var/lib/hyperhive/agents/``/agents/` (RW) — proposed Agents holding the `can_manage_top_level_agents` topology role
repos. The root agent edits + commits per-agent config here. (defined as `ROLE_CAN_MANAGE_TOP_LEVEL_AGENTS` in `hive-c0re/src/topology.rs`)
- `/var/lib/hyperhive/applied/``/applied/` (RO) — every get additional host-side bind mounts via `set_nspawn_flags`:
agent's authoritative applied repo, including `.git`.
- `/var/lib/hyperhive/agents/``/agents/` (RW) — all top-level
agents' proposed repos (not just direct children).
- `/var/lib/hyperhive/applied/``/applied/` (RO) — every agent's
authoritative applied repo, including `.git`.
- `/var/lib/hyperhive/meta/``/meta/` (RO) — the swarm-wide - `/var/lib/hyperhive/meta/``/meta/` (RO) — the swarm-wide
deploy flake. deploy flake.
This is the **root agent's** view — RW over *every* agent's config. An The root agent holds this role; a sub-manager that only manages a
agent with the `approvals` group that owns a subtree (a sub-manager) has subtree does not, and only has its direct children's config dirs.
the equivalent RW scoped to its own children's config repos.
Each proposed repo (`/agents/<n>/config/`) is pre-configured Each proposed repo (`/agents/<n>/config/`) is pre-configured
with `applied` as a git remote pointing at with `applied` as a git remote pointing at
`/applied/<n>/.git`. Useful incantations from inside the `/applied/<n>/.git`. Useful incantations from inside an agent with
root agent's container: the full `/applied` mount:
```sh ```sh
git -C /agents/<n>/config fetch applied git -C /agents/<n>/config fetch applied
@ -433,9 +444,8 @@ git -C /meta log --oneline # swarm-wide deplo
cat /meta/flake.lock | jq '.nodes | with_entries(select(.key | startswith("agent-")))' cat /meta/flake.lock | jq '.nodes | with_entries(select(.key | startswith("agent-")))'
``` ```
The RO binds block push at the kernel level, so the root agent The RO binds block push at the kernel level — git plumbing inside the
can only fetch / read — git plumbing inside the container container cannot corrupt either authoritative repo.
cannot corrupt either authoritative repo.
## Migration from the pre-tag / pre-meta schemes ## Migration from the pre-tag / pre-meta schemes
@ -495,25 +505,25 @@ updates the root agent itself.
## Root-agent policy ## Root-agent policy
From `hive-ag3nt/prompts/system.md` (`<!-- role:manager -->` block, The system prompt (`hive-ag3nt/prompts/system.md`, rendered via
rendered via `hive_ag3nt::prompt::render`): the root agent does NOT `hive_ag3nt::prompt::render`) is the **same for every agent**; what
rubber-stamp sub-agent config requests. It verifies (role match, varies is which MCP tools are surfaced (gated by tool groups and
package legitimacy, cheaper alternative, blast radius) before capabilities in `agent.nix`). There is no `role:manager` block that
committing and calling `request_apply_commit`. renders only for the root agent. The root agent's approval-gating
behaviour comes from its CLAUDE.md / agent-specific instructions, not
the system prompt template.
For ambiguous cases or anything that needs human signal, the `ask(question, options?, multi?, ttl_seconds?, to?)` is available to
the root agent calls `ask(question, options?, multi?, ttl_seconds?, to?)` **any agent** — it queues a question and returns the id immediately.
queues the question and returns the id immediately. When `to` is When `to` is omitted (or `"operator"`) the question shows up on the
omitted (or `"operator"`) the question shows up on the dashboard; dashboard; when `to` is another agent's name, the recipient receives a
when `to` is a sub-agent's name, the recipient receives a
`HelperEvent::QuestionAsked` and answers via their own `answer` `HelperEvent::QuestionAsked` and answers via their own `answer`
tool. Either way the answer arrives back as tool. Either way the answer arrives back as
`HelperEvent::QuestionAnswered { id, question, answer, answerer }` `HelperEvent::QuestionAnswered { id, question, answer, answerer }`
in the asker's inbox. Storage is `hive-c0re::operator_questions` in the asker's inbox. Storage is `hive-c0re::operator_questions`
(sqlite) — same table, with a nullable `target` column (sqlite) — same table, with a nullable `target` column
(NULL = operator). Dispatch goes through (NULL = operator). Dispatch goes through
`hive-c0re/src/questions.rs::{handle_ask, handle_answer}` so both `hive-c0re/src/questions.rs::{handle_ask, handle_answer}`. The answer flow is:
the agent + root-agent surfaces stay aligned. The answer flow is:
``` ```
POST /answer-question/{id} agent: Answer { id, answer } POST /answer-question/{id} agent: Answer { id, answer }
@ -526,22 +536,21 @@ POST /answer-question/{id} agent: Answer { id, answer }
Two more paths resolve a pending question with a sentinel answer: Two more paths resolve a pending question with a sentinel answer:
- `POST /cancel-question/{id}` (✗ CANC3L button on the dashboard) - `POST /cancel-question/{id}` (✗ CANC3L button on the dashboard)
resolves with `[cancelled]`. The root agent sees a terminal state resolves with `[cancelled]`. The asking agent sees a terminal state
and can fall back. and can fall back.
- `ttl_seconds` deadline: a tokio watchdog spawned at submit time - `ttl_seconds` deadline: a tokio watchdog spawned at submit time
fires `answer(id, "[expired]")` once the ttl runs out. Already- fires `answer(id, "[expired]")` once the ttl runs out. Already-
resolved races no-op. The dashboard surfaces a `⏳ MM:SS` chip resolved races no-op. The dashboard surfaces a `⏳ MM:SS` chip
on each pending question with a deadline. on each pending question with a deadline.
## Helper events to the root agent ## Helper events to the submitting agent
`Coordinator::notify_manager(&HelperEvent)` enqueues an inbox `Coordinator::notify_submitter(approval_id, &HelperEvent)` routes the
message from sender `system` with the event JSON in the body. The event to the agent that originally submitted the approval (looked up from
root agent's harness no longer short-circuits these — they drive a the `submitter` column on the `approvals` table). The harness delivers it
regular claude turn so the root agent can react. (Today these go to the as a regular `system` inbox message so it drives a normal claude turn.
root agent regardless of which agent submitted the approval — routing to Legacy approval rows that predate the submitter column fall back to the
the submitting agent is tracked in #1953.) Variants root agent. Variants (`hive_sh4re::HelperEvent`):
(`hive_sh4re::HelperEvent`):
- `ApprovalResolved { id, agent, commit_ref, status, note }` - `ApprovalResolved { id, agent, commit_ref, status, note }`
fired by `actions::approve` + `actions::deny` whenever an fired by `actions::approve` + `actions::deny` whenever an