Apply contraction fixes across ~40 doc files (setup, integrations, lifecycle, networking, scheduler, swarm, tools, trust-boundary, UI, etc.). Skipped 14 hits: - 10 where words appear in ALL CAPS for deliberate emphasis (is NOT, do NOT, etc.) - 4 where text could not be safely located due to markdown formatting or column position Applied via systematic scan with checks for fenced code blocks, inline code spans, and intentional caps. Preserves sentence-initial capitalization throughout.
231 lines
12 KiB
Markdown
231 lines
12 KiB
Markdown
# MCP surface
|
|
|
|
The harness ships an embedded MCP server (rmcp 2). The built-in
|
|
`hyperhive` surface is served over streamable HTTP by a persistent
|
|
`hive-mcp-http` daemon (loopback, `127.0.0.1:<hyperhive.mcp.httpPort>`,
|
|
per-container private netns). Claude connects to its stable URL via
|
|
`--mcp-config` rather than respawning a stdio child each turn, so the
|
|
URL survives the per-turn claude re-spawn (and a host-side hive-c0re
|
|
restart) — there is no per-turn MCP re-registration race for the
|
|
built-in surface. HTTP is the sole transport for it (no stdio fallback).
|
|
Extra servers (`hyperhive.extraMcpServers`) pick their own transport per
|
|
entry (`type = "stdio" | "http"`, default `"stdio"`): `matrix` stays a
|
|
stdio bridge, `bash` runs its own persistent streamable-http listener
|
|
(`hive-bash-daemon`) — same reasoning as the built-in surface. The
|
|
server name is `hyperhive`, so the tools land in claude as
|
|
`mcp__hyperhive__<tool>`.
|
|
|
|
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.
|
|
|
|
## Core tools (always available)
|
|
|
|
**Messaging** (`messaging` group): `send(to, body, in_reply_to?)`,
|
|
`recv(max?)`, `ack_until(up_to)`.
|
|
|
|
- `send` — message a peer (logical name) or the operator
|
|
(`to: "operator"`). Use `to: "<parent>"` to address the topology
|
|
parent without hardcoding the label; the broker resolves the
|
|
sentinel at delivery time. Optional `in_reply_to: i64` links the
|
|
message to a prior id for thread rendering. Per-agent
|
|
`hyperhive.allowedRecipients` (default: empty = unrestricted) limits
|
|
which names `send` accepts — useful for sandboxing: set
|
|
`[ "operator" ]` to restrict a sub-agent to operator messages only
|
|
(the topology parent is always reachable regardless of this list —
|
|
that carve-out is structural, keyed on parent relationship, not name).
|
|
- `recv` — drain inbox. Always an immediate peek, never blocks. `max`
|
|
(default 1, cap 5) drains up to N rows. Each returned row is prefixed with
|
|
`[msg #<id>]` (broker row id; note the highest id seen, then pass
|
|
it to `ack_until` to bulk-triage the batch). **Graceful shutdown**: when the harness
|
|
receives a stop signal, the inbox becomes fenced and `recv` returns an
|
|
explicit `from: "graceful-stop"` message instead of an empty inbox.
|
|
This unmissably directs the agent to flush durable state (`/state`
|
|
files) and end the turn — the container exits when the turn completes.
|
|
The graceful-stop turn takes the same post-turn compaction path as any
|
|
other turn: if the context crossed the watermark the harness runs a
|
|
notes-checkpoint turn and then `/compact`. Compacting before shutdown
|
|
keeps a later cold start cheap instead of re-uploading a huge transcript.
|
|
- `ack_until(up_to)` — bulk-mark inbox rows handled: every row with
|
|
broker id `<= up_to` is stamped as acked in a single UPDATE.
|
|
Recipient-scoped (agents can only ack their own rows). Use when a
|
|
restart redelivers a large backlog of already-handled messages: read
|
|
the highest `[msg #N]` from the set you've actually processed, then
|
|
`ack_until(N)` to prevent re-pop. Acked rows never redeliver.
|
|
Transient pings (sentinel id 0) have nothing to ack and show no marker.
|
|
|
|
**System messages** (from sender `system`): the higher-urgency
|
|
lifecycle events (`hive_sh4re::manager::HelperEvent`) are
|
|
delivered as regular inbox messages (same `recv` path; body is a JSON
|
|
object with an `event` discriminant field). The **submitting agent**
|
|
(the root agent for top-level containers; an agent with the `approvals`
|
|
tool group for its own subtree) receives `container_crash`,
|
|
`needs_update`, and `approval_resolved` this way. The remaining, lower-urgency lifecycle
|
|
notices — `spawned`, `rebuilt`, `killed`, `destroyed`, `needs_login`,
|
|
`logged_in`, `config_ready` — skip the inbox entirely: they land as
|
|
todos on the submitting agent's in-container todo socket instead
|
|
(`Coordinator::push_todo`/`push_todo_submitter`, `subsystem = "core"`),
|
|
which still wakes a turn (the todo-wake path — see [Turn
|
|
outcomes](README.md#turn-outcomes)) but via a generic "call
|
|
`get_loose_ends`" prompt rather than the event body itself. Full
|
|
payload shapes and routing logic in
|
|
[`docs/agent-lifecycle/approvals.md` § Helper events](../agent-lifecycle/approvals.md#helper-events-to-the-submitting-agent).
|
|
|
|
**Inbox** (`inbox` group): `get_loose_ends(agent?)`,
|
|
`cancel_loose_end(kind, id)`, `remind(message, delay_seconds? |
|
|
at_unix_timestamp?)`.
|
|
|
|
- `get_loose_ends(agent?)` — list scheduled reminders, pending
|
|
approvals you submitted, and active local tasks published by
|
|
external MCP daemons (e.g. running bash tasks from
|
|
`hive-bash-daemon`). Each row carries an id + kind for
|
|
`cancel_loose_end`. Omit `agent` to list your own threads. Pass
|
|
`agent: "<name>"` to inspect a direct child agent (always accessible
|
|
per topology enforcement); non-children require the
|
|
`query_agent_state` capability. The `"*"` hive-wide query isn't
|
|
available on the agent socket.
|
|
- `cancel_loose_end` — hard-delete a `reminder`, cancel a pending
|
|
`approval` row, or clear a `todo` row (loose-ends-v2). Agents may
|
|
only cancel rows they own; the `approval` kind is further restricted
|
|
to the root agent (`ruth`) server-side.
|
|
- `remind` — schedule a reminder in this agent's own inbox. Large
|
|
payloads spill to `/agents/<self>/state/reminders/`. Pending count
|
|
capped at 50 per agent (`HIVE_REMIND_MAX_PENDING_PER_AGENT`).
|
|
|
|
There is no same-turn self-continue tool — see
|
|
[Turn outcomes](README.md#turn-outcomes) for why. Multi-step work rides
|
|
`remind` for a durable self-wake, or an in-container todo wake
|
|
(bash-task completion, forge notification, matrix activity) for work
|
|
already in flight.
|
|
|
|
**Meta** (`meta` group): `set_status(text)`, `get_agent_meta(name?)`.
|
|
|
|
- `set_status` — set a free-text status string visible on the
|
|
dashboard. Single line, ≤ 200 chars. Persisted to
|
|
`{state_dir}/hyperhive-status`. Pass `""` to clear.
|
|
- `get_agent_meta` — fetch identity + status metadata for an agent:
|
|
`{ name, hyperhive_rev, running, status_text, status_set_at,
|
|
hive_name?, swarm_name?, matrix_accounts? }`. `matrix_accounts` is a
|
|
list of matrix identities the agent can act as (`name`, `user_id?`,
|
|
`homeserver`); omitted for agents with no matrix provisioning. Omit
|
|
`name` to query self.
|
|
|
|
**Always-on, no tool group** (like `set_status`): `compact()`.
|
|
|
|
- `compact` — agent self-service equivalent of the operator dashboard's
|
|
`/compact` button. No args. Gated server-side on the last completed
|
|
turn's context usage: refused (with an explanation, no side effect)
|
|
unless usage is above 66% of the effective context window. On a
|
|
pass, queues the same deferred `compact_pending` flag the dashboard
|
|
button sets — consumed at the end of the current turn, so it never
|
|
races a live claude process, and the usual pre-compaction
|
|
notes-checkpoint turn still fires first. Dispatched through the
|
|
in-agent socket (`hive-agent-sock::Request::Compact`), not the
|
|
broker — see `hive-agent/src/todo_server.rs`.
|
|
|
|
## Privileged tools (by tool group)
|
|
|
|
- **Bash execution** (`execution`) — background shell tasks. See
|
|
[`docs/tools/bash.md`](../tools/bash.md).
|
|
- **Lifecycle + config** (`lifecycle`, `approvals`) — manage child
|
|
agents, spawn new ones, apply config commits. See
|
|
[`docs/tools/lifecycle.md`](../tools/lifecycle.md).
|
|
- **Scheduling + diagnostics** (`scheduling`, `diagnostics`) —
|
|
scheduled prompts, `get_logs`. See
|
|
[`docs/tools/scheduling.md`](../tools/scheduling.md).
|
|
- **Forge repos** (`forge`) — `create_repo` — the only agent path to
|
|
create a repo under the `agents/` org (direct forge token creation is
|
|
disabled for agents). The repo is created in the c0re-owned `agents`
|
|
org; the calling agent gets write collaborator access; the default
|
|
branch is branch-protected (operator-team must approve merges, so the
|
|
agent can't self-merge). Opt-in; not in any default preset.
|
|
See [`docs/tools/forge.md — Repo management`](../tools/forge.md).
|
|
- **Web egress** (`web_tools`) — enables Claude's built-in `WebFetch`
|
|
and `WebSearch` tools (not MCP tools; added directly to the
|
|
`--allowedTools` list). Off by default; add the group in the
|
|
P3RM1SS10NS tab and rebuild to enable.
|
|
- **Capability-gated** — `get_host_journal` (requires
|
|
`read_host_journal` capability set via the P3RM1SS10NS tab;
|
|
orthogonal to tool groups). Full list of capabilities and their
|
|
effects in [`docs/process/conventions.md#capabilities`](../process/conventions.md).
|
|
Also documented in [`docs/tools/scheduling.md`](../tools/scheduling.md).
|
|
- **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
|
|
|
|
External MCP servers (and any other in-container process) can
|
|
inject a wake-up event into the agent's inbox via the per-agent
|
|
socket at `/run/hive/mcp.sock`. Speak the wire protocol directly —
|
|
JSON-line over the unix socket: `{"cmd":"wake","from":"matrix","body":
|
|
"new dm from @alice"}\n`. Same shape as any other request on this
|
|
socket; see `hive_core_agent_sock::Request::Wake`. Every built-in producer that wakes
|
|
the harness (matrix, bash) dials the socket directly — there is no
|
|
CLI wrapper, just the raw protocol.
|
|
|
|
The wake event lands in the broker as `{from:<label>,
|
|
to:<agent>, body}`, waking whatever `recv` call the harness
|
|
is currently blocked on. The next turn fires with the wake
|
|
prompt formed from that message.
|
|
|
|
Identity = socket: anything that can connect to
|
|
`/run/hive/mcp.sock` is implicitly trusted to inject these —
|
|
the bind-mount is the agent's own container only.
|
|
|
|
## Authoritative state
|
|
|
|
`hive-agent`'s `events::Bus` carries the current turn-loop state in
|
|
addition to the broadcast channel and the events history. Variants:
|
|
|
|
- `Idle` — sitting on `Recv` waiting for mail.
|
|
- `Thinking` — `claude --print` is running for a turn.
|
|
- `Compacting` — operator-triggered `/compact` is in flight.
|
|
|
|
The harness flips state at the relevant transitions
|
|
(`set_state(Thinking)` before `drive_turn`, `set_state(Idle)`
|
|
after; `set_state(Compacting)` around an idle operator compact in
|
|
`turn::run_pending_compact`). Exposed via `/api/state.turn_state` +
|
|
`turn_state_since` (unix seconds); the agent page renders this rather
|
|
than deriving from SSE events.
|
|
|
|
## Tool envelope
|
|
|
|
`mcp::run_tool_envelope`: every MCP tool handler logs the request,
|
|
runs the body, logs the result. Pre-/post-log only — the inbox
|
|
status hint lives in the wake prompt + UI header, not here.
|
|
|
|
## Tool allowlist (`mcp_config::ALLOWED_BUILTIN_TOOLS`)
|
|
|
|
- Allowed built-ins: `Edit`, `Glob`, `Grep`, `Read`, `Skill`, `Write`.
|
|
`Skill` is what makes an installed plugin's `SKILL.md` invokable —
|
|
without it, a skill's `description` frontmatter never gets seen by
|
|
the model no matter how well it matches the task.
|
|
- Tool-group-gated built-ins: `WebFetch`, `WebSearch` (added when the
|
|
`web_tools` tool group is enabled — see P3RM1SS10NS tab).
|
|
- Denied by omission (absent from the harness `--tools` /
|
|
`--allowedTools`, so they "literally don't exist" in a harness turn):
|
|
`Bash`, `Task`, `NotebookEdit`, `TodoWrite`.
|
|
- Additionally in the managed-settings deny list
|
|
(`/etc/claude-code/managed-settings.json`, un-overridable): `Task`,
|
|
`TodoWrite`. `Bash` is **not** in the managed deny — see below.
|
|
- Allowed MCP tools: as listed above (by tool group).
|
|
|
|
`Bash` is disallowed for the autonomous harness — shell execution goes
|
|
through `mcp__bash__run` (background tasks with structured output +
|
|
task-id tracking) instead of an interactive shell. The harness gate is
|
|
`--tools` / `--allowedTools` (Bash absent from `ALLOWED_BUILTIN_TOOLS`),
|
|
so Bash never exists in a harness turn regardless of managed settings.
|
|
`Bash` is deliberately **not** in the managed-settings deny so that the
|
|
operator-driven `hivectl choom` session — which passes neither `--tools`
|
|
nor `--allowedTools` — gets claude's built-in synchronous `Bash` tool
|
|
(inline, human-approved). That sidesteps the async `mcp__bash__run`
|
|
completion wake landing in the wrong session (the harness inbox) for a
|
|
choom-started task (#2356); `choom` is an operator (root) action, so
|
|
built-in shell there stays within the existing trust boundary. The bash MCP server
|
|
(`run` / `status` / `kill`) uses `allowedTools = ["*"]` so all
|
|
`mcp__bash__*` tools are always available regardless of tool groups.
|
|
|
|
`WebFetch` / `WebSearch` are off by default; enable the `web_tools`
|
|
tool group in the P3RM1SS10NS tab and rebuild the agent to enable them.
|