`start` takes an optional `goal`. With one set a session stops being a single turn: when a turn ends and nothing has said to stop, the daemon spawns another turn re-prompting the subagent toward that goal, up to `max_turns` (default 5, per-session). Without a goal nothing changes — one turn, one todo, same as before. Four things end a run, each recorded distinctly and reported by `status`: the turn ending with no goal, `goal_reached`, `need_help`, and the turn cap. The last says so out loud rather than stopping quietly — the todo states the harness limit was reached and the goal was never reported reached. Every stop extends the done message rather than replacing it, and lands in the session's report file when it has one. The path is never inferred: it comes from `start`'s `report_file` or from the subagent naming where it wrote. `goal_reached` and `need_help` are the subagent's own, served on a second route (`/signal/mcp`) that carries those two tools and nothing else, so reporting on a run can't become starting one. `goal_reached` is built as a label, never a gate: it is self-reported by a subagent that has just been re-prompted with "you haven't reached the goal", which is exactly the incentive to claim it — the same failure class as a build report asserting the tests pass. Every surface that renders it says so. `need_help` is the blocking signal, and shows in `status` as its own state so a parent polling it sees the block without reading a file. `status` also carries `turn N of M`: with 4330's last-event age, that separates working from wedged from out of turns off one answer. Two bugs the new tests caught: a `tokio::fs::File` was dropped without flushing, so the report line was written to nothing, and the plain idle answer dropped the turn counter. Also documents `await_resume`'s third case — a closed channel with no send, which fails open the same as `Underway` — per argus on #4411. Refs #4403
30 lines
1.4 KiB
Markdown
30 lines
1.4 KiB
Markdown
# hive-subagent-mcp
|
|
|
|
Per-agent daemon (`hive-subagent-daemon`) that spawns nested headless
|
|
`claude` sessions on request and serves the tool surface
|
|
(`start`/`continue`/`status`/`interrupt`, plus a separate
|
|
subagent-facing `goal_reached`/`need_help` route) directly over
|
|
streamable-http. No stdio bridge, no per-turn respawn — claude
|
|
reconnects to the same stable URL every turn.
|
|
|
|
Independent of `hive-bash-mcp` — a subagent spawns a full nested
|
|
`claude` session, a much heavier capability than a bash command, worth
|
|
its own deployable/restartable unit.
|
|
|
|
## Shape
|
|
|
|
One bin (`hive-subagent-daemon`, `src/main.rs`) built from the crate's
|
|
own lib (`src/lib.rs`):
|
|
|
|
- **`session.rs`** — the actual claude-facing logic: `Claude::spawn` +
|
|
`RunningClaude::wait`/`cancel_handle` (not `InfiniteSession::run`,
|
|
which has no cancel handle to reach in — see the module doc for the
|
|
v1 scope this trades away), the turn-continuation loop a `goal`
|
|
switches on, and the in-memory maps that are the _only_ state this
|
|
daemon keeps (no task files — a restart stops whatever's running;
|
|
the actual claude session is the durable store, found again by name
|
|
via `hive_claude::SessionStore`).
|
|
- **`mcp.rs`** — the `rmcp` tool routers (the parent's
|
|
`start`/`continue`/`status`/`interrupt` on `/mcp`, the subagent's
|
|
`goal_reached`/`need_help` on `/signal/mcp`) + `serve_http`.
|
|
- **`paths.rs`** — the in-agent todo-socket path.
|