[FEATURE] BeforeToolSelection Hook for Dynamic Tool Filtering

Resolved 💬 3 comments Opened Jan 28, 2026 by coygeek Closed Feb 28, 2026

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

Claude Code currently allows hooks to validate and block tool calls after the model has already selected a tool (PreToolUse). However, there's no way to proactively filter which tools are available before the model makes its selection.

This creates several problems:

  1. Wasted inference: The model may select a tool that will be blocked, requiring a retry and consuming additional tokens
  2. No context-aware tool restriction: Cannot dynamically limit tools based on the current task, user prompt, or environment
  3. Inefficient security policies: Blocking tools after selection is reactive rather than preventive
  4. No "read-only mode": Cannot easily restrict Claude to observation-only tools (Read, Glob, Grep) without write tools (Edit, Write, Bash)

Proposed Solution

Add a new hook event: BeforeToolSelection

Hook Behavior

Fires before the LLM request is sent, specifically to allow filtering the available tools. Receives:

{
  "session_id": "abc123",
  "hook_event_name": "BeforeToolSelection",
  "prompt": "Current user prompt...",
  "available_tools": ["Bash", "Read", "Write", "Edit", "Glob", "Grep", "WebFetch", "WebSearch", "Task"],
  "llm_request": {
    "messages": [...],
    "config": {...}
  }
}

Output options:

{
  "hookSpecificOutput": {
    "hookEventName": "BeforeToolSelection",
    "mode": "ANY",
    "allowedToolNames": ["Read", "Glob", "Grep"]
  }
}

Mode Options

| Mode | Behavior |
|------|----------|
| AUTO | Model chooses from all available tools (default) |
| ANY | Model can only use tools in allowedToolNames |
| NONE | Disable all tools for this turn (text-only response) |

Union Aggregation

When multiple hooks return tool filters, use union aggregation:

  • Multiple allowedToolNames lists are intersected (only tools in ALL lists are allowed)
  • Any hook returning mode: "NONE" overrides all others and disables tools entirely

Configuration Example

{
  "hooks": {
    "BeforeToolSelection": [
      {
        "hooks": [
          {
            "type": "command",
            "command": "/path/to/tool-filter.py"
          }
        ]
      }
    ]
  }
}

Alternative Solutions

  1. PreToolUse blocking: Currently you can block tools in PreToolUse, but this happens after selection—wasting inference and requiring the model to retry.
  1. Permission modes: Claude Code's permission modes (plan, acceptEdits, etc.) provide some tool restriction, but these are user-facing modes, not programmatic hooks.
  1. CLAUDE.md instructions: You can instruct Claude not to use certain tools, but this is non-deterministic and the model may still attempt to use them.
  1. MCP server filtering: For MCP tools, you could disable servers, but this doesn't help with built-in tools.

Priority

High - Significant impact on productivity

This enables efficient, context-aware tool restriction without wasting inference on blocked tools.

Feature Category

Configuration and settings

Use Case Example

Scenario: Read-only exploration mode

  1. User wants Claude to analyze a codebase without making any changes
  2. BeforeToolSelection hook restricts tools to ["Read", "Glob", "Grep", "WebFetch", "WebSearch"]
  3. Claude can explore freely but cannot accidentally modify files
  4. No wasted inference on Write/Edit/Bash attempts that would be blocked

Scenario: RAG-based tool filtering

  1. Hook analyzes the user prompt using a fast local LLM or keyword matching
  2. For documentation questions: allow ["Read", "Glob", "Grep", "WebSearch"]
  3. For code changes: allow ["Read", "Edit", "Write", "Bash"]
  4. For web research: allow ["WebFetch", "WebSearch"]
  5. Model receives only relevant tools, improving focus and reducing errors

Scenario: Environment-based restrictions

  1. CI/CD environment detected via environment variable
  2. Hook automatically restricts to ["Read", "Glob", "Grep", "Bash"] (no file writes)
  3. Prevents accidental modifications during automated testing

Scenario: Sensitive directory protection

  1. User is working in a directory containing production configs
  2. Hook detects this and sets mode: "NONE" or restricts to read-only tools
  3. Provides an extra layer of protection beyond PreToolUse blocking

Additional Context

Prior Art

Gemini CLI implements BeforeToolSelection:

"Use allowedFunctionNames array with mode: 'ANY' to restrict available tools based on user intent."

Their documentation describes:

  • Filtering tools intelligently based on LLM request analysis
  • Union aggregation where multiple hooks combine results
  • mode: "NONE" override to disable all tools

This validates both the concept and the implementation approach.

Implementation Considerations

  • Timing: Must fire early enough to modify the tool list before the LLM request is constructed
  • Caching: Tool lists could be cached per-session if they don't change between turns
  • UI feedback: Consider showing the user which tools are available when restrictions are active
  • Subagents: Decide whether tool filtering applies to subagents or only the main agent
  • MCP tools: Ensure filtering works for both built-in tools and MCP-provided tools

View original on GitHub ↗

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