The Problem

Developers using Claude Code need a way to route requests to different LLM providers, apply request/response transformations, and manage models from the command line. Without a router they must edit Claude Code’s config manually or write ad‑hoc scripts, which is error‑prone and hard to version.

What This Does

claude-code-router sits between Claude Code and the underlying model APIs. It reads a JSON config (~/.claude-code-router/config.json) and, based on the request type, selects a provider (OpenRouter, Gemini, Ollama, etc.) and applies a transformer chain. The core logic lives in packages/core/src (transformers, plugin manager, server) while the CLI front‑end lives in packages/cli/src. The documentation site (docs/src/pages/index.tsx) and the example presets (examples/*.json) illustrate typical usage.

How It Is Wired

  1. Entry point – the CLI is launched via packages/cli/src/cli.ts (main function, line 99).
  2. main parses arguments (via @inquirer/prompts) and calls run in packages/cli/src/utils/index.ts (line 186).
  3. run creates a readline interface, then invokes getServer from packages/server/src/index.ts.
  4. getServer constructs an Express app (packages/core/src/server.ts:createApp) and registers routes from packages/core/src/api/routes.ts.
  5. When a Claude Code request arrives, the route handler calls registerNamespace → initialize → registerDefaultTransformersInternal (see the call chain start → registerNamespace → initialize → registerDefaultTransformersInternal). This iterates Object.values(Transformers) and triggers each transformer (e.g., packages/core/src/transformer/anthropic.transformer.ts, openai.responses.transformer.ts).
  6. The selected transformer calls the underlying model SDK (10 distinct functions across the repo, e.g., post in packages/server/src/index.ts). These are the only outward‑facing calls: they perform HTTP requests to provider endpoints.
  7. After the model response returns, the transformer chain may modify the payload before the server sends it back to Claude Code.

Blast‑radius hotspots – packages/core/src/types/llm.ts and packages/core/src/types/transformer.ts are imported by 17 other modules each, making them high‑impact “hub” modules. The import cycle among packages/core/src/types/llm.ts, packages/core/src/types/transformer.ts, and packages/cli/src/utils/index.ts adds instability (instability = 1). The most‑connected functions (cn, delete, post) are called from dozens of places, so changes there ripple widely.

How To Use It

# 1. Install Claude Code (global)
npm install -g @anthropic-ai/claude-code

# 2. Install the router (global)
npm install -g @musistudio/claude-code-router

# 3. Create a config (example path shown in README)
cat > ~/.claude-code-router/config.json <<'EOF'
{
  "PROXY_URL": "http://127.0.0.1:7890",
  "LOG": true,
  "LOG_LEVEL": "debug",
  "APIKEY": "your-secret-key",
  "HOST": "127.0.0.1"
}
EOF

# 4. Start the router server (CLI command)
ccr start   # implemented in packages/cli/src/cli.ts

# 5. Switch models from Claude Code
/model gpt-4   # routed through the `/model` command handled by the transformer chain

All commands are documented under docs/docs/cli/commands/ and the example presets (examples/simple-preset-example.json) show how to declare provider‑specific settings.

Real‑World Use

A CI pipeline can run unit tests, then invoke ccr start in a Docker container (see packages/server/Dockerfile). A GitHub Action can call ccr model list to verify that the correct provider is selected before deploying code generation steps. Because the router logs both server‑level (pino files) and application‑level events, operators can audit which model answered a given request.

Code Health & Issues

  • High – Pin GitHub Actions – .github/workflows/* uses version tags (@v4, @v3). Replace with 40‑char commit SHAs to avoid supply‑chain attacks.
  • High – No test suite – 157 source files, 0 test files. Add at least one test per public entry point and run them in CI.
  • Medium – Enable Dependabot – No dependabot.yml; add to keep dependencies patched.
  • Medium – Use lockfile in CI – Workflows run npm install; switch to npm ci (or pnpm install --frozen-lockfile).
  • Medium – Pin Docker base image – node:20-alpine should be referenced by digest.
  • Medium – Add vulnerability scan – No dependency‑review step; integrate osv-scanner or dependency-review-action.
  • Medium – Checkout without persisting credentials – Add persist-credentials: false to the checkout step.
  • Medium – Run as non‑root – Dockerfile lacks a non‑root USER.
  • Low – Job timeouts – .github/workflows/docker-publish.yml omits timeout-minutes.
  • Low – Repository conventions – Missing .editorconfig, .gitattributes, and formatter config.

Additional observations: the repo includes a full Docusaurus site, Docker support, and CI, but lacks automated tests and some hardening best practices identified above.

The Bottom Line

claude-code-router provides a concrete, extensible way to route Claude Code requests across multiple LLM providers and apply custom transformations, with a clear CLI and server architecture. However, the lack of tests, the presence of import cycles, and several security‑hardening gaps mean the codebase needs prudent review before production deployment. It is suitable for teams comfortable tweaking TypeScript monorepos and willing to add the missing test and hardening steps.