Watch
0
0
Fork
You've already forked hyperhive
0

claude runtime: interrupting a session kills every process it started

hive-claude 0.1.3 spawns claude as the leader of its own process group,
and its `Cancel::cancel` and idle watchdog signal that group instead of
claude's pid alone. Commands claude started (a `nix build`, a test run)
used to survive a subagent `interrupt` and keep running.

Bump hive-claude to 0.1.3. The subagent `interrupt` call site needs no
code change: `Cancel::cancel(force)` kept its signature.

The harness's `/cancel` and `/logout` did not go through hive-claude:
they ran `kill -INT <pid>` on the claude child they found in /proc. They
now SIGINT the group that child leads, through `libc::kill`. A `claude`
child that leads no group (the `claude plugin` calls) shares the
harness's group and is still signalled alone.

Tests: an interrupted subagent's grandchild dies, for both SIGINT and
`force`, and fails on hive-claude 0.1.2; a harness cancel stops a
turn's grandchild, and fails when only the pid is signalled.
This commit is contained in:
atlas 2026-10-10 13:44:10 +02:00 • committed by mara
commit 028c283ff9
8 changed files with 244 additions and 24 deletions

View file

@ -166,6 +166,11 @@ from how the child exited. `continue` clears it and hands the session a
fresh turn allowance, which is what makes an interrupt a pause you can
undo rather than a session you have to abandon.
On `claude`, the signal goes to claude's whole process group, so the
commands the subagent started (a `nix build`, a test run) get it too. The
signal doesn't reach a command that moved itself out of the group
(`setsid`).
When the session knows where its report goes — `start`'s `report_file`,
or the path the subagent names when it signals — the daemon appends the
stop reason to that file as well, so the artifact you were going to read