Automatic model routing and token optimization for Claude Code.
Stop burning Opus tokens on simple searches. This project makes Claude Code automatically route cheap tasks to Haiku and reserve full reasoning power for complex work — saving 3-5x on token costs with zero quality loss.
You: "find all python files that import pandas"
→ [ROUTING: T0_LOOKUP] → Delegated to Haiku subagent (cheap, fast)
You: "fix the null check in auth.py line 45"
→ [ROUTING: T1_STANDARD] → Answered directly (normal)
You: "security review the RLS implementation for bypass vulnerabilities"
→ [ROUTING: T2_DEEP] → Full Opus reasoning + specialized agents (thorough)
┌─────────────────────────────────────────────────────────────┐
│ You type a prompt │
└──────────────────────┬──────────────────────────────────────┘
│
▼
┌──────────────────────────────────────────────────────────���──┐
│ UserPromptSubmit Hook (classify.sh) │
│ ┌─────────┐ ┌──────────┐ ┌──────────┐ ┌────────────┐ │
│ │T0_LOOKUP│ │T0_EXPLAIN│ │T1_STANDARD│ │ T2_DEEP │ │
│ │ Haiku │ │ Haiku │ │ Direct │ │ Full Power │ │
│ └─────────┘ └──────────┘ └──────────┘ └────────────┘ │
└──────────────────────┬──────────────────────────────────────┘
│ injects [ROUTING: T*] into context
▼
┌─────────────────────────────────────────────────────────────┐
│ Claude reads the routing tag + CLAUDE.md protocol │
│ and acts accordingly: │
│ T0 → Agent(model="haiku") for the work │
│ T1 → answers directly, haiku for background research │
│ T2 → full reasoning, specialized agents │
└─────────────────────────────────────────────────────────────┘
+
┌─────────────────────────────────────────────────────────────┐
│ Environment Variables (always active) │
│ CLAUDE_CODE_SUBAGENT_MODEL=haiku ← cheap subagents │
│ CLAUDE_CODE_EFFORT_LEVEL=medium ← don't overthink │
└─────────────────────────────────────────────────────────────┘
Five layers working together:
| Layer | What | Where | Effect |
|---|---|---|---|
| Hook | Classifies every prompt into T0/T1/T2 | ~/.claude/hooks/classify.sh |
Injects routing advice into context |
| CLAUDE.md | Tells Claude how to act on routing tags | ~/.claude/CLAUDE.md |
Claude delegates T0 to Haiku, goes deep on T2 |
| Env vars | Forces all subagents to use Haiku | ~/.zshrc or ~/.bashrc |
Every Explore/research agent runs cheap |
| Effort | Sets default reasoning effort to medium | ~/.claude/settings.json |
Prevents overthinking on routine tasks |
| Commands | Pins per-command model tiers | .claude/commands/*.md |
/dev uses Haiku, /audit uses Opus |
- Claude Code installed and working
- Python 3.8+ (used by the classifier hook)
- macOS, Linux, or Windows with Git Bash / WSL
git clone https://github.com/bijumailbox/claude-auto-router.git
cd claude-auto-router
bash scripts/install.shgit clone https://github.com/bijumailbox/claude-auto-router.git
cd claude-auto-router
powershell -ExecutionPolicy Bypass -File scripts\install.ps1bash tests/verify.shExpected output:
PASS python3 found
PASS Hook file exists
PASS Hook file is executable
PASS Lookup → T0_LOOKUP
PASS Explain → T0_EXPLAIN
PASS Standard → T1_STANDARD
PASS Deep → T2_DEEP
PASS Shell injection attempt safely handled
PASS UserPromptSubmit hook registered in settings.json
PASS settings.json is valid JSON
PASS Routing protocol found in CLAUDE.md
Results: 11 passed, 0 failed, 0 warnings / 11 checks
All critical checks passed!
# Restart your terminal (or source your rc file)
source ~/.zshrc # or ~/.bashrc
# Start a new Claude Code session — the hook fires automatically
claudeIf you prefer to understand and control every change, follow these steps manually.
Create the file ~/.claude/hooks/classify.sh:
mkdir -p ~/.claude/hooksCopy the contents of hooks/classify.sh into ~/.claude/hooks/classify.sh, then:
chmod +x ~/.claude/hooks/classify.shTest it:
echo '{"input": "find all python files"}' | bash ~/.claude/hooks/classify.sh
# Should output JSON with T0_LOOKUPEdit ~/.claude/settings.json (create it if it doesn't exist):
Important: If you already have hooks in settings.json, merge the
UserPromptSubmitarray — don't replace the whole hooks object.
Append this to ~/.claude/CLAUDE.md (the global one, not a project file):
## Auto-Routing Protocol (Token Optimization)
A `UserPromptSubmit` hook classifies every prompt and injects a `[ROUTING: T*]` tag.
| Tag | What to do |
|-----|-----------|
| `T0_LOOKUP` | Delegate entirely to `Agent(model="haiku")`. Pure search/grep/list. |
| `T0_EXPLAIN` | Delegate research to `Agent(model="haiku")`, synthesize result yourself in 2-3 sentences. |
| `T1_STANDARD` | Answer directly. Use `Agent(model="haiku")` only for background file exploration. |
| `T2_DEEP` | Full reasoning. Use specialized agents for parallel analysis when available. |
**Defaults**: All subagent exploration/research uses `model="haiku"` unless multi-step reasoning is required. Never duplicate work you delegated to a subagent.Add to your ~/.zshrc (or ~/.bashrc):
# Claude Code Auto-Router: Token Optimization
export CLAUDE_CODE_SUBAGENT_MODEL=haiku
export CLAUDE_CODE_EFFORT_LEVEL=mediumThen: source ~/.zshrc
If you have custom commands in .claude/commands/, add model frontmatter:
---
model: haiku
---
Start the development environment.
...| Command Type | Recommended Model |
|---|---|
Docker/infra commands (/dev, /deploy) |
haiku |
Training/pipeline scripts (/train) |
haiku |
Test scaffolding (/test) |
sonnet |
Onboarding/explanations (/onboard) |
sonnet |
Security audits (/audit) |
opus |
Architecture reviews (/review) |
opus |
Prompts that start with:
find,list,show me,where is,what issearch,grep,count,how many files,which file
Why Haiku? These are pure retrieval tasks. The model barely matters — it's just calling Grep/Glob/Read. Haiku costs ~50x less than Opus per token.
Prompts that start with:
explain,what does,what's,how doesdescribe,summarize,tell me about
Why? The heavy work is reading files (cheap). The synthesis is 2-3 sentences (minimal tokens).
Everything that doesn't match T0 or T2. Coding, debugging, single-file edits, writing tests.
Why? Your session model (Opus/Sonnet) is already right for this. Haiku subagents handle any background research.
Prompts containing:
security,review,architect,design,planthreat,migration,refactor across,auditvulnerability,breaking change
Why? These require multi-step reasoning, cross-file analysis, and nuanced judgment. Wrong answers here are expensive.
Rough estimates based on typical Claude Code usage:
| Without Auto-Router | With Auto-Router |
|---|---|
| 100% Opus tokens | ~30% Opus, ~20% Sonnet, ~50% Haiku |
| All subagents inherit session model | All subagents use Haiku |
| Max effort on every prompt | Medium effort default, max on demand |
Effective savings: 3-5x on token costs depending on your prompt mix.
The biggest single win is CLAUDE_CODE_SUBAGENT_MODEL=haiku — every Explore agent, every background research task, every file search that Claude spawns as a subagent now runs on Haiku instead of inheriting Opus.
The auto-router sets sensible defaults. You can always override per-prompt:
/effort max # Deep reasoning for the next exchange
/effort low # Minimal thinking for trivial tasks
/model opus # Force Opus for rest of session
/model sonnet # Drop to Sonnet for routine work
Edit ~/.claude/hooks/classify.sh to add your own routing rules. The classifier uses Python regex:
# Add your own T0 patterns (cheap tasks):
if re.match(r"^(your_pattern_here)", prompt):
advice = "[ROUTING: T0_LOOKUP] ..."
# Add your own T2 patterns (expensive tasks):
elif re.search(r"(your_keyword|another_keyword)", prompt):
advice = "[ROUTING: T2_DEEP] ..."Contributing new patterns? See CONTRIBUTING.md.
bash scripts/uninstall.shpowershell -File scripts\uninstall.ps1Both scripts restore from backups when available.
Q: Does this change which model I'm running?
No. Your session model stays whatever you set it to. The hook only injects context that tells Claude when to delegate to cheaper subagents. The CLAUDE_CODE_SUBAGENT_MODEL env var affects subagents only.
Q: Can the hook block my prompt?
No. The hook always exits 0. If anything fails, it returns {} and your prompt proceeds normally.
Q: Does this work with Claude Code in VS Code / JetBrains? Yes. The hook runs at the Claude Code engine level, not the IDE level.
Q: What if I want Sonnet as default instead of Haiku for subagents?
Change CLAUDE_CODE_SUBAGENT_MODEL=sonnet in your shell profile and update the CLAUDE.md routing protocol to reference model="sonnet".
Q: Will Claude always follow the routing advice? Claude treats CLAUDE.md and hook context as high-priority instructions, but it's not enforcement — it's guidance. In practice, compliance is very high (90%+), especially when the routing protocol is clear and specific.
Q: Is the hook secure? Yes. User input is piped to Python via stdin — there's no shell interpolation. See the security section in CONTRIBUTING.md.
claude-auto-router/
├── hooks/
│ ├── classify.sh # Main classifier (macOS/Linux)
│ └── classify.ps1 # Windows PowerShell variant
├── scripts/
│ ├── install.sh # Installer (macOS/Linux)
│ ├── install.ps1 # Installer (Windows)
│ ├── uninstall.sh # Uninstaller (macOS/Linux)
│ └── uninstall.ps1 # Uninstaller (Windows)
├── tests/
│ └── verify.sh # Post-install verification
├── examples/
│ ├── CLAUDE.md.example # Example routing protocol for CLAUDE.md
│ └── commands/ # Example command files with model frontmatter
│ ├── dev.md
│ ├── test.md
│ └── audit.md
├── README.md # This file
├── CONTRIBUTING.md # How to contribute
├── CHANGELOG.md # Version history
└── LICENSE # MIT License
MIT License. See LICENSE.
Contributions welcome! See CONTRIBUTING.md for guidelines.
Areas where contributions are especially valuable:
- Better classification patterns (new keywords, smarter regex)
- Machine-learning-based classifier (replace regex with a lightweight model)
- Cost tracking and reporting (measure actual savings)
- Integration with other LLM tools beyond Claude Code
- Windows testing and edge cases
{ // ... your existing settings ... "hooks": { "UserPromptSubmit": [ { "hooks": [ { "type": "command", "command": "bash ~/.claude/hooks/classify.sh" } ] } ] // ... your other hooks ... } }