SubagentStop hook cannot identify which specific subagent finished due to shared session IDs
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
- Cannot track individual subagent performance - No way to measure execution time per agent type
- Cannot maintain agent-specific state - Session-based mapping gets overwritten with each new subagent
- Cannot implement agent-specific cleanup - SubagentStop hook doesn't know which agent's resources to clean up
- 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:
- Automatic propagation - All tool calls from the subagent inherit the
subagent_sessionID - Complete traceability - Can track all actions performed by a specific subagent instance
- Simpler implementation - Leverages existing session ID infrastructure
- Better observability - Each subagent gets its own "session" for logging and monitoring
- 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.Showing cached comments. Read the full discussion on GitHub ↗
9 Comments
Found 1 possible duplicate issue:
This issue will be automatically closed as a duplicate in 3 days.
🤖 Generated with Claude Code
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
SubagentStophook 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 parentsession_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_sessionor a similar unique identifier to the hook payloads. It would unlock a lot of advanced use cases.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.
Still interested in the resolution ...
Heads up that the SubagentStop hook now includes
agent_id. So...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.
+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:+1
Still no solution??