How Model Routing Can Cut Claude Code Token Usage by 90%

Think about what happens during a normal coding session.
You ask Claude Code a question about one method, and it reads five large files first. You ask it to create a test, and it reads several existing test files to understand the project's patterns. You ask it to update documentation, and more tokens are spent processing information that doesn't require much reasoning.
The model is capable of solving complex problems, but we're using it for a lot of routine work.
That raises an interesting question:
What if we could send simple, predictable tasks to a cheaper model and reserve the powerful model for the work that actually requires reasoning?
That's where model routing comes in.
The basic idea
Instead of letting Claude handle every operation, we can split the workload:
┌── Complex reasoning ──> Claude
│
Claude Code ─────────┼── Large file reading ─> Worker model
│
└── Boilerplate code ───> Worker model
For example, a cheaper model can handle:
Reading and summarizing large files
Generating repetitive tests
Creating configuration files
Generating type definitions
Other predictable, pattern-based tasks
Claude can then focus on debugging, architecture, complex reasoning, and decisions where model quality actually matters.
One implementation of this idea uses AiKA Modes in Portal by Spotify.
What are AiKA Modes?
AiKA Modes are essentially configurable agents that run on an ephemeral runtime.
You define:
What the agent should do
Which model it should use
Parameters such as temperature
Optional MCP tools
Portal handles the underlying runtime, so you don't need to build and maintain separate infrastructure.
For this workflow, two modes are enough:
bulk-reader — for reading and summarizing large amounts of code.
code-writer — for generating predictable code based on existing patterns.
You could use a cheaper model such as Gemini 2.5 Flash for both.
1. bulk-reader
The purpose of bulk-reader is simple:
Let a smaller model read large files so Claude doesn't have to put all that content into its context.
A simplified configuration could look like this:
name: bulk-reader
description: Bulk file reader for code analysis
instructions: |
You are a precise code analyst.
Read the provided files and answer the question concisely.
Output structured bullets only.
No greetings or unnecessary explanations.
Lead every bullet with the relevant name, type, or line number.
Skip anything the caller did not ask for.
visibility: public
model: gemini-2.5-flash
resourceLimits:
temperature: 0.2
tags:
- coding
- delegation
The important part isn't the exact configuration.
It's the concept: the worker returns only the useful information instead of sending the entire file contents back to Claude.
2. code-writer
The second mode handles predictable code generation.
For example:
Unit tests
Configuration files
Type definitions
Boilerplate
Code following an existing pattern
name: code-writer
description: Boilerplate code generator
instructions: |
Generate code based on the specification and reference files.
Match the existing patterns, naming, conventions, and style exactly.
Output only the code.
If the specification is ambiguous, follow the reference code.
visibility: public
model: gemini-2.5-flash
resourceLimits:
temperature: 0.2
tags:
- coding
- delegation
That "output only the code" instruction is important.
If the worker returns explanations and Markdown fences along with the code, Claude has to process that extra output too. The whole point of delegation is to keep the expensive model out of unnecessary work.
How do we decide what gets delegated?
This is where the workflow becomes interesting.
Instead of simply telling Claude:
"Please use the cheaper model sometimes."
You can enforce the routing using Claude Code hooks.
One implementation, called Shunt, uses hooks, scripts, and skills to create this routing layer.
Layer 1: Hooks
Hooks can run before Claude uses a tool.
For example, a check-file-size hook can inspect every Read operation.
If Claude tries to read a file larger than a certain threshold, the hook blocks the operation and tells Claude to use the bulk-reader instead.
Small or targeted reads can still go directly to Claude.
For example:
{
"env": {
"SHUNT_MIN_LINES": "500"
}
}
This means you aren't blindly delegating everything.
That's important because delegation itself introduces latency.
Layer 2: Scripts
Scripts provide a simple interface between Claude Code and Portal.
A bulk-read command could look like:
bulk-read \
--question "What does this service do?" \
--paths src/Service.java src/Handler.java
Instead of Claude reading both files into its own context, the worker model processes them and returns a concise answer.
You can then ask another question about the same files:
bulk-read \
--question "Which methods call the database?" \
--paths src/Service.java src/Handler.java
The important difference is that the raw source code doesn't have to consume Claude's context.
Code generation works similarly
code-write \
--spec "Write tests for UserService" \
--reference tests/OrderTest.java \
--target tests/UserTest.java
The worker receives the specification and an existing test as a reference.
It generates the new test and can write it directly to disk.
Claude doesn't need to consume all of those generated tokens.
The reference file is important because it gives the worker a concrete example of your project's conventions. Without it, the generated code may be technically valid but completely inconsistent with the codebase.
Layer 3: Skills
The final layer is the set of skills that explain to Claude when and how to use these scripts.
This creates a simple flow:
Claude tries to read a large file
↓
Hook checks it
↓
Read is blocked
↓
Claude is directed to the skill
↓
bulk-reader runs
↓
Claude receives a compact summary
The nice thing about this architecture is that the hook provides enforcement while the skill provides guidance.
The 90% token reduction
The most interesting result is the potential token saving.
In testing across a Java monorepo, bulk-reading reportedly reduced the tokens consumed by Claude by around 90% in the tested scenarios.
Why?
Because instead of:
Large source files
↓
Claude reads everything
↓
Claude processes everything
↓
Tokens consumed
the workflow becomes:
Large source files
↓
Worker model reads them
↓
Compact summary
↓
Claude reasons over the summary
The expensive model receives the information it needs, rather than the entire dataset.
The code-generation case can save even more unnecessary context because the generated code can go directly to disk instead of being returned to Claude as output tokens.
But you shouldn't delegate everything
This approach has clear limitations.
Don't delegate precise editing
A summary from another model isn't always enough to safely modify code.
If Claude needs to change a specific function, it should still read that section directly.
The goal isn't to eliminate Claude's access to the codebase.
It's to prevent unnecessary large reads.
Don't delegate complex reasoning
Smaller models can be very good at pattern recognition, but they can still miss subtle problems.
Things like:
Complex debugging
Architecture decisions
Security-sensitive logic
Concurrency issues
Safety-critical code
are better handled by the stronger model.
Don't delegate tiny tasks
Every delegation adds network latency.
The request has to travel through the routing layer, reach the worker model, and return.
For a 50-line file, spending 10–30 seconds delegating the task might be worse than simply letting Claude read it.
That's why a threshold-based approach makes sense.
The bigger lesson: use the right model for the job
The 90% number is interesting, but I think the more important idea is model specialization.
We often treat AI models as if every task should go to the most capable model available.
That's similar to using a senior engineer for every task in a project.
You wouldn't ask a senior engineer to spend their entire day copying configuration files or generating repetitive test scaffolding.
AI agents shouldn't work that way either.
A better architecture is:
┌──────────────────────────┐
│ Claude Code │
│ │
│ Complex reasoning │
│ Debugging │
│ Architecture │
│ Decision making │
└────────────┬─────────────┘
│
Model Router
│
┌───────────────┴───────────────┐
↓ ↓
Worker: bulk-reader Worker: code-writer
│ │
Large file analysis Boilerplate
Summarization Tests
Code extraction Configs
And the system can easily grow.
You could create:
doc-writerfor documentationreviewerfor code-review summariestranslatorfor localizationtest-generatorfor repetitive tests
Each worker can use a model appropriate for the task.
Why this matters for AI-assisted development
As AI coding agents become more common, token efficiency will become just as important as model capability.
Sending every file, every generated output, and every simple operation through an expensive model doesn't scale particularly well.
Model routing gives us another option:
Use expensive intelligence where reasoning matters, and cheaper intelligence where predictable work is enough.
That's the real idea behind this approach.
You're not replacing Claude.
You're making sure Claude spends its context and tokens on the problems that actually deserve them.
And that's what makes a reported 90% reduction in token usage particularly interesting—not because one model suddenly became better, but because the workload was split more intelligently.