Skip to content

ceoimperiumprojects/claude-code-router

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

3 Commits
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Claude Code Router

Use cheaper models in Claude Code without losing your Max subscription.

A ~90 line Node.js proxy that intercepts Claude Code requests and routes them — haiku goes to MiniMax M2.7 at a fraction of the cost, while Opus and Sonnet stay on Anthropic with your OAuth token passed through untouched.

┌──────────────┐         ┌──────────────────┐         ┌─────────────────────┐
│  Claude Code │────────▶│  Claude Code      │────────▶│  api.anthropic.com  │
│              │         │  Router (:4000)   │         │  (OAuth passthrough)│
│  /model opus │         │                  │         └─────────────────────┘
│  /model sonnet│        │  Reads model from │
│  /model haiku │        │  request body,    │         ┌─────────────────────┐
│              │         │  routes by prefix  │────────▶│  api.minimax.io     │
└──────────────┘         └──────────────────┘         │  (MiniMax M2.7)     │
                                                       └─────────────────────┘

The Problem

If you have a Claude Code Max subscription, you authenticate via OAuth (sk-ant-oat-* tokens). You might want to route cheaper tasks (linting, simple edits, boilerplate) to a cheaper model like MiniMax M2.7 while keeping Opus/Sonnet for the heavy lifting.

The obvious tool for this is LiteLLM — but it doesn't work here. LiteLLM never forwards the Authorization header to LLM providers (it's a security feature, not a bug). Your OAuth token gets swallowed, and Anthropic rejects every request. There's also an open issue where the anthropic-beta header gets overwritten when it detects OAuth, breaking extended thinking.

We spent a day debugging this before realizing a simple reverse proxy solves it in 90 lines.

Quick Start

# 1. Clone
git clone https://github.com/ceoimperiumprojects/claude-code-router.git
cd claude-code-router

# 2. Set your MiniMax API key (get one free at https://platform.minimax.io)
export MINIMAX_API_KEY="your-key-here"

# 3. Start the router
node server.mjs

# 4. In another terminal, point Claude Code at the router
export ANTHROPIC_BASE_URL="http://localhost:4000"
claude

That's it. Now inside Claude Code:

Command Routed to Auth
/model opus api.anthropic.com Your OAuth token (passthrough)
/model sonnet api.anthropic.com Your OAuth token (passthrough)
/model haiku api.minimax.io/anthropic MiniMax API key

Install (systemd — runs forever)

The install script sets up a systemd user service that starts on login, restarts on crash, and survives terminal closures.

chmod +x install.sh
./install.sh

This does three things:

  1. Copies server.mjs to ~/.claude-proxy/
  2. Installs and enables a systemd user service (claude-code-router.service)
  3. Adds export ANTHROPIC_BASE_URL to your .bashrc

After install, manage with:

systemctl --user status claude-code-router    # check status
systemctl --user restart claude-code-router   # restart
journalctl --user -u claude-code-router -f    # tail logs

Why Not LiteLLM?

We tried. Here's what happened:

LiteLLM This proxy
OAuth passthrough Strips Authorization header Forwards verbatim
anthropic-beta header Overwrites on OAuth Untouched
Dependencies Python + dozens of packages None (just Node.js 18+)
Code ~100K+ lines ~90 lines
Startup 5-10s <100ms
Memory ~200MB ~20MB

How It Works

The proxy reads the model field from each request body:

  • Model starts with claude-haiku → Rewrite model to MiniMax-M2.7, swap auth header with your MiniMax API key, forward to api.minimax.io/anthropic
  • Anything else → Forward the entire request to api.anthropic.com with every header intact. Your OAuth token, anthropic-beta, streaming — all preserved.

Two technical details that took us a while to figure out:

  1. ZlibError fix — Node.js fetch() auto-decompresses gzip responses but keeps the content-encoding: gzip header. The client then tries to decompress already-decompressed data. We strip accept-encoding from requests and content-encoding from responses.

  2. Model name mapping — MiniMax's Anthropic-compatible endpoint defaults to M2.5 if you send an unknown model name like claude-haiku-4-5-20251001. We rewrite the model field to MiniMax-M2.7 explicitly.

Configuration

Env Variable Default Description
MINIMAX_API_KEY (required) Your MiniMax API key
PORT 4000 Port the router listens on
MINIMAX_MODEL MiniMax-M2.7 Which MiniMax model to use. Options: MiniMax-M2.7, MiniMax-M2.7-highspeed, MiniMax-M2.5, MiniMax-M2.5-highspeed

Troubleshooting

Invalid signature in thinking block

This happens when you switch between MiniMax and Anthropic within the same conversation. Thinking blocks contain cryptographic signatures tied to the provider that generated them — the other provider rejects them.

Fix: Run /clear in Claude Code before switching models.

ConnectionRefused / Unable to connect to API

The router process died. This happens if you ran it manually with node server.mjs & and the parent shell closed.

Fix: Use the systemd install (./install.sh) — it auto-restarts the router on crash and starts it on login. Or restart manually: systemctl --user restart claude-code-router

ZlibError

Node.js fetch() auto-decompresses responses but keeps the content-encoding header, so the client tries to decompress again.

Fix: Make sure you're running the latest server.mjs — it strips encoding headers. If you still see this, pull the latest version and restart.

MINIMAX_API_KEY env var is required

The router needs a MiniMax API key to route haiku requests.

Fix: export MINIMAX_API_KEY="your-key" before starting the router. Get one at platform.minimax.io.

Extending

The routing logic is ~10 lines. Want to route to a different provider? Edit the if block in server.mjs:

// Example: route claude-haiku to your own endpoint
if (typeof body.model === 'string' && body.model.startsWith('claude-haiku')) {
  useMinimax = true;
  targetBase = 'https://your-provider.com/v1';
  body.model = 'your-model-name';
  // swap auth headers as needed
}

You could add multiple providers, route by model version, or add request logging — it's just a Node.js HTTP server.

Requirements

  • Node.js 18+ (uses native fetch API)
  • Claude Code with Max subscription
  • MiniMax API keyfree to create

License

MIT

About

Lightweight Node.js proxy for Claude Code — route haiku to MiniMax M2.7, keep Opus/Sonnet on Anthropic OAuth. Zero dependencies, ~90 lines. Replaces LiteLLM.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors