PreToolUse hook deny not enforced for Agent tool calls
Status Closed — not planned
Maintainer reply None cached
Activity 4 comments · opened Apr 7, 2026 · closed May 19, 2026
Summary
PreToolUse hooks returning permissionDecision: "deny" are not enforced for Agent tool calls. The deny JSON is correctly output by the hook, but Claude proceeds to spawn the agent anyway.
Reproduction
- Configure a PreToolUse hook that denies Agent calls with a specific
subagent_type:
# In PreToolUse hook
def guard_agent(data):
ti = data.get("tool_input", {})
subtype = ti.get("subagent_type", "")
if subtype == "Explore":
print(json.dumps({
"hookSpecificOutput": {
"hookEventName": "PreToolUse",
"permissionDecision": "deny",
"permissionDecisionReason": "Explore agents blocked by policy"
}
}))
sys.exit(0)
- Running the hook standalone confirms correct output:
echo '{"tool": "Agent", "tool_input": {"subagent_type": "Explore", "prompt": "test", "run_in_background": true}}' \
| python3 hook.py
# Output: {"hookSpecificOutput": {"hookEventName": "PreToolUse", "permissionDecision": "deny", ...}}
# Exit: 0
- Despite the hook returning deny, Claude spawns the Explore agent and it runs to completion.
Expected behavior
The Agent tool call should be blocked, same as deny works for Bash, Read, Write, Edit, etc.
Observed behavior
- Without
run_in_background: hook deny seems ignored, user gets a permission prompt (can manually reject) - With
run_in_background: true: agent launches and completes with no interception
Environment
- Claude Code v2.1.92
- Linux (Fly.io)
Additional context
The permissions.deny field in settings.json also doesn't support Agent subagent type filtering (e.g., "Agent(Explore)" has no effect).
This issue has 4 comments on GitHub. Read the full discussion on GitHub ↗