[FEATURE] Add agent identities to tool event payloads
Preflight Checklist
- [x] I have searched existing requests and this feature hasn't been requested yet
- [x] This is a single feature request (not multiple features)
Problem Statement
When Claude Code runs subagents, the PreToolUse and PostToolUse hooks fire for tool calls made inside the subagent but the payload contains no information about which agent invoked the tool. This makes it impossible to write hook logic that is conditional on the calling agent.
Today, SubagentStart and SubagentStop correctly include agent_id and agent_type in their payloads. But the tool-level hooks (PreToolUse, PostToolUse) that fire between those boundaries are anonymous. There is no way to determine at hook-execution time whether the tool call originated from the parent session or from a specific subagent, let alone which subagent.
This is a significant gap for any hook that needs to enforce per-agent policy:
- Security and permission boundaries: a hook cannot block a specific tool for a specific subagent type while allowing it for others. For example, you may want to allow a
web-researchersubagent to useWebSearchfreely but require approval before anycode-writersubagent callsWriteorEdit. Withoutagent_idin the hook payload, a blanket block or blanket allow is the only option. - Audit logging and observability: hooks used for compliance logging cannot attribute tool calls to the agent that made them. Log entries are missing a critical dimension: who (which agent) performed the action.
- Rate limiting and resource control: hooks that enforce budget or rate limits (e.g., max API calls, max files written) cannot maintain per-agent counters. All agents share an undifferentiated pool.
- Conditional tool interception: a hook cannot safely modify or enrich
PreToolUseinputs differently depending on the agent context (e.g., injecting different working directories or prefixes for different subagent roles).
Proposed Solution
Add agent_id and agent_type fields to the PreToolUse, PostToolUse, and PostToolUseFailure hook payloads whenever the tool call originates inside a subagent. When the call originates from the parent (main) session, both fields should be null or omitted.
The proposed payload addition:
{
"hook_event_name": "PreToolUse",
"tool_name": "Write",
"tool_input": { ... },
"tool_use_id": "toolu_abc123",
"agent_id": "a2e586e02eeb9c9a4",
"agent_type": "file-summarizer"
}
agent_id: the same opaque identifier already present in SubagentStart/SubagentStop payloads, so hooks can correlate tool calls to a specific subagent lifecycleagent_type: the subagent'snamefield from its definition (e.g.,"file-summarizer"), enabling policy decisions based on agent role without needing to trackagent_idstate across hook invocations- Both fields should be
null(or absent) when the tool call originates from the parent session, preserving backwards compatibility
No changes to hook registration or the settings.json schema seem necessary.
Alternative Solutions
_No response_
Priority
Medium - Would be very helpful
Feature Category
Developer tools/SDK
Use Case Example
Consider a multi-agent code review pipeline with scoped tool permissions
A team uses Claude Code with two subagents defined in .claude/agents/:
code-analyzer: reads files and produces a review report (should only useRead,Glob,Grep)code-fixer: applies the suggested fixes (usesEdit,Write,Bash)
They want a PreToolUse hook that enforces this separation. They want to block code-analyzer from ever writing files, even if the model decides to try.
Step 1: User runs: "_Analyze the auth module for bugs and fix any you find._"
Step 2: Claude spawns both subagents. code-analyzer starts reading files. Its PreToolUse hooks fire with tool_name: "Read" and the hook sees agent_type: "code-analyzer", allows it through.
Step 3: The model inside code-analyzer attempts to call Write directly (hallucination or prompt drift). The PreToolUse hook fires. With agent_type in the payload, the hook script checks: if agent_type == "code-analyzer" and tool_name in ("Write", "Edit", "Bash"): block. The write is denied before it executes.
Step 4: code-fixer calls Edit. The hook sees agent_type: "code-fixer", allows it.
Without this feature, the hook at Step 3 cannot distinguish whether the Write came from code-analyzer (block it) or code-fixer (allow it). The only option is to block Write for all agents which breaks code-fixer, or allow it for all agents which defeats the security boundary entirely.
Additional Context
_No response_
This issue has 3 comments on GitHub. Read the full discussion on GitHub ↗