subagent: add status tool, cut docs down to operator-facing + no cli flags

This commit is contained in:
damocles 2026-09-09 19:02:27 +02:00
commit c2fb3c6e3e
7 changed files with 136 additions and 195 deletions

View file

@ -29,9 +29,9 @@ debug agent behavior.
- **[bash](bash.md)** — background shell execution (`mcp__bash__*`),
available on every agent unconditionally.
- **[subagent](subagent.md)** — spawn nested headless claude sessions
(`mcp__subagent__{start,continue,interrupt}`), shipped default-on for
every agent today alongside `bash` (expected to become a real opt-in
capability later).
(`mcp__subagent__{start,continue,status,interrupt}`), shipped
default-on for every agent today alongside `bash` (expected to become a
real opt-in capability later).
- **[forge](forge.md)** — the `hive-forge` Forgejo CLI every agent has
for issues, PRs, and comments. Not an MCP tool — a binary agents
shell out to instead of ad-hoc curl.

View file

@ -102,12 +102,6 @@ MCP tools directly over streamable-http on `hyperhive.mcp.bashHttpPort`
stdio child, so there's no per-turn MCP re-registration race and no
round-trip socket hop for tool calls.
Independent daemon (own crate, own process/systemd unit/MCP server
`subagent`): `hive-subagent-daemon` — see [`subagent.md`](subagent.md).
Spawns nested claude sessions rather than shell commands, so it keeps no
task files here or anywhere else; a subagent task never shows up in this
daemon's `status`/`kill` or the running-tasks panel.
### Completion as a todo (loose-ends v2)
When a bash task changes state, `hive-bash-daemon` upserts a single keyed

View file

@ -1,102 +1,54 @@
# Subagent tools
# Subagent daemon
Spawns nested headless `claude` sessions via `hive-subagent-daemon`. Tools
land as `mcp__subagent__<tool>` (the MCP server name is `subagent`, not
`hyperhive`). Shipped default-on for every agent today —
`nix/agent-modules/mcp.nix` always injects `subagent` into
`hyperhive.extraMcpServers` (with `allowedTools = ["*"]`), same as `bash`.
The operator's own framing: shipped default-on for now, expected to become
a real opt-in capability later (not built yet).
`hive-subagent-daemon` (crate `hive-subagent-mcp`) spawns nested headless
`claude` sessions on request. Own process, own systemd unit, own MCP
server (`subagent`, not `hyperhive`) — independent of `hive-bash-daemon`:
a subagent is a full nested claude process, a materially heavier
capability than a background shell command, so it gets its own
deployable/restartable unit rather than living inside the bash daemon.
See the `base:claude-subagents` skill for _when_ to reach for this
(mechanical, bounded batches) versus doing the work inline.
Shipped default-on for every agent — `nix/agent-modules/mcp.nix` injects
`subagent` into `hyperhive.extraMcpServers` unconditionally (`allowedTools
= ["*"]`), same as `bash`. The operator's own framing: default-on for
now, a real opt-in capability later.
For what the tools do and when an agent should reach for them, see the
`subagent` MCP server's own tool descriptions and the
`base:claude-subagents` skill — this page covers the daemon as deployed
infrastructure, not the agent-facing API.
## Tools
### `start(name, prompt_file, model?, trigger?)`
Served under the `subagent` MCP server (`mcp__subagent__<tool>`): `start`,
`continue`, `status`, `interrupt`.
Start a fresh subagent session under `name`, running in the background.
Returns as soon as the process is confirmed running — not once it
finishes.
## State
- `name` — session display name: claude's own `--name`/`--resume` session
title, and this daemon's tracking key while the process is alive.
`[a-z0-9-]`, max 63 chars. Reusable once a prior session under that name
has _finished_; refused while one is still running.
- `prompt_file` — path to a file passed as `--append-system-prompt-file`,
the subagent's actual task instructions. A file, not an inline string,
to avoid `ARG_MAX` on a large recipe.
- `model``--model` for the subagent's own claude invocation. Omit for
claude's own default.
- `trigger` — written to the subagent's stdin as its first turn's prompt.
Defaults to a generic "carry out your instructions" nudge.
In-memory only: a map of currently-running processes, live only as long
as the daemon process is. A daemon restart stops whatever was running
rather than adopting it. The durable record of a subagent's existence is
claude's own on-disk session (`hive_claude::SessionStore`), which
`continue` reattaches to independent of the daemon's own lifetime — a
restart loses the *in-flight turn*, not the subagent's history.
A prior _finished_ session under the same name is archived first (renamed
`.jsonl.archived`, not deleted) — a real fresh start, not a silent resume
of old history.
## Compaction trade-off
Exposed as `mcp__subagent__start`.
Built on `hive_claude::Claude::spawn` + `RunningClaude::wait` directly
rather than `InfiniteSession::run`, since only the low-level driver
exposes a cancel handle to stop a turn mid-flight — that's what makes
`interrupt` genuinely stop a running turn rather than only cancelling a
still-pending one. The cost: a turn that overflows the context window
surfaces as an error rather than self-healing via reactive compaction.
Subagents are meant to be bounded, single-batch work, not sessions
long-lived enough to need in-place compaction — a real follow-up if that
assumption stops holding.
### `continue(name, prompt, model?)`
## Configuration
Give an existing named session a new turn — whether that means "the
previous turn finished, here's a follow-up instruction" or "the daemon
restarted, reattaching to a session that survived it independently."
Returns as soon as confirmed running, same as `start`. Refused for a name
with no session on disk at all, or one currently running.
`hyperhive.mcp.subagentHttpPort` — the daemon's streamable-http listen
port. Same pattern as `bashHttpPort`/`matrixHttpPort`: a per-agent default
assigned by `nix/agent-modules/mcp.nix`, only worth overriding for an
agent that needs a stable or non-default port.
- `name` — the existing session's name (from a prior `start`).
- `prompt` — the new turn's prompt.
- `model``--model` for this turn; doesn't have to match whatever
`start` used.
Exposed as `mcp__subagent__continue`.
### `interrupt(name, force?)`
Signal `name`'s currently-running process. Only works while it's actually
running — there's no queued/pending state to cancel pre-emptively.
- `force: false` (default) — SIGINT, letting claude shut down cleanly if
it's mid-response.
- `force: true` — SIGKILL.
Exposed as `mcp__subagent__interrupt`.
Always runs with `--dangerously-skip-permissions --strict-mcp-config` (no
`--mcp-config` override — a safety property, not a knob).
## Checking on a subagent
There's no `status` tool. A subagent's own claude session — not a
parallel log this daemon writes — is the record of what it did; read that
the same way you'd catch up on any other agent, by asking it directly
(`continue` with a prompt). The daemon pushes exactly one todo per
session lifetime: when a turn finishes, its completion summary lands via
`get_loose_ends` like any other producer's todo. `continue` on a name
that's still running is refused (with that as the tell it's still going)
rather than queuing behind it.
## Architecture
`hive-subagent-daemon` (own crate, `hive-subagent-mcp`) is independent of
`hive-bash-daemon` — a subagent spawns a full nested `claude` process, a
materially heavier capability than a bash command, worth its own
deployable/restartable unit. Own systemd unit, own streamable-http
listener on `hyperhive.mcp.subagentHttpPort`.
**No task files.** The daemon's only state is an in-memory map of
currently-running processes (`name -> Cancel`), live only as long as the
process is — a restart stops whatever's running rather than adopting it.
The durable record of a subagent's existence is claude's own on-disk
session, found again by name via `hive_claude::SessionStore`; that's what
`continue` reattaches to, restart or not.
**No mid-turn compaction.** Built on `hive_claude::Claude::spawn` +
`RunningClaude::wait` directly, not `InfiniteSession::run` — the latter
has no cancel handle to reach in from the outside, which is what would
make `interrupt` a no-op. The trade: a turn that overflows the context
window surfaces as a plain error instead of self-healing via reactive
compaction. Subagents are meant to be bounded, single-batch work (see the
`base:claude-subagents` skill), not sessions long-lived enough to need
in-place compaction — a real follow-up if that assumption stops holding.
Own systemd unit, defined alongside the other per-agent MCP daemons in
`nix/agent-modules/mcp.nix`.