prompts+docs: the lifecycle tools reach the whole subtree, not just direct children
`require_descendant` (`socket_server/mod.rs:666`) authorises
kill/start/restart/update/get_logs with `topology::is_descendant_of` — the
caller's whole subtree, itself included. That has been true since `53b4e752`
(#1865), whose message says "a parent owns its whole subtree; the root covers
every agent as a consequence, no positional privilege", and two tests pin it
(`is_descendant_of_in_grandchild`, `is_descendant_of_in_self_is_true`).
The prose never followed. The four lifecycle tool descriptions, their
`// IMPORTANT:` comments, `docs/tools/lifecycle.md`, the tools README,
hive-agent-mcp's README and the system prompt every agent is rendered from all
still said "direct children only" — while `list_containers`, four tools away in
the same file, said "direct children + their subtrees".
`lifecycle.md` also taught the model #1865 deleted: "Privileged agents (for
example ruth) may operate on any sub-agent — the topology scope applies to all
others." There is no privileged class to belong to; ruth reaches every agent
because the check is transitive and everything sits under it.
Same drift on the state-query side: `resolve_agent_state_target` is
subtree-scoped by the same commit, so `get_loose_ends`' argument doc, the
`QueryAgentState` capability doc and `docs/turn-loop/mcp.md` were all telling a
parent it needs a capability to read a grandchild's threads.
Two smaller corrections found on the way:
* `list_containers` returns the caller itself. `is_descendant_of` is true for
`candidate == ancestor` and `handle_list_descendants` filters the topology
with it; called from a leaf agent it answers one row, that agent.
* `request_init_config` accepts any unused name — the requester becomes its
parent — or an existing agent already in the caller's subtree, not "a direct
child". The editing surface is narrower than the guard, though: only direct
children's config repos are bind-mounted, so re-seeding deeper in the subtree
leaves no local copy to edit. `lifecycle.md` now says so.
The prompt's other stale claim, the dead `request_apply_commit`, is #4226 and
was fixed independently by damocles in #4227 while this was being gated. This
branch keeps only the scope wording on that line.
Closes #4225.
This commit is contained in:
parent
7135931722
commit
0a80f21003
10 changed files with 93 additions and 66 deletions
|
|
@ -1,14 +1,15 @@
|
|||
# Lifecycle and approvals tools
|
||||
|
||||
Two tool groups govern agent lifecycle management and config changes.
|
||||
The server scopes both to **direct children only** (topology-enforced: it
|
||||
rejects any name that's not a direct child of the calling
|
||||
agent per `topology.json`). Privileged agents (for example ruth) may operate
|
||||
on any sub-agent — the topology scope applies to all others.
|
||||
The server scopes both to the caller's **own subtree** (topology-enforced
|
||||
per `topology.json`: a child, a child's child, every agent below them —
|
||||
plus the caller itself). No privileged class exists to belong to; the
|
||||
root agent reaches every agent purely because the check is transitive and
|
||||
everything sits under it.
|
||||
|
||||
## `lifecycle` tool group
|
||||
|
||||
No operator approval required. Direct children only.
|
||||
No operator approval required. The caller's own subtree.
|
||||
|
||||
### `kill(name)`
|
||||
|
||||
|
|
@ -31,17 +32,19 @@ to `needs_update` system events.
|
|||
|
||||
### `list_containers()`
|
||||
|
||||
List all **descendant** containers (children + their subtrees) with
|
||||
running status. Topology-scoped to descendants only.
|
||||
List the caller's whole **subtree** with running status — children,
|
||||
their children, every agent below them. The calling agent is part of its
|
||||
own subtree, so it appears in its own listing; a leaf agent gets a
|
||||
one-row answer naming itself.
|
||||
|
||||
## `approvals` tool group
|
||||
|
||||
Config changes and new-agent spawns route through the operator
|
||||
approval queue. Direct children only (topology-enforced).
|
||||
approval queue. Topology-enforced the same way.
|
||||
|
||||
### `request_init_config(name, description?)`
|
||||
|
||||
Step 1 of spawning a new direct child agent. Queues an `InitConfig`
|
||||
Step 1 of spawning a new sub-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,
|
||||
|
|
@ -54,6 +57,17 @@ Subsequent config changes go through a **forge PR** on the agent's
|
|||
open/update — no MCP tool involved), not a tool call. See
|
||||
`docs/agent-lifecycle/approvals.md`.
|
||||
|
||||
`name` must be either unused — in which case the caller becomes its
|
||||
parent on approval — or an agent already in the caller's subtree whose
|
||||
config is being re-seeded. The server refuses a name that exists outside
|
||||
that subtree, so one agent can't hijack another's.
|
||||
|
||||
Only **direct** children's config repos are bind-mounted into a parent's
|
||||
container, though (`bind_child_agent_dirs`, driven by
|
||||
`topology::children_of`). The server accepts re-seeding an agent further
|
||||
down the subtree, and that still leaves the caller without a local copy
|
||||
to edit afterwards.
|
||||
|
||||
Fails if a proposed config repo for `name` already exists.
|
||||
`name` is ≤ 9 characters.
|
||||
|
||||
|
|
@ -69,12 +83,12 @@ agents after the approval resolves.
|
|||
|
||||
## Boundary summary
|
||||
|
||||
| Operation | Requires approval? | Scope |
|
||||
| --------------------------------------- | ------------------ | --------------------- |
|
||||
| `kill` / `start` / `restart` / `update` | No | Direct children |
|
||||
| `list_containers` | No | All descendants |
|
||||
| `request_init_config` | Yes (InitConfig) | New direct child only |
|
||||
| `request_update_meta_inputs` | Yes (MetaUpdate) | Meta flake (global) |
|
||||
| Operation | Requires approval? | Scope |
|
||||
| --------------------------------------- | ------------------ | ---------------------------------- |
|
||||
| `kill` / `start` / `restart` / `update` | No | Own subtree |
|
||||
| `list_containers` | No | Own subtree, caller included |
|
||||
| `request_init_config` | Yes (InitConfig) | Unused name, or one in own subtree |
|
||||
| `request_update_meta_inputs` | Yes (MetaUpdate) | Meta flake (global) |
|
||||
|
||||
## See also
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue