Repository navigation
orchestrate: kill-tree skips running agents under handed-off subplanner branches, diverging from crawl and from its own help text #641
Description
What happens
The crawl and kill-tree commands walk the same orchestrate tree with two parallel implementations in scripts/cli/util.ts, and they disagree on which subplanner branches to descend into:
-
crawlBranch(used bycrawl) recurses into a subplanner branch when its status isrunningorhanded-off:orchestrate/skills/orchestrate/scripts/cli/util.ts:100-110if ( t.type === "subplanner" && (t.status === "running" || t.status === "handed-off") ) { crawlBranch(...); }
-
collectRunningAgentsInTree(used bykill-tree/filterVictimsToSubtree) only recurses when the status isrunning:orchestrate/skills/orchestrate/scripts/cli/util.ts:174if (t.type === "subplanner" && t.status === "running") { collectRunningAgentsInTree(...); }
The two claims that they agree:
cli/util.ts:123— doc comment oncollectRunningAgentsInTree: "Walk the tree the same waycrawldoes and collect everyrunningtask's (agentId, runId)"cli/forensics.ts:84—kill-treehelp text: "Cancel every running cloud agent across an orchestrate tree. Walks state.json likecrawl, collectsrunning(agentId, runId) pairs, and cancels each via the SDK."
Walkthrough
Consider a tree where a subplanner's own cloud run has ended (its row in the parent's state.json is handed-off), but the state.json committed on the subplanner's branch (orch/<slug>/<name>) still contains rows with status: "running" and non-null agentId/runId — e.g. a verifier/respawn it kicked off before returning, or workers it spawned that were still in flight when its run stopped:
bun cli.ts crawl <repo> <root-branch> <root-slug>descends intoorch/<slug>/<name>(thehanded-offcase matches) and lists those running agents.bun cli.ts kill-tree <repo> <root-branch> <root-slug> -ycallscollectRunningAgentsInTree, which does not descend intohanded-offsubplanner branches, so those(agentId, runId)pairs are never collected.- If those are the only running agents in the tree,
kill-treeprints:
nothing to kill — no running agents found in the tree.
and exits without cancelling anything — whilecrawlon the same tree displays running agents one command earlier.
--agent-id <id> scoping is affected the same way: filterVictimsToSubtree only walks parent links among already-collected victims, so a victim in a handed-off subplanner branch is unreachable even when its parentAgentId chain points at the given root.
Expected vs actual
- Expected (per both doc comments and the
kill-treehelp text): kill-tree sees and cancels every running cloud agent thatcrawlshows. - Actual: running agents under a
handed-offsubplanner branch are invisible tokill-tree; orphaned cloud agents keep running (and keep consuming quota) after the operator used the command whose purpose is to stop them.
Evidence summary
- Divergent recursion condition:
cli/util.ts:105vscli/util.ts:174. - Parity claims contradicted by code:
cli/util.ts:123,cli/forensics.ts:84. collectRunningAgentsInTree/filterVictimsToSubtreehave no tests (no references underscripts/__tests__/).
Suggested fix
Make collectRunningAgentsInTree recurse on t.status === "running" || t.status === "handed-off" to match crawlBranch, or (if skipping handed-off is intentional for some reason) update both doc comments and the kill-tree help text to say which agents it can miss. A regression test mirroring a handed-off subplanner branch containing a running worker would pin this down.
Activity
deanrie commentedon Oct 16, 2026
Hey @rahul05ranjan, confirmed on
main, both snippets are as you quote them and the help text does promise parity. Fix is up as #647:crawlBranchandcollectRunningAgentsInTreenow share onedescendsIntoSubplannerpredicate (runningorhanded-offsubplanner), sokill-treefollows the same branchescrawldoes and cannot drift again; a test builds a two-branch repo with a handed-off subplanner and a running worker under it and checks both walkers see the worker (it fails onmain, 0 collected). Whether skipping handed-off branches was ever intentional is the orchestrate owners' call, and the PR says so; if it was, the helper is the single place to encode it and the help text should change with it.