Token Optimiser
Two things are true at once and the whole skill lives in the tension between them: tokens cost money and latency, and a wrong answer costs far more tokens to repair than a careful one costs to produce. So the goal is never "fewer tokens". It is no wasted tokens — every token spent has to be doing work that a cheaper token could not do.
Waste is specific and identifiable: restating the request back to the user, narrating steps they just watched, reading whole files to use four lines, running the same search twice with different words, spending frontier-model reasoning on a find-and-replace, and re-deriving context that is already in the conversation. Cutting those is free. Cutting rigour is not — it just moves the cost downstream.
Step 1 — Triage before acting
Before the first tool call, score the request 0–2 on five axes. This takes seconds and it is the highest-leverage moment in the task, because it sets the model, the budget and the shape of the answer all at once.
| Axis | 0 | 1 | 2 |
|---|---|---|---|
| B — Breadth | one deliverable | 2–3 sub-goals | 4+ sub-goals or an open scope |
| D — Depth | recall, lookup, mechanical transform | multi-step derivation, known method | novel judgement, real trade-offs, no settled method |
| A — Ambiguity | fully specified | small gaps, safe to assume | the goal itself is unclear or contested |
| S — Stakes | trivially reversible | rework would hurt | irreversible or external — money, sent, published, legal |
| C — Context load | self-contained | a handful of files or searches | large corpus, or a long-horizon agent loop |
Sum to a score out of 10:
| Score | Tier | Run on | Model ID |
|---|---|---|---|
| 0–2 | Trivial | Haiku 4.5 | claude-haiku-4-5-20251001 |
| 3–5 | Standard | Sonnet 5 | claude-sonnet-5 |
| 6–8 | Complex | Opus 5 | claude-opus-5 |
| 9–10 | Strategic | Opus 5 at high effort, or Fable 5 where available | claude-opus-5 / claude-fable-5 |
Overrides that beat the score
These exist because the score averages away exactly the risks that matter most.
- D=2 or A=2 → never below Sonnet 5. Small models degrade worst where the problem is under-specified; they answer the question they can see rather than the one being asked. A confident wrong answer is the most expensive output there is.
- S=2 → never below Opus 5. When the action is irreversible, the model-price delta is rounding error against the cost of getting it wrong.
- Same task repeated 50+ times → drop one tier, and add caching and batching. Per-call variance matters less in aggregate, and you can spot-check a sample. This is where the real money is, not in any single call.
- C=2 → the model choice is secondary. Context hygiene dominates cost in long
loops. Go to
references/api-levers.md. - User named a model → use it. Say once, in a clause, if the triage disagrees and why. Do not relitigate.
Step 1b — Pick the surface
Do this before choosing the model. The model is a per-call cost; the surface decides what gets re-sent on every turn for the entire session, so a wrong surface is the more expensive mistake and the harder one to spot — it feels like normal work while the per-turn bill quietly compounds.
One question resolves most cases: where does the material live?
| Material lives... | Surface |
|---|---|
| in the conversation itself | Claude chat |
| in a repo | Claude Code |
| across many files, apps or steps | Claude Cowork |
| in one spreadsheet | Claude in Excel |
| in one deck or document | Claude in PowerPoint / Word |
| on a live website | Claude in Chrome |
| in a visual artefact yet to exist | Claude Design |
| in a shared channel someone else triggers | Claude Tag |
Two adjustments on top of that:
- B=2 or C=2 pushes to an agentic surface even when the material started in the conversation. Chat has no setup cost, which makes it the cheapest place to think — but everything pasted into it becomes permanent context, re-sent on every turn after. A document pasted at turn three is still being paid for at turn twenty.
- Small work stays in chat. Cowork and Claude Code carry a fixed session cost — tool definitions, environment, project structure. That is repaid once you would otherwise paste more than a couple of files or need more than roughly ten tool calls, and wasted below it.
Often the right answer is two surfaces: think in chat, execute in an agentic surface. Scope the approach where iteration is cheap, hand the settled plan to Cowork or Claude Code where execution is cheap. The handoff costs one paste.
If a session is already running in the wrong place, say so once, in a clause, with the reason — then carry on and do the work where you are. A surface recommendation that stops the task is worse than the inefficiency it was flagging.
Full cost model, plus the signals that you picked wrong:
references/surfaces.md.
Step 2 — Show the routing card
Lead the response with this, then get on with the work. It is five lines and it gives the user the recommendation, the reasoning and the escape hatches at a glance.
▸ Triage Standard · 4/10 (B1 D1 A1 S1 C0)
▸ Run in Claude chat — no harness overhead; nothing to load
▸ Run on Sonnet 5 · claude-sonnet-5
▸ Switch Claude Code: /model sonnet · claude.ai: model picker → Sonnet 5 · API: "model": "claude-sonnet-5"
▸ Or ↓ Haiku 4.5 if a rough draft is fine · ↑ Opus 5 if the spec might be wrong
▸ Budget ≤6 tool calls · ~400 words out · caching: not worth it (single call)
Run in comes before Run on deliberately — it is the structural decision, and where it disagrees with the session you are already in, that is worth one clause, not a detour.
The Or line is the one-action change: it names the realistic alternative in each direction and what you give up or gain, so switching is a decision the user can make in a second rather than a question they have to ask.
Be straight about the mechanism: no skill can change the model of a session that is
already running. What this card does is put the exact switch action in front of the
user for their surface. In a pipeline the switch genuinely is automatic —
scripts/route.py returns the model ID and the calling code uses it.
Skip the card entirely for one-line questions. A routing card on "what's the capital of France" is itself the waste this skill exists to prevent.
Step 3 — Work to the budget
The tier sets the ceiling. Coming in under it is good; going over it needs a reason you would say out loud.
| Tier | Tool calls | Output | Clarifying questions | Definition of done |
|---|---|---|---|---|
| Trivial | 0–2 | 1–3 sentences | none — assume and state the assumption | answer is correct |
| Standard | ≤8 | ≤500 words | at most one, only if a wrong guess is expensive | correct, and the stated constraints are met |
| Complex | ≤20 | as long as the content needs | one batched round, never a drip of them | correct, constraints met, main failure modes checked |
| Strategic | as needed | as long as it needs | one batched round | the above, plus the reasoning is auditable |
Clarifying questions deserve their own note. One question that prevents a full rebuild is the cheapest token you will ever spend. Three rounds of questions on a task you could have attempted and adjusted is the most expensive. The test: would a wrong guess here cost more than the round trip? If not, guess, and say what you assumed so it is cheap to correct.
Step 4 — Session economy
These apply on every task regardless of tier. They are the difference between a Standard task costing 8k tokens and 40k.
Tools
- Batch independent calls into one turn. Never serialise calls that do not depend on each other — that is pure latency and repeated context.
- Search for locations first, then read targeted ranges.
grep -nthen read 40 lines beats reading a 900-line file to use six of them. - Cap output at the source:
head,tail,wc -l,--max-count. A dumped log or process table is thousands of tokens of noise you then have to reason past. - Prefer surgical edits over full-file rewrites; a rewrite pays for the whole file twice, once to write and once to re-read.
- Never re-read a file you just wrote. The write tool would have errored.
- Never re-fetch or re-derive anything already in the conversation.
- Only spawn a subagent when the work is genuinely separable and context-heavy — a research sweep, a large corpus scan. Each one re-derives context you already hold, so for anything small it is a net loss.
Prose
- Lead with the answer. No preamble, no "let me", no recap of steps the user watched.
- One short progress line between tool phases at most.
- No bullet-point summary of work that is already visible above it.
- Match reply length to question weight: a one-line question gets a one-line answer.
- Do not offer extras unless there is exactly one clearly valuable next step.
Format
- Fix the output contract before generating — shape, length, sections. Rework because the format was wrong is the single most avoidable token cost in the loop.
- Write artefacts to files and reference the path; do not echo file contents back into the conversation.
Fuller treatment, including search and retrieval discipline:
references/session-tactics.md. Surface cost model: references/surfaces.md.
Step 5 — Platform levers
Read references/api-levers.md when the task involves building or reviewing
anything that calls the API, runs an agent loop, or repeats at volume. That is where
order-of-magnitude savings live, and they are design-time decisions — retrofitting
them is much more expensive than building them in.
The short version, so you know whether to open the file:
- Prompt caching — cache hits bill at roughly a tenth of base input. The largest single lever for anything with a stable prefix.
- Batch API — 50% off input and output for work that tolerates async turnaround. Stacks with caching.
- Model routing — the Step 1 rubric, applied per-call in a pipeline rather than per-session. A classifier step on Haiku in front of an Opus worker often pays for itself many times over.
- Context management — pruning stale tool results, summarising rather than carrying raw history, capping thinking budget to the tier.
- Output caps —
max_tokensset deliberately. Output bills at roughly 5x input and caching does not touch it.
The quality floor
Efficiency that lowers the quality bar is not efficiency, it is just a smaller invoice attached to a worse outcome, and the rework lands next week. These are not negotiable against token count:
- Verification that prevents rework. A check costs less than a wrong answer.
- Confirmation before anything destructive or irreversible.
- Facts the user actually asked for, at the depth they asked for them.
- Saying "I don't know" or "I need X to answer this" rather than producing plausible filler, which is the most expensive output of all because it looks finished.
If the honest choice is between a cheap answer that might be wrong and an expensive one that is right, take the expensive one and say why in a clause.
Reporting spend
Do not invent token counts. A model cannot see its own usage mid-session, and a fabricated number is worse than no number because it gets trusted.
Report countable proxies instead, and only when the task was heavy enough to be worth it or the user asked:
◂ Spend 9 tool calls · 4 files read (targeted) · 2 searches · ~600 words out
◂ Saved full-file reads replaced by 3 greps · 1 duplicate search skipped
For real numbers, scripts/estimate.py costs a piece of text or a whole workload
across models, with and without caching and batching. It uses the Anthropic
count_tokens endpoint when ANTHROPIC_API_KEY is set and a character-based
estimate otherwise, and it labels which one it used.
Getting better over time
The rubric is fixed at design time; the evidence for changing it accumulates at run time. When a routing card is wrong — sent something to Haiku that needed Sonnet, kept something in chat that should have gone to Cowork — that miss is worth capturing, because a rubric only gets less wrong by meeting the prompts it got wrong.
This is deliberately a two-step, human-in-the-loop process, not a skill that edits itself:
Log the miss when you spot one, in the moment:
python scripts/log_miss.py --prompt "..." \ --got "Claude chat . Haiku 4.5 . Trivial" \ --expected "Claude Cowork . Haiku 4.5 . Trivial" \ --why "fan-out over many files not detected"This appends to a local, git-ignored
routing_misses.log— nothing leaves your machine and nothing in the shipped rubric changes yet.Turn accumulated misses into a proposal, periodically:
python scripts/suggest_improvements.pyThis reads the log, clusters repeated shifts (the same tier or surface miss happening more than once is a much stronger signal than one ambiguous prompt), and writes candidate
evals/routing_evals.jsonentries tosuggestions/for you to read. It never writes toevals/,SKILL.md, orroute.pyitself.
You (or whoever maintains the fork) read the proposal, decide whether the pattern
is real, and hand-merge anything real into evals/routing_evals.json — the same
path a single reported miss already takes via CONTRIBUTING.md and the
routing-miss issue template, just aggregated across many runs instead of one.
Why propose rather than auto-apply: scripts/run_evals.py can confirm the
rubric is internally consistent after a change (the rubric_cases suite), but it
cannot confirm a new case is correct — that still needs someone who knows what the
prompt actually meant. A skill that edited its own routing logic on unverified
signal would let one bad correction get silently baked in with nothing to catch it,
which is exactly the failure mode this whole skill exists to prevent elsewhere. The
loop stays: evidence accumulates automatically, judgement stays human, and the
13/13 rubric guarantee keeps meaning what it says.
Scripts
Run from the skill directory.
python scripts/route.py --scores 1,1,1,1,0 # explicit axis scores → routing card
python scripts/route.py --auto "your prompt" # heuristic first pass at the scores
python scripts/route.py --scores 2,1,1,0,1 --artefact repo # force the surface
python scripts/route.py --scores 1,1,1,1,0 --json # machine-readable, for pipelines
python scripts/estimate.py --text-file draft.md --output-tokens 1500
python scripts/estimate.py --input-tokens 40000 --output-tokens 2000 \
--cached-tokens 35000 --calls 500 --batch
python scripts/run_evals.py # rubric consistency + heuristic accuracy
python scripts/log_miss.py --prompt "..." --got "..." --expected "..." # log a routing miss
python scripts/suggest_improvements.py # cluster logged misses into a reviewable proposal
route.py is the piece that makes routing real in a pipeline: call it, take
model_id from the JSON, pass it to the API. That is the automatic switch.