docs(#1251): split MCP tool docs into docs/tools/ sub-mds by feature

This commit is contained in:
damocles 2026-06-04 12:29:04 +02:00 committed by mara
commit 78a00d1258
6 changed files with 350 additions and 268 deletions

View file

@ -354,6 +354,8 @@ docs/
web-ui/agent.md (header, terminal, composer, web-ui/agent.md (header, terminal, composer,
inbox, live view, per-agent endpoints, stats) inbox, live view, per-agent endpoints, stats)
turn-loop.md claude invocation, wake prompt, MCP tool surface turn-loop.md claude invocation, wake prompt, MCP tool surface
tools/ per-group tool docs (bash.md, lifecycle.md,
scheduling.md, matrix.md)
approvals.md approval flow, manager policy, helper events approvals.md approval flow, manager policy, helper events
persistence.md sqlite dbs, retention, state dir layout persistence.md sqlite dbs, retention, state dir layout
terminal-rendering.md per-agent terminal row taxonomy (as built) terminal-rendering.md per-agent terminal row taxonomy (as built)

49
docs/tools/bash.md Normal file
View file

@ -0,0 +1,49 @@
# Bash execution tools (`execution` tool group)
Background shell execution via `hive-bash-mcp`. Tools land as
`mcp__bash__<tool>` (the MCP server name is `bash`, not `hyperhive`).
Enabled for any agent whose tool groups include `execution` — the
default preset (`AGENT_DEFAULT`) includes it.
## Tools
### `run(cmd, timeout_secs?)`
Submit a shell command for background execution (`sh -c <cmd>`).
Returns a task ID immediately; the command runs asynchronously in a
harness-managed tokio task. Stdout and stderr stream to
`harness/bash-tasks/<id>.{out,err}`. When the task completes (or
times out, or the process errors), the harness wakes the agent with a
summary body — handle on a future turn. Optional `timeout_secs`: pass
a value for a deadline, or omit for no timeout (runs until natural exit).
Exposed as `mcp__bash__run`.
### `status(id)`
Poll the status of a task submitted with `run`. Returns:
- `status``pending` / `running` / `done` / `timed_out` / `interrupted`
- `exit_code` — set when done
- run duration
- last 4 KiB of stdout and stderr (full output in the `.out` / `.err` files)
Tasks marked `interrupted` had their process killed by a harness
restart; a best-effort wake was still sent so the agent is not
silently blocked.
Exposed as `mcp__bash__status`.
## Namespace note
`run` and `status` live in the `bash` MCP server, not `hyperhive`. So
the tool names in claude are `mcp__bash__run` and `mcp__bash__status`.
The `Bash` built-in tool is blocked — all shell execution goes through
this structured path so tasks get task-id tracking and structured output.
## Tool whitelist cross-reference
`mcp__bash__run` and `mcp__bash__status` are unconditionally in
`--allowedTools` whenever the harness spawns claude (they are not
gated by the `execution` group at the `--allowedTools` level — the
group only gates whether the MCP server registers the tools at all).

91
docs/tools/lifecycle.md Normal file
View file

@ -0,0 +1,91 @@
# Lifecycle and approvals tools
Two tool groups govern agent lifecycle management and config changes.
Both are scoped to **direct children only** (topology-enforced: the
server rejects any name that is not a direct child of the calling
agent per `topology.json`). Privileged agents (e.g. ruth) may operate
on any sub-agent — the topology scope applies to all others.
## `lifecycle` tool group
No operator approval required. Direct children only.
### `kill(name)`
Graceful stop. Container state is preserved; recreating the agent
reuses prior config and credentials.
### `start(name)`
Start a stopped sub-agent.
### `restart(name)`
Stop + start in one call.
### `update(name)`
Rebuild: re-applies the current hyperhive flake + `agent.nix`,
then restarts. Idempotent — safe to call repeatedly. Used in response
to `needs_update` system events.
### `list_containers()`
List all **descendant** containers (children + their subtrees) with
running status. Topology-scoped to descendants only.
## `approvals` tool group
Config changes and new-agent spawns route through the operator
approval queue. Direct children only (topology-enforced).
### `request_init_config(name, description?)`
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.
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.
### `request_update_meta_inputs(inputs?, description?)`
Queue an approval to run `nix flake update [inputs...]` on the meta
flake. Pass specific input names (e.g. `["bitburner-agent"]`) or omit
/ pass `[]` for all inputs. Returns immediately; the lock update runs
on operator approval.
Does NOT trigger container rebuilds — call `update(name)` on affected
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_apply_commit` | Yes (ApplyCommit) | Direct children |
| `request_update_meta_inputs` | Yes (MetaUpdate) | Meta flake (global) |
## See also
- [`docs/approvals.md`](../approvals.md) — full approval flow, kinds,
helper events (`config_ready`, `approval_resolved`), flake.lock
validation.

62
docs/tools/matrix.md Normal file
View file

@ -0,0 +1,62 @@
# Matrix MCP tools and extra MCP servers
## Built-in matrix MCP (`mcp__matrix__*`)
When `hyperhive.matrix.enable = true` and the host-level matrix
tuwunel is configured, the harness auto-injects `hive-matrix-mcp` as
a second stdio MCP server. Tools land as `mcp__matrix__<name>`:
### Messaging
- `send_message(room, body)` — send a markdown message; `room`
accepts `!id:server` or `#alias:server`, daemon resolves either
- `send_dm(user_id, body)` — send a direct message to a matrix user
- `send_reply(room, event_id, body)` — threaded reply to a specific
event
- `send_reaction(room, event_id, key)` — react to a message with an
emoji key
### Reading
- `read_room(room, limit?)` — recent timeline events
- `list_rooms()` — enumerate joined rooms
(`{ id, canonical_alias, name, member_count }` per room)
- `list_room_members(room)` — members of a room
### Receipts
- `mark_read(room, event_id)` — advance the read receipt
## Architecture
The daemon (`hive-matrix-daemon`) holds the long-running matrix-sdk
`Client` + sync loop; the stdio bridge (`hive-matrix-mcp`) is spawned
per turn and forwards tool calls over `/run/hive-matrix.sock`. Both
silently exit when `<state>/matrix-token` is absent (account not yet
provisioned).
Incoming room events wake the agent via `AgentRequest::Wake` with
`from: "matrix"` and a teaser body
(`[matrix] <sender> in <room>: <first-100c>…`).
See [`docs/matrix.md`](../matrix.md) for the homeserver setup,
provisioning flow, and federation config.
## Extra MCP servers (per-agent)
Each agent's NixOS config can declare additional MCP servers via
`hyperhive.extraMcpServers.<key> = { command, args, env,
allowedTools }`. The module writes the map to
`/etc/hyperhive/extra-mcp.json`; the harness reads it at boot and
merges every entry into `--mcp-config` (under `mcpServers.<key>`)
and `--allowedTools` (as `mcp__<key>__<pattern>`).
The agent's `flake.nix` forwards every flake input to `agent.nix` as
the `flakeInputs` module arg, so external MCP-server flakes are pulled
in by adding them to `inputs.*` and referenced as
`flakeInputs.<name>.packages.${pkgs.system}.default` — the resolved
sha lands in the agent's own `flake.lock` and rolls up to meta's.
`allowedTools` defaults to `["*"]`, which expands to
`mcp__<key>__*` (every tool from that server auto-approved). Restrict
to specific tool names when you want finer control.

68
docs/tools/scheduling.md Normal file
View file

@ -0,0 +1,68 @@
# Scheduling and diagnostics tools
## `scheduling` tool group
Scheduled prompts fan a message body out to one or more agent inboxes
at a future time, optionally recurring. All scheduling ops go through
the operator approval queue (even self-targeted schedules — use
`remind` for unapproved self-wake). Authorization for read/cancel/edit
ops: you can act on schedules you own or any owned by a sub-agent in
your topology subtree.
### `request_schedule_prompt(targets, body, first_fire_at_unix, interval_seconds?, description?)`
Queue an operator-approval for a scheduled prompt. On approve,
`body` is fanned out to each agent in `targets` at
`first_fire_at_unix` (Unix timestamp). Recurring when `interval_seconds`
is set, one-shot otherwise.
Catch-up clamp: if hive-c0re is down across multiple intervals, only
ONE delayed fire happens on resume (per recurring schedule). The
skipped-cycle count surfaces in the per-target `last_result` for
audit.
### `edit_schedule(id, body?, description?, interval_seconds?, next_fire_at_unix?, targets_add?, targets_remove?)`
Partial-update a schedule. Pass only the fields to change; absent
fields are left alone. `targets_add` / `targets_remove` mutate the
recipient list in the same transaction — re-adding a previously
cancelled target drops its tombstone and starts fresh. Clearing
`interval_seconds` to null flips recurring → one-shot. Refuses
cancelled rows (terminal state).
### `cancel_schedule(id, targets?)`
Cancel a schedule. Omit `targets` / pass empty to cancel the whole
schedule; pass a list to cancel just those recipients (the schedule
auto-cancels when every target is removed).
### `fire_schedule_now(id)`
Fire a scheduled prompt out of band immediately. Recurring schedules
keep their cadence — the manual fire is additive. One-shot schedules
are consumed by the manual fire and cancelled afterwards.
### `list_schedules()`
Snapshot every schedule (active + cancelled-but-not-reaped): id,
owner, body, per-target `last_fired_at` + `last_result`,
`next_fire_at_unix`, `interval_seconds`. Use to look up an id before
cancelling, or to audit upcoming wake-ups across the swarm.
## `diagnostics` tool group
### `get_logs(agent, lines?)`
Fetch recent journal lines for a sub-agent container. Useful for
diagnosing MCP-registration failures, startup crashes, plugin install
errors, or any harness issue you can't see from inside the container.
Pass the plain logical agent name (e.g. `"gui"`) — hive-c0re resolves
the machine name (`h-<name>`). `lines` defaults to 50, host-capped at 500.
## See also
- `remind` (no-approval self-wake path) — documented in
[`docs/turn-loop.md`](../turn-loop.md).
- [`docs/approvals.md`](../approvals.md) — approval flow for
`request_schedule_prompt`.

View file

@ -5,9 +5,8 @@ claude has access to in return.
## The loop ## The loop
Each agent harness (`hive serve`, with role picked from `$HIVE_ROLE` Each agent harness (`hive serve`, role set via `$HIVE_ROLE` — always
`"agent"` for sub-agents, `"manager"` for the manager — one `"agent"`, one binary) runs:
binary, not two) runs:
1. Long-poll `Recv` on its socket. The host-side broker 1. Long-poll `Recv` on its socket. The host-side broker
(`broker.rs::recv_blocking_batch`) returns immediately if there's (`broker.rs::recv_blocking_batch`) returns immediately if there's
@ -292,115 +291,74 @@ The harness ships an embedded MCP server (rmcp 1.7). Claude launches
it as a stdio child via `--mcp-config`. The hyperhive socket name is it as a stdio child via `--mcp-config`. The hyperhive socket name is
`hyperhive`, so the tools land in claude as `mcp__hyperhive__<tool>`. `hyperhive`, so the tools land in claude as `mcp__hyperhive__<tool>`.
### Sub-agent tools Tool access is gated by tool groups (`HIVE_TOOL_GROUPS`). The default
preset (`AGENT_DEFAULT`) includes `messaging`, `meta`, `inbox`, and
`execution`. Privileged groups (`lifecycle`, `approvals`, `scheduling`,
`diagnostics`) are opt-in via the P3RM1SS10NS tab.
- `send(to, body, in_reply_to?)` — message a peer (logical agent ### Core tools (always available)
name), another agent, or the operator (recipient `operator`,
surfaces in the dashboard inbox). Use `to: "<parent>"` to **Messaging** (`messaging` group): `send(to, body, in_reply_to?)`,
address the agent's topology parent without knowing its label; `recv(wait_seconds?, max?)`, `ask(question, options?, multi?,
the broker resolves the sentinel at delivery time (falls back ttl_seconds?, to?)`, `answer(id, answer)`.
to `operator` for root agents). Optional `in_reply_to: i64`
links this message to a prior message id for thread rendering - `send` — message a peer (logical name) or the operator
in the dashboard message flow and the per-agent inbox. (`to: "operator"`). Use `to: "<parent>"` to address the topology
- `recv(wait_seconds?, max?)` — drain inbox messages. Without parent without hardcoding the label; the broker resolves the
`wait_seconds` (or with `0`) returns immediately, a cheap sentinel at delivery time. Optional `in_reply_to: i64` links the
"anything pending?" peek. Positive value parks the turn up message to a prior id for thread rendering.
to that many seconds (cap 180) — incoming messages wake - `recv` — drain inbox. Without `wait_seconds` (or `0`) returns
instantly, otherwise returns empty at the timeout. `max` immediately. Positive value parks the turn up to that many seconds
(default 1, server-side cap 32) drains up to N popped rows (cap 180) — incoming messages wake instantly. `max` (default 1, cap
in one round-trip; `wait_seconds` applies to the *first* 32) drains up to N rows; `wait_seconds` applies to the first, then
message, then the call drains up to `max` total. drains up to `max` total.
- `ask(question, options?, multi?, ttl_seconds?, to?)` - `ask` — surface a structured question to the operator (default) or
surface a structured question. Same shape as the manager's; a peer agent (`to: "<agent>"`). Non-blocking — returns a question
recipient defaults to the operator (dashboard) but can be set id; the answer arrives as a `question_answered` system event in the
to a peer agent name via `to: "<agent>"`. Answer routes back asker's inbox. `options` is advisory; `multi=true` renders as
to the asker's own inbox as `HelperEvent::QuestionAnswered` checkboxes; `ttl_seconds` auto-cancels with answer `[expired]`.
via `coord.notify_agent`. For peer questions the recipient - `answer` — respond to a `question_asked` event routed to this
sees a `HelperEvent::QuestionAsked` event and replies with agent. Strict authorisation: only the declared target can answer.
`answer(id, answer)`.
- `answer(id, answer)` — respond to a `question_asked` event **Inbox** (`inbox` group): `get_loose_ends()`,
routed to this agent. Authorisation is strict: only the `cancel_loose_end(kind, id)`, `remind(message, delay_seconds? |
declared target (or the operator via the dashboard) can at_unix_timestamp?)`, `request_next_turn()`.
answer.
- `get_loose_ends()` — list everything still pending against - `get_loose_ends` — list pending questions (asked/owed) and
this agent: unanswered questions it asked / was asked, plus scheduled reminders. Each row carries an id + kind for
reminders it scheduled. Each row carries an id + kind for
`cancel_loose_end`. `cancel_loose_end`.
- `cancel_loose_end(kind, id)` — withdraw a `question` - `cancel_loose_end` — withdraw a `question` (posts `[cancelled by
(posts `[cancelled by <self>]` to unblock the asker), a <self>]`) or hard-delete a `reminder`. Agents may only cancel rows
`reminder` (hard-delete before fire), or (manager only) an they own.
`approval` (transitions to `Cancelled`; sub-agents refused with a - `remind` — schedule a reminder in this agent's own inbox. Large
clear error). Sub-agents may only cancel rows they own. payloads spill to `/agents/<self>/state/reminders/`. Pending count
- `remind(message, due)` — schedule a reminder that lands in capped at 50 per agent (`HIVE_REMIND_MAX_PENDING_PER_AGENT`).
this agent's own inbox at a future time (sender shows as - `request_next_turn` — ask the harness to start another turn
`reminder`). Large payloads spill to immediately after this one ends, even if the inbox is empty.
`/agents/<self>/state/reminders/` with the inbox message a Next turn fires with `from: "self"` and `body: "continue"`.
short pointer. Each agent's pending-reminder count is capped
(default 50, override via `HIVE_REMIND_MAX_PENDING_PER_AGENT`);
scheduling a new one fails if the cap is already hit.
- `set_status(text)` — set a free-text status string visible on
the operator dashboard. Persisted to
`{state_dir}/hyperhive-status`; survives harness restarts. Pass
an empty string to clear. Validated: must be a single line and
≤ 200 Unicode characters; the server rejects multi-line or
over-length text with a clear error.
- `get_agent_meta(name?)` — fetch identity + status metadata for
an agent: `{ name, role, hyperhive_rev, running, status_text,
status_set_at, hive_name?, swarm_name? }`. Pass `name` to query
a peer (e.g. check whether a sub-agent is idle before sending it
work). Omit `name` to get your own identity stamp — replaces the
previous `whoami` tool. `running` is `true` when the container is
up. When `running` is `false` the host clears `status_text` /
`status_set_at` (they would be stale snapshots from before the
container stopped) before serving the response. Status fields are
also `None` when the target has never called `set_status` or has
cleared it. `hive_name` and `swarm_name` are present when
`services.hyperhive.hiveName` / `services.hyperhive.swarmName`
are configured on the host; omitted in single-hive deployments.
- `request_next_turn()` — ask the harness to start another turn
immediately after this one ends, even if the inbox is empty. Use for
multi-turn tasks (long builds, sequential steps) where you want to
continue without waiting for an external message. The next turn starts
with `from: "self"` and `body: "continue"`. No-op if new inbox
messages arrive before this turn ends. No args.
- `run(cmd, timeout_secs?)` — submit a shell command for
background execution (`sh -c <cmd>`). Returns a task ID immediately;
the command runs asynchronously in a harness-managed tokio task. Stdout
and stderr stream to `harness/bash-tasks/<id>.{out,err}`. When the
task completes (or times out, or the process errors), the harness wakes
the agent with a summary body — handle on a future turn. Optional
`timeout_secs`: pass a value for a deadline, or omit for no timeout
(runs until natural exit). Requires the `execution` tool group.
Exposed as `mcp__bash__run`.
- `status(id)` — poll the status of a task submitted with
`run`. Returns status (`pending`/`running`/`done`/`timed_out`/
`interrupted`), exit code, run duration, and the last 4 KiB of stdout
and stderr (full output in the `.out`/`.err` files). Tasks marked
`interrupted` had their process killed by a harness restart; a best-
effort wake was still sent so the agent is not silently blocked.
Exposed as `mcp__bash__status`.
**Agent lifecycle + config tools** (direct children only; requires **Meta** (`meta` group): `set_status(text)`, `get_agent_meta(name?)`.
`lifecycle` or `approvals` tool group):
- `kill(name)`, `start(name)`, `restart(name)`, `update(name)` — manage - `set_status` — set a free-text status string visible on the
a direct child sub-agent (graceful stop, start, stop+start, rebuild). dashboard. Single line, ≤ 200 chars. Persisted to
No approval required. Topology-enforced: `name` must be a direct child `{state_dir}/hyperhive-status`. Pass `""` to clear.
per `topology.json`. Server rejects all other agent names. Requires - `get_agent_meta` — fetch identity + status metadata for an agent:
`lifecycle` tool group. `{ name, hyperhive_rev, running, status_text, status_set_at,
- `list_containers()` — list all descendant containers with running hive_name?, swarm_name? }`. Omit `name` to query self.
status. Topology-enforced (descendants only). Requires `lifecycle`
tool group. ### Privileged tools (by tool group)
- `request_init_config(name, description?)` — step 1 of spawning a new
direct child agent. Queues an `InitConfig` approval; on operator - **Bash execution** (`execution`) — background shell tasks. See
approve, hive-c0re seeds the proposed config repo with a default [`docs/tools/bash.md`](tools/bash.md).
`agent.nix` template. `name` must be a direct child. Topology-enforced. - **Lifecycle + config** (`lifecycle`, `approvals`) — manage child
Fails if config already exists. Requires `approvals` tool group. agents, spawn new ones, apply config commits. See
- `request_apply_commit(agent, commit_ref, description?)` — step 2 of [`docs/tools/lifecycle.md`](tools/lifecycle.md).
spawning a new direct child (or updating an existing child's config). - **Scheduling + diagnostics** (`scheduling`, `diagnostics`) —
Submit a commit sha from the child's proposed config repo for operator scheduled prompts, `get_logs`. See
approval. `agent` must be a direct child. Topology-enforced. `commit_ref` [`docs/tools/scheduling.md`](tools/scheduling.md).
must be a 7-40 char hex sha. Requires `approvals` tool group. - **Matrix MCP + extra servers**`mcp__matrix__*` tools and
per-agent extra MCP config. See
[`docs/tools/matrix.md`](tools/matrix.md).
### Waking the agent from inside the container ### Waking the agent from inside the container
@ -411,170 +369,22 @@ socket at `/run/hive/mcp.sock`. Two equivalent paths:
- **Shell out to `hive wake --from <label> --body <text>`** - **Shell out to `hive wake --from <label> --body <text>`**
(use `--body -` to read body from stdin). Already on the (use `--body -` to read body from stdin). Already on the
container's `PATH` since the harness binary is in container's `PATH` since the harness binary is in
`systemPackages`. Convenient for shell-script integrations. `systemPackages`. Convenient for shell-script integrations and
Works for both `agent` and `manager` roles. co-process daemons (matrix bridge, webhook listeners, scrapers).
- **Speak the wire protocol directly** — JSON-line over the - **Speak the wire protocol directly** — JSON-line over the
unix socket: `{"cmd":"wake","from":"matrix","body":"new dm unix socket: `{"cmd":"wake","from":"matrix","body":"new dm
from @alice"}\n`. Same shape any other AgentRequest uses; from @alice"}\n`. Same shape as any other `AgentRequest`;
see `hive-sh4re::AgentRequest::Wake`. see `hive-sh4re::AgentRequest::Wake`.
The wake event lands in the broker as `{from:<label>, The wake event lands in the broker as `{from:<label>,
to:<agent>, body}`, which wakes whatever `recv` call the to:<agent>, body}`, waking whatever `recv` call the harness
harness is currently blocked on. Next turn fires with the is currently blocked on. The next turn fires with the wake
wake prompt formed from that message — claude sees "from: prompt formed from that message.
matrix" (or whatever label) and reacts.
Identity = socket: anything that can connect to Identity = socket: anything that can connect to
`/run/hive/mcp.sock` is implicitly trusted to inject these, `/run/hive/mcp.sock` is implicitly trusted to inject these —
which is fine because the bind-mount is the agent's own the bind-mount is the agent's own container only.
container only.
### Built-in matrix MCP (`mcp__matrix__*`)
When `hyperhive.matrix.enable = true` (default) and the host-level
matrix tuwunel is configured, the harness auto-injects `hive-matrix-mcp`
as a second stdio MCP server. Tools land as `mcp__matrix__<name>`:
- `send_message(room, body)` — send a markdown message; `room` accepts
`!id:server` or `#alias:server`, daemon resolves either
- `send_dm(user_id, body)` — send a direct message to a matrix user
- `send_reaction(room, event_id, key)` — react to a message
- `send_reply(room, event_id, body)` — threaded reply
- `mark_read(room, event_id)` — advance the read receipt
- `list_rooms()` — enumerate joined rooms
(`{ id, canonical_alias, name, member_count }` per room)
- `list_room_members(room)` — members of a room
- `read_room(room, limit?)` — recent timeline events
The daemon (`hive-matrix-daemon`) holds the long-running matrix-sdk
`Client` + sync loop; the stdio bridge (`hive-matrix-mcp`) is spawned
per turn and forwards tool calls over `/run/hive-matrix.sock`. Both
silently exit when `<state>/matrix-token` is absent (account not yet
provisioned). Incoming room events wake the agent via `AgentRequest::Wake`
with `from: "matrix"` and a teaser body
(`[matrix] <sender> in <room>: <first-100c>…` where `<sender>` is
the matrix user id and `<room>` is the alias or id as reported by
the SDK).
### Extra MCP servers (per-agent)
Each agent's NixOS config can declare additional MCP servers via
`hyperhive.extraMcpServers.<key> = { command, args, env,
allowedTools }`. The module writes the map to
`/etc/hyperhive/extra-mcp.json`; the harness reads it at boot and
merges every entry into `--mcp-config` (under `mcpServers.<key>`)
and `--allowedTools` (as `mcp__<key>__<pattern>`). The agent's
flake.nix forwards every flake input to `agent.nix` as the
`flakeInputs` module arg, so external MCP-server flakes are pulled
in by adding them to `inputs.*` and referenced as
`flakeInputs.<name>.packages.${pkgs.system}.default` — the
resolved sha lands in the agent's own `flake.lock` and rolls up to
meta's.
### Manager tools (in addition to send/recv)
- `request_init_config(name, description?)` — first step of a
two-step spawn. Queues an `InitConfig` approval (≤9 char name);
on operator approve, hive-c0re seeds the proposed config repo
with a default `agent.nix` template and sends the manager a
`HelperEvent::ConfigReady { agent }`. The manager then edits
`agent.nix`, commits the changes, and calls `request_apply_commit`
with the commit sha — the first ApplyCommit on a freshly-init'd
config creates the container. Fails if a proposed repo for this
name already exists. (The operator can also direct-spawn an empty
agent from the dashboard's `◆ R3QU3ST SP4WN` button, which routes
via `HostRequest::RequestSpawn`.) Also available to agents for direct
children only (requires `approvals` tool group; see agent lifecycle
tools section above).
- `kill(name)` — graceful stop. No approval required. Also available to
agents for direct children only (requires `lifecycle` tool group; see
agent lifecycle tools section above).
- `start(name)` — start a stopped sub-agent. No approval. Also available
to agents for direct children only.
- `restart(name)` — stop + start. No approval. Also available to agents
for direct children only.
- `update(name)` — rebuild (re-applies the current hyperhive flake
+ agent.nix, restarts). No approval, idempotent. Manager calls
this on receipt of a `needs_update` system event. Also available to
agents for direct children only.
- `request_apply_commit(agent, commit_ref)` — submit a config
change for any agent (`root` for the manager's own config) for
operator approval. Also available to agents for direct children only
(requires `approvals` tool group; see agent lifecycle tools section
above).
- `request_update_meta_inputs(inputs?, description?)` — queue an
approval to run `nix flake update [inputs...]` on the meta flake.
Pass specific input names (e.g. `["bitburner-agent"]`) or omit
for all. Returns immediately; lock update runs on operator
approval. Does NOT trigger rebuilds — call `update(name)` on
affected agents after approval resolves.
- `ask(question, options?, multi?, ttl_seconds?, to?)`
surface a structured question to the operator (default) or a
sub-agent (`to: "<agent>"`). Non-blocking — returns the
queued question id; the answer arrives later as
`HelperEvent::QuestionAnswered { id, question, answer,
answerer }` in the asker's inbox. Options always render
alongside a free-text fallback; `multi=true` renders options
as checkboxes. `ttl_seconds` auto-cancels with answer
`[expired]` (and `answerer: "ttl-watchdog"`) after the
deadline (useful for time-sensitive decisions that become moot
if no one has responded). The operator can also manually
cancel with `[cancelled]` via the dashboard.
- `answer(id, answer)` — respond to a `question_asked` event
that was routed to the manager (a sub-agent did
`ask(to: "manager", ...)`). Surfaces in the asker's inbox as
the same `question_answered` event.
- `get_logs(agent, lines?)` — fetch recent journal lines for a
sub-agent container (diagnose MCP-registration failures,
startup crashes, etc.). Pass the plain logical agent name;
hive-c0re resolves the machine name (`h-<name>`, manager
`root`). `lines` defaults to 50, host-capped at 500.
- `request_schedule_prompt(targets, body, first_fire_at_unix, interval_seconds?, description?)`
queue an operator-approval for a scheduled prompt. On approve,
`body` is fanned out to each `targets` agent at
`first_fire_at_unix`; recurring if `interval_seconds` is set,
one-shot otherwise. Even self-targeted schedules go through
approval (use `remind` for unapproved self-wake). Long downtime
fires once per recurring row on resume (catch-up clamp).
- `edit_schedule(id, body?, description?, interval_seconds?, next_fire_at_unix?, targets_add?, targets_remove?)`
partial-update a schedule. Pass only the fields to
change; absent fields are left alone. `targets_add` / `targets_remove`
mutate the recipient list in the same transaction; re-adding a
previously-cancelled target drops its tombstone + history (fresh
start). Clearing a scalar (e.g. `interval_seconds: null`) flips
recurring→one-shot. Refuses cancelled rows. Same authorization as
`cancel_schedule`.
- `cancel_schedule(id, targets?)` — cancel a schedule. Omit
`targets` / pass empty to cancel the whole schedule; pass a list
to cancel just those recipients (auto-cancels when every target
is removed). Authorization: manager can cancel schedules it owns
or any owned by a sub-agent in its topology subtree.
- `fire_schedule_now(id)` — fire a scheduled prompt out of band.
Runs the per-target fan-out once immediately. Recurring schedules
keep their cadence (the manual fire is additive); one-shot
schedules are consumed by the fire and cancelled afterwards. Same
authorization rules as `cancel_schedule`.
- `list_schedules()` — snapshot every schedule (active +
cancelled-but-not-reaped): id, owner, body, per-target
`last_fired_at` + `last_result`, `next_fire_at_unix`,
`interval_seconds`. Use to look up an id before cancelling or to
audit upcoming wake-ups across the swarm.
- `remind` / `get_loose_ends` / `cancel_loose_end` / `set_status`
/ `get_agent_meta` — same as the sub-agent tools above.
`get_loose_ends` scopes to the manager's own items by default;
pass `agent: "*"` for a hive-wide view, or `agent: "<name>"`
to inspect one agent.
`cancel_loose_end` may cancel any agent's row.
The boundary: lifecycle ops on *existing* direct children
(`kill`/`start`/`restart`/`update`) are discretionary — no operator
approval required (manager can do so for any sub-agent; agents can do so
only for direct children with `lifecycle` tool group). Creating a new
agent (`request_init_config``request_apply_commit` for the first sha)
and changing any agent's config (`request_apply_commit`) still go through
the approval queue (same topology scoping for agents: direct children only
with `approvals` tool group).
### Authoritative state ### Authoritative state
@ -604,7 +414,7 @@ status hint moved to the wake prompt + UI header.
`web_tools` tool group is enabled — see P3RM1SS10NS tab). `web_tools` tool group is enabled — see P3RM1SS10NS tab).
- Denied by omission or `claude-settings.json` deny list: `Bash`, - Denied by omission or `claude-settings.json` deny list: `Bash`,
`Task`, `NotebookEdit`, `TodoWrite`. `Task`, `NotebookEdit`, `TodoWrite`.
- Allowed MCP tools: as listed above per flavor. - Allowed MCP tools: as listed above (by tool group).
`Bash` is disallowed — shell execution goes through `Bash` is disallowed — shell execution goes through
`mcp__bash__run` (background tasks with structured output + `mcp__bash__run` (background tasks with structured output +