Karan

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

Sep 15, 20267 min read
How Model Routing Can Cut Claude Code Token Usage by 90%
Fullscreen

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:

text
                     ┌── 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:

  1. bulk-reader — for reading and summarizing large amounts of code.

  2. 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:

yaml
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

yaml
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:

json
{
  "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:

bash
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:

bash
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

bash
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:

text
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:

text
Large source files
       ↓
Claude reads everything
       ↓
Claude processes everything
       ↓
Tokens consumed

the workflow becomes:

text
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:

text
             ┌──────────────────────────┐
             │      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-writer for documentation

  • reviewer for code-review summaries

  • translator for localization

  • test-generator for 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.

ClaudeCodeAIAgentsModelRoutingLLMTokenOptimizationGeminiSpotifyPortalAiKAModesDeveloperToolsCodingProductivitySoftwareDevelopment