Switch between 40+ third-party models mid-conversation — no restarts, no config editing.
ccmr is a lightweight gateway that runs on your machine: Claude Code talks to it, and it forwards every request verbatim to whichever model you pick — DeepSeek, Kimi, Qwen, GLM, MiniMax, Step, MiMo or Doubao Seed, 42 models across 8 vendors, all prewired. Type /model kimi in a session and the very next message runs on Kimi. When a key dies, the error tells you exactly which env var to fix, where to get a new key, and the command that verifies it. Config edits hot-reload in about a second. Loopback-only by default; everything stays local.
English · 简体中文
$ npx claude-code-model-router@latest setup
Providers (key status from environment and .env):
1. DeepSeek DEEPSEEK_API_KEY [no key]
2. Kimi KIMI_API_KEY [no key]
... (18 entries, console URLs included)
Configure which providers? 1
Paste DEEPSEEK_API_KEY for DeepSeek (get one: https://platform.deepseek.com/): ********
Verify keys now with one tiny request per provider? [y/N] y
[OK] deepseek-v4-pro
Default model [deepseek-flash] (Enter = accept):
$ ccmr claude # into Claude Code — switch freely, in-session:
> /model kimi # last message was DeepSeek, this one is Kimi
> /model glm # and now GLM-5.3
For most setups, switching models means editing env vars or config files and restarting Claude Code. ccmr is a live gateway: switching happens inside the session (/model, effective on the next message, context preserved), because Claude Code always faces one stable local address — the change happens behind it.
| Manual env editing | Config switchers | ccmr | |
|---|---|---|---|
| Switching models | Edit file + restart | Edit file + restart | /model in-session, instant |
| Conversation context | Lost on restart | Lost on restart | Preserved |
| Built-in models | Fill in per-vendor endpoints/IDs | Enter per vendor | 42 models / 8 vendors prewired, alias to pick |
| Key health | You find out on failure | — | ccmr doctor: one tiny real request per model |
| On a 401 | One raw passthrough line | — | Vendor text kept + which var, which console, which command |
| Usage stats | — | — | Per-model requests / errors / tokens |
| Failover | — | — | 5xx/429 falls through your fallback chain |
| Hot reload | — | — | models.yaml/.env edits live in ~1s |
| Alongside your subscription | — | Often collide | Isolated config dir; claude and ccmr claude never touch each other |
Honest scope: ccmr is an Anthropic-protocol passthrough gateway — it does no protocol conversion and only talks to vendors' official Anthropic-compatible endpoints (that's why Zhipu CN is supported via its Coding Plan only: its pay-as-you-go side offers no Anthropic endpoint). Streaming, tool calls and thinking blocks are forwarded as-is; your context is never parsed or rewritten.
# One command: pick providers → paste keys (hidden input) → optional live
# verification → set the default model
npx claude-code-model-router@latest setup # the gateway auto-starts when needed
# Start Claude Code (third-party models, gateway mode)
npx claude-code-model-router claude
# Or install globally and use ccmr directly
npm install -g claude-code-model-router
ccmr setup
ccmr claude# CI / scripts (no prompts): takes keys from the environment, verifies each
# provider, exits 1 if every validation fails
DEEPSEEK_API_KEY=sk-... npx claude-code-model-router setup --yes --validateYou can also run the gateway in the foreground with
ccmr start(logs in your terminal); gateways auto-started byccmr claudelog to~/.ccmr/gateway.log. Plainclaudestill uses your official subscription — the two modes have fully isolated configs.
ccmr init # Generate config files (.env is gitignored automatically inside a git repo)
ccmr init --global # Write to ~/.ccmr so every directory shares one config
ccmr setup # Guided key setup: hidden input, optional per-provider verification
ccmr setup --yes --validate # Non-interactive (CI): env keys + verification
ccmr start # Run the gateway in the foreground (config hot-reloads, no restarts)
ccmr start --port 9000 --host 0.0.0.0 # custom port / LAN (auth token required)
ccmr status # List running gateways (port / PID / version / config source / key status)
ccmr stop [--port N | --all] # Stop gateways (identity-verified, not by port alone)
ccmr models # List models; * marks the default, per-model key status included
ccmr use kimi # Set the default model (persisted; a running gateway picks it up live)
ccmr doctor # Connectivity check: one tiny real request per keyed model,
# surfacing dead keys / unactivated models / wrong endpoints verbatim
ccmr stats # Per-model usage from the running gateway (names the port it read)
ccmr claude # Launch Claude Code through the gateway (auto-starts it if needed)
ccmr update # Update ccmr itself from npm (--check to only look)Config discovery:
-c path>./models.yaml>./config/models.yaml>./.claude-router.yaml>~/.ccmr/models.yaml. An explicit-cthat is missing or invalid errors out — it never silently falls back to another file..envloads as~/.ccmr/.env<./.env< the config-adjacent.env, with parent-process env vars winning over all files (CCMR_HOMErelocates the global dir).
| Started by | After you close the terminal | Logs |
|---|---|---|
ccmr start |
Exits (foreground process) | Your terminal |
Auto-started by ccmr claude |
Keeps running (detached, own process group) | ~/.ccmr/gateway.log |
The auto-started gateway intentionally survives its terminal so several Claude Code sessions can share it; it also can't be confused with another project's gateway — ccmr claude compares config paths, routing contents and irreversible key digests before reusing one, and refuses when they don't match. ccmr stop verifies both the /health identity and a local random identity file before signalling anything.
Security: the gateway binds to
127.0.0.1by default and proxies with your local vendor keys — anyone who can reach the port can spend your quota. Exposing it (--host 0.0.0.0) requiresCCMR_REQUIRED_AUTH_TOKEN(callers send it asx-api-keyorAuthorization: Bearer); without the token the gateway refuses to start rather than listen in the clear. Unauthenticated remote/healthreturns only bare liveness.
ccmr claude passes through every native flag:
ccmr claude --dangerously-skip-permissions # YOLO mode
ccmr claude --continue # resume the latest session
ccmr claude --resume <session-id> # resume a specific session
ccmr claude -p "question" --output-format json # headless / scripting
ccmr claude --model glm-flash # one-off model override
ccmr claude --permission-mode acceptEdits --ideccmr claude injects isolated env vars for gateway mode only — CLAUDE_CONFIG_DIR=~/.claude-gateway, ANTHROPIC_BASE_URL=127.0.0.1:<port>, plus the default model. Models with a ≥1M context window get the [1m] suffix automatically (the only marker Claude Code honors to actually open 1M context; the gateway strips it before upstream), and CLAUDE_CODE_AUTO_COMPACT_WINDOW is sized from the launch model so Claude Code doesn't clip third-party models to ~200k. Nothing touches your official ~/.claude config.
42 models across 8 vendors; short names and version aliases both work everywhere (/model, ccmr use, --model).
| Model | Aliases | Provider |
|---|---|---|
deepseek-v4-pro |
deepseek, deepseek-v4, deepseek-pro, ds |
DeepSeek (vendor is retiring it; routes to V4.1 Flash from 09-14) |
deepseek-flash |
deepseek-chat, ds-4.1, deepseek-vision, … |
DeepSeek V4.1 Flash (natively multimodal) |
kimi-k3 / kimi-k2.6 / kimi-k2.7-code / kimi-k2.7-code-highspeed |
kimi, k3, moonshot, kimi-code, … |
Moonshot (global) |
kimi-cn-* (same four) |
kimi-cn, moonshot-cn, … |
Moonshot (CN open platform) |
kimi-plan-k3-1m / kimi-plan-k3 / kimi-plan-for-coding / kimi-plan-for-coding-highspeed |
kimi-plan, kimi-for-coding |
Kimi Code membership (coding plans) |
minimax-m3 |
minimax, mm |
MiniMax CN |
minimax-global-m3 |
minimax-global, minimax-io |
MiniMax Global |
qwen3.8-max / qwen3.7-max / qwen3.8-flash |
qwen, tongyi, qwen-max, qwen-flash |
Alibaba Cloud (pay-as-you-go) |
qwen-plan-3.8-max / qwen-plan-3.7-max / qwen-plan-3.8-flash |
qwen-plan, qwen-plan-max, … |
Qwen Token Plan (subscription) |
glm-plan-5.3 / glm-plan-5.2 / glm-plan-5.3-flash |
glm, zhipu, chatglm, glm-flash |
Zhipu GLM Coding Plan (subscription) |
glm-global-5.3 / glm-global-5.2 / glm-global-5.3-flash |
glm-global, zai, zai-flash |
Z.ai (international) |
step-5-preview |
step, step-5, stepfun |
StepFun (pay-as-you-go) |
step-plan-5-preview |
step-plan, stepplan |
StepFun Step Plan (subscription) |
mimo-v2.5-pro / mimo-v2.5 |
mimo, mimo-pro, xiaomi |
MiMo Token Plan (SGP) |
mimo-token-cn-v2.5-pro / mimo-token-ams-v2.5-pro |
mimo-cn, mimo-ams |
MiMo Token Plan (CN / AMS clusters) |
mimo-payg-v2.5-pro |
mimo-payg |
MiMo pay-as-you-go |
seed-2.1-pro / seed-2.1-turbo |
seed, doubao, seed-turbo |
Volcengine Ark (pay-as-you-go) |
seed-plan-2.1-pro / seed-plan-2.1-turbo |
seed-plan, doubao-plan |
Volcengine Ark (Agent Plan) |
Run ccmr models for the authoritative list with per-model key status, or see the Chinese README for the full alias table and the context-window/max-output matrix.
Claude Code's built-in Web Search is a server-side tool — whether it actually executes depends on the vendor implementing it. Measured (2026-07-17, one real web_search request each): supported by Moonshot CN, DeepSeek and MiniMax CN; silently ignored by Zhipu GLM and Qwen pay-as-you-go (Did 0 searches). Unmeasured vendors vary — check with ccmr doctor-style realism, and for models without it, add a client-side MCP search tool (claude mcp add tavily -- npx -y tavily-mcp), which runs locally regardless of model. WebFetch is client-side and works everywhere.
ccmr setup is the guided path; editing .env by hand works too:
DEEPSEEK_API_KEY=sk-xxx # https://platform.deepseek.com/
KIMI_API_KEY=sk-xxx # Kimi global: https://platform.kimi.ai/
KIMI_CN_API_KEY=sk-xxx # Kimi CN platform: https://platform.kimi.com/
KIMI_CODE_API_KEY=sk-xxx # Kimi Code membership: https://www.kimi.com/code/console
MINIMAX_API_KEY=xxx # https://platform.minimaxi.com/
MINIMAX_GLOBAL_API_KEY=xxx # https://platform.minimax.io/
QWEN_API_KEY=sk-xxx # https://dashscope.console.aliyun.com/
QWEN_PLAN_API_KEY=sk-sp-xx # Qwen Token Plan: https://platform.qianwenai.com/
GLM_PLAN_API_KEY=xxx # GLM Coding Plan: https://bigmodel.cn/claude-code
GLM_GLOBAL_API_KEY=xxx # Z.ai: https://z.ai/model-api
ARK_API_KEY=xxx # Volcengine Ark: https://console.volcengine.com/ark
ARK_PLAN_API_KEY=xxx # Volcengine Agent Plan key
STEP_API_KEY=xxx # https://platform.stepfun.com/
STEP_PLAN_API_KEY=xxx # StepFun Step Plan
MIMO_API_KEY=tp-xxx # MiMo Token Plan (SGP)
MIMO_TOKEN_CN_API_KEY=tp-xxx # MiMo Token Plan (CN cluster)
MIMO_TOKEN_AMS_API_KEY=tp-xxx # MiMo Token Plan (AMS cluster)
MIMO_PAYG_API_KEY=sk-xxx # https://platform.xiaomimimo.com/
GATEWAY_PORT=8080 # optional overrides
REQUEST_TIMEOUT=300
LOG_LEVEL=INFO # DEBUG / INFO / WARN / ERROR / SILENT
CCMR_REQUIRED_AUTH_TOKEN= # required when binding non-loopbackMiMo Token Plan keys (tp-*) are cluster-bound — use the CN/AMS vars if your subscription page shows those clusters. Zhipu CN supports Coding Plan subscriptions only on its Anthropic endpoint (pay-as-you-go keys get 429 [1309]; no conversion is done — see the honesty note above).
ccmr init generates a full providers → variants template you can customize: your own vendors, model IDs, aliases, per-variant fallback chains. Edits hot-reload in ~1s (keys, routes, even the inbound auth token); only gateway.host/gateway.port need a restart. Diagnosing which config a gateway actually uses:
curl -s :8080/health | jq '{version, config_file, ccmr_home, default_model}'Config discovery is cwd-first: a ./models.yaml wins over ~/.ccmr/models.yaml (each merges over built-in defaults); .env merges per-variable with project > global, shell env above both. Keys in a project .env make that gateway project-scoped — ccmr claude from other directories refuses to reuse it (cross-project protection). ccmr init --global + keys in ~/.ccmr/.env gives you ccmr claude from anywhere. Common combo: global keys, per-project models.yaml where routing differs.
Any variant can declare a fallback chain; upstream 5xx/429/connection failures walk it in order. Client errors (4xx) never trigger failover, and switching stops once a stream has produced output:
providers:
deepseek:
variants:
v4-pro:
model_id: deepseek-v4-pro
fallback: [kimi-k2.6, glm-plan-5.2]┌──────────────────────────────────────────────┐ ┌──────────────────────────────────────────────┐
│ Official subscription │ │ Third-party models (gateway) │
│ command: claude │ │ command: ccmr claude │
│ config: ~/.claude │ │ config: ~/.claude-gateway (isolated) │
│ uses: Claude official models │ │ uses: DeepSeek / GLM / Qwen / Kimi / … │
└──────────────────────────────────────────────┘ └──────────────────────────────────────────────┘
Switching models in gateway mode never touches your official setup. In-session switching:
> /model deepseek # DeepSeek
> /model qwen-plan # Qwen3.8 Max via Token Plan
> /model glm # GLM-5.3 via Coding Plan
> /model step # Step 5 Preview
> /model kimi-highspeed # Kimi K2.7 Code HighSpeed
| Endpoint | Method | Purpose |
|---|---|---|
/v1/messages |
POST | Anthropic Messages API (passthrough) |
/v1/messages/count_tokens |
POST | Forwarded to the vendor's compatible endpoint |
/v1/models |
GET | Model list (what /model consumes) |
/usage |
GET | Per-model usage counters (reset on gateway restart) |
/health |
GET | Liveness; loopback/authenticated callers also get PID, config source, key status |
Step zero, always: ccmr doctor. One tiny real request per keyed model answers most "model X doesn't work" cases: dead key, unactivated model, wrong endpoint — with the vendor's verbatim error.
- Port busy →
ccmr start --port 9000 - API key errors →
ccmr doctorshows the upstream text; fix.env(hot-reloads, no restart);ccmr modelsshows key status ccmr clauderefused after changing directories → your keys are project-scoped; runccmr init --globaland put keys in~/.ccmr/.envDid 0 searches→ the vendor doesn't implement server-side Web Search; see the table above and the MCP alternative- "Region not supported" → you ran plain
claude; gateway mode isccmr claude(it setsANTHROPIC_BASE_URL/auth locally, skipping the official login/region path) - DeepSeek
Invalid user_id→ handled by the gateway (it strips the metadata field that some sessions carry)
git clone https://github.com/luwill/Claude-Code-Model-Router.git && cd Claude-Code-Model-Router
npm install
npm run check # typecheck + tests + build + smoke + audit
npm test # vitest, fast and offlineccmr setup: one guided command — provider table with key status, hidden key input, optional per-provider live verification (the same tiny requestdoctorsends),.envwritten in place (gitignored automatically), default model set.--yesruns non-interactively from env keys;--validateexits 1 when every provider fails (a CI gate that can actually fail).- Self-healing key errors: a 401 now names the env var, the vendor console URL, and the
ccmr doctorcommand — on the streaming path too, with the vendor's original text preserved. ccmr modelsmarks the default model (*+ legend);ccmr statsnames the gateway port it read.- Honesty regression-locks across
listModels//v1/models//health;console_urlpinned by consistency tests across DEFAULT_CONFIG, the YAML template and the.envcomments.
Full history (v1.8.0 → v1.21.0, in Chinese) lives in README.zh-CN.md.