refactor(#2416): remove the non-pr config-change flow (request_apply_commit / applycommit)

This commit is contained in:
damocles 2026-07-15 20:45:29 +02:00 committed by mara
commit c2bd7db998
34 changed files with 293 additions and 1635 deletions

View file

@ -98,7 +98,7 @@ Once enforcement lands the rules collapse into:
| ----------------------------------------------------------------------- | --------------------------------------------------------------------------------------- |
| `kill` / `start` / `restart` / `update` (any descendant) | any ancestor |
| `request_init_config` (spawn a new child) | any agent, child added under self |
| `request_apply_commit` (any descendant's config) | any ancestor |
| config change via forge PR (any descendant's config) | any ancestor |
| `get_logs` (any descendant) | any ancestor |
| moderate questions / reminders (cancel any open thread of a descendant) | any ancestor |
| `send` / `recv` routing | parent ↔ same-parent siblings ↔ self ↔ descendants; explicit allow-list for anyone else |
@ -133,7 +133,6 @@ can't:
| variant | semantic | post-milestone |
| --------------------------------------- | ---------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `RequestInitConfig` | seed an agent's proposed config repo | **topology** — existing direct child (re-init) or a brand-new name (child added under self on approval); a name owned by a different parent is refused |
| `RequestApplyCommit` | submit a commit sha for operator approval | **topology** — descendants only |
| `Kill` / `Start` / `Restart` / `Update` | container lifecycle on an existing agent | **topology** — descendants only |
| `RequestUpdateMetaInputs` | bump meta `flake.lock` | **per-agent cap** (root-only today; a future "let coder bump its own input" might grant it) |
| `GetLogs` | journalctl scrape of a sub-agent | **topology** — descendants only |

View file

@ -10,67 +10,55 @@ informed about what happens after a decision lands.
## End-to-end approval flow
Config changes flow through a **forge pull request** on the agent's
`agent-configs/<name>` repo — the same surface agents use for code PRs.
There is no bespoke MCP tool for config changes: opening the PR IS the
request.
1. The submitting agent (the child's parent, holding the `approvals`
tool group) edits files in the child's proposed config repo
(any tracked path, but `agent.nix` is the contract entry point)
and commits with its own git identity. The parent's container has
the child's proposed config repo bind-mounted read-write at
(any tracked path, but `agent.nix` is the contract entry point),
commits with its own git identity, and pushes a branch + opens a PR
on `agent-configs/<name>` with `hive-forge`. 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,
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
approval pins an immutable commit.
3. **hive-c0re immediately fetches that commit from the proposed
repo into the applied repo and tags it `proposal/<id>`.** It
resolves the sha locally against the proposed repo, fetches all
of proposed's heads into applied's object db, then tags the
resolved commit — `git fetch <remote> <sha>:<dst>` can't fetch
by a bare sha (the left side of a refspec is a remote *ref
name*), so the resolution happens on hive-c0re's side. The
approval row stores both the submitted sha and the
canonical hive-c0re-vouched sha. From here on the proposed
repo is irrelevant for this approval — the submitter can amend,
force-push, or `rm -rf` the proposed repo and the queued
approval still points at an immutable git object inside
applied.
3a. **Flake validation (ApplyCommit only):** after the proposal tag
is planted, hive-c0re reads `proposal/<id>:flake.lock` and
runs two checks. If either check fails, no
pending approval is created for the operator — the row is
marked failed and surfaces on the dashboard with the
validation message:
- **Stale lock** — materialises the commit in a temp worktree,
runs `nix flake lock` (no `--update-input` flags, so it only
fills missing entries), and rejects if the committed
`flake.lock` differs from the result. Triggered when the
submitter added or removed `inputs` in `flake.nix` without
re-running `nix flake lock`. Fix: run `nix flake lock` in
the config repo, commit, and re-submit.
- **Duplicate inputs** — groups lock nodes by their canonical
`original` field; rejects if two or more nodes share the same
source. This usually means an input is missing
`inputs.<x>.inputs.nixpkgs.follows = "nixpkgs"`. Fix: add
the `follows` directive, re-lock, and re-submit.
Both checks only flag *new* violations — agents whose lock
already carried duplicates before this check was added are
unaffected until a coordinated config-change pass.
4. Operator sees the proposal as a card on the dashboard — a
full multi-file diff, toggleable between three bases (vs the
running tree / vs the last approved proposal / vs the
previous queued proposal) — and clicks ◆ APPR0VE (or
`hive-c0re approve <id>` on the CLI).
5. hive-c0re moves the working tree to `proposal/<id>` and runs
the build under a sequence of tags (see below). On success,
`applied/main` fast-forwards to the proposal commit. On
failure, main stays put and the working tree resets back to
the previous deployed commit.
6. `HelperEvent::ApprovalResolved` (and `Rebuilt` for the
ApplyCommit kind) land in the **submitting agent's** inbox, carrying
both the canonical sha and the terminal tag. Helper events route to
the submitting agent via `notify_submitter` (the approval row carries
a `submitter` column recording which agent called `request_apply_commit`
or `request_init_config`).
Branch protection (push/merge whitelist = `core`, approvals whitelist
= operator team; see "Forge mirror" and #1787) makes the agent a
write collaborator that **cannot merge its own config PR**.
2. hive-c0re's `/webhook/config-pr` endpoint receives the Forgejo
`pull_request` event (opened / synchronized / reopened) and queues a
`MergeConfigPr` approval; a poll fallback catches any missed webhook.
The approval row stores the PR **number** (`commit_ref`) and the PR
**head sha at queue time** (`fetched_sha` — the "reviewed" sha). If
the PR head later moves, the stale approval is superseded by a fresh
one pinned to the new head, so the operator always reviews what will
actually deploy.
3. The operator reviews the PR **on the forge** (native diff, threaded
comments, CI status) and sees a matching card on the dashboard with a
"review PR on forge" deep link. They click ◆ APPR0VE (or
`hive-c0re approve <id>` on the CLI) once satisfied.
4. On approve, `run_merge_config_pr`:
- re-reads the live PR head and **aborts if it drifted** from the
reviewed `fetched_sha` (the submitter must push again, which queues
a fresh approval);
- fetches that head into the applied repo and **eval-verifies** it —
a flake eval on a throwaway checkout. This is the trust gate: it
relies on c0re's own eval, not on any in-repo (agent-forgeable)
signal like a CI status;
- fast-forwards the forge config repo's `main` to the reviewed head
(this IS the merge — a `core`-authenticated ff-push, so a moved PR
head can't substitute bytes) and marks the PR merged (best-effort;
`main` is already there);
- runs the shared deploy tail (`deploy_applied_target`): builds under
the tag sequence below, and on success `applied/main`
fast-forwards to the reviewed commit + the meta lock bumps. On
failure, main stays put and the working tree resets to the previous
deployed commit.
5. `HelperEvent::ApprovalResolved` (and `Rebuilt`) land in the
**submitting agent's** inbox via `notify_submitter`, carrying both the
canonical sha and the terminal tag (the approval row carries a
`submitter` column recording the agent the change is for).
### Withdrawing a pending approval
@ -88,53 +76,47 @@ 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 are the first step in a two-step spawn
flow. On approve, hive-c0re seeds the proposed config repo with
a default `agent.nix` template and sends `HelperEvent::ConfigReady { agent }`
to the submitting agent's inbox via `notify_submitter`. The submitting
agent then reviews,
edits, and commits the template before calling `request_apply_commit`
to proceed to an `ApplyCommit` approval. The first `ApplyCommit`
creates the container; subsequent ones rebuild it with new config.
This gives the submitting agent (and operator) an explicit review gate on the
initial configuration before any container is created.
`InitConfig` approvals seed a brand-new agent's proposed config repo.
On approve, hive-c0re seeds it with a default `agent.nix` template and
sends `HelperEvent::ConfigReady { agent }` to the submitting agent's
inbox via `notify_submitter`. The submitting agent reviews, edits, and
commits the template; the operator then **spawns** the agent (the
`Spawn` approval / `◆ R3QU3ST SP4WN` button), which creates the
container from that config. From then on, config changes go through a
forge PR (`MergeConfigPr`) — never a fresh spawn. This gives the
submitting agent (and operator) an explicit review gate on the initial
configuration before any container is created.
### Approval kinds (wire shapes)
`ApprovalKind` carries six variants; each maps to a different
`ApprovalKind` carries five variants; each maps to a different
`commit_ref` encoding because that field is overloaded as the
kind-specific payload carrier.
- `ApplyCommit``commit_ref` is the submitted git sha
(7-40 hex chars). The canonical, hive-c0re-vouched sha after the
proposal fetch lives in `fetched_sha` on the same `Approval`
row (only `ApplyCommit` populates it). See the End-to-end flow
above.
- `MergeConfigPr` — the PR-based config flow's counterpart to
`ApplyCommit`. Triggered automatically: when an agent opens (or
force-pushes) a PR on its `agent-configs/<agent>` forge repo,
hive-c0re's `/webhook/config-pr` endpoint receives the Forgejo
pull_request event and queues this approval row. No MCP tool call
needed — the forge PR IS the request. `commit_ref` stores the
**PR number** (decimal), and `fetched_sha` is the PR **head sha
at queue time** (the "reviewed" sha). On approve,
- `MergeConfigPr` — the config-change flow. Triggered automatically:
when an agent opens (or force-pushes) a PR on its
`agent-configs/<agent>` forge repo, hive-c0re's `/webhook/config-pr`
endpoint receives the Forgejo pull_request event and queues this
approval row. No MCP tool call needed — the forge PR IS the request.
`commit_ref` stores the **PR number** (decimal), and `fetched_sha` is
the PR **head sha at queue time** (the "reviewed" sha). On approve,
`run_merge_config_pr` re-reads the live PR head and aborts if it
drifted from `fetched_sha` (submitter must push again to
re-trigger), then fetches that head into the applied repo,
eval-verifies it, fast-forwards the forge config repo's `main` to
it (the merge), marks the PR merged (best-effort — `main` is
already there), and runs the same shared deploy tail as
`ApplyCommit` (`deploy_applied_target`). Never a first spawn.
- `Spawn` — direct container creation under the default
`agent.nix` template. `commit_ref` is empty. Submitted via
`HostRequest::RequestSpawn` (operator-gated, the
`◆ R3QU3ST SP4WN` dashboard button + `hive-c0re request-spawn`
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). The
agent-side `RequestSpawn` is gone; the submitting agent goes through the
`InitConfig``ApplyCommit` two-step instead so the spawn
captures the customised config.
already there), and runs the shared deploy tail
(`deploy_applied_target`). Never a first spawn.
- `Spawn` — direct container creation from the agent's config repo.
`commit_ref` is empty. Submitted via `HostRequest::RequestSpawn`
(operator-gated, the `◆ R3QU3ST SP4WN` dashboard button +
`hive-c0re request-spawn` 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).
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.
@ -239,14 +221,14 @@ module that `setup_applied` used to generate inline.
Containers run against `--flake /var/lib/hyperhive/meta#<n>`.
Per-deploy lock flow (two-phase, owned by
`actions::run_apply_commit` → `meta::{prepare,finalize,abort}
_deploy`):
`actions::run_merge_config_pr` → `deploy_applied_target`
`meta::{prepare,finalize,abort}_deploy`):
1. `meta::prepare_deploy(name)` runs
`nix flake lock --update-input agent-<n>` without
committing. Working tree of meta now points the input at
`applied/<n>/main` (which `run_apply_commit` already
fast-forwarded to `proposal/<id>`).
`applied/<n>/main` (which the deploy already fast-forwarded to
the reviewed PR head).
2. `lifecycle::rebuild_no_meta` runs
`nixos-container update <c> --flake meta#<name>`. Nix
evaluates against the staged lock.
@ -323,34 +305,29 @@ wraps it with identity + `HIVE_PORT` / `HIVE_LABEL` /
### Tag state machine
Every approval id walks through a fixed set of tags on the
underlying commit inside the applied repo:
Each deploy leaves a tag on the underlying commit inside the applied
repo:
| Tag | When | Annotated? |
|---|---|---|
| `proposal/<id>` | request_apply_commit, after fetch | no |
| `approved/<id>` | operator approve | no |
| `building/<id>` | rebuild started | no |
| `deployed/<id>` | rebuild succeeded — `main` ff's here | no |
| `failed/<id>` | rebuild failed | yes (body = error) |
| `denied/<id>` | operator deny | yes (body = operator note) |
`applied/main` is always the latest `deployed/*`. `denied/` and
`failed/` are terminal; the submitting agent submits a new commit + new
approval id to retry. Because tags are first-class git objects,
rejected and failed trees stay browsable forever — `git log
--tags` in the applied repo is the audit trail.
`deployed/0` is planted at first spawn. `applied/main` is always the
latest `deployed/*`. A `failed/` tree stays browsable forever — `git log
--tags` in the applied repo is the audit trail. A denied or failed config
PR carries no extra state on the forge side: the PR stays open, and the
submitter pushes again (or closes it) to retry.
### Dispatch via the job queue
Long-running approval work — `ApplyCommit`, `UpdateMetaInputs`,
Long-running approval work — `MergeConfigPr`, `UpdateMetaInputs`,
`Spawn` — no longer runs inline inside `actions::approve`. Instead
the approval handler submits a DAG to the global job queue
(`docs/coordinator.md::Job queue`):
| `ApprovalKind` | DAG submitted | source |
|---|---|---|
| `ApplyCommit` | `rebuild` (single opaque `ApprovalDeploy` node) | `approval` |
| `MergeConfigPr` | `rebuild` (single opaque `ApprovalDeploy` node) | `approval` |
| `UpdateMetaInputs` | `meta_update` (`MetaLock` + rebuild fan-out) | `approval` |
| `Spawn` | `spawn` (`Create → WriteDropin → Reconcile`) | `approval` |
@ -358,9 +335,8 @@ the approval handler submits a DAG to the global job queue
| `SchedulePrompt` | — runs inline (single sqlite insert) | — |
The DAG carries the originating `approval_id`. The `ApprovalDeploy`
node runs the kind-specific pipeline (`run_approval_apply_commit` /
`run_approval_merge_config_pr` — the two-phase meta deploy stays
inside `actions.rs`) and fires the matching `HelperEvent::*` via
node runs `run_approval_merge_config_pr` (the two-phase meta deploy
stays inside `actions.rs`) and fires the matching `HelperEvent::*` via
`finish_approval` itself; `Spawn` and `UpdateMetaInputs` DAGs resolve
through `actions::resolve_approval_dag` when the DAG settles terminal
(a spawn additionally runs the post-spawn forge bookkeeping there).
@ -391,22 +367,25 @@ The bundled `hive-forge` container is mandatory (it deploys with
hyperhive), and hive-c0re mirrors every agent's applied repo into a
private `agent-configs` Forgejo org. `forge::push_config(<name>)` pushes `applied/main` plus
every tag to `agent-configs/<name>` after each ref mutation:
the spawn that seeds `deployed/0`, every `request_apply_commit`
(which plants `proposal/<id>`), every approve / deny, and a
the spawn that seeds `deployed/0`, every successful deploy (which
plants `deployed/<id>`) or failed build (`failed/<id>`), and a
sweep at startup. Pushes are best-effort — a missing or stopped
forge never blocks a deploy.
The org is private and agents are not members, so only the
`core` user (a Forgejo site admin) can read it: an agent can't
reach another agent's config — or even its own — through the
forge. The tokenised push URL is passed inline to `git push`,
never written into `applied/<n>/.git/config`; that repo is
RO-bind-mounted into the root agent, and a stored token would leak
core's admin credential to an agent.
Each agent is a **write collaborator on its own** `agent-configs/<name>`
repo — so it can push a branch and open a config PR — but not a member
of any other agent's, so it can't reach another agent's config through
the forge. Branch protection keeps `main` push/merge `core`-only with
operator-team approval, so an agent can't fast-forward its own config or
self-merge its PR (see the End-to-end flow + #1787). The tokenised push
URL is passed inline to `git push`, never written into
`applied/<n>/.git/config`; that repo is RO-bind-mounted into the root
agent, and a stored token would leak core's admin credential to an
agent.
The dashboard deep-links into this org — a `config repo` link
per container row and a `commit on forge` link per approval
card. See `docs/web-ui.md`.
per container row and a `review PR on forge` link per config-PR
approval card. See `docs/web-ui.md`.
### Submitting agent's view of config repos
@ -484,8 +463,8 @@ hive-c0re creates it. The root agent's flake lives at
`/var/lib/hyperhive/applied/ruth/`; its proposed config at
`/var/lib/hyperhive/agents/ruth/config/`. The root agent can edit its own
`agent.nix` (visible inside the container at `/agents/ruth/config/`)
and submit `request_apply_commit("ruth", <sha>)` for operator
approval.
and open a config PR on `agent-configs/ruth` for operator approval,
same as any other agent.
Differences from sub-agents:
@ -559,11 +538,11 @@ root agent. 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` (first-time
ApplyCommit-kind) + admin `HostRequest::Spawn` (deprecated).
- `Spawned { agent, ok, note }`the `Spawn` approval DAG +
admin `HostRequest::Spawn`.
- `Rebuilt { agent, ok, note }``auto_update::rebuild_agent`
(covers startup scan + manual `/rebuild` from dashboard) +
`actions::approve` (ApplyCommit).
the `MergeConfigPr` deploy.
- `Killed { agent }` — admin `HostRequest::Kill` + dashboard
`/kill` + the `Kill` MCP tool.
- `Destroyed { agent }``actions::destroy`.
@ -582,9 +561,9 @@ root agent. Variants (`hive_sh4re::HelperEvent`):
often greets the agent on this event.
- `ConfigReady { agent }` — a new agent's proposed config repo was
just seeded (post-`InitConfig` approval). The root agent can now
edit `/agents/<agent>/config/agent.nix`, commit the changes,
and submit `request_apply_commit` with the commit sha to create
the container (first ApplyCommit also triggers spawn bookkeeping).
edit `/agents/<agent>/config/agent.nix`, commit the changes, and
hand off to the operator to **spawn** the agent (the `Spawn`
approval creates the container from that config).
- `NeedsUpdate { agent }` — sub-agent's recorded flake rev is
stale. The root agent calls `update(name)` to rebuild — idempotent,
no approval required.

View file

@ -325,7 +325,7 @@ binary flavor.
| `inbox` | `get_loose_ends`, `cancel_loose_end`, `remind`, `request_next_turn` |
| `execution` | vestigial — `mcp__bash__run` / `mcp__bash__status` are always available unconditionally via `extraMcpServers`; this group's entries expand to non-existent `mcp__hyperhive__run` / `mcp__hyperhive__status` and have no effect. See `docs/tools/bash.md`. |
| `lifecycle` | `kill`, `start`, `restart`, `update` *(privileged)* |
| `approvals` | `request_init_config`, `request_apply_commit`, `request_update_meta_inputs` *(privileged)* |
| `approvals` | `request_init_config`, `request_update_meta_inputs` *(privileged)* |
| `scheduling` | `request_schedule_prompt`, `fire_schedule_now`, `cancel_schedule`, `edit_schedule`, `list_schedules` *(privileged)* |
| `diagnostics` | `get_logs` *(privileged)* |

View file

@ -201,7 +201,7 @@ per template.
### Approvals
`ApplyCommit` / `MergeConfigPr` approvals ride as single-node
`MergeConfigPr` approvals ride as single-node
`ApprovalDeploy` DAGs: the two-phase `prepare_deploy` / `finalize_deploy` /
`abort_deploy` meta orchestration stays inside `actions.rs` in v1
(deliberately not modeled as scheduler nodes) and resolves the approval
@ -274,7 +274,7 @@ Key operations:
init the repo on first call, relock if the rendered contents changed, commit.
Called by spawn / destroy / startup migration.
- **`prepare_deploy` + `finalize_deploy` / `abort_deploy`** — two-phase for the
`RequestApplyCommit` path so a failed `nixos-container update` leaves no orphan
`MergeConfigPr` deploy path so a failed `nixos-container update` leaves no orphan
commit in meta. Prepare writes the new lock without committing; finalize commits
with the deploy message; abort restores the lock.
- **`lock_update_hyperhive`** — one-shot for the boot-reconcile path (the

View file

@ -20,7 +20,7 @@ header/targets split, and the per-agent power-intent registry:
under the agent's state dir; the worker delivers a short
pointer instead. `attempt_count` / `last_error` accumulate
on delivery-failed retries.
- `approvals` — the queue. `agent / kind (apply_commit | spawn |
- `approvals` — the queue. `agent / kind (merge_config_pr | spawn |
init_config | update_meta_inputs | schedule_prompt) /
commit_ref / requested_at / status / resolved_at / note`.
- `operator_questions``ask` / `answer` queue (despite the

View file

@ -65,12 +65,15 @@ the container, via MCP tools):
request_init_config(name: "iris")
# → operator approves → config_ready event lands in the inbox
# Step 2: edit /agents/iris/config/agent.nix, commit it, then:
request_apply_commit(agent: "iris", commit_ref: "<sha>")
# → operator approves → container built + started
# Step 2: edit /agents/iris/config/agent.nix and commit it. Then the
# operator spawns iris (dashboard ◆ R3QU3ST SP4WN / Spawn approval),
# which builds + starts the container from that config.
# Later config changes: open a PR on agent-configs/iris (hive-forge);
# the operator reviews + approves it — no MCP tool call.
```
See [`approvals.md`](approvals.md) for the full two-step flow.
See [`approvals.md`](approvals.md) for the full flow.
### 5 · Useful host commands
@ -97,8 +100,8 @@ See [`tools/hivectl.md`](tools/hivectl.md) for every `hivectl` verb.
- **No forge admin token is stored in any agent state dir.** Agents
hold a regular agent token in their `forge-token` file; sensitive
creds (the core token, the matrix admin token) live on the host.
- All config changes (`request_apply_commit`) go through operator
approval — agents can't unilaterally rebuild containers, by design.
- All config changes (forge PRs on `agent-configs/<name>`) go through
operator approval — agents can't unilaterally rebuild containers, by design.
See [`boundary.md`](boundary.md) and [`security.md`](security.md).
Once the hive is running, ruth records anything it needs to remember

View file

@ -164,7 +164,6 @@ name as-is.
| `get_logs*` | `get_logs* name` or `get_logs* name NL` |
| `get_host_journal*` | `get_host_journal*()` or with `[container] · [/grep/] · NL` |
| **Approvals / config** | |
| `request_apply_commit*` | `request_apply_commit* agent @ sha12` |
| `request_init_config*` | `request_init_config* name` |
| `request_update_meta_inputs*` | `request_update_meta_inputs* [inp1, …]` or `all` |
| **Scheduling** | |

View file

@ -45,24 +45,17 @@ Step 1 of spawning a new direct child agent. Queues an `InitConfig`
approval; on operator approve, hive-c0re seeds the proposed config
repo at `/agents/<name>/config/agent.nix` with a default template and
delivers a `config_ready` system event. Then edit `agent.nix`, commit,
and call `request_apply_commit` with the commit sha — the first
`ApplyCommit` on a freshly-init'd config creates the container.
and the operator **spawns** the agent (the dashboard `◆ R3QU3ST SP4WN`
button / `Spawn` approval, routed via `HostRequest::RequestSpawn`),
which creates the container from that config.
Subsequent config changes go through a **forge PR** on the agent's
`agent-configs/<name>` repo (queues a `MergeConfigPr` approval on
open/update — no MCP tool involved), not a tool call. See
`docs/approvals.md`.
Fails if a proposed config repo for `name` already exists.
`name` is ≤ 9 characters. The operator can also spawn an empty agent
via the dashboard `◆ R3QU3ST SP4WN` button, which routes via
`HostRequest::RequestSpawn`.
### `request_apply_commit(agent, commit_ref, description?)`
Step 2 of spawning (or updating an existing child's config). Submit a
commit sha from the child's proposed config repo for operator
approval. On approve, hive-c0re rebuilds the container with the
pinned commit.
`commit_ref` must be a 7-40 char hex sha (branch/tag names are
rejected — the approval pins the exact commit). `agent` must be a
direct child. Topology-enforced.
`name` is ≤ 9 characters.
### `request_update_meta_inputs(inputs?, description?)`
@ -81,7 +74,6 @@ agents after the approval resolves.
| `kill` / `start` / `restart` / `update` | No | Direct children |
| `list_containers` | No | All descendants |
| `request_init_config` | Yes (InitConfig) | New direct child only |
| `request_apply_commit` | Yes (ApplyCommit) | Direct children |
| `request_update_meta_inputs` | Yes (MetaUpdate) | Meta flake (global) |
## See also

View file

@ -1066,7 +1066,6 @@ renderApprovals`) with three stacked sections:
| kind | glyph | chip | sha shown |
|---|---|---|---|
| `apply_commit` | `→` | `apply` | proposal sha (`sha_short`) |
| `merge_config_pr` | `⇒` | `merge-pr` | PR-head sha (`sha_short`) |
| `update_meta_inputs` | `↻` | `meta-update` | — |
| `schedule_prompt` | `⏱` | `schedule` | — |
@ -1080,26 +1079,16 @@ renderApprovals`) with three stacked sections:
than at the next `renderApprovals` call.
- **what-changed body** — the submitting agent's description, then
kind-specific drill-in triggers:
- `apply_commit`: `↳ view diff` opens the inline diff side-panel;
`↳ commit on forge ↗` deep-links the proposal commit into
`agent-configs/<agent>` (shown only when `forge_present`).
- `merge_config_pr`: `↳ review PR on forge ↗` deep-links the
config PR into `agent-configs/<agent>/pulls/<pr_number>` (shown
only when `forge_present` and `pr_number` is set). No inline diff
side-panel (apply_commit-only for now).
only when `forge_present` and `pr_number` is set). The config diff
lives on the forge PR itself — no inline diff side-panel.
- `init_config` / `spawn`: 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 submitting agent as
`HelperEvent::ApprovalResolved.note`.
The diff panel has a 3-way base toggle — **vs applied** (the
running tree, served instantly from the diff already on the
approval), **vs last-approved**, **vs previous proposal** — the
latter two fetched on click from `GET /api/approval-diff/{id}
?base=approved|previous`. Each line is classified client-side
(`+` / `-` / `@@` / `--- ` / `+++ ` → add / del / hunk / file).
A `pending · N` / `history · N` tab pair switches the section
between the live queue and the last 30 resolved approvals.
@ -1199,12 +1188,8 @@ that's a browser-level decision, not ours.
`"ok"`/`"err"`, `detail` nullable), newest first, server-clamped to
500; `total` is the full row count for a "latest 500 of N" header.
Backs the LOGS page AUDIT sub-tab.
- `GET /api/approval-diff/{id}?base=applied|approved|previous`
on-demand unified diff for an `ApplyCommit` approval against
the chosen base (running tree / last approved proposal /
previous queued proposal). Raw diff text, classified
client-side. `GET /static/marked.js` serves the vendored
`marked` bundle the side panel uses for markdown previews.
- `GET /static/marked.js` serves the vendored `marked` bundle used
for markdown previews.
- `GET /api/state-file?path=<host-or-container-path>` — bounded
text read of a file under the per-agent `state/` subtree or
the shared `/var/lib/hyperhive/shared/`. Accepts the