Subagent (Agent tool) does not fire Stop hook on completion
Status Fixed / completed
Maintainer reply None cached
Workaround ✓ Mentioned in thread ↓
Activity 5 comments · opened Mar 11, 2026 · closed Mar 11, 2026
Description
When a subagent spawned via the Agent tool (or TeammateTool) completes and returns results to the parent agent, no Stop hook is fired. Other lifecycle hooks (UserPromptSubmit, PreToolUse, PostToolUse) fire correctly for the subagent with its own session_id, but the completion event is missing.
Steps to reproduce
- Configure a Stop hook in
.claude/settings.jsonthat logssession_id - Spawn a subagent via the Agent tool (e.g.,
subagent_type: "Explore") - Wait for the subagent to complete and return results to the parent
- Observe that the Stop hook fires for the parent session but never fires for the subagent session
Expected behavior
When a subagent completes (returns results to parent), a Stop hook should fire with the subagent's session_id, allowing external tools to detect session lifecycle completion.
Actual behavior
- Subagent fires
UserPromptSubmitandPreToolUsehooks → external tools register a new session - Subagent completes → no Stop hook → external tools see a "ghost session" that never ends
- Ghost sessions accumulate over time
Impact
Hook-based external tools (session monitors, sidebars, etc.) cannot distinguish between:
- A subagent that is still running
- A subagent that has completed
This leads to ghost sessions accumulating in any tool that tracks sessions via hooks.
Environment
- Claude Code version: 2.1.x (latest)
- OS: macOS (Darwin)
- Hooks used: Stop (shell script)
Related issues
- #7881 — SubagentStop
session_idsharing (different: about ID collision, not missing events) - #19045 — Orphaned processes after parent ends (different: about process cleanup, not hook lifecycle)
- #29881 — Stop hook not fired on silent tool stop (related but about mid-turn stalls, not subagent completion)
5 Comments
Found 2 possible duplicate issues:
This issue will be automatically closed as a duplicate in 3 days.
🤖 Generated with Claude Code
This is a real pain point — our cc-reaper Stop hook relies on exactly this lifecycle event, and the fact that subagents don't fire it means Layer 1 cleanup only covers the parent session.
Our workaround: PGID-based process group cleanup. Since Claude Code sessions are process group leaders, the parent session's Stop hook can
kill -- -$PGIDto clean up the entire process tree — including subagent children that never fired their own Stop hook. This sidesteps the missing subagent Stop event entirely.For crash scenarios where no Stop hook fires at all, we fall back to a background daemon (proc-janitor) that scans every 30s for orphaned process groups.
Would love to see this fixed upstream though — proper subagent lifecycle hooks would make community tooling much more reliable.
Closing as duplicate of #27755 and #25147, which cover this problem more comprehensively.
Our specific observation (foreground Agent tool / TeammateTool subagents also don't fire Stop hooks on completion — not just
run_in_backgroundagents) is a subset of the same root cause described in #27755.Thanks to the authors of those issues for the detailed analysis and workaround documentation.
Closing as duplicate of #27755 and #25147, which cover this problem more comprehensively.
Our specific observation (foreground Agent tool / TeammateTool subagents also don't fire Stop hooks on completion — not just
run_in_backgroundagents) is a subset of the same root cause described in #27755.Thanks to the authors of those issues for the detailed analysis and workaround documentation.
This issue has been automatically locked since it was closed and has not had any activity for 7 days. If you're experiencing a similar issue, please file a new issue and reference this one if it's relevant.