PreToolUse hooks: allow changing tool type (updatedToolName)
Feature Request
Problem
The PreToolUse hook currently supports updatedInput to modify a tool call's parameters, but there is no way to change the tool type itself. This means a hook cannot redirect a Read call to a Bash call, or a Grep call to a Bash call.
Use Case: CLI Token Optimization (RTK)
RTK is a CLI proxy that intercepts Bash commands and compresses their output by 60-90%, significantly reducing token consumption. It works via a PreToolUse hook that rewrites Bash commands:
Bash("cat file.ts") → Bash("rtk read file.ts") ✅ works
Bash("rg pattern") → Bash("rtk grep pattern") ✅ works
However, Claude Code's system prompt instructs the model to prefer native tools (Read, Grep, Glob) over Bash equivalents. When the model uses native tools, RTK never sees the call and can't compress the output:
Read("file.ts") → ??? cannot redirect to Bash ❌
Grep("pattern") → ??? cannot redirect to Bash ❌
Current workarounds and their limitations:
| Approach | Reliability | Problem |
|----------|------------|---------|
| CLAUDE.md instructions | ~70% | Overridden by system prompt's "use dedicated tools" |
| --append-system-prompt | ~80-85% | Doesn't propagate to subagents |
| deny hook + retry | ~100% | Wastes a round-trip (more tokens than RTK saves) |
| tweakcc (unofficial) | ~100% | Fragile, breaks on updates |
Proposed Solution
Add an optional updatedToolName field to the PreToolUse hook output:
{
"hookSpecificOutput": {
"hookEventName": "PreToolUse",
"permissionDecision": "allow",
"updatedToolName": "Bash",
"updatedInput": { "command": "rtk read file.ts" }
}
}
This would allow a hook to transparently redirect:
Read({file_path: "src/foo.ts"})→Bash({command: "cat src/foo.ts"})Grep({pattern: "TODO", path: "src/"})→Bash({command: "rg TODO src/"})Glob({pattern: "**/*.ts"})→Bash({command: "find . -name '*.ts'"})
Why This Matters
Token optimization proxies like RTK can save 60-90% on read operations, but only if they can intercept the calls. The current hook API makes it impossible to fully leverage these tools without unreliable prompt engineering or unofficial patches.
Alternatives Considered
- Separate
ToolRedirecthook event: More complex API surface for the same outcome - Making
updatedInputaccept a tool name field: Overloading existing field semantics - Adding a model-level tool preference setting: Less flexible than hooks, doesn't cover all use cases
This issue has 3 comments on GitHub. Read the full discussion on GitHub ↗