refactor(hive-c0re): drop the request_init_config tool and InitConfig approval

swarm-controller's `InitAgentConfigRepo` node already covers config-repo
creation, so this deletes a duplicate rather than a capability; old
`init_config` rows are skipped by `collect_lenient` with no migration, by
operator decision.

Refs #4398
This commit is contained in:
atlas 2026-09-14 18:50:24 +02:00
commit a3b672d1d5
31 changed files with 134 additions and 601 deletions

View file

@ -21,11 +21,10 @@ Topology lives in the hive-c0re-owned **meta repo**, alongside
`null` = root-level agent. New agents **default to root** — there is no
structural manager that everything hangs under. Hierarchy is built
explicitly: an agent that requests a sub-agent gets a
requester-as-parent edge written at its `init_config` approval (so
`alice` spawned `bob` above), and the operator can reparent any
agent, including the bootstrap container (`ruth`) — it's just another
root. The manager is reparentable like any other agent; there's no
explicitly: an agent gets a parent edge written before its first spawn,
or the operator reparents it afterwards (so `bob` above sits under
`alice`). Any agent is reparentable, the bootstrap container (`ruth`)
included — it's just another root. The manager is reparentable like any other agent; there's no
"structurally root" carve-out. Its privileges live on its MCP socket,
not its tree position (see _Manager special-casing today_ below).
@ -63,10 +62,11 @@ where system-level facts live.
install that hasn't synced yet).
- **Reconcile** — runs alongside the periodic meta/flake regeneration.
New agents default to root unless they already carry an explicit
parent edge from an `init_config` approval; Reconcile preserves existing entries
(including operator overrides); removed agents drop.
Agents that are approved but not yet spawned keep their edge too, so
it survives the gap until the container actually appears.
parent edge written before their first spawn; Reconcile preserves
existing entries (including operator overrides); removed agents drop.
Agents whose config repo exists but that haven't spawned yet keep
their edge too, so it survives the gap until the container actually
appears.
- **Inject** — hive-c0re exposes each container's parent (if any) to its own
environment as `HIVE_PARENT`, so the harness / system-prompt
renderer can see it.
@ -90,7 +90,6 @@ umount-old / mount-new / restart-cascade step.
| operation | who can do it |
| ----------------------------------------------------------- | --------------------------------------------------------------------------------------- |
| `kill` / `start` / `restart` / `update` (any descendant) | any ancestor |
| `request_init_config` (spawn a new child) | any agent, child added under self |
| config change via forge PR (any descendant's config) | any ancestor |
| `get_logs` (any descendant) | any ancestor |
| moderate reminders (cancel any open thread of a descendant) | any ancestor |
@ -110,15 +109,15 @@ other agents don't:
- **Naming/bootstrap** — the manager's broker recipient name, state-dir
key, and nixos-container name are all `ruth` (container `h-ruth`).
`hive-c0re` spawns it directly at boot if missing, with no operator
approval step — every other agent goes through `request_init_config`
→ approval. Topology-wise, `ruth` is still just another root agent.
approval step — every other agent goes through a `Spawn` approval.
Topology-wise, `ruth` is still just another root agent.
- **Wire-protocol** — the privileged `Request` variants
(`RequestInitConfig`; `Kill` / `Start` / `Restart` / `Update`;
(`Kill` / `Start` / `Restart` / `Update`;
`GetLogs`; `RequestUpdateMetaInputs`) — marked `*(privileged)*` in
`hive-core-agent-sock`'s unified `Request` enum — are reachable only
from the manager's socket flavour today. Planned rule for each is in the
table above ("any agent, child added under self" for init-config,
"any ancestor" for lifecycle/logs); `RequestUpdateMetaInputs` stays
table above ("any ancestor" for lifecycle/logs);
`RequestUpdateMetaInputs` stays
a root-only capability even post-milestone, not a topology rule.
One exception: `Wake` (inject a `from: <X>` message into the
caller's own inbox) isn't really privileged — every per-agent daemon

View file

@ -24,12 +24,14 @@ CLI) before it takes effect. What you'll see, and what to do with it:
anything in that chain fails, the change rolls back automatically —
the agent stays on its last-good config, no recovery action needed
from you.
- **New agent** (`InitConfig` then `Spawn`) — creating a brand-new
agent is two approvals. `InitConfig` creates the config repo and
seeds it from a template; `Spawn` creates the container from that
config. Tailoring the template first isn't a separate mechanism —
it's the config-change flow above, a PR you review like any other. Every later change goes through the config-change flow
above — there's no repeat "spawn" for an existing agent.
- **New agent** (`Spawn`) — the one approval in creating a brand-new
agent. Its config repo is scaffolded first, outside the approval
queue, by the swarm controller's `InitAgentConfigRepo` job
(`POST /api/agents`); `Spawn` then creates the container from that
config. Tailoring what the template seeded isn't a separate
mechanism — it's the config-change flow above, a PR you review like
any other. Every later change goes through that flow — there's no
repeat "spawn" for an existing agent.
- **Meta/flake update** (`UpdateMetaInputs`) — an agent asked to bump
one or more Nix flake inputs (or all of them). Approving runs the
update and commits the lock change; it doesn't rebuild anything by
@ -131,11 +133,10 @@ agent that lacks the `approvals` tool group: only an agent with that
group submits approvals (for its direct children), so an agent
without it has nothing of its own to withdraw.
`InitConfig` approvals create a brand-new agent's config repo. On
approve, hive-c0re seeds it with a default `agent.nix` template and
pushes a todo (`push_todo_submitter`) into the submitting agent's
in-container store. The operator then **spawns** the agent (the
`Spawn` approval / `◆ R3QU3ST SP4WN` button), which creates the
A brand-new agent's config repo is created outside this queue, by the
swarm controller's `InitAgentConfigRepo` job, which seeds it with a
default `agent.nix` template. The operator then **spawns** the agent
(the `Spawn` approval / `◆ R3QU3ST SP4WN` button), which creates the
container from that config.
Changing what the template seeded isn't a special case: like every
@ -146,7 +147,7 @@ through the web UI or the forge.
### Approval kinds (wire shapes)
`ApprovalKind` carries five variants; each maps to a different
`ApprovalKind` carries four variants; each maps to a different
`commit_ref` encoding because that field is overloaded as the
kind-specific payload carrier.
@ -169,13 +170,11 @@ kind-specific payload carrier.
`hivectl agent <name> request-create` CLI). The host-level `HostRequest::Spawn`
variant bypasses the approval queue entirely — privileged-context use
only (operator on the host shell, test scripts, one-off recoveries;
`hivectl agent <name> create`). This is the **canonical first-spawn**: a new agent's `InitConfig`
seeds its config repo, the submitting agent customises it, then the
operator spawns to create the container. Subsequent config changes go
through a `MergeConfigPr` PR.
- `InitConfig``commit_ref` is empty; the variant just gates
"seed the proposed repo with the default template" against
operator approval. Step 1 of the two-step spawn flow above.
`hivectl agent <name> create`). This is the **canonical first-spawn**: the
swarm controller's `InitAgentConfigRepo` job seeds the agent's config
repo, it gets customised through a PR, then the operator spawns to
create the container. Subsequent config changes go through a
`MergeConfigPr` PR.
- `UpdateMetaInputs``commit_ref` stores the JSON-encoded inputs
array (`"[]"` = all inputs, `"[\"nixpkgs\"]"` = just nixpkgs,
etc.). hive-c0re sets the `agent` field to the requesting root agent.
@ -421,7 +420,6 @@ rather than run inline:
| `MergeConfigPr` | `rebuild` (`DeployWindow` root + `MergeVerify → DeployApply` + `DeployTail`) | `approval` |
| `UpdateMetaInputs` | `meta_update` (`MetaLock` + rebuild fan-out) | `approval` |
| `Spawn` | `spawn` (`Create → WriteDropin → Reconcile`) | `approval` |
| `InitConfig` | — runs inline (sub-second git seed) | — |
| `SchedulePrompt` | — runs inline (single sqlite insert) | — |
The DAG carries the originating `approval_id`, surfaced on the node that
@ -604,7 +602,7 @@ as a regular `system` inbox message so it drives a normal claude turn.
through `Coordinator::push_todo`/`push_todo_submitter` instead, a direct
live dial of the target agent's in-container todo socket (same
`UpsertTodo` request in-container producers use); `finish_approval` fires
one of these too for `InitConfig`/`Spawn`/`MergeConfigPr`, *in addition to*
one of these too for `Spawn`/`MergeConfigPr`, *in addition to*
the `ApprovalResolved` HelperEvent above, not instead of it. Legacy
approval rows that predate the submitter column fall back to the
root agent. Variants (`hive_sh4re::manager::HelperEvent`):
@ -625,7 +623,7 @@ root agent. Variants (`hive_sh4re::manager::HelperEvent`):
no approval required.
The remaining lower-urgency lifecycle notices — `Rebuilt`, `Killed`,
`Destroyed`, `NeedsLogin`, `LoggedIn`, `ConfigReady` — are "FYI, check
`Destroyed`, `NeedsLogin`, `LoggedIn` — are "FYI, check
when convenient" events with no reason to drive an immediate turn, so
they deliver via `push_todo`/`push_todo_submitter` (see above) instead
of `HelperEvent`: an `agent_todo_socket` push instead of a broker
@ -638,7 +636,7 @@ hive-c0re-vouched commit sha. Optional `tag` carries the deploy
bookkeeping tag — `deployed/<id>` on a successful build or
`failed/<id>` on a failed one, planted by the `MergeConfigPr` deploy.
Both fields are `Option`: `None` on the paths that don't deploy a new
commit (spawn / init_config / meta-update / deny, and the autoupdate
commit (spawn / meta-update / deny, and the autoupdate
sweep's `job_queue::templates::rebuild` reapplying the existing main,
or the dashboard `↻ R3BU1LD` button when the lock didn't move). When set,
`git show <sha>` against `/applied/<n>/.git` inside the

View file

@ -58,7 +58,7 @@ power-intent registry:
below](#state-dirs-per-agent) for where reminders (and todos)
actually live now.
- `approvals` — the queue. `agent / kind (merge_config_pr | spawn |
init_config | update_meta_inputs | schedule_prompt) /
update_meta_inputs | schedule_prompt) /
commit_ref / requested_at / status / resolved_at / note`.
- `scheduled_prompts` — recurring + one-shot prompt queue.
`owner / body / interval_seconds (NULL = one-shot) /
@ -353,9 +353,9 @@ tree anyone edits in place. Mounting it writable would leave a second
path to the same file that skips the review entirely, which makes the
boundary a convention rather than a permission.
⚠️ Not to be confused with the seeding done when an `InitConfig`
approval resolves: that writes the child's initial config repo as
**hive-c0re, against the host path**, and `read_only` on a bind
⚠️ Not to be confused with the config-repo seeding hive-c0re does at
spawn (`lifecycle::setup_proposed`): that writes the child's initial
config repo as **hive-c0re, against the host path**, and `read_only` on a bind
constrains writers *inside* a container only. The two are unrelated —
conflating them can lead you to reason your way into thinking this
mount should be writable when it shouldn't.
@ -443,7 +443,7 @@ nothing is automigrated: existing agents keep their plain dirs
until an explicit opt-in upgrade.
- **Creation:** `lifecycle::ensure_agent_state_subvolume` runs before
hive-c0re creates the per-agent subdirs (spawn / rebuild / InitConfig).
hive-c0re creates the per-agent subdirs (spawn / rebuild).
It skips the work when the root already exists; otherwise it asks
hive-priv (`EnsureAgentSubvolume`) to `btrfs subvolume create` the
root when the FS is btrfs (`statfs` magic gate) and chown it to the