@timo972/cc-router 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (74) hide show
  1. package/CHANGELOG.md +96 -0
  2. package/Dockerfile +42 -0
  3. package/LICENSE +21 -0
  4. package/README.md +716 -0
  5. package/accounts.example.json +25 -0
  6. package/dist/cli/cmd-accounts.js +248 -0
  7. package/dist/cli/cmd-client.js +612 -0
  8. package/dist/cli/cmd-configure.js +145 -0
  9. package/dist/cli/cmd-docker.js +140 -0
  10. package/dist/cli/cmd-logs.js +85 -0
  11. package/dist/cli/cmd-models.js +125 -0
  12. package/dist/cli/cmd-service.js +193 -0
  13. package/dist/cli/cmd-setup.js +501 -0
  14. package/dist/cli/cmd-start.js +318 -0
  15. package/dist/cli/cmd-status.js +177 -0
  16. package/dist/cli/cmd-stop.js +100 -0
  17. package/dist/cli/cmd-telemetry.js +58 -0
  18. package/dist/cli/cmd-update.js +37 -0
  19. package/dist/cli/index.js +59 -0
  20. package/dist/config/manager.js +262 -0
  21. package/dist/config/paths.js +21 -0
  22. package/dist/config/telemetry.js +64 -0
  23. package/dist/daemon/launcher.js +163 -0
  24. package/dist/daemon/pid.js +98 -0
  25. package/dist/daemon/service.js +260 -0
  26. package/dist/interceptor/mitmproxy-manager.js +616 -0
  27. package/dist/protocol/anthropic-to-openai.js +51 -0
  28. package/dist/protocol/anthropic-types.js +1 -0
  29. package/dist/protocol/model-ref.js +36 -0
  30. package/dist/protocol/model-routing-config.js +30 -0
  31. package/dist/protocol/openai-response-to-anthropic.js +20 -0
  32. package/dist/protocol/openai-responses-types.js +1 -0
  33. package/dist/protocol/openai-stream-to-anthropic.js +75 -0
  34. package/dist/protocol/openai-to-anthropic.js +61 -0
  35. package/dist/protocol/sse.js +17 -0
  36. package/dist/providers/model-discovery.js +71 -0
  37. package/dist/providers/openai/account-pool.js +11 -0
  38. package/dist/providers/openai/account-record.js +33 -0
  39. package/dist/providers/openai/codex-transport.js +36 -0
  40. package/dist/providers/openai/device-oauth.js +116 -0
  41. package/dist/providers/openai/token-refresher.js +56 -0
  42. package/dist/providers/route-selector.js +8 -0
  43. package/dist/providers/types.js +1 -0
  44. package/dist/proxy/account-deletion.js +44 -0
  45. package/dist/proxy/anthropic-proxy.js +26 -0
  46. package/dist/proxy/anthropic-routing.js +90 -0
  47. package/dist/proxy/lease-lifecycle.js +68 -0
  48. package/dist/proxy/logger.js +39 -0
  49. package/dist/proxy/messages-cross-route.js +179 -0
  50. package/dist/proxy/models-server.js +150 -0
  51. package/dist/proxy/provider-routing.js +14 -0
  52. package/dist/proxy/responses-server.js +91 -0
  53. package/dist/proxy/server.js +875 -0
  54. package/dist/proxy/session-router.js +171 -0
  55. package/dist/proxy/stats.js +25 -0
  56. package/dist/proxy/stream-lifecycle.js +83 -0
  57. package/dist/proxy/token-pool.js +407 -0
  58. package/dist/proxy/token-refresher.js +209 -0
  59. package/dist/proxy/types.js +29 -0
  60. package/dist/ui/Dashboard.js +640 -0
  61. package/dist/ui/accountsApi.js +48 -0
  62. package/dist/ui/modelsApi.js +47 -0
  63. package/dist/utils/claude-config.js +185 -0
  64. package/dist/utils/codex-config.js +62 -0
  65. package/dist/utils/network.js +16 -0
  66. package/dist/utils/platform.js +13 -0
  67. package/dist/utils/self-update.js +239 -0
  68. package/dist/utils/telemetry.js +88 -0
  69. package/dist/utils/token-extractor.js +95 -0
  70. package/dist/utils/token-validator.js +26 -0
  71. package/docker-compose.yml +63 -0
  72. package/litellm-config.yaml +44 -0
  73. package/package.json +69 -0
  74. package/src/interceptor/addon.py +78 -0
package/README.md ADDED
@@ -0,0 +1,716 @@
1
+ # CC-Router
2
+
3
+ **Local multi-account router for Claude Max and OpenAI ChatGPT/Codex subscriptions.**
4
+ Distribute Claude Code requests across Claude subscriptions, and expose an OpenAI Responses-compatible route for Codex CLI through the same proxy.
5
+
6
+ [![npm](https://img.shields.io/npm/v/@timo972/cc-router)](https://www.npmjs.com/package/@timo972/cc-router)
7
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)
8
+
9
+ > **An actively maintained fork of [VictorMinemu/CC-Router](https://github.com/VictorMinemu/CC-Router)**, published as
10
+ > [`@timo972/cc-router`](https://www.npmjs.com/package/@timo972/cc-router) with bug fixes and added features — most
11
+ > notably **cache-aware sticky session routing**, which pins each Claude Code session to one account so a conversation
12
+ > keeps hitting the same prompt cache instead of scattering its shared prefix across accounts. Also includes
13
+ > load-aware account leases, byte-transparent streaming fixes, and a round of security hardening.
14
+ > See [CHANGELOG.md](CHANGELOG.md) for the full list.
15
+
16
+ ![CC-Router Dashboard](assets/dashboard.png)
17
+
18
+ ### Features
19
+
20
+ - **Cache-aware session routing** — keep each Claude Code session on one account while distributing new sessions across 2-20 Claude Max accounts
21
+ - **Multi-provider routing** — route `openai/*` models to OpenAI ChatGPT/Codex subscription accounts and Claude models to Claude subscriptions
22
+ - **Transparent Claude proxy** — Claude Code works normally; streaming, thinking, tool use, prompt caching all pass through
23
+ - **Codex CLI support** — configure Codex to use CC-Router as a Responses-compatible provider
24
+ - **Automatic token refresh** — OAuth tokens are refreshed before they expire, saved atomically to disk
25
+ - **Rate limit awareness** — detects 429/529 responses and coolsdown accounts; picks the least-loaded one
26
+ - **Client mode** — connect to a remote CC-Router from any machine with one command (`cc-router client connect <url>`)
27
+ - **Claude Desktop support** — route Cowork / Agent-mode traffic through CC-Router via mitmproxy interception (macOS, Windows, Linux)
28
+ - **Guided setup wizard** — interactive `cc-router setup` extracts tokens from Keychain or credentials file, configures everything
29
+ - **Live dashboard** — real-time terminal UI showing account health, request counts, token usage, recent activity
30
+ - **Proxy authentication** — Bearer / x-api-key secret; required when binding a non-loopback interface
31
+ - **Update notifications** — new releases are announced in the CLI; installing is opt-in (`autoUpdate: true`)
32
+ - **Multiple deployment modes** — background daemon, native OS auto-start (launchd/systemd), foreground, Docker Compose
33
+ - **Cross-platform** — macOS, Linux, Windows; Node.js 20+
34
+
35
+ ---
36
+
37
+ > **Warning**
38
+ > Read the [disclaimer](#disclaimer) before using this tool.
39
+
40
+ ---
41
+
42
+ ## How it works
43
+
44
+ ```
45
+ Claude Code (terminal) ─┐
46
+ │ ANTHROPIC_BASE_URL=http://localhost:3456
47
+
48
+ Claude Desktop ─[mitmproxy]─┐ (optional — intercepts api.anthropic.com)
49
+
50
+
51
+ ┌─────────────────────────────────────┐
52
+ │ CC-Router :3456 │
53
+ │ │
54
+ │ 1. Receives /v1/messages or │
55
+ │ /v1/responses │
56
+ │ 2. Parses model provider prefix │
57
+ │ 3. Picks a Claude or OpenAI account│
58
+ │ 4. Refreshes token if expiring │
59
+ │ 5. Injects Authorization: Bearer │
60
+ │ 6. Forwards to Anthropic, OpenAI │
61
+ │ Codex backend, or LiteLLM │
62
+ └──────────────┬──────────────────────┘
63
+
64
+
65
+ api.anthropic.com
66
+ (authenticated with
67
+ OAuth token of account N)
68
+ ```
69
+
70
+ All standard Claude Code features work transparently on the Claude route: streaming, extended thinking, tool use, prompt caching. OpenAI subscription routing is available for Codex-compatible Responses requests and Claude Code cross-routing with the limitations documented below.
71
+
72
+ ### Cache-aware Claude account routing
73
+
74
+ CC-Router keeps requests from one Claude Code session on the same healthy Anthropic subscription account. This session affinity preserves prompt-cache locality instead of scattering a conversation's shared prefix across account-specific caches. New sessions prefer the account with the fewest in-flight requests, then the fewest bound sessions, then the most rate-limit headroom; exact ties use a rotating round-robin order.
75
+
76
+ If an upstream account returns 401, 429, or 529, CC-Router passes that response through unchanged and invalidates the session's affinity. The client's next retry can then select another usable account; the router never retries after response bytes have started. Affinity mappings exist only in process memory, expire after one hour of inactivity, and are capped in size. Session IDs are never persisted or logged.
77
+
78
+ Streaming remains byte-transparent. In particular, CC-Router never appends a synthetic `message_stop` event. `proxyRequestTimeoutMs` protects only the phase before Anthropic response headers arrive; once a response starts, its body continues through the native byte-exact proxy pipe. Automatic `cc-router configure` setup manages Claude Code's event-level and byte-level stream idle watchdogs at 30 minutes. Restart any existing Claude Code process after configuration so it inherits those values.
79
+
80
+ **Claude Desktop support** is opt-in and requires a small interceptor (mitmproxy) because Claude Desktop doesn't expose a custom API endpoint setting. See [Claude Desktop support](#claude-desktop-support).
81
+
82
+ 📖 **Running this for a team?** [docs/session-routing.md](docs/session-routing.md) covers how accounts are picked, what per-account throttles do, how to monitor affinity, and how to read the failure modes.
83
+
84
+ ---
85
+
86
+ ## Use cases
87
+
88
+ ### Heavy user — one account isn't enough
89
+
90
+ Claude Max has rate limits per account. If you hit them regularly mid-session — waiting for cooldowns, getting 429s — you're a good candidate.
91
+
92
+ With two accounts you double your effective rate limit. With three, you triple it. The proxy distributes requests automatically; you don't change how you use Claude Code at all.
93
+
94
+ ```text
95
+ 1 account → hit limit, wait 60s, continue
96
+ 3 accounts → new sessions spread across all three; each session stays cache-local
97
+ ```
98
+
99
+ ---
100
+
101
+ ### Hosting cc-router on a shared machine
102
+
103
+ Run cc-router on a machine everyone on the team can reach — a home server, a VPS, or a spare machine on the office network.
104
+
105
+ #### On the server
106
+
107
+ ```bash
108
+ npm install -g @timo972/cc-router
109
+ cc-router setup # configure the accounts
110
+ cc-router start # first run asks: background/boot/server mode — choose "server mode"
111
+ ```
112
+
113
+ When you enable server mode during `cc-router start`, the proxy automatically binds to all interfaces (`0.0.0.0`) and prints instructions for connecting clients.
114
+
115
+ #### On each developer's machine
116
+
117
+ No installation needed. Just set two environment variables in `~/.claude/settings.json`:
118
+
119
+ ```json
120
+ {
121
+ "env": {
122
+ "ANTHROPIC_BASE_URL": "http://192.168.1.50:3456",
123
+ "ANTHROPIC_AUTH_TOKEN": "proxy-managed"
124
+ }
125
+ }
126
+ ```
127
+
128
+ Replace `192.168.1.50` with the server's IP or hostname. Then run `claude` normally.
129
+
130
+ Or use the CLI to write the settings automatically:
131
+
132
+ ```bash
133
+ cc-router configure --port 3456
134
+ # Then manually update ANTHROPIC_BASE_URL to the remote IP
135
+ ```
136
+
137
+ ---
138
+
139
+ ### Hosting on a VPS (internet-accessible)
140
+
141
+ If your team is distributed or works remotely, run cc-router on a VPS and expose it over HTTPS via a reverse proxy.
142
+
143
+ #### Recommended nginx config
144
+
145
+ ```nginx
146
+ server {
147
+ listen 443 ssl;
148
+ server_name cc-router.yourcompany.com;
149
+
150
+ # ... SSL cert config (e.g. Let's Encrypt) ...
151
+
152
+ location / {
153
+ proxy_pass http://127.0.0.1:3456;
154
+ proxy_buffering off; # required for SSE streaming
155
+ proxy_read_timeout 1800s; # outer-proxy body idle timeout
156
+ proxy_set_header X-Forwarded-For $remote_addr;
157
+ }
158
+ }
159
+ ```
160
+
161
+ These settings protect different phases. CC-Router's `proxyRequestTimeoutMs` in `~/.cc-router/config.json` applies only while waiting for Anthropic response headers. An outer proxy's `proxy_read_timeout` applies while reading the response body, so configure that outer timeout separately with enough headroom for long thinking pauses. Neither timeout repairs a missing upstream terminal event, and CC-Router never synthesizes `message_stop`.
162
+
163
+ Each developer then points to:
164
+ ```json
165
+ {
166
+ "env": {
167
+ "ANTHROPIC_BASE_URL": "https://cc-router.yourcompany.com",
168
+ "ANTHROPIC_AUTH_TOKEN": "proxy-managed"
169
+ }
170
+ }
171
+ ```
172
+
173
+ **Security note:** if the proxy is internet-accessible, add authentication at the nginx level (basic auth, mTLS, or IP allowlist) so only your team can use it. cc-router does not implement user authentication itself.
174
+
175
+ ---
176
+
177
+ ## Quickstart
178
+
179
+ ```bash
180
+ # 1. Install
181
+ npm install -g @timo972/cc-router
182
+
183
+ # 2. Wizard: extract tokens + configure Claude Code automatically
184
+ cc-router setup
185
+
186
+ # 3. Start the proxy
187
+ cc-router start
188
+
189
+ # 4. Use Claude Code normally — the proxy is transparent
190
+ claude
191
+ ```
192
+
193
+ That's it. Claude Code will route through the proxy without any further changes.
194
+
195
+ On first run, `cc-router start` asks how you want to run (background/foreground, auto-start on boot, server mode) and remembers your choice. Next time, it just starts. To change preferences later:
196
+ ```bash
197
+ cc-router start --reconfigure
198
+ ```
199
+
200
+ ---
201
+
202
+ ## Installation
203
+
204
+ **Requirements:** Node.js 20 or 22.
205
+
206
+ ```bash
207
+ npm install -g @timo972/cc-router
208
+ ```
209
+
210
+ Verify:
211
+ ```bash
212
+ cc-router --version
213
+ ```
214
+
215
+ ---
216
+
217
+ ## Setup by platform
218
+
219
+ ### macOS
220
+
221
+ cc-router can extract OAuth tokens directly from the macOS Keychain — no manual copy-pasting needed.
222
+
223
+ ```bash
224
+ cc-router setup
225
+ # Select "Extract automatically from macOS Keychain"
226
+ ```
227
+
228
+ For multiple accounts, you need to switch accounts in Claude Code between extractions:
229
+ ```bash
230
+ # Account 1 is already logged in — run setup and extract
231
+ cc-router setup
232
+
233
+ # To add account 2:
234
+ claude logout && claude login # log in with account 2
235
+ cc-router setup --add # extract and merge
236
+ claude logout && claude login # log back in with account 1
237
+ ```
238
+
239
+ ### Linux
240
+
241
+ Tokens are read from `~/.claude/.credentials.json`:
242
+ ```bash
243
+ cc-router setup
244
+ # Select "Read from ~/.claude/.credentials.json"
245
+ ```
246
+
247
+ Make sure Claude Code is installed and you have run `claude login` at least once.
248
+
249
+ ### Windows
250
+
251
+ Same as Linux — tokens are read from `~/.claude/.credentials.json` (Windows path: `%USERPROFILE%\.claude\.credentials.json`).
252
+
253
+ ```bash
254
+ cc-router setup
255
+ ```
256
+
257
+ ---
258
+
259
+ ## CLI Reference
260
+
261
+ ```text
262
+ cc-router setup Interactive wizard: extract tokens + configure Claude Code
263
+ cc-router setup --add Add another account to an existing configuration
264
+
265
+ cc-router start Start proxy (asks preferences on first run, then remembers)
266
+ cc-router start --foreground Run in the foreground (stays in terminal)
267
+ cc-router start --reconfigure Re-ask run preferences (background/service/server mode)
268
+ cc-router start --litellm Start with LiteLLM in Docker (advanced mode)
269
+
270
+ cc-router stop Stop proxy (offers to remove auto-start / config)
271
+ cc-router stop --keep-config Stop proxy only (keep settings.json)
272
+ cc-router stop --full Stop + remove auto-start + revert Claude Code (no prompts)
273
+ cc-router revert Same as stop --full
274
+
275
+ cc-router status Live dashboard (updates every 2s, press q to quit)
276
+ cc-router status --json Print current stats as JSON and exit
277
+
278
+ cc-router models list List models discovered live from provider APIs
279
+ cc-router models list --json Print discovered models + routing as JSON
280
+ cc-router models set --claude-model anthropic/claude-sonnet-4-6
281
+ cc-router models set --openai-model openai/gpt-5-codex
282
+
283
+ cc-router logs View proxy logs (background mode)
284
+ cc-router logs -f Follow log output in real time
285
+ cc-router logs --lines 100 Show last 100 lines
286
+
287
+ cc-router accounts list List configured accounts (live stats if proxy is running)
288
+ cc-router accounts add Add an account interactively
289
+ cc-router accounts login-openai Sign in to OpenAI subscription auth with device code
290
+ cc-router accounts add-openai Add an OpenAI subscription account manually (experimental)
291
+ cc-router accounts remove <id> Remove a Claude or OpenAI account
292
+
293
+ cc-router configure (Re)write ~/.claude/settings.json
294
+ cc-router configure codex (Re)write ~/.codex/config.toml for Codex CLI
295
+ cc-router configure codex --model openai/gpt-5-codex
296
+ cc-router configure models --claude-model claude-sonnet-4-6 --openai-model gpt-5-codex
297
+ cc-router configure --show Show current Claude Code proxy settings
298
+ cc-router configure --remove Remove cc-router settings (same as revert without stopping)
299
+
300
+ cc-router client connect <url> Connect Claude Code to a remote CC-Router
301
+ cc-router client connect --desktop Also configure Claude Desktop interception
302
+ cc-router client disconnect Revert all client configuration
303
+ cc-router client status Show connection + remote server health
304
+ cc-router client start-desktop Start mitmproxy interceptor for Claude Desktop
305
+ cc-router client stop-desktop Stop mitmproxy interceptor
306
+
307
+ cc-router docker up Start full Docker stack (cc-router + LiteLLM)
308
+ cc-router docker up --build Rebuild cc-router image before starting
309
+ cc-router docker down Stop Docker containers
310
+ cc-router docker logs Tail all Docker logs
311
+ cc-router docker ps Show container status
312
+ cc-router docker restart [service] Restart a service
313
+ ```
314
+
315
+ ---
316
+
317
+ ## Modes of operation
318
+
319
+ ### Standalone (default — no Docker)
320
+
321
+ ```text
322
+ Claude Code → cc-router:3456 → api.anthropic.com
323
+ ```
324
+
325
+ Best for personal use. No Docker required. Runs in the background by default, auto-starts on boot if you choose.
326
+
327
+ ```bash
328
+ cc-router start
329
+ ```
330
+
331
+ ### Full mode with LiteLLM (optional — requires Docker)
332
+
333
+ ```text
334
+ Claude Code → cc-router:3456 → LiteLLM:4000 → api.anthropic.com
335
+ ```
336
+
337
+ Adds a LiteLLM layer for usage logging, rate limiting, and a web dashboard at `http://localhost:4000/ui`.
338
+
339
+ ```bash
340
+ cc-router docker up
341
+ # or: cc-router start --litellm
342
+ ```
343
+
344
+ See [docs/litellm-setup.md](docs/litellm-setup.md) for details.
345
+
346
+ ---
347
+
348
+ ## Codex CLI support (experimental)
349
+
350
+ CC-Router exposes an OpenAI Responses-compatible endpoint for Codex CLI at `/v1/responses`. This lets Codex use OpenAI ChatGPT/Codex subscription accounts through the same local router that Claude Code uses for Claude subscriptions.
351
+
352
+ Configure Codex:
353
+
354
+ ```bash
355
+ cc-router configure codex --model openai/gpt-5-codex
356
+ ```
357
+
358
+ This writes a managed provider block to `~/.codex/config.toml`:
359
+
360
+ ```toml
361
+ model = "openai/gpt-5-codex"
362
+ model_provider = "cc-router"
363
+
364
+ [model_providers.cc-router]
365
+ name = "CC-Router"
366
+ base_url = "http://localhost:3456/v1"
367
+ wire_api = "responses"
368
+ env_key = "CC_ROUTER_TOKEN"
369
+ ```
370
+
371
+ Configure router-side model defaults and aliases:
372
+
373
+ ```bash
374
+ cc-router configure models \
375
+ --claude-model claude-sonnet-4-6 \
376
+ --openai-model gpt-5-codex
377
+ ```
378
+
379
+ This writes `modelRouting` to `~/.cc-router/config.json`. It sets the Claude default, the OpenAI default, and practical aliases so `claude/sonnet`, `sonnet`, `openai/default`, and `openai/codex` resolve to the models you selected. Restart the router after changing these values.
380
+
381
+ Model discovery is dynamic. `GET /v1/models` returns an OpenAI-compatible model list by querying the configured Anthropic and OpenAI subscription APIs live:
382
+
383
+ ```bash
384
+ curl http://localhost:3456/v1/models
385
+ ```
386
+
387
+ Results are provider-prefixed, for example `anthropic/claude-sonnet-4-6` and `openai/gpt-5-codex`. Configured aliases such as `openai/codex` are added when their upstream model is available. If one provider is temporarily unavailable, CC-Router still returns the models discovered from the other providers.
388
+
389
+ Then run Codex with the proxy secret in `CC_ROUTER_TOKEN` when your router is password-protected:
390
+
391
+ ```bash
392
+ CC_ROUTER_TOKEN=cc-rtr-your-secret codex -m openai/gpt-5.5
393
+ ```
394
+
395
+ Model prefixes:
396
+
397
+ | Prefix | Upstream |
398
+ |--------|----------|
399
+ | `openai/*` | OpenAI ChatGPT/Codex subscription route |
400
+ | `claude/*` | Claude subscription route |
401
+ | `anthropic/*` | Claude subscription route |
402
+
403
+ Examples after the configuration above:
404
+
405
+ | Public model | Routed upstream model |
406
+ |--------------|----------------------|
407
+ | `openai/codex` | `gpt-5-codex` |
408
+ | `openai/default` | `gpt-5-codex` |
409
+ | `claude/sonnet` | `claude-sonnet-4-6` |
410
+
411
+ Claude Code can also send a `/v1/messages` request with an `openai/*` model. CC-Router translates that Anthropic Messages request into an OpenAI Responses request and converts JSON or basic text SSE responses back into Anthropic-shaped message responses.
412
+
413
+ Current limitation: OpenAI-to-Anthropic streaming currently covers text deltas and final usage. Streaming tool-call normalization is still experimental.
414
+
415
+ OpenAI subscription account records are separated from Claude accounts with `provider: "openai_subscription"` so they do not enter the Anthropic token pool:
416
+
417
+ ```json
418
+ {
419
+ "id": "openai-primary",
420
+ "provider": "openai_subscription",
421
+ "accessToken": "eyJ...",
422
+ "refreshToken": "...",
423
+ "expiresAt": 1999999999000,
424
+ "scopes": ["openid", "profile", "email", "offline_access"]
425
+ }
426
+ ```
427
+
428
+ Recommended OpenAI subscription login:
429
+
430
+ ```bash
431
+ cc-router accounts login-openai
432
+ ```
433
+
434
+ This uses the Codex device-code auth flow: the CLI prints a verification URL and one-time code, you approve the login in your browser, and CC-Router saves the resulting OpenAI subscription account record.
435
+
436
+ Manual account entry is also available for debugging:
437
+
438
+ ```bash
439
+ cc-router accounts add-openai
440
+ ```
441
+
442
+ This prompts for the OpenAI access token, refresh token, expiry timestamp, and scopes, validates the record shape, and saves it without overwriting Claude accounts.
443
+
444
+ ---
445
+
446
+ ## Client mode — connecting to an existing CC-Router
447
+
448
+ If someone on your team already hosts a CC-Router instance (on a VPS, home server, or another machine on the LAN), you don't need to install accounts locally. You just point your Claude Code at the remote proxy.
449
+
450
+ The setup wizard asks about this at the very first step:
451
+
452
+ ```bash
453
+ cc-router setup
454
+ # → What do you want to do?
455
+ # • Host CC-Router on this machine
456
+ # • Connect to an existing CC-Router server ← pick this
457
+ ```
458
+
459
+ Or use the dedicated command directly:
460
+
461
+ ```bash
462
+ # Quick connect — just point Claude Code at the remote proxy
463
+ cc-router client connect http://192.168.1.50:3456 --secret cc-rtr-abc123...
464
+
465
+ # Check status
466
+ cc-router client status
467
+
468
+ # Disconnect (restores Claude Code defaults)
469
+ cc-router client disconnect
470
+ ```
471
+
472
+ Client mode writes `ANTHROPIC_BASE_URL` and `ANTHROPIC_AUTH_TOKEN` into `~/.claude/settings.json`, so Claude Code talks directly to the remote proxy. Nothing runs locally — no accounts, no proxy process, no resources.
473
+
474
+ ### CLI reference
475
+
476
+ ```text
477
+ cc-router client connect <url> Connect Claude Code to a CC-Router server
478
+ cc-router client connect --desktop Also configure Claude Desktop interception
479
+ cc-router client connect -s <secret> Pass the proxy secret inline (or use --secret)
480
+ cc-router client disconnect Revert all client configuration
481
+ cc-router client status Show current connection + remote server health
482
+ cc-router client start-desktop Start the Claude Desktop mitmproxy interceptor
483
+ cc-router client stop-desktop Stop the Claude Desktop interceptor
484
+ ```
485
+
486
+ ---
487
+
488
+ ## Claude Desktop support
489
+
490
+ Claude Desktop (chat + Cowork) **can be routed through CC-Router**, but unlike Claude Code it does not respect `ANTHROPIC_BASE_URL`. It talks directly to `api.anthropic.com` via an embedded Anthropic SDK. To redirect its traffic, CC-Router uses [mitmproxy](https://mitmproxy.org/) in *local redirect mode* — a process-scoped interceptor that only captures Claude Desktop's network traffic and forwards it to the proxy.
491
+
492
+ This is **opt-in** — the setup wizard will ask if you want it.
493
+
494
+ ### Requirements
495
+
496
+ - **mitmproxy ≥ 10.1.5** (macOS, Windows) or **≥ 11.1** (Linux — requires kernel ≥ 6.8)
497
+ - Admin access to install the mitmproxy CA certificate
498
+ - On macOS: manual approval of mitmproxy's Network Extension (one time, via System Settings)
499
+
500
+ ### Installing mitmproxy
501
+
502
+ ```bash
503
+ # macOS
504
+ brew install mitmproxy
505
+
506
+ # Windows
507
+ # Download the installer from https://mitmproxy.org/downloads/
508
+ # (or: pip install mitmproxy)
509
+
510
+ # Linux
511
+ pip install mitmproxy # kernel 6.8+ required for local mode
512
+ ```
513
+
514
+ ### Enabling Desktop interception
515
+
516
+ During `cc-router setup` or `cc-router client connect`, answer **Yes** when asked about Claude Desktop. The wizard will:
517
+
518
+ 1. Check that mitmproxy is installed
519
+ 2. Generate the mitmproxy CA certificate (if not already present)
520
+ 3. Install the CA into the OS trust store (requires sudo/admin)
521
+ 4. Write the redirect addon to `~/.cc-router/interceptor/addon.py`
522
+ 5. On macOS, prompt you to approve the Network Extension
523
+
524
+ Then start the interceptor:
525
+
526
+ ```bash
527
+ cc-router client start-desktop
528
+ ```
529
+
530
+ Open Claude Desktop and send a message. The request will be intercepted and redirected to CC-Router. Requests carrying exactly one valid `X-Claude-Code-Session-Id` receive cache-aware sticky affinity; requests without one valid session header use load-aware **unscoped** routing and do not receive sticky affinity. Claude Desktop traffic normally follows the unscoped path.
531
+
532
+ ### Stopping / removing Desktop interception
533
+
534
+ ```bash
535
+ cc-router client stop-desktop # Stop the interceptor (keep configuration)
536
+ cc-router client disconnect # Stop + remove all client config
537
+ ```
538
+
539
+ ### How it works under the hood
540
+
541
+ ```
542
+ Claude Desktop
543
+
544
+ │ tries to connect to api.anthropic.com:443
545
+
546
+ mitmproxy (local mode)
547
+ │ addon.py rewrites scheme/host to CC-Router
548
+
549
+ CC-Router :3456 ──► api.anthropic.com (with OAuth Bearer token)
550
+ ```
551
+
552
+ mitmproxy's local mode is *process-scoped* — it only intercepts traffic from the Claude process, not your browser, curl, or any other app. The OS-level interception uses:
553
+
554
+ | Platform | Mechanism |
555
+ |----------|-----------|
556
+ | macOS | Network Extension (App Proxy Provider API) |
557
+ | Windows | WinDivert (WFP kernel driver) |
558
+ | Linux | eBPF (kernel ≥ 6.8) |
559
+
560
+ ### Troubleshooting
561
+
562
+ - **macOS: "provider rejected new flow"** — re-enable Mitmproxy Redirector in System Settings → General → Login Items & Extensions → Network Extensions, then restart mitmproxy.
563
+ - **Windows: UAC prompt every start** — expected; mitmproxy's redirector needs admin at runtime.
564
+ - **Linux: "eBPF program failed to load"** — check your kernel version with `uname -r`. You need ≥ 6.8.
565
+ - **Chat shows "failed to connect"** — make sure CC-Router is reachable from the mitmproxy process. Run `curl http://localhost:3456/cc-router/health` to verify the proxy is up.
566
+
567
+ ---
568
+
569
+ ## Reverting to normal Claude Code
570
+
571
+ To stop using cc-router and go back to normal Claude Code authentication:
572
+
573
+ ```bash
574
+ cc-router revert
575
+ ```
576
+
577
+ This stops the proxy process, removes the auto-start service (if installed), and removes cc-router's settings from `~/.claude/settings.json`. Claude Code will use its own authentication on the next launch.
578
+
579
+ For a gentler approach, `cc-router stop` interactively asks what you want to clean up.
580
+
581
+ ---
582
+
583
+ ## Status dashboard
584
+
585
+ ```bash
586
+ cc-router status
587
+ ```
588
+
589
+ ```text
590
+ CC-Router · standalone → api.anthropic.com · up 2h 14m · [q] quit
591
+
592
+ OPERATIONS base http://localhost:3456 · auth protected · models dynamic
593
+ Claude 2/2 healthy OpenAI 1/1 healthy · cross-route ready
594
+ endpoints /v1/messages /v1/responses /v1/models /cc-router/accounts
595
+ routing claude=claude-sonnet-4-6 aliases[sonnet] openai=gpt-5-codex aliases[codex]
596
+ models [m] list/select change [c] Claude [o] OpenAI
597
+
598
+ MODELS [m/r] refresh [↑/↓] select [c] Claude default [o] OpenAI default
599
+ current claude=claude-sonnet-4-6 openai=gpt-5-codex
600
+ ▶ anthropic/claude-sonnet-4-6 Claude
601
+ openai/gpt-5-codex OpenAI
602
+
603
+ ACCOUNTS 2/2 healthy
604
+
605
+ ● max-account-1 ok req 142 err 0 expires 6h 48m last 2s ago
606
+ ● max-account-2 ok req 139 err 0 expires 6h 51m last 5s ago
607
+
608
+ TOTALS requests 281 · errors 0 · refreshes 2
609
+
610
+ RECENT ACTIVITY
611
+ 14:23:01 → max-account-1 route
612
+ 14:22:58 → max-account-2 route
613
+ 14:22:45 ↻ max-account-1 refresh
614
+ ```
615
+
616
+ Press `q` to quit. Run with `--json` for non-interactive output; the JSON includes an `operational` block with capabilities, endpoints, provider readiness, auth status, and model routing. Secrets and account tokens are never included.
617
+
618
+ The dashboard is also a control surface. In local mode it controls the local proxy; in client mode it controls the remote CC-Router configured by `cc-router client connect`.
619
+
620
+ | Key | Action |
621
+ |-----|--------|
622
+ | `Tab` | Switch focus between logs, accounts, and models |
623
+ | `n` | Add a Claude account |
624
+ | `e` | Enable/disable selected Claude account |
625
+ | `w` / `s` | Change selected Claude account weekly/session cap |
626
+ | `d` | Delete selected Claude account |
627
+ | `m` / `r` | Load or refresh discovered provider models |
628
+ | `c` | Set selected `anthropic/*` model as Claude default |
629
+ | `o` | Set selected `openai/*` model as OpenAI default |
630
+
631
+ List and change models without waiting for a package update:
632
+
633
+ ```bash
634
+ cc-router models list
635
+ cc-router models set --claude-model anthropic/claude-sonnet-4-6
636
+ cc-router models set --openai-model openai/gpt-5-codex
637
+ ```
638
+
639
+ When the proxy is running, `models set` updates the live router and persists the new defaults. If the proxy is offline, it writes the configuration for the next start.
640
+
641
+ ---
642
+
643
+ ## Security
644
+
645
+ - Tokens are stored locally in `~/.cc-router/accounts.json`, **never in the repository**
646
+ - The file is excluded by `.gitignore`
647
+ - Writes are atomic (write to `.tmp`, then rename) — no corruption on crash
648
+ - Keychain reads use `execFile` with a fixed argument array — no shell injection
649
+ - Anonymous opt-out telemetry via [Aptabase](https://aptabase.com) (see [Telemetry](#telemetry) below)
650
+
651
+ See [docs/security.md](docs/security.md) for details.
652
+
653
+ ---
654
+
655
+ ## Telemetry
656
+
657
+ CC-Router sends a handful of anonymous lifecycle events to [Aptabase](https://aptabase.com) (privacy-first, open source, EU-hosted). The goal is simple: know how many people use the project, which versions are live, and roughly how many instances are running — so we can prioritize fixes and features.
658
+
659
+ **What we send** — the entire payload lives in [`src/utils/telemetry.ts`](src/utils/telemetry.ts), audit it yourself:
660
+
661
+ | Event | When | Custom props |
662
+ | -------------------- | ------------------------------------------------ | ---------------------------------------- |
663
+ | `app_started` | First proxy start after install | `first_run: true` |
664
+ | `setup_completed` | Setup wizard finishes successfully | `account_count` |
665
+ | `proxy_started` | Each `cc-router start` | `account_count`, `mode` |
666
+ | `proxy_heartbeat` | Every hour while the proxy is running | `uptime_minutes`, `account_count` |
667
+ | `telemetry_disabled` | When you run `cc-router telemetry off` | — |
668
+
669
+ Plus anonymous system props with every event: `appVersion`, `osName` (macOS/Linux/Windows), `osVersion`, `locale`, `engineVersion` (Node), and an anonymous `installId` (random UUID generated on first run, stored in `~/.cc-router/telemetry.json`).
670
+
671
+ **What we never send**: IPs, OAuth tokens, account names, request content, prompts, responses, URLs, hostnames, usernames, file paths — nothing that could identify you or your usage patterns.
672
+
673
+ **Disable it** — three ways, any one works:
674
+
675
+ ```bash
676
+ # 1. Persistent opt-out (recommended)
677
+ cc-router telemetry off
678
+
679
+ # 2. Respect the de-facto standard (honored by many OSS tools)
680
+ export DO_NOT_TRACK=1
681
+
682
+ # 3. Project-specific override
683
+ export CC_ROUTER_TELEMETRY=0
684
+ ```
685
+
686
+ Check status anytime: `cc-router telemetry status`.
687
+
688
+ ---
689
+
690
+ ## Disclaimer
691
+
692
+ > CC-Router uses the OAuth tokens of your own Claude Max subscriptions.
693
+ >
694
+ > **Read Anthropic's Terms of Service before using this tool.**
695
+ > Using multiple Max subscriptions to increase throughput may violate the ToS. Anthropic has been known to ban accounts for unusual OAuth usage patterns.
696
+ >
697
+ > The authors are not responsible for any account bans, loss of access, or other consequences resulting from the use of this software. Use at your own risk.
698
+
699
+ ---
700
+
701
+ ## Contributing
702
+
703
+ See [CONTRIBUTING.md](CONTRIBUTING.md).
704
+
705
+ Bug reports → [GitHub Issues](https://github.com/Timo972/cc-router/issues)
706
+
707
+ ---
708
+
709
+ ## License
710
+
711
+ [MIT](LICENSE)
712
+
713
+ This project began as a fork of [VictorMinemu/CC-Router](https://github.com/VictorMinemu/CC-Router)
714
+ and is now maintained independently as [`@timo972/cc-router`](https://www.npmjs.com/package/@timo972/cc-router).
715
+ It is not affiliated with the upstream project, and issues should be filed here rather than upstream.
716
+ The original MIT copyright notice is retained in [LICENSE](LICENSE).