skill
claude-route
Zero-token model router for Claude Code: deterministic classifier picks the cheapest capable model per task. /route skill + always-on hook + statusline telemetry + claude-code-router integration.
Set up
Skills are installed by placing their folder where your agent loads skills.
The download comes from github.com/justutsav/claude-route itself, not from our server, so what you get is exactly what its author published.
Install instructions come from the README
README
synced Oct 23, 2026claude-route — zero-token model router for Claude Code
Picks the best/cheapest model for each task without burning a single token
on the routing decision itself. The classifier is a deterministic Python
script (regex + scoring), not an LLM call. Works as a /route skill inside
Claude Code, an always-on hook, or a custom router for
claude-code-router
(covers OpenRouter, Ollama, Cursor/Codex via proxy).
The numbers
Routing overhead: 0 tokens, <10ms, fully offline. An LLM-as-router burns ~300–800 input tokens per decision; at 200 prompts/day that's 60k–160k tokens/day spent just deciding — this spends none.
Cost per session (worked example). A session with 1M input / 200k output tokens, at July 2026 API pricing (Opus $5/$25, Sonnet $2/$10, Haiku $1/$5 per M):
| Strategy | Cost |
|---|---|
| everything on Opus | $10.00 |
| routed: 30% opus (hard parts) / 50% sonnet / 20% haiku | $5.40 (−46%) |
On subscription plans the same arithmetic applies to your 5-hour usage limit — limit consumption is weighted by model cost, so routed work drains it roughly half as fast.
Classifier accuracy: 44/44 (100%) on the bundled eval
(tests/eval.py) — see Evals for the honest caveats.
What this does NOT do: shrink your token count. Routing changes the price per token, not how many you use. To also cut the count, pair it with caveman (~75% fewer output tokens) — the savings multiply.
Install
git clone https://github.com/justutsav/claude-route ~/.claude/skills/route
Then add the trigger to ~/.claude/CLAUDE.md so Claude Code picks it up:
# route
- **route** (`~/.claude/skills/route/SKILL.md`) - zero-token model router. Trigger: `/route`
When the user types `/route`, invoke the Skill tool with `skill: "route"`.
Optional extras:
- Always-on routing (never type
/routeagain): installscripts/prompt-hook.shas aUserPromptSubmithook — see the header comment in that file for the settings.json snippet. Every prompt gets classified and the tier is injected as context automatically. - Token telemetry statusline: wire
scripts/statusline.py— see Statusline. - Local-LLM fallback: install Ollama, pull a small
model (
ollama pull qwen2.5:3b), set it inconfig.json→classifier.ollama_model. - Full proxy routing (OpenRouter / other IDEs): see Use with OpenRouter.
Why not an LLM router?
Asking a model "which model should handle this?" adds input tokens to every request — the exact problem we're solving. The layered approach here:
- Heuristics first (
scripts/classify.py) — free, <10ms, handles ~90% of cases. Scores task text on reasoning markers, complexity markers, simplicity markers, code presence, multi-step structure, and input size. - Local LLM fallback (
--llm-fallback) — only when heuristic confidence is low. Uses a small Ollama model already on disk (configurable inconfig.json→classifier.ollama_model). Local inference = zero API cost. - Never a cloud-LLM routing call.
Components
| File | Purpose |
|---|---|
SKILL.md | /route skill for Claude Code sessions |
scripts/classify.py | the routing brain — CLI, outputs JSON |
config.json | provider catalogs + tier → model maps |
ccr-router.js | same heuristics as a claude-code-router custom router |
Use inside Claude Code
/route refactor the payment service into two modules
→ classifies (complex), recommends /model opus, or offers to offload
simple subtasks to a haiku subagent while the session stays on the strong model.
Use with OpenRouter / other IDEs (Cursor, Codex, Antigravity)
Any tool that speaks the Anthropic or OpenAI API can be pointed at claude-code-router (MIT):
npm install -g @musistudio/claude-code-router
In ~/.claude-code-router/config.json:
{
"CUSTOM_ROUTER_PATH": "/absolute/path/to/.claude/skills/route/ccr-router.js"
}
(CCR does not expand ~ — use the absolute path, e.g. $HOME/.claude/skills/route/ccr-router.js resolved.)
Then launch Claude Code with ccr code. Every request is auto-routed
per the ccr.tiers map in config.json — no manual /route needed.
Other IDEs: point their base URL at the CCR proxy (default
http://127.0.0.1:3456).
CLI examples
python3 scripts/classify.py "fix typo in readme"
# {"tier": "simple", "model": "haiku", ...}
python3 scripts/classify.py --provider openrouter "design a distributed job queue"
# {"tier": "complex", "model": "anthropic/claude-opus-4.1", ...}
python3 scripts/classify.py --llm-fallback --explain "hmm do the thing with the stuff"
# low confidence → escalates to local qwen2.5:3b via ollama
Keeping the catalog fresh
Model slugs go stale fast. Refresh config.json tier maps when new models
ship, or run /route setup to re-scan local Ollama models. For OpenRouter
you can also punt entirely: set every tier to openrouter/auto and let
their server-side router decide.
Scoring system
classify.py scores task text on six signals, all computed with regex — no LLM:
| Signal | What it detects | Effect |
|---|---|---|
reasoning_hits | prove/proof/theorem/optimize/algorithm/complexity/big-O/trade-offs/mathemat*/derive/logic puzzle/formally verify | ≥2 hits (or 1 + multistep) → reasoning |
complex_hits | architecture/refactor/migrate/concurrency/race condition/security audit/root cause/multi-file/build-a-system | ≥2 hits (or 1 + multistep) → complex |
simple_hits | typo/rename/format/lint/docstring/quick fix/bump version/translate/summarize | ≥1 hit + no complexity + short input → simple |
est_input_tokens | word count × 1.3 | > 7800 → long_context |
long_context_hint | "whole repo", "entire codebase", "large log dump" | → long_context |
code_present / multistep | code snippets, "first…then…", numbered steps | confidence modifiers |
Decision order: long_context → reasoning → complex → simple → standard (default).
Each verdict carries a confidence 0–1; below 0.6, --llm-fallback escalates to
a local Ollama model (still zero API tokens). Ties between reasoning and
complex go to reasoning (its markers are more specific).
Evals
tests/eval.py — 44 labeled real-world task phrasings across all 5 tiers.
Distinguishes adjacent misses (simple↔standard, complex↔reasoning — similar
model cost, low harm) from bad misses (e.g. complex routed to a cheap model).
Exits nonzero on any bad miss, so it works as a CI gate.
Current results (2026-07-12): 44/44 exact (100%), 0 bad misses.
Honest caveat: the eval set was written by the same author as the classifier,
so this is a regression suite, not proof of generalization. On unseen phrasings
expect roughly 85–90% — the documented escape hatch is the confidence score +
local-LLM fallback. Add your own misrouted tasks to CASES as you hit them.
python3 tests/eval.py # human report
python3 tests/eval.py --json # machine-readable
How our routing differs from others
| System | Decision mechanism | Routing cost | Transparency |
|---|---|---|---|
| this skill | deterministic regex scoring | 0 tokens, <10ms, offline | full — every rule readable/editable |
| RouteLLM | trained router (Elo/BERT/LLM classifier) | model inference per request | opaque weights |
| Arch-Router-1.5B | 1.5B LLM, preference-aligned | local GPU/CPU inference, ~200ms | prompt-configurable, weights opaque |
| claude-code-router (built-in) | static scenario mapping (default/background/think/longContext) | 0 tokens | full, but no content analysis |
openrouter/auto | server-side router (NotDiamond) | hidden, server-side | none |
Are we better? Depends on the axis. Better: routing cost (zero), latency
(<10ms), privacy (nothing leaves the machine), auditability (misroute → read the
regex, fix it, add an eval case). Worse: nuanced classification of vague or
novel phrasings — a trained 1.5B router beats regex there (~93% on paraphrase
benchmarks vs our ~85–90% off-suite estimate). Our mitigation is layered: the
confidence score routes uncertain cases to a local LLM fallback, and everything
falls back to standard (sonnet-class) — so a miss costs mid-tier money, never
a botched task on a bottom-tier model. For a single developer optimizing token
spend, zero-overhead routing that is right ~9/10 times beats paying inference
on every request to be right 9.3/10 times.
Statusline
scripts/statusline.py renders live token telemetry in the Claude Code
statusline (wired via ~/.claude/hooks/route-statusline.sh in settings.json):
[CAVEMAN] Fable 5 | ctx 10% | sess 617k in / 93k out | 5h 709.9k [62% left]
- model — current session model
- ctx % — context window used (auto-detects 1M vs 200k window)
- sess — this session's input/output tokens (parsed from the transcript)
- 5h — tokens burned across ALL sessions in the rolling 5-hour window (Claude plan limits reset per 5h block); scan cached 30s
- [% left] — only shown if you set
statusline.five_hour_token_budgetinconfig.json; Anthropic doesn't expose the plan's exact limit to scripts, so calibrate once against/usageand set the budget number
Prior art (all open source)
- claude-code-router — the proxy this plugs into
- RouteLLM (LMSYS) — trained routers, 85% cost cut
- Arch-Router-1.5B — small routing model, runs on Ollama
- LLMRouter (UIUC) — 16+ router library
- ypollak2/llm-router — free-first fallback chains for coding tools