| Filename | Latest commit message | Latest commit date |
|---|---|---|
`interrupt` killed the child and trusted that to end the run. It didn't: the default signal is SIGINT, and `claude --print` handles SIGINT by writing its terminal `result` event and exiting **zero**. A zero exit is `TurnEnd::Complete`, so `spawn_and_track`'s killed-turn early return — the code that was supposed to stop the run — never fired, and the loop went straight on to spawn the next goal turn. An interrupted run carried on to completion; the interrupt changed nothing about the outcome. Measured, not inferred: `claude --print --verbose --output-format stream-json`, SIGINT'd mid-turn, exits 0 on every run. So record the reason instead of inferring it. `interrupt` writes `StopReason::Cancelled` — the same path `goal_reached`/`need_help` already use — while it still holds the `running` lock, so there is no instant in which the name has lost its cancel handle but not yet gained its stop reason. `plan_after_turn` checks stop reasons ahead of the goal, so the run stops whichever way the child ends up exiting. `force`'s SIGKILL still produces a `TurnEnd::Killed`, and `status` still prefers the kill record it already had. `continue`'s budget reset is untouched: it clears the stop reason and hands back a fresh allowance, which is what makes a cancel a pause an operator can undo. The test spawns the real continuation loop against a fake claude that exits 0 on SIGINT, interrupts it, and asserts turn two never starts — it reports `left: 2` without the fix. |
||
| .. | ||
| src | ||
| Cargo.toml | ||
| README.md | ||
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, one per-session URL)
directly over streamable-http. No stdio bridge, no per-turn respawn — an
agent's 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(notInfiniteSession::run, which has no cancel handle to reach in — see the module doc for the v1 scope this trades away), the turn-continuation loop agoalswitches 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 viahive_claude::SessionStore).mcp.rs— thermcptool routers (the parent'sstart/continue/status/interrupton/mcp, the subagent'sgoal_reached/need_helpon/signal/mcp/<token>) +serve_http. Neither signal tool takes a session name: the token in the path is minted per run and resolved to a session before dispatch, so a subagent has no way to name — and therefore no way to signal — a sibling. One route with a path parameter, because theRouteris built once at startup and sessions come and go for the daemon's whole life.paths.rs— the in-agent todo-socket path.