PreToolUse hook payload carries no caller identity, so per-actor guardrails cannot be written
Environment
- Claude Code 2.1.222
- macOS 26.5.2, Node v26.5.0
- Project with
.claude/agents/*.mdsubagents and.claude/settings.jsonhooks
What I was trying to do
Enforce a project rule mechanically instead of by prose: the main agent must not edit source files; it delegates that to a subagent role. The natural implementation is a PreToolUse hook on Edit|Write|NotebookEdit that denies when the caller is the main agent and allows when the caller is a subagent.
What happens
The hook input JSON has no field identifying which agent issued the tool call. Logging the payload keys of every Edit/Write gives exactly:
{"tool":"Write","session":"2e28371b-5034-4ea1-9aec-9d0ad169afef","path":"/…/.claude/settings.json","keys":["session_id","tool_input","tool_name"]}
session_id, tool_input, tool_name — nothing about the actor. A path-based deny therefore blocks the subagents too, which are exactly the actors that are supposed to be allowed to edit those paths. The guardrail cannot be written at all.
Reproduce
- Add to
.claude/settings.json:
{
"hooks": {
"PreToolUse": [
{
"matcher": "Edit|Write|NotebookEdit",
"hooks": [
{
"type": "command",
"command": "jq -c '{tool: .tool_name, session: .session_id, keys: keys}' >> /tmp/payload.jsonl"
}
]
}
]
}
}
- Have the main agent edit a file, then have a subagent edit a file.
cat /tmp/payload.jsonl— no field distinguishes the two.
Expected
Something in the payload that identifies the caller — e.g. agent_type ("main" / the subagent's name), or a documented guarantee that a subagent's session_id differs from the main session's so the hook can compare against a known value.
Impact
This is the central use case for hooks in a multi-agent setup: different actors have different privileges, and prose in a charter is not enforcement. Without caller identity, every hook must treat all actors as one, so a project can only write rules that apply to everyone or to no one.
Honest limitation of my evidence
I only captured payloads from main-agent edits. I did not confirm whether subagent tool calls fire PreToolUse hooks at all, or what session_id they carry if they do. If subagent calls simply do not fire hooks, that is itself worth documenting, because it changes what a hook can be relied on to cover.
This issue has 1 comment on GitHub. Read the full discussion on GitHub ↗