← back to gallery

Claude Code Swap

Every LLM you can drop into Claude Code with one env-var swap. Live pricing & cache discount.

dev-toolsclaude-codeanthropic-protocolllm-pricingdrop-inopenrouterleaderboardcache-discountdeveloper-tools
Open product ↗

cc-swap

Every LLM you can drop into Claude Code (or any Anthropic Messages SDK) with one env-var swap. Live pricing, context window, cache discount, and ready-to-copy ANTHROPIC_BASE_URL setup.

What

Anthropic, z.ai, Moonshot, and Alibaba's DashScope all expose Anthropic-Messages-protocol endpoints — meaning you can point Claude Code or any Anthropic SDK at them by changing two env vars (ANTHROPIC_BASE_URL + ANTHROPIC_AUTH_TOKEN) and nothing else. Other providers (OpenAI, Google, DeepSeek, MiniMax, ...) need a translation gateway like LiteLLM in front. cc-swap is a live, public, no-auth board that lists every model under both buckets — with current pricing, cache discount, context window, and a copy-pasteable setup snippet.

Why

How (data)

| Source | URL | Used for | Refresh |
| --- | --- | --- | --- |
| OpenRouter Models API | https://openrouter.ai/api/v1/models | Every model's id, name, context, prompt/completion/cache-read pricing | every 30 minutes (cron /30 *) |
| Static compat map | data/compat_tiers.json | Anthropic-protocol compatibility tier + base URL + provider docs link | hot-reloadable on POST /api/refresh |

The compat map's base URLs and docs URLs are publicly documented facts (e.g. https://api.z.ai/api/anthropic, https://docs.z.ai/guides/develop/claude/introduction) sourced from each provider's docs. They are not synthesized data — they're configuration constants, like saying "Postgres listens on 5432". All changing data points (pricing, context window, cache-read price, model presence/removal) come from the OpenRouter live fetch.

No mock data. No seed data. No Math.random. If OpenRouter is unreachable on boot, the table is empty until the first successful refresh.

Endpoints

All public — no authentication. Reads and the manual refresh trigger are equally open.

| Method | Path | Notes |
| --- | --- | --- |
| GET | /cc-swap/ | Single-page board (vanilla JS, no framework) |
| GET | /cc-swap/health | Orchestrator smoke-check; returns 200 with model count + last refresh |
| GET | /cc-swap/api/models | All models, with computed session_cost_usd and cache_discount_pct. Query: ?compat=native,gateway&provider=Anthropic,z.ai (Zhipu)&min_context=200000&sort=session_cost&limit=200 |
| GET | /cc-swap/api/model/:id | One model + last 30 days of price points |
| GET | /cc-swap/api/stats | Counts by tier and provider, cheapest native, cheapest gateway, last refresh |
| GET | /cc-swap/api/compat | The loaded compat-tier map (for transparency / debugging) |
| GET | /cc-swap/api/refresh-log | Last 50 refresh attempts |
| POST | /cc-swap/api/refresh | Manual refresh. Mutex-guarded; rate-limited server-side to 1 / 60 seconds |

Compat tiers

| Tier | Meaning |
| --- | --- |
| native | Provider ships a public Anthropic Messages protocol endpoint. Drop-in via ANTHROPIC_BASE_URL only. |
| gateway | No native Anthropic endpoint — bridge via LiteLLM, Vercel AI Gateway, or OpenRouter's anthropic-compat shim. |
| unknown | Provider not yet in data/compat_tiers.json. Falls through here. |

Synthetic session cost

For ranking purposes, every model gets a "session cost" = the cost of one typical Claude Code session:

session_cost_usd = (cache_read_per_mtok ?? prompt_per_mtok) * 0.18    // 180K cached input
                 + prompt_per_mtok * 0.02                              // 20K fresh input
                 + completion_per_mtok * 0.03                          // 30K output

This is a sorting lever, not a guarantee for any specific workflow — but it surfaces the bang-for-buck winners that pure input-price sorts miss (cache-heavy agent loops benefit massively from high cache discount, regardless of headline input price).

Run

npm install
cp .env.example .env
npm start
# open http://127.0.0.1:4903/cc-swap/

Requires Node 18+ (for global fetch) and better-sqlite3 build dependencies.

Environment

| Var | Default | Notes |
| --- | --- | --- |
| PORT | 4903 | HTTP port |
| BASE_PATH | /cc-swap | Mount prefix (must match nginx route) |
| DB_PATH | ./cc-swap.db | SQLite file (WAL mode) |
| REFRESH_CRON | /30 * | UTC |
| OPENROUTER_URL | https://openrouter.ai/api/v1/models | Override only for testing |

No API keys required. OpenRouter /models is anonymously fetchable.

File layout

cc-swap/
  server.js                # express bootstrap, helmet, compression, cron, boot refresh
  db.js                    # better-sqlite3 (WAL) + migrations
  fetchers/openrouter.js   # the fetch/classify/upsert worker
  routes/api.js            # all /api/* handlers
  data/compat_tiers.json   # static prefix -> compat-tier map (provider docs sourced)
  public/
    index.html
    app.js                 # vanilla JS SPA
    style.css              # dark theme
  package.json
  .env.example
  README.md                # this file
  CLAUDE.md                # tips for future Claude Code sessions
  SPEC.md                  # original product spec
  DEPLOY_MANIFEST.json     # RNDLAB orchestrator manifest

License

MIT.