SubagentStop still doesn't fire for subagents launched via the Agent tool (async/background) — reopening after #27755 / #33049 / #25147 went stale-closed
Title
SubagentStop still doesn't fire for subagents launched via the Agent tool (async/background) — reopening after #27755 / #33049 / #25147 went stale-closed
Preflight Checklist
- [x] I searched existing issues — this is a re-report: #27755, #33049, #25147 all describe the same core problem, but all three were closed by the stale-bot for inactivity (not because they were fixed) and are now locked, so I can't comment on them directly.
- [x] Single bug report
- [x] Using latest version of Claude Code (2.1.220)
What's Wrong?
A SubagentStop hook registered via a plugin's hooks.json never fires when the subagent is launched via the Agent tool in its async/background form — i.e. the call returns immediately with an agentId, and the caller is notified later via a task-notification when the subagent finishes. Meanwhile, other hooks registered in the same hooks.json (e.g. PreToolUse with matcher Bash) fire correctly and reliably for the very same session.
This isn't a plugin misconfiguration or a ${CLAUDE_PLUGIN_ROOT} resolution problem — I verified both directly (see Evidence).
Steps to Reproduce
- Register a plugin with two hooks in
hooks.json: aPreToolUse(matcherBash) hook, and aSubagentStophook. Point both at scripts resolved via"${CLAUDE_PLUGIN_ROOT:-<fallback>}"/hooks/<script>.sh. - In the
SubagentStopscript, unconditionally write/create some observable state (e.g.mkdir -p $TMPDIR/some-marker-dir) before doing any pass/fail logic, so you can prove the script was invoked at all, independent of what it decides. - From a running session, launch a subagent via the
Agenttool (async/background — returns anagentId, notified later). - Have the subagent read/do something that should trigger the hook's logic, then let it finish normally.
- Check whether the marker from step 2 was created anywhere.
Actual Behavior
- The subagent completes normally and the caller receives the
task-notification. - The
SubagentStophook script's marker is never created anywhere — meaning the script was not invoked at all (not "invoked but exited early"). - The sibling
PreToolUse:Bashhook from the samehooks.jsonfires reliably and correctly for regular tool calls in the same session.
Expected Behavior
SubagentStop should fire when a subagent launched via the Agent tool (in its async/background execution mode) completes, the same way it's documented to fire for subagent completion generally.
Evidence Ruling Out Config/Env Causes
To rule out "the plugin/path just isn't wired up," I:
- Confirmed the plugin appears in
/plugin listand all its slash commands are registered. - Triggered the sibling
PreToolUse:Bashhook (samehooks.json, same plugin) with a harmlessgit add -A— it fired correctly with its exact expected stderr message and blocked the command as designed. - Temporarily added one debug line to the
PreToolUsehook script logging${CLAUDE_PLUGIN_ROOT:-}(empty-string default, not the script's own fallback) to a scratch file, re-triggered it, and confirmed the env var is genuinely populated with the correct real plugin path at hook-invocation time — then reverted the debug line. - Only
SubagentStop— invoked via the asyncAgenttool subagent path specifically — never fires. Same plugin, samehooks.json, same session.
This matches the root cause already documented across #27755, #33049, and #25147: hook lifecycle events for subagent completion are unreliable/non-firing specifically for the Agent/Task tool's async execution path, while other hook types on the same session work fine.
Related Issues (all closed by stale-bot, not by a fix, and now locked)
- #27755 — "SubagentStart/SubagentStop unreliable for settings.json hooks — cascade failures break agent lifecycle management" (includes a
DEBUG_CLAUDE_AGENT_SDK=1workaround report for containerized deployments — worth checking whether that's relevant here too) - #33049 — "Subagent (Agent tool) does not fire Stop hook on completion" (closed as duplicate of #27755/#25147)
- #25147 — "Background agents bypass Stop hooks"
Suggested Fix
Either:
- Make
SubagentStopfire reliably for async/backgroundAgent-tool subagent completions, matching its documented behavior, or - If that's architecturally not feasible for the async path, add an explicitly named, documented hook event for async-agent completion (e.g. something like
AsyncAgentComplete), and update the hooks reference docs to state plainly thatSubagentStopdoes not cover this case.
Environment
- Claude Code version: 2.1.220
- OS: Linux (Ubuntu, kernel 6.8.0)
- Hooks used:
SubagentStop,PreToolUse(shell scripts)