[FEATURE] BeforeToolSelection Hook for Dynamic Tool Filtering
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:
- Wasted inference: The model may select a tool that will be blocked, requiring a retry and consuming additional tokens
- No context-aware tool restriction: Cannot dynamically limit tools based on the current task, user prompt, or environment
- Inefficient security policies: Blocking tools after selection is reactive rather than preventive
- 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
allowedToolNameslists 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
- PreToolUse blocking: Currently you can block tools in
PreToolUse, but this happens after selection—wasting inference and requiring the model to retry.
- Permission modes: Claude Code's permission modes (
plan,acceptEdits, etc.) provide some tool restriction, but these are user-facing modes, not programmatic hooks.
- 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.
- 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
- User wants Claude to analyze a codebase without making any changes
BeforeToolSelectionhook restricts tools to["Read", "Glob", "Grep", "WebFetch", "WebSearch"]- Claude can explore freely but cannot accidentally modify files
- No wasted inference on Write/Edit/Bash attempts that would be blocked
Scenario: RAG-based tool filtering
- Hook analyzes the user prompt using a fast local LLM or keyword matching
- For documentation questions: allow
["Read", "Glob", "Grep", "WebSearch"] - For code changes: allow
["Read", "Edit", "Write", "Bash"] - For web research: allow
["WebFetch", "WebSearch"] - Model receives only relevant tools, improving focus and reducing errors
Scenario: Environment-based restrictions
- CI/CD environment detected via environment variable
- Hook automatically restricts to
["Read", "Glob", "Grep", "Bash"](no file writes) - Prevents accidental modifications during automated testing
Scenario: Sensitive directory protection
- User is working in a directory containing production configs
- Hook detects this and sets
mode: "NONE"or restricts to read-only tools - Provides an extra layer of protection beyond PreToolUse blocking
Additional Context
Prior Art
Gemini CLI implements BeforeToolSelection:
"UseallowedFunctionNamesarray withmode: '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
This issue has 3 comments on GitHub. Read the full discussion on GitHub ↗