DEV Community

Kernel
Kernel

Posted on Originally published at larebelion.com

A model router for Claude Code, benchmarked: 82% cheaper, 2 tests lost

Originally published on larebelion.com.

Most of us pick one model when a Claude Code session starts and let it do everything: plan a migration, write a test, summarise a file, touch up a README. Every one of those requests is billed at the price of that model, and on simple tasks the price rarely buys a better result.

To put numbers on it, we built Rebel Router (open source, MIT), a local proxy that picks a model per request, and ran it through a small benchmark of our own. This post covers how it works, how to set it up, and what it measured, including what it lost.

What it is

Rebel Router runs on your machine (127.0.0.1:8787) between your coding agent and the model providers:

Claude Code (Anthropic Messages) ─┐
                                  ├─► Rebel Router ─► Anthropic · OpenAI · xAI · Gemini · DeepSeek · Ollama
OpenCode (OpenAI Chat)  ──────────┘        │
                                           └─► SQLite ledger ─► dashboard · CSV · rebel spend
Enter fullscreen mode Exit fullscreen mode

It has three parts:

  • Broker: a catalogue of models with price, speed, context and a quality score per task class, which ranks the top 3 for each request.
  • Router: the classifier plus the proxy, translating between the Anthropic and OpenAI formats (streaming and tool calls included) when the chosen provider needs it.
  • FinOps: daily and per-project budgets, and a ledger of every request with its cost.

Providers: Anthropic, OpenAI, xAI (Grok), Google Gemini, DeepSeek and local Ollama models. Bring your own keys, or a single OpenCode Zen key that reaches GPT, Grok, DeepSeek, GLM, Qwen and Kimi through one endpoint.

How it decides

  1. Classify. Every request lands in one of six classes (orchestration, complex_code, bulk_code, unit_tests, qa_automation, documentation) with a complexity score from 0 to 1.
    • With a VENICE_API_KEY, it asks Venice's JEV decision model (in beta). Any error, odd answer or response slower than 800 ms falls back to the rules, and results are cached per instruction so an agent's tool loop doesn't ask again every turn.
    • Without it, local rules look at keywords (English and Spanish), the tools used in recent turns (Task, TodoWrite, Edit…), file types (.spec.ts, .md…), context size and Claude Code's request type. Compaction and auxiliary calls go to the cheapest documentation model.
  2. Rank. The Broker drops models below a quality floor for the class (raised by complexity or an opus request, lowered by haiku), then weighs quality, price (input:output blended 3:1) and speed with per-class weights. The top 3 become the chosen model plus two fallbacks.
  3. Budget. At 80 % of a budget it prefers cheaper models; at 100 % it downgrades to the cheapest acceptable model or answers HTTP 402 (onLimit: block).
  4. Forward. Claude-to-Claude requests pass through untouched apart from model (headers such as anthropic-beta and the SSE stream are relayed as-is). Everything else is translated.
  5. Record. One ledger row per request: timestamp, project, class, provider, model, input/output/cache tokens, cost, latency, which classifier decided and why.

One thing to know: no Claude Code hook can change the session model. The UI keeps showing the model Claude Code asked for; the router's status line shows the one that actually answered.

Setup

git clone https://gitlab.com/larebelion/rebel-router.git && cd rebel-router
npm install && npm link                 # puts `rebel` on your PATH
cp .env.example .env                    # fill in the providers you use
set -a; . ./.env; set +a; rebel start   # router on http://127.0.0.1:8787
Enter fullscreen mode Exit fullscreen mode

Providers without a key are skipped; Ollama models are used only if they're pulled locally.

Claude Code

rebel init claude --global     # ~/.claude/settings.json: every project, CLI, claude -p, IDE extensions, Agent SDK
rebel init claude              # or just this project (.claude/settings.local.json)
rebel init claude --uninstall  # remove it again (add --global for the user-level install)
Enter fullscreen mode Exit fullscreen mode

It backs up your settings and sets:

  • ANTHROPIC_BASE_URL=http://127.0.0.1:8787, so the main session, subagents and background calls all go through the router;
  • ANTHROPIC_CUSTOM_HEADERS=x-rebel-project: <name> for per-project budgets and rules;
  • CLAUDE_CODE_GATEWAY_HINT_HEADERS=1, so the router can tell a main call from a subagent or compaction one;
  • optional hooks that tag the task, a status line with the routed model and today's spend, and the /rebel-spend and /rebel-top slash commands.

The Claude desktop app is the exception: it takes its gateway from Developer → Configure Third-Party Inference, not from settings.

OpenCode

rebel init opencode   # writes opencode.json (provider "rebel") and a small plugin
Enter fullscreen mode Exit fullscreen mode

Then select rebel/auto, or pin a class with rebel/auto:unit_tests, rebel/auto:documentation and so on.

Pin a class from your prompt

Write #rebel:tests, #rebel:docs, #rebel:qa, #rebel:bulk, #rebel:complex or #rebel:plan anywhere in a prompt. The router uses that class for the session until your next prompt.

Configuration

rebel.yaml in the project or in ~/.rebel-router/:

routing:
  excludeProviders: [xai]
  classModels: { documentation: deepseek/deepseek-flash }
  aliases: { opus: passthrough, haiku: hint }   # keep Opus requests on Opus; route Haiku freely
budgets:
  daily: 10
  projects: { shop: 3 }
  onLimit: downgrade
projects:
  secret-client: { localOnly: true }            # this project never leaves the machine
Enter fullscreen mode Exit fullscreen mode

Watching the spend

Command What it does
rebel status router status, today's spend, budget state
rebel top --task tests top 3 for a class, with reasons
rebel spend --today --by model spend by model, class, project or day (--csv, --json)
rebel export --days 30 CSV of the ledger
rebel dashboard local dashboard on :8788
rebel classify "<prompt>" see how a prompt would be classified

The benchmark

12 real tasks, two per class, each scored deterministically: hidden tests, mutation testing, deliberately buggy servers and rubrics. No model grades another. Run on 11 October 2026 with 10 models, one attempt per task, 1.78 USD in total. Tasks and raw results are public.

Model Cost per task (USD) Pass rate Tasks run
gpt-6-luna 0.0010 92 % 12
gemini-3.1-flash-lite 0.0012 67 % 12
claude-haiku-5-5 0.0023 75 % 12
gemini-3.5-flash-lite 0.0028 83 % 12
deepseek-flash 0.0051 88 % 8
deepseek-v4-pro 0.0097 100 % 2
qwen3.8-max 0.0137 100 % 1
glm-5.3 0.0198 67 % 6
claude-sonnet-5-5 0.0306 83 % 12
claude-opus-5-5 0.0799 92 % 12

Rows with fewer than 12 tasks are partial runs; don't read much into a 100 % on one or two tasks.

Router vs. Opus for everything

  • Cost: 0.17 USD with the router choosing, against 0.96 USD with Opus 5.5 on every task: 82 % less.
  • Quality: 9 of 12 passed (75 %) against 11 of 12 (92 %). The three misses were two unit-test tasks and one QA task the router sent to Claude Haiku 5.5, whose answers ran past the 8,000-token limit.
  • Latency: mean time per task dropped from 31.7 s to 19.5 s.
  • Classifier: the rule classifier (no JEV) put 9 of 12 tasks in the right class.

GPT-6 Luna passed the same 11 of 12 as Opus at roughly 1/80 of the cost on this set. That doesn't make it an Opus replacement; it says many everyday tasks don't need the most expensive model.

Limits

  • 12 tasks, one attempt each. Per-class numbers are indicative, not a leaderboard.
  • The savings cost two tasks Opus solved, both in testing and QA. Keep Opus wherever you ask for Opus (aliases.opus: passthrough) or pin a model per class with classModels.
  • Not covered: Grok, Gemini Pro, Ollama, and GPT models other than Luna. JEV was not measured; the benchmark used the rules.
  • Anthropic doesn't support routing Claude Code to non-Claude models. It works, but Claude-only features are dropped in translation.
  • JEV and Venice's Decisions API are in beta, so their request and response shape may change.
  • Cost is list price: reported tokens times the official price in the catalogue.

More

The number I'd watch is the 75 %. A router saving 82 % is only worth it if the tests it skips aren't the ones that would have warned you, so watch the ledger for the first few weeks before trusting it with your test suite.

Top comments (0)