PreToolUse hook on Agent tool fires but does not block execution

Resolved 💬 3 comments Opened Apr 10, 2026 by JaekyunIm Closed Apr 13, 2026

Summary

PreToolUse hook with matcher: "Agent" fires correctly (stdin payload received, script executes, exit code 1 returned) but does not actually block the Agent tool from executing. The Explore subagent proceeds regardless of the deny signal.

Environment

  • Claude Code CLI (macOS, Darwin 25.4.0)
  • Model: claude-sonnet-4-6
  • Permission mode: plan

Setup

.claude/settings.json:

{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Agent",
        "hooks": [
          {
            "type": "command",
            "command": "python3 .claude/block-explore.py"
          }
        ]
      }
    ]
  }
}

block-explore.py:

import json, sys

payload = json.loads(sys.stdin.read())
desc = payload.get('tool_input', {}).get('description', '').lower()

if 'explore' in desc:
    print('BLOCKED: Use pre-built context files instead of Explore agent.')
    sys.exit(1)  # Should deny the tool

What happens

  1. Hook script runs ✅ (confirmed via debug log — full payload received)
  2. Script detects keyword in description ✅
  3. Script prints deny message and exits with code 1 ✅
  4. Agent/Explore tool executes anyway

Debug log (actual payload received by hook)

{
  "session_id": "...",
  "tool_name": "Agent",
  "tool_input": {
    "description": "Explore some service methods",
    "prompt": "Search for patterns in the codebase...",
    "subagent_type": "Explore"
  },
  "hook_event_name": "PreToolUse"
}

Expected behavior

Exit code 1 from a PreToolUse hook should deny/block the Agent tool call, same as it does for Bash, Edit, and other tools.

Use case

We maintain pre-built context maps (wiki + knowledge graph notes) for each project. We want to enforce a lookup-first strategy via hooks — read pre-built context before allowing broad file exploration. Without the ability to block the Agent tool via hooks, Claude defaults to Explore agents (~50K tokens) instead of targeted reads from pre-built context (~4K tokens).

Workarounds attempted

  • CLAUDE.md instructions — ignored for complex planning tasks
  • hookify plugin action: block on prompt event — does not intercept Agent tool
  • PreToolUse hook with exit code 1 — fires but doesn't block (this issue)

🤖 Generated with Claude Code

View original on GitHub ↗

This issue has 3 comments on GitHub. Read the full discussion on GitHub ↗