SubagentStop hook cannot identify which specific subagent finished due to shared session IDs

Status Fixed / completed
Maintainer reply None cached
Activity 11 comments · opened Sep 19, 2025 · closed Aug 17, 2026

Environment

  • Platform (select one):
  • [X] Anthropic API
  • [ ] AWS Bedrock
  • [ ] Google Vertex AI
  • Claude CLI version: 1.0.119 (Claude Code)
  • Operating System: Ubuntu 24 running under WSL2 / Windows 11
  • Terminal: All

Problem Description

When multiple subagents (Task tool invocations) run within the same Claude Code session, they all share the same session_id. This makes it impossible for the SubagentStop hook to determine which specific subagent has just completed, as the hook only receives the session ID without any subagent-specific identifier.

This limitation prevents proper tracking of individual subagent lifecycle, metrics collection per agent type, and coordination between multiple specialized agents.

Current Behavior

Multiple subagents invoked in the same conversation all use the same session ID:

Example 1 - Task tool invocation for frontend-developer:

{
  "hook_event_name": "PreToolUse",
  "tool_name": "Task",
  "session_id": "cb67a406-fd98-47ca-9b03-fcca9cc43e8d",
  "tool_input": {
    "description": "Create HTML structure",
    "subagent_type": "frontend-developer",
    "prompt": "Create a simple, well-structured HTML webpage..."
  }
}

Example 2 - Task tool invocation for ui-designer (same session):

{
  "hook_event_name": "PreToolUse", 
  "tool_name": "Task",
  "session_id": "cb67a406-fd98-47ca-9b03-fcca9cc43e8d",  // Same session ID!
  "tool_input": {
    "description": "Style the webpage",
    "subagent_type": "ui-designer",
    "prompt": "Create a modern, responsive CSS stylesheet..."
  }
}

Example 3 - SubagentStop event (which agent stopped?):

{
  "hook_event_name": "SubagentStop",
  "session_id": "cb67a406-fd98-47ca-9b03-fcca9cc43e8d",  // No way to know if this is frontend-developer or ui-designer!
  "transcript_path": "/home/andrei/.claude/projects/.../cb67a406-fd98-47ca-9b03-fcca9cc43e8d.jsonl",
  "stop_hook_active": false
}

Impact

  1. Cannot track individual subagent performance - No way to measure execution time per agent type
  2. Cannot maintain agent-specific state - Session-based mapping gets overwritten with each new subagent
  3. Cannot implement agent-specific cleanup - SubagentStop hook doesn't know which agent's resources to clean up
  4. Breaks monitoring/observability - Can't send accurate metrics about which agents are being used

Proposed Solutions

Option 1: Add subagent_id + subagent_type

Include a unique subagent_id and subagent_type in subagent events:

// PreToolUse for Task
{
  "session_id": "cb67a406-fd98-47ca-9b03-fcca9cc43e8d",
  "subagent_id": "cb67a406-task-001",  // New unique ID for this subagent
  "tool_name": "Task",
  "tool_input": {
    "subagent_type": "frontend-developer"
  }
}

// SubagentStop
{
  "session_id": "cb67a406-fd98-47ca-9b03-fcca9cc43e8d",
  "subagent_id": "cb67a406-task-001",  // Can identify which specific subagent stopped
  "subagent_type": "frontend-developer"  // Also include type for convenience
}
Option 2: Use subagent_session + subagent_type (Recommended)

Create unique session IDs for each subagent, which would naturally propagate to all tool calls made by that subagent:

// PreToolUse for Task
{
  "session_id": "cb67a406-fd98-47ca-9b03-fcca9cc43e8d",           // Parent session
  "subagent_session": "cb67a406-fd98-47ca-9b03-fcca9cc43e8d-task-001", // Unique subagent session
  "tool_name": "Task",
  "tool_input": {
    "subagent_type": "frontend-developer"
  }
}

// SubagentStop
{
  "session_id": "cb67a406-fd98-47ca-9b03-fcca9cc43e8d",           // Parent session
  "subagent_session": "cb67a406-fd98-47ca-9b03-fcca9cc43e8d-task-001", // Identifies which subagent stopped
  "subagent_type": "frontend-developer"  // Also include type for convenience
}

// All subsequent tool calls from this subagent would also include:
{
  "session_id": "cb67a406-fd98-47ca-9b03-fcca9cc43e8d",           // Parent session
  "subagent_session": "cb67a406-fd98-47ca-9b03-fcca9cc43e8d-task-001", // Same subagent session
  "tool_name": "edit_files",  // Any tool the subagent uses
  // ... other tool data
}

Why Option 2 is recommended:

  1. Automatic propagation - All tool calls from the subagent inherit the subagent_session ID
  2. Complete traceability - Can track all actions performed by a specific subagent instance
  3. Simpler implementation - Leverages existing session ID infrastructure
  4. Better observability - Each subagent gets its own "session" for logging and monitoring
  5. Natural grouping - All events from one subagent execution are automatically grouped

"parent_session_id": "cb67a406-fd98-47ca-9b03-fcca9cc43e8d"
}


### Use Case

We're building a monitoring system that tracks which specialized agents are used most frequently, their success rates, and execution times. Without being able to identify which specific subagent has stopped, we can only track that "some subagent" finished, losing critical observability data.

### Current Workaround

We maintain a session-to-agent mapping file, but this breaks when multiple subagents share a session:
1. frontend-developer starts → map[session] = "frontend-developer"
2. ui-designer starts → map[session] = "ui-designer" (overwrites!)
3. SubagentStop fires → we incorrectly think ui-designer stopped (could be frontend-developer)

### Environment
- Claude Code version: Latest
- OS: Ubuntu Linux
- Hook implementation: Python

### Priority
This is a significant limitation for anyone trying to build proper observability around multi-agent workflows in Claude Code.

---

Would implementing **Option 2** (`subagent_session` + `subagent_type`) be feasible? This approach would be easier to implement since it leverages existing session infrastructure, and provides superior traceability by ensuring all tool calls from a subagent share the same `subagent_session` identifier. This would enable complete end-to-end tracking of subagent behavior while maintaining backward compatibility.

View original on GitHub ↗

9 Comments

github-actions[bot] · 11 months ago

Found 1 possible duplicate issue:

  1. https://github.com/anthropics/claude-code/issues/6024

This issue will be automatically closed as a duplicate in 3 days.

  • If your issue is a duplicate, please close it and 👍 the existing issue instead
  • To prevent auto-closure, add a comment or 👎 this comment

🤖 Generated with Claude Code

coygeek · 11 months ago

This is a fantastic and incredibly well-documented issue. Thanks for putting this together.

I can confirm I've run into this exact limitation. The current SubagentStop hook is indeed ambiguous when you have multiple subagents in flight. I just checked the latest documentation on hooks and subagents, and there's no mention of a subagent-specific ID in the payload, just the parent session_id, which confirms your findings.

Your analysis of the two potential solutions is spot on. I strongly agree that Option 2 (subagent_session) is the superior approach. It's not just about knowing which agent stopped; it's about being able to trace the entire lifecycle of that subagent's execution, including any subsequent tool calls it makes. Having a unique session ID for the subagent that propagates through its tool calls would be a game-changer for proper logging, metrics, and state management.

I tried a similar workaround to yours with a session-to-agent mapping, and as you pointed out, it falls apart the moment a second agent starts. It's just not reliable for any kind of parallel or sequential agent execution.

This feels like a crucial feature for building any kind of robust, observable multi-agent system on top of Claude Code.

+1 from me on this feature request. Hopefully, the maintainers can consider adding a subagent_session or a similar unique identifier to the hook payloads. It would unlock a lot of advanced use cases.

github-actions[bot] · 8 months ago

This issue has been inactive for 30 days. If the issue is still occurring, please comment to let us know. Otherwise, this issue will be automatically closed in 30 days for housekeeping purposes.

aaiordac · 8 months ago

Still interested in the resolution ...

acreeger · 8 months ago

Heads up that the SubagentStop hook now includes agent_id. So...

  1. Parse the transcript_path JSONL file
  2. Look for tool_use entries where toolUseResult.agentId matches the agent_id from hookData
  3. Grab the tool_use_id from that tool_result's message content
  4. Find the Task tool_use entry with that same id
  5. Extract input.subagent_type from there
kitaekatt · 7 months ago

I agree it looks like the original issue has been addressed by the inclusion of agent_id for SessionStop specifically.

However #14859 shows that this is insufficient for hooks to distinguish between subagents and agents.

Heads up that the SubagentStop hook now includes agent_id. So... 1. Parse the transcript_path JSONL file 2. Look for tool_use entries where toolUseResult.agentId matches the agent_id from hookData 3. Grab the tool_use_id from that tool_result's message content 4. Find the Task tool_use entry with that same id 5. Extract input.subagent_type from there
anthony-spruyt · 7 months ago

+1 for this feature.

My use case: building hookify-extended plugin with rate-limited warnings (warn_once, warn_interval).
Without subagent_id/subagent_session, warnings are conversation-scoped instead of agent-scoped.

Evidence that Claude Code already tracks this internally - Task tool response includes agentId:

{                                                                                                                                                                                                                                                                                                                                                                                                                  
    "tool_response": {                                                                                                                                                                                                                                                                                                                                                                                               
      "agentId": "a886b27",                                                                                                                                                                                                                                                                                                                                                                                          
      ...                                                                                                                                                                                                                                                                                                                                                                                                            
    }                                                                                                                                                                                                                                                                                                                                                                                                                
  }
johns10 · 5 months ago

+1

NyaMisty · 5 months ago

Still no solution??

Showing cached comments. Read the full discussion on GitHub ↗