claude-code-router
Health Uyari
- License — License: MIT
- Description — Repository has a description
- Active repo — Last push 0 days ago
- Low visibility — Only 7 GitHub stars
Code Gecti
- Code scan — Scanned 12 files during light audit, no dangerous patterns found
Permissions Gecti
- Permissions — No dangerous permissions requested
Bu listing icin henuz AI raporu yok.
A local gateway that routes Claude Code sessions to OpenAI-compatible and Anthropic-compatible models, with same-session switching and visible compatibility behavior.
Claude Code Router
ccr is a local gateway for using Claude Code with first-party Anthropic models
and configured third-party model providers in one session. It keeps Claude Code
connected to one loopback-only gateway while routing each request to the selected
model safely and visibly.
CCR is built for users who want to keep Claude Code's normal workflow while
adding providers such as OpenRouter, Z.AI, LiteLLM, or a local OpenAI-compatible
endpoint. It never silently falls back to a different model or provider.
Install
Homebrew (macOS)
brew install hishamkaram/tap/claude-code-router
GitHub Releases (macOS and Linux)
Download the archive for your operating system and CPU from the
latest release,
verify it against checksums.txt, then place ccr on your PATH.
tar -xzf <downloaded-archive>.tar.gz
mkdir -p ~/.local/bin
install -m 755 ccr ~/.local/bin/ccr
ccr version
Go
Install from source with Go 1.25 or newer:
go install github.com/hishamkaram/claude-code-router/cmd/ccr@latest
ccr version
Requirements
- Claude Code must be installed and
available asclaude. - Sign in to Claude Code when you want to use first-party Anthropic routes.
- Set any external-provider credentials in environment variables, a
0600key
file, or the OS keychain. CCR never stores raw API keys in SQLite. - Local Claude subscription account pools require individual Claude Code
subscription accounts that you personally control. For teams, services, and
third-party products, use Anthropic's official API authentication instead of
pooling personal subscription logins.
Run this after installation to check the local setup:
ccr doctor
Quick Start
The guided path is the shortest way to add a provider, choose credentials, import
models, and review aliases before anything is saved.
ccr init
ccr provider add --interactive
ccr model list
ccr launch
ccr launch defaults to --auth-mode auto. When a working Claude subscription
login or Anthropic API key is available, CCR preserves it and adds safe
registered aliases to the /model picker beside the permitted Anthropic models.
If Claude auth is not available, launch with an explicit provider alias; CCR
resolves auto to provider-only local gateway auth for that launch. Without
Claude auth and without --model, CCR fails before starting Claude Code instead
of choosing a provider implicitly. CCR also prints each picker ID, such as/model anthropic.ccr.<alias>, for scripted selection. Models with an effective
context window of at least one million tokens are advertised with Claude Code's
terminal [1m] marker. Picker rows are computed once per launch; after
capability or alias changes, relaunch Claude Code to refresh the visible picker.
To start directly on one alias, including a chat-only alias that disables
tools for the launch, pass it explicitly:
ccr launch --model <alias> --chrome
Local Claude Subscription Account Pool
ccr claude-account registers local Claude subscription accounts forccr launch --auth-mode subscription-pool. OAuth access and refresh tokens are
stored only in the OS keychain. SQLite stores account metadata and keyring
references; CLI output redacts those refs as keyring:***. Raw OAuth tokens are
never stored in SQLite or printed.
Import exactly one credential source. On Linux and Windows, --from current
reads the current Claude login from the local Claude credentials file. On macOS,
Claude stores the current login in Keychain, so --from current is unsupported;
run claude setup-token, then provide only the generated token to--oauth-token-stdin.--oauth-token-stdin stores an access token only, with unknown expiry, and does
not contact Anthropic. When stdin is a terminal, CCR reads the token without
echoing it. Account names are local CCR labels. claude setup-token runs a
separate OAuth authorization flow and does not replace the CLI login; authorize
the intended browser account for each label.
ccr claude-account import personal --from current
claude setup-token
ccr claude-account import work --oauth-token-stdin
ccr claude-account list
ccr claude-account show personal
ccr claude-account test personal
ccr claude-account test --all --live
ccr claude-account clear-cooldown personal
ccr claude-account clear-cooldown --all
ccr claude-account refresh personal --from current
ccr claude-account disable work
ccr claude-account enable work
ccr claude-account remove work --yes
Use the pool for a plain interactive launch:
ccr launch --auth-mode subscription-pool
ccr launch --auth-mode subscription-pool --claude-account personal
Automatic pool selection atomically selects and stamps the least recently used
enabled, unexpired, non-cooling account. This is load balancing, not an
exclusive lifetime lease; overlapping launches can reuse an account after each
eligible account has been selected. An explicit --claude-account selects only
that local account label and never rotates to another one. Claude Code receives
only a generated loopback gateway credential. Account OAuth tokens stay in the
OS keychain and CCR gateway memory; Claude's UI profile and cached usage may
still show the shared local login.
CCR treats a first-party Anthropic HTTP 429 as subscription exhaustion only
when Anthropic reports a rejected unified usage limit with a representative
claim and no available model fallback. A rejected model limit with fallback
available, a rejection without a recognized representative claim, token-count
throttling, and other temporary or ambiguous 429 responses do not cool or
rotate accounts.
For confirmed account-wide exhaustion, the gateway records the cooldown,
selects the next usable keychain credential, and retries the same buffered
request before writing a response to Claude. The Claude process, PID, session,
tools, browser connection, and gateway stay unchanged. Concurrent stale
rejections reuse the account already selected by another request instead of
rotating twice. If no replacement is usable, CCR forwards Anthropic's original
limit response and keeps Claude Code running. claude-account list reports the
cooldown deadline and safe reason class. Use clear-cooldown only after
independently verifying a false or stale cooldown; it does not change
credentials, expiry, or enablement.
claude-account test --all --live resolves every keychain credential, queries
the same advisory profile and usage services used by Claude Code, and reports a
non-reversible identity fingerprint plus known quota-window utilization and
reset times. Matching fingerprints identify labels backed by the same
subscription. This diagnostic fails visibly when the private service is
unavailable; routing does not depend on it.
Scripted Setup
For automation, add providers and models without prompts:
export OPENROUTER_API_KEY='replace-with-your-key'
ccr provider add openrouter --api-key-env OPENROUTER_API_KEY
ccr provider test openrouter
ccr provider import-models openrouter --all
Or import with the searchable review flow:
ccr provider import-models openrouter
For providers without model discovery, add aliases explicitly:
ccr model add coding-model --provider openrouter --model <provider-model-id>
ccr model test coding-model
Your organization may restrict which Claude Code model options are available;
CCR reports that limitation instead of bypassing it.
How Routing Works
- CCR launches Claude Code through a loopback-only local gateway.
- Default
--auth-mode autopreserves a working Claude Code subscription login
or Anthropic API key. In that resolved preserve mode, registered, non-blocked,
routable, tool-compatible aliases are added to the/modelpicker.
Tool-disabled aliases are available by starting directly withccr launch --model <alias>. - If Claude auth is absent and
--model <alias>names a registered provider
alias,autoresolves to provider-only local gateway auth. If Claude auth is
absent and no model alias is selected, launch fails visibly. Standard
first-party model names route to Anthropic only when preserved or
subscription-pool auth is available. - While a CCR alias is active in a Claude session, auto-mode safety classifier
requests from that session follow the alias. A classifier routing failure is
returned visibly; CCR does not retry it through first-party Anthropic. With
no active CCR alias, the classifier uses Claude Code's requested first-party
route. - CCR checks provider capabilities before a request is sent. Unsupported or
unsafe behavior is rejected with an explanation; it is never redirected to
Claude or another configured provider.
Capability truth is explicit and inspectable. Effective values come from, in
order, local overrides, provider discovery, and recognized provider-model hints.
Unknown stays unknown; CCR does not reinterpret missing metadata as support or
non-support. Vision is allowed only when the effective model capability says the
route supports image input. Unsupported image, PDF, audio, structured-output,
tool, thinking, or computer-use requests fail before provider submission.
Model self-identification is generated text, not proof of routing. When an
OpenAI-compatible model is asked which model is active, CCR adds route context
so the answer can reflect the current alias and provider model instead of an
older turn from the same Claude Code session.
Use ccr launch --auth-mode provider-only --model <alias> when you want a
provider-only session, or rely on default auto to choose that mode when Claude
auth is absent and a startup alias is explicit. That mode intentionally disables
the original Anthropic subscription and API-key authentication. It also lets
Claude Code authenticate to CCR's /v1/models endpoint for friendly discovery
metadata. The older gateway-token spelling remains accepted for compatibility.
Auto-mode safety classification follows the active CCR alias, including aliases
selected later through /model; it does not require a preserved Anthropic
subscription. CCR's pinned/latest real-CLI fixture matrix verifies this request
contract and rejects any classifier traffic that reaches first-party Anthropic.
Upstream connection liveness
Each gateway owns a reusable upstream HTTP transport. Unused pooled connections
close after at most 15 seconds, preserving shorter configured idle limits, so
the next turn does not reuse a connection near an idle health-probe timeout.
Active HTTP/2 connections send a ping after 20 seconds without received frames
and wait up to 15 seconds for an ACK. This protects long requests against the
reproduced idle disconnect; it does not extend
request deadlines or prove that an individual generation is making progress.
HTTP/1.1 remains supported, but does not receive HTTP/2 ping protection.
ccr trace includes upstream_transport_policy and request-correlatedupstream_transport lifecycle events. These distinguish HTTP/2 protection,
HTTP/1.1, unknown negotiation, and externally managed clients. They contain no
request bodies or credentials. Image fetching retains its separate restricted
client. Caller-injected gateway HTTP clients retain their original ownership.
CCR does not add an application retry for ambiguous EOFs or restart a committed
response. A disconnected request may still be processing upstream. Provider-side
fallback policies remain independent of connection liveness.
Gateway shutdown drains active requests within its shutdown deadline, then
cancels remaining gateway requests and closes owned connections if needed.
Existing processes retain the behavior of the binary they launched.
Common Commands
ccr provider list # show configured providers
ccr model list # show model aliases
ccr model refresh --all # refresh discoverable model capabilities
ccr model show <alias> --json # inspect sources, overrides, and effective values
ccr model test <alias> # validate a route against its provider
ccr conformance run <alias> # record compatibility checks
ccr conformance run --all # check every registered non-blocked routable alias
ccr launch # auto auth; preserve Claude auth when available
ccr launch --model <alias> # start directly on one CCR alias; provider-only if no Claude auth
ccr claude-account import personal --from current
ccr claude-account list
ccr launch --auth-mode subscription-pool
ccr status # show the latest observed route and health
ccr trace --follow # follow redacted route and lifecycle events
ccr sessions --active # list active launches and Claude sessions
ccr agents --active # list active agents, teammates, and tasks
ccr doctor --live # probe one model per configured provider
ccr doctor --live --all # diagnose routable aliases; report excluded aliases as skipped
ccr profile export team.json # export routing config without credentials
ccr status, ccr trace, ccr sessions, and ccr agents also support stableschema_version: 1 JSON output. Launches inject a compact CCR status line and
Claude lifecycle hooks for that process only. Existing hooks and status lines
keep their behavior. In subscription-pool mode, CCR preserves the existing
command through a launch-only credential-isolation wrapper: it can readCCR_CLAUDE_ACCOUNT, while OAuth and gateway credentials are removed from its
environment. Windows visibly falls back to CCR's account-aware line because the
POSIX isolation wrapper is unavailable. If no status line is configured, the
injected line shows account=<name> | limits=unknown; a higher-precedence
explicit statusLine: null remains disabled. Launch-generated settings use
POSIX mode 0600 inside a mode-0700 temporary directory, or the user-scoped
temporary-directory ACL on Windows; they never use raw process arguments and
are removed after Claude exits. User settings files are not changed. On
confirmed pool exhaustion CCR resolves the next account before
stopping Claude. If none is usable, the current Claude process and gateway stay
open with Claude Code's native limit behavior. Use --no-statusline,--no-lifecycle, or --no-history to disable those features independently for
one launch.
Detached Jobs
For durable headless work, use detached jobs:
ccr launch --model <alias> --detach -p --prompt-file prompt.txt
ccr status <job_id> --json
ccr cancel <job_id> --json
The launch receipt survives the launching CLI. Cancellation is requested by job
ID, and cleanup coverage is reported separately from the workload's exit status.
Linux uses systemd user scopes when available; macOS uses a degraded native path.
Team Profiles
Export provider and model routing configuration for another machine without
exporting credentials:
ccr profile export team.json
ccr profile import team.json --dry-run
ccr profile import team.json --credential openrouter=OPENROUTER_API_KEY
Profiles may carry environment-variable names, but never raw secret values,
keychain identifiers, or credential-file paths. Imports are validated and
applied atomically; conflicts fail without partial changes.
Documentation
- Getting started
- Providers and model aliases
- Routing, authentication, and compatibility
- Troubleshooting
- Maintainer release process
Security and Local State
CCR stores provider configuration, model aliases, redacted route history,
hook-observed lifecycle state, and compatibility metadata in a local SQLite
database. By default it uses$XDG_DATA_HOME/claude-code-router/ccr.db, or~/.local/share/claude-code-router/ccr.db when XDG_DATA_HOME is unset. Use--db <path> to keep state elsewhere.
SQLite contains only secret references such as env:OPENROUTER_API_KEY or
redacted keyring:***, never the API-key or OAuth-token value. Claude account
access and refresh tokens are stored only in the OS keychain. Route history
never stores prompts, responses, tool
arguments, hook bodies, transcript paths, or authorization headers. CCR records
provider-reported token usage when available but does not estimate monetary
cost. Redacted route and lifecycle metadata is bounded by the local retention
policy, currently 30 days and 10,000 combined events, and can be purged withccr trace purge --all --yes. See
provider credential handling for the supported
secret sources.
Computer-use automation has two explicit boundaries. Direct first-party
Anthropic CUA is client-managed: Claude Code owns the browser, approvals, and
tool-result loop. OpenAI Responses computer use is managed by CCR only. Without
a launch-scoped managed executor, CCR rejects that request before provider
submission rather than emitting a tool action Claude Code cannot execute.
Managed CUA routes run only when explicitly configured for a supported executor:
Docker browser image, trusted host browser, external executor, or unsigned macOS
helper preview. Managed CUA requires an OpenAI Responses-capable provider and a
selected alias with effective Responses and computer-use support. External
managed executors must use a public HTTPS base URL with no credentials, query
string, fragment, or redirects, and launch requires a bearer token supplied
through an environment-variable reference such as:
export CCR_CUA_EXTERNAL_TOKEN='<external-executor-token>'
ccr launch --model <responses-cua-alias> \
--ccr-cua-mode managed \
--ccr-cua-executor external:browser \
--ccr-cua-external-url https://executor.example/cua \
--ccr-cua-external-token-env CCR_CUA_EXTERNAL_TOKEN
CCR records local approval and audit metadata, not screenshots, prompts, page
contents, or credentials. The macOS helper preview is source-built only. It is
not included in Homebrew bottles or GoReleaser archives, is unsigned, and is
not a production security boundary.
Development
make build
make test
make check
make test-cua-macos-fixture
make test-live-fixture
CCR_LIVE_REAL_MATRIX=1 make test-live-real
CCR_LIVE_REAL_MATRIX=1 make test-live-matrix
# With every optional real vision/CUA/executor environment configured:
CCR_LIVE_REAL_MATRIX=1 make test-live-real-full
CCR_LIVE_REAL_MATRIX=1 make test-live-matrix-full
The required fixture target needs an installed Claude Code CLI but no provider
credential. CI runs 12 fixture jobs without skips: Linux and macOS, pinned
Claude Code 2.1.209 and the latest npm release, and openai-chat,anthropic-native, and openai-responses protocols. A separate macOS CI
job validates the portable helper protocol fixtures and compiles the source-built
preview helper. The default real target uses first-party Anthropic
authentication and every configured non-blocked routable alias in the selected
database. test-live-matrix runs the fixture target plus that default real
target locally. Set CCR_LIVE_REAL_CLAUDE_ACCOUNT=<name> to run the matrix's
first-party Anthropic checks with that exact registered subscription-pool
account instead of the currently logged-in Claude identity. Real vision,
Anthropic CUA, OpenAI Responses CUA, and executor
coverage stay opt-in through the individual test-live-real-* targets or thetest-live-real-full aggregate; skipped real tests are not evidence of a
verified runtime route.
HTTP/2 release acceptance
Run make test-live-http2-idle for real Claude CLI sessions with a 90-second
upstream silence and a 60-second idle cutoff. This uses a local TLS fixture and
requires no real-provider credentials.
Build a candidate separately, then run the executable-level real-provider gate:
make build BIN_DIR=/tmp/ccr-candidate
CCR_LIVE_HTTP2_BINARY=/tmp/ccr-candidate/ccr \
CCR_LIVE_HTTP2_EVIDENCE_DIR=/tmp/ccr-http2-evidence \
CCR_LIVE_HTTP2_EXPECTED_DEPLOYMENTS=/tmp/expected-deployments.json \
make test-live-http2-binary
This contacts the configured litellm-grok-4-6 and litellm-gpt-5-6-terra aliases
and incurs provider usage. CCR_LIVE_CONFIGURED_DB can select the source registry;
the gate reads it without migrating it and creates separate test databases with
only the required definitions and secret references. It launches the candidate
CCR executable and real Claude CLI with isolated Claude configuration and
default permission mode and preapproval limited to the fixture MCP image tool
or Agent tool. Agent sessions pin CLAUDE_CODE_SUBAGENT_MODEL to the requested
CCR alias and set CLAUDE_CODE_SUBAGENT_MODEL_FORCE=1 so generated Agent arguments
cannot override that choice. They verify forwarded child output, two separate
user turns, and deployment receipts. Classifier routing is exercised by the
existing live suite; classifier fallbacks are separate from these model-specific
acceptance sessions. The gate does not replace the installed CCR or stop existing
sessions. Required failures are
not skipped. Evidence contains process/route metadata and assertions, not prompts,
credentials, or provider response bodies. The expected-deployments JSON must map
each provider model name to its verified
LiteLLM deployment ID, for example {"grok-4.6":{"deployment_id":"<id>"}, "gpt-5.6-terra":{"deployment_id":"<id>"}}. Obtain these non-secret IDs from
LiteLLM's model metadata before running the gate. Response deployment IDs must
match; missing identity or a fallback fails model acceptance. The gate also
cancels its own test Claude child while a separate session completes.
Embedding callers with custom global TLS dial hooks must inject Config.HTTPClient;
those callers retain transport lifecycle ownership. The normal standard transport
preserves TLS verification, proxy discovery, and HTTP/1.1 negotiation.
Transport observations admit only bounded LiteLLM call/deployment IDs and retry/
fallback counters from documented response headers. Missing metadata remains
unknown; differing observations are marked mixed. No response bodies are logged.
Contributing and Security
Read CONTRIBUTING.md before opening a pull request. Report
security vulnerabilities privately as described in SECURITY.md.
License
MIT. See LICENSE.
Yorumlar (0)
Yorum birakmak icin giris yap.
Yorum birakSonuc bulunamadi