SubagentStop still doesn't fire for subagents launched via the Agent tool (async/background) — reopening after #27755 / #33049 / #25147 went stale-closed

Status Open
Reported on v2.1.220
Maintainer reply None cached
Activity 0 comments · opened Jul 29, 2026

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

  1. Register a plugin with two hooks in hooks.json: a PreToolUse (matcher Bash) hook, and a SubagentStop hook. Point both at scripts resolved via "${CLAUDE_PLUGIN_ROOT:-<fallback>}"/hooks/<script>.sh.
  2. In the SubagentStop script, 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.
  3. From a running session, launch a subagent via the Agent tool (async/background — returns an agentId, notified later).
  4. Have the subagent read/do something that should trigger the hook's logic, then let it finish normally.
  5. Check whether the marker from step 2 was created anywhere.

Actual Behavior

  • The subagent completes normally and the caller receives the task-notification.
  • The SubagentStop hook script's marker is never created anywhere — meaning the script was not invoked at all (not "invoked but exited early").
  • The sibling PreToolUse:Bash hook from the same hooks.json fires 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:

  1. Confirmed the plugin appears in /plugin list and all its slash commands are registered.
  2. Triggered the sibling PreToolUse:Bash hook (same hooks.json, same plugin) with a harmless git add -A — it fired correctly with its exact expected stderr message and blocked the command as designed.
  3. Temporarily added one debug line to the PreToolUse hook 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.
  4. Only SubagentStop — invoked via the async Agent tool subagent path specifically — never fires. Same plugin, same hooks.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=1 workaround 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:

  1. Make SubagentStop fire reliably for async/background Agent-tool subagent completions, matching its documented behavior, or
  2. 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 that SubagentStop does not cover this case.

Environment

  • Claude Code version: 2.1.220
  • OS: Linux (Ubuntu, kernel 6.8.0)
  • Hooks used: SubagentStop, PreToolUse (shell scripts)

View original on GitHub ↗