Skip to content

Always-Friday/ccm

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

ccm - Claude Code Model-switcher

A thin proxy wrapper for Claude Code that automatically routes API calls to the right model depending on what Claude is doing.

Why

Claude Code has a built-in opusplan model alias that is supposed to switch from Opus (for planning) to Sonnet (for execution), but it has known reliability issues. ccm solves this properly by running a local HTTP proxy that:

  • Uses your plan model (default: claude-opus-4-6) while Claude is in Plan mode - where it reasons about what to do and structures its approach
  • Automatically switches to your execution model (default: claude-sonnet-4-6) the moment Claude exits Plan mode to start doing the work
  • Falls back through a configurable chain of models when rate-limited (HTTP 429), so your session never gets stuck
  • Shows which model is active in the terminal at all times

How it works

Claude Code  →  ccm proxy (localhost:7777)  →  Anthropic API

The proxy intercepts every /v1/messages request and rewrites the model field based on current session state. It detects the plan→execution transition by watching the streaming API response for the exit_plan_mode internal tool call that Claude Code emits when leaving Plan mode.

Per-model API keys are supported, so you can use a high-tier key for plan requests and a standard key for execution, keeping billing separate.

Installation

npm / npx (recommended)

npm install -g claude-model-router

This is the recommended installation method for download tracking and automatic updates.

Manual

git clone https://github.com/Always-Friday/ccm
cd ccm
npm link     # or: ln -s "$(pwd)/bin/ccm.js" /usr/local/bin/ccm

Requires Node.js 22+ (already installed if you have Claude Code).

Setup

1. Configure models

ccm setup

This creates ~/.ccm/config.json. You will be prompted for:

Setting Default Description
Plan mode API base URL https://api.anthropic.com Anthropic API (or Azure/Bedrock endpoint) for plan requests
Plan model claude-opus-4-6 Used while in Plan mode
Plan API key env ANTHROPIC_API_KEY Optional separate key for plan requests
Execution mode API base URL (same as plan) Optional separate URL for execution requests
Execution model claude-sonnet-4-6 Used after exiting Plan mode
Execution API key env ANTHROPIC_API_KEY Optional separate key for execution requests
Proxy port 7777 Local port for the proxy daemon

2. Install the shell hook (optional but recommended)

ccm install

This appends a claude() wrapper function to your shell RC file (~/.zshrc, ~/.bashrc, or ~/.config/fish/config.fish). After that, typing claude in any terminal automatically:

  1. Checks whether the ccm proxy daemon is already running
  2. Starts it in the background if it isn't
  3. Launches Claude Code with ANTHROPIC_BASE_URL pointing at the proxy

Restart your terminal (or source ~/.zshrc) once after running ccm install. Running ccm install again is safe — it detects the existing hook and does nothing.

If you prefer not to use the hook, just replace claude with ccm in your workflow — they are equivalent.

Usage

# One-time install so `claude` routes through ccm automatically
ccm install

# Then use `claude` as normal — ccm handles the rest
claude
claude --continue
claude "fix the failing test in auth.spec.ts"

Or, without the shell hook, replace claude with ccm:

# Start a new session
ccm

# Pass any claude arguments as normal
ccm --continue
ccm "fix the failing test in auth.spec.ts"
ccm --model claude-opus-4-6   # override per-session if needed

# Check which model is currently active
ccm status

# Stop the background proxy daemon
ccm stop

Terminal output

On startup:

[ccm] plan: claude-opus-4-6  →  exec: claude-sonnet-4-6  |  port 7777

When Claude exits Plan mode:

[ccm] plan → execution  |  now using: claude-sonnet-4-6

On a 429 rate limit:

[ccm] rate limited  |  claude-opus-4-6 → claude-sonnet-4-6

Configuration

~/.ccm/config.json (created by ccm setup):

{
  "planModel": "claude-opus-4-6",
  "planApiKey": null,
  "planBaseUrl": "https://api.anthropic.com",
  "executionModel": "claude-sonnet-4-6",
  "executionApiKey": null,
  "executionBaseUrl": null,
  "fallbackChain": [
    { "model": "claude-sonnet-4-6", "apiKey": null },
    { "model": "claude-haiku-4-5-20251001", "apiKey": null }
  ],
  "proxyPort": 7777
}

Setting an apiKey to null falls back to the ANTHROPIC_API_KEY environment variable.

Using different API keys per model

If you have multiple Anthropic accounts (e.g. a high-tier account for planning and a standard account for execution), configure keys explicitly:

{
  "planModel": "claude-opus-4-6",
  "planApiKey": "sk-ant-opus-key...",
  "planBaseUrl": "https://api.anthropic.com",
  "executionModel": "claude-sonnet-4-6",
  "executionApiKey": "sk-ant-sonnet-key...",
  "executionBaseUrl": "https://api.anthropic.com",
  "fallbackChain": [
    { "model": "claude-haiku-4-5-20251001", "apiKey": "sk-ant-fallback-key..." }
  ]
}

Using Azure / Bedrock / custom endpoints

Set planBaseUrl and/or executionBaseUrl to your provider's endpoint. The proxy forwards all headers including anthropic-version and x-api-key as-is (replacing x-api-key with the configured key for the active model).

API compatibility

ccm only works with endpoints that speak the Anthropic Messages API format. It will not work with OpenAI-compatible APIs (e.g. Ollama, local models, or any provider using Authorization: Bearer + OpenAI request/response shapes).

Provider Compatible Notes
Anthropic API Yes Default
AWS Bedrock (Claude models) Yes Set planBaseUrl/executionBaseUrl to your Bedrock endpoint
Azure AI (Claude models) Yes Set planBaseUrl/executionBaseUrl to your Azure endpoint
LiteLLM Yes Only when configured in Anthropic-format passthrough mode
OpenAI API No Different auth header and request/response format
Ollama / local models No OpenAI-compatible format only

The proxy relies on three Anthropic-specific details that have no OpenAI equivalent:

  • Auth via x-api-key header (not Authorization: Bearer)
  • Request body with a model field inside POST /v1/messages
  • SSE events shaped as content_block_start with tool_use type, used to detect the exit_plan_mode transition

Proxy daemon

The proxy runs as a background daemon process. It starts automatically when you run ccm and persists between sessions on the same machine (so subsequent ccm invocations start instantly).

The daemon's PID is stored in ~/.ccm/state.json. If the process dies unexpectedly, ccm restarts it automatically on the next launch.

To stop it manually:

ccm stop

Uninstall

To completely remove ccm from your system:

# Stop the proxy daemon
ccm stop

# Uninstall the npm package
npm uninstall -g claude-model-router

# Remove configuration and state files
rm -rf ~/.ccm

# Remove the shell hook from your shell RC file
# For zsh:
sed -i '' '/# ccm shell hook/,+1d' ~/.zshrc
# For bash:
sed -i '/# ccm shell hook/,+1d' ~/.bashrc
# For fish:
# Edit ~/.config/fish/config.fish and remove the ccm section

After removing the shell hook, restart your terminal or run source ~/.zshrc (or source ~/.bashrc).

License

MIT

About

Automatic model routing for Claude Code - smart plan/execution model switching with 429 fallback

Topics

Resources

License

Stars

Watchers

Forks

Contributors