{"id":50112300,"url":"https://github.com/ike-li/ccs","last_synced_at":"2026-05-29T17:00:28.590Z","repository":{"id":359775149,"uuid":"1246055390","full_name":"Ike-li/ccs","owner":"Ike-li","description":"Claude Code API provider 切换工具 — 在 Anthropic / OpenRouter / DeepSeek / Kimi 等多个 provider 间安全切换，含 API 验证、模型映射、原子写入、健康诊断、配置导入导出","archived":false,"fork":false,"pushed_at":"2026-05-23T11:56:56.000Z","size":104,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-05-23T13:05:44.720Z","etag":null,"topics":["anthropic","api-key-management","claude","claude-code","cli","deepseek","developer-tools","openrouter","provider-switching","python"],"latest_commit_sha":null,"homepage":null,"language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Ike-li.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-05-21T20:37:24.000Z","updated_at":"2026-05-23T11:57:00.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/Ike-li/ccs","commit_stats":null,"previous_names":["ike-li/ccs"],"tags_count":2,"template":false,"template_full_name":null,"purl":"pkg:github/Ike-li/ccs","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Ike-li%2Fccs","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Ike-li%2Fccs/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Ike-li%2Fccs/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Ike-li%2Fccs/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Ike-li","download_url":"https://codeload.github.com/Ike-li/ccs/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Ike-li%2Fccs/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":33662205,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-05-29T02:00:06.066Z","response_time":107,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["anthropic","api-key-management","claude","claude-code","cli","deepseek","developer-tools","openrouter","provider-switching","python"],"created_at":"2026-05-23T13:04:06.524Z","updated_at":"2026-05-29T17:00:28.560Z","avatar_url":"https://github.com/Ike-li.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# ccs: Claude Code provider switcher\n\nEnglish | [简体中文](README.zh.md)\n\n[![CI](https://github.com/Ike-li/ccs/actions/workflows/test.yml/badge.svg)](https://github.com/Ike-li/ccs/actions/workflows/test.yml)\n[![Release](https://img.shields.io/github/v/release/Ike-li/ccs?sort=semver)](https://github.com/Ike-li/ccs/releases)\n[![Homebrew](https://img.shields.io/badge/install-Homebrew-fbb040.svg)](#install)\n[![License: GPL-3.0](https://img.shields.io/badge/License-GPL--3.0-blue.svg)](LICENSE)\n[![Shell](https://img.shields.io/badge/runtime-POSIX%20sh-2f7d32.svg)](bin/ccs)\n[![Claude Code](https://img.shields.io/badge/Claude%20Code-provider%20switcher-6b5cff.svg)](docs/compare.md)\n\nSwitch Claude Code between Anthropic-compatible providers in seconds. No proxy. No daemon. No Node runtime.\n\n`ccs` manages multiple Anthropic-compatible endpoints and writes the active provider into Claude Code's supported `~/.claude/settings.json` env block:\n\n- API key providers use `ANTHROPIC_API_KEY`\n- Bearer token providers use `ANTHROPIC_AUTH_TOKEN`\n\nIt is useful for Anthropic-compatible endpoints, LiteLLM or internal gateways, OpenRouter, DeepSeek, Kimi, Hugging Face, and similar providers that already speak Claude Code's Anthropic Messages API shape. It is not a protocol translator for OpenAI, Gemini, Ollama, or custom chat APIs.\n\n\u003csub\u003eSearch terms: Claude Code provider switcher, Anthropic-compatible endpoint manager, OpenRouter / DeepSeek / Kimi / LiteLLM setup helper, API key and auth token conflict doctor.\u003c/sub\u003e\n\n## Quick Decision\n\n| If you are... | `ccs` helps by... |\n|---|---|\n| Switching between Claude Code providers | Running `ccs use \u003cname\u003e` instead of hand-editing JSON |\n| Setting up DeepSeek, OpenRouter, Kimi, or a gateway | Capturing base URL, auth mode, and model aliases in a reusable provider file |\n| Debugging API key vs auth token conflicts | Running `ccs doctor` to find stale settings or shell env state |\n| Avoiding local proxies and extra runtimes | Writing official Claude Code settings with POSIX `sh` only |\n| Sharing setup steps with a team | Keeping provider layout and commands copyable and reviewable |\n\n## 60-Second Start\n\nHomebrew is the recommended install path:\n\n```bash\nbrew install Ike-li/tap/ccs\nccs init\nccs preset deepseek --key sk-...\nccs use deepseek\n```\n\n![ccs terminal demo](docs/demo.gif)\n\nRestart the Claude Code session after switching so the new settings are loaded.\n\nIf Homebrew is unavailable, the install script is the fallback path. It defaults to a pinned release tag and verifies the downloaded `bin/ccs` sha256. If you override `CCS_INSTALL_REF`, also override `CCS_INSTALL_SHA256`.\n\n```bash\ncurl -fsSL https://raw.githubusercontent.com/Ike-li/ccs/main/install.sh | sh\n```\n\n## Use Cases\n\n- Switch between Anthropic, DeepSeek, OpenRouter, Kimi, Hugging Face, LiteLLM, or an internal Anthropic-compatible gateway.\n- Give LiteLLM or gateway users a small Claude Code client setup layer without changing the upstream architecture.\n- Put provider recipes in a README, runbook, or onboarding guide.\n- Use `ccs doctor` to inspect settings readability, active provider completeness, and shell secret conflicts.\n- Keep provider switching auditable without introducing a background daemon or local port.\n\n## Comparison\n\n| Approach | Best for | Main cost | How `ccs` fits |\n|---|---|---|---|\n| Hand-edit `~/.claude/settings.json` | One-off experiments | Easy to leave stale env values or invalid JSON | Turns switching into a repeatable command |\n| `export ANTHROPIC_*` scripts | Temporary shell sessions | Conflicts with settings and disappears across terminals | Writes Claude Code's official settings path and prints cleanup hints |\n| Local proxy / router | Protocol translation and routing | Requires a running process, port, and more config | Does not proxy; switches endpoints that already work with Claude Code |\n| Secret managers / `.env` tools | Encrypted or team secret workflows | Does not model Claude Code provider semantics | Stays lightweight and can receive keys from those workflows |\n\nMore tradeoffs are in [docs/compare.md](docs/compare.md).\n\n## Features\n\n- `ccs set` creates providers interactively or from flags.\n- `ccs preset \u003cdeepseek|openrouter\u003e` creates common provider recipes.\n- `ccs use \u003cname\u003e` writes Claude Code's `settings.json`.\n- API key and bearer token modes are mutually exclusive; switching removes the stale managed secret env.\n- Provider config lives in `~/.config/ccs/providers/\u003cname\u003e.conf`.\n- `ccs ls`, `ccs current`, and `ccs show` inspect provider state.\n- `ccs verify [name]` sends one Anthropic Messages probe request.\n- `ccs doctor` checks local dependencies, settings, active provider, and shell env conflicts.\n\n## Install\n\nRecommended:\n\n```bash\nbrew install Ike-li/tap/ccs\n```\n\nFallback installer:\n\n```bash\ncurl -fsSL https://raw.githubusercontent.com/Ike-li/ccs/main/install.sh | sh\n```\n\nThe fallback installer is less reviewable than Homebrew. It pins the default install to the latest supported release tag and checks sha256 before installing into `~/.local/bin`.\n\nLocal repository install:\n\n```bash\nmkdir -p ~/.local/bin\ninstall -m 755 bin/ccs ~/.local/bin/ccs\n```\n\nOr run without installing:\n\n```bash\n./bin/ccs --help\n```\n\nRelease and Homebrew tap maintenance are documented in [docs/releasing.md](docs/releasing.md).\n\n### Shell Completion\n\nBash:\n\n```bash\n. /path/to/ccs/completions/ccs.bash\n```\n\nzsh:\n\n```bash\nmkdir -p ~/.zsh/completions\ncp completions/_ccs ~/.zsh/completions/_ccs\n# Add to ~/.zshrc:\n#   fpath=(~/.zsh/completions $fpath)\n#   autoload -Uz compinit \u0026\u0026 compinit\n```\n\n## Usage\n\nInitialize the config directory:\n\n```bash\nccs init\n```\n\nCreate a provider interactively:\n\n```bash\nccs set deepseek\n```\n\nTTY-capable terminals let you choose the secret env with left/right arrows:\n\n```text\nBase URL:\nSecret env (\u003c-/-\u003e, Enter): ANTHROPIC_API_KEY  ANTHROPIC_AUTH_TOKEN\nKey for ANTHROPIC_AUTH_TOKEN:\nModel (optional):\nOpus model (optional):\nSonnet model (optional):\nHaiku model (optional):\n```\n\n`Model` writes `ANTHROPIC_MODEL`. `Opus model`, `Sonnet model`, and `Haiku model` write the `/model` alias defaults. A single-model provider can use the same value for all aliases; multi-model providers can set each alias separately.\n\nSwitch providers:\n\n```bash\nccs use deepseek\n```\n\n`ccs use` verifies the provider by default. For local-only switching:\n\n```bash\nccs use deepseek --no-verify\n```\n\nIf Claude Code reports `Auth conflict: Both a token ... and an API key ... are set`, the current shell usually still exports the opposite secret. `ccs use` prints a cleanup hint:\n\n```bash\nunset ANTHROPIC_AUTH_TOKEN\nclaude\n```\n\nFor eval-safe cleanup output:\n\n```bash\neval \"$(ccs use deepseek --shell)\"\n```\n\n`--shell` still writes `settings.json`, prints cleanup commands to stdout, and sends ordinary status text to stderr.\n\n## Common Commands\n\n| Command | Purpose |\n|---|---|\n| `ccs init` | Create `~/.config/ccs` |\n| `ccs set [name]` | Create or update a provider interactively |\n| `ccs set \u003cname\u003e --base-url URL --key KEY` | Create or update from flags |\n| `ccs set \u003cname\u003e --use-auth-token` | Store the secret as `ANTHROPIC_AUTH_TOKEN` |\n| `ccs preset deepseek --key KEY` | Create the DeepSeek recipe |\n| `ccs preset openrouter --key KEY` | Create the OpenRouter recipe |\n| `ccs use \u003cname\u003e` | Switch active provider and verify first |\n| `ccs use \u003cname\u003e --no-verify` | Switch without a network request |\n| `ccs verify [name]` | Verify a provider |\n| `ccs doctor` | Diagnose settings, active provider, dependencies, and shell conflicts |\n| `ccs ls` | List providers |\n| `ccs current` | Show active provider |\n| `ccs show \u003cname\u003e [--show-key]` | Show provider details; keys are masked by default |\n| `ccs rm \u003cname\u003e` | Remove a provider; active removal clears managed settings env |\n\nAdvanced model and env options:\n\n```bash\nccs set \u003cname\u003e --model claude-sonnet-4-6\nccs set \u003cname\u003e --opus-model claude-opus-4-7\nccs set \u003cname\u003e --sonnet-model claude-sonnet-4-6\nccs set \u003cname\u003e --haiku-model claude-haiku-4-5\nccs set \u003cname\u003e --unset-model\nccs set \u003cname\u003e -e ANTHROPIC_DEFAULT_SONNET_MODEL=claude-sonnet-4-6\nccs set \u003cname\u003e -e CLAUDE_CODE_SUBAGENT_MODEL=claude-haiku-4-5\nccs set \u003cname\u003e -e CLAUDE_CODE_EFFORT_LEVEL=max\nccs set \u003cname\u003e --unset-env ANTHROPIC_DEFAULT_SONNET_MODEL\n```\n\n`--unset-model` only removes `ANTHROPIC_MODEL`. Use `--unset-env KEY` for Opus/Sonnet/Haiku aliases, Claude Code subagent model, and effort level.\n\n## Scripted Examples\n\nAPI key provider:\n\n```bash\nccs set anthropic \\\n  --base-url https://api.anthropic.com \\\n  --key sk-ant-... \\\n  --use-api-key\n```\n\nAuth token provider:\n\n```bash\nccs set openrouter \\\n  --base-url https://openrouter.ai/api \\\n  --key sk-or-v1-... \\\n  --use-auth-token \\\n  --opus-model '~anthropic/claude-opus-latest' \\\n  --sonnet-model '~anthropic/claude-sonnet-latest' \\\n  --haiku-model '~anthropic/claude-haiku-latest' \\\n  -e CLAUDE_CODE_SUBAGENT_MODEL='~anthropic/claude-opus-latest'\n```\n\nDeepSeek's Claude Code setup uses `ANTHROPIC_AUTH_TOKEN` / Bearer auth. If an older DeepSeek provider was created in API key mode:\n\n```bash\nccs set ds --use-auth-token\nccs use ds\n```\n\nMore provider recipes are in [docs/providers.md](docs/providers.md).\n\nAvoid shell history by reading the key from stdin:\n\n```bash\nprintf '%s\\n' 'sk-or-v1-...' | ccs set openrouter \\\n  --base-url https://openrouter.ai/api \\\n  --key - \\\n  --use-auth-token\n```\n\n## File Layout\n\n```text\n~/.config/ccs/\n  active\n  providers/\n    kimi.conf\n\n~/.claude/settings.json\n  env:\n    ANTHROPIC_BASE_URL:    ...\n    ANTHROPIC_API_KEY:     ...  # API key mode\n    ANTHROPIC_AUTH_TOKEN:  ...  # auth token mode\n    ANTHROPIC_MODEL:       ...  # optional\n    ANTHROPIC_DEFAULT_OPUS_MODEL:    ...  # optional, /model opus alias\n    ANTHROPIC_DEFAULT_SONNET_MODEL:  ...  # optional, /model sonnet alias\n    ANTHROPIC_DEFAULT_HAIKU_MODEL:   ...  # optional, /model haiku alias\n    CLAUDE_CODE_SUBAGENT_MODEL:      ...  # optional, subagent model\n    CLAUDE_CODE_EFFORT_LEVEL:        ...  # optional, provider-recommended effort level\n```\n\nProvider files are plain `KEY=value`:\n\n```text\nauth=api_key\nkey=sk-...\nANTHROPIC_BASE_URL=https://api.example.com/anthropic\nANTHROPIC_MODEL=claude-sonnet-4-6\nANTHROPIC_DEFAULT_OPUS_MODEL=claude-opus-4-7\nANTHROPIC_DEFAULT_SONNET_MODEL=claude-sonnet-4-6\nANTHROPIC_DEFAULT_HAIKU_MODEL=claude-haiku-4-5\nCLAUDE_CODE_SUBAGENT_MODEL=claude-haiku-4-5\n```\n\nWhen writing settings, `ccs` removes managed provider env values and the legacy `apiKeyHelper`, writes the active provider, and preserves unrelated top-level fields plus non-managed `env` entries. If `jq` is available, settings are reserialized through `jq` for readable nested JSON. Without `jq`, the POSIX awk fallback keeps JSON semantics but minifies non-`env` top-level fields.\n\n## Verify\n\n`ccs verify` sends one `max_tokens=1` probe request to `${ANTHROPIC_BASE_URL}/v1/messages` to catch:\n\n- 401 / 403 auth failures\n- unsupported or misspelled model names\n- unreachable base URLs and timeouts\n\n`CCS_VERIFY_TIMEOUT` changes the timeout in seconds. The default is 10.\n\nThe probe model uses `ANTHROPIC_MODEL` first, then `ANTHROPIC_DEFAULT_OPUS_MODEL`, `ANTHROPIC_DEFAULT_SONNET_MODEL`, `ANTHROPIC_DEFAULT_HAIKU_MODEL`, and finally the built-in probe model.\n\n`ccs verify` prints the target URL before sending. If a non-loopback `http://` base URL is used, it warns that the provider secret will cross plain HTTP.\n\n## Doctor\n\n`ccs doctor` is local-only and does not send network requests. It checks:\n\n- `claude` and `curl` availability\n- `~/.config/ccs` and provider count\n- `~/.claude/settings.json` readability and writability\n- active provider presence, key, and base URL\n- current shell exports of the opposite secret env\n- DeepSeek providers still using API key mode\n\n```bash\nccs doctor\n```\n\nExample output:\n\n```text\nccs doctor 0.7.0\nok:   config dir exists: ~/.config/ccs\nok:   providers configured: 1\nok:   claude command found\nok:   curl command found\nok:   settings file exists: ~/.claude/settings.json\nok:   settings file is readable\nok:   settings file is writable\nok:   active provider: deepseek\nok:   active provider key is set: \u003clen=8\u003e\nok:   active provider base URL: https://api.deepseek.com/anthropic\nok:   active provider secret env: ANTHROPIC_AUTH_TOKEN\nsummary: 0 failure(s), 0 warning(s)\n```\n\n## Troubleshooting\n\n| `ccs verify` output | Meaning | Suggested fix |\n|---|---|---|\n| `Authentication failed (401)` | Provider key is wrong or expired | Check with `ccs show \u003cname\u003e --show-key`; update with `ccs set \u003cname\u003e --key NEW` |\n| `Access denied (403)` | Key is valid but denied | Check provider account scope, quota, or IP rules |\n| `Provider rejected: \u003cmessage\u003e` | Provider rejected the request | Read the message; for bad models, set `--model` or individual aliases |\n| `Connection failed: ...` | Base URL, DNS, or timeout problem | Test with `curl -v ${BASE_URL}/v1/messages`; adjust `CCS_VERIFY_TIMEOUT` |\n| `unsupported scheme: file` | Base URL is not HTTP(S) | Use `ccs set \u003cname\u003e --base-url https://...` |\n\nIf Claude Code reports an API key/token conflict, see the provider switching section above and unset the stale secret from the current shell.\n\n## Security Model\n\n- `~/.config/ccs/providers/*.conf` contains plaintext provider keys.\n- `~/.claude/settings.json` contains the active provider key/token in plaintext.\n- `ccs` creates new sensitive files under `umask 077` and tries to set files to `0600` and config directories to `0700`.\n- If chmod fails on a filesystem that cannot enforce owner-only permissions, `ccs` warns on stderr.\n- Treat synced or backed-up `settings.json` as a plaintext secret file.\n\n## Maintenance\n\n- Version history: [CHANGELOG.md](CHANGELOG.md)\n- Comparison with hand-editing settings, shell exports, proxies, and GUI switchers: [docs/compare.md](docs/compare.md)\n- Contributing: [CONTRIBUTING.md](CONTRIBUTING.md)\n- Security boundary and reporting: [SECURITY.md](SECURITY.md)\n- Outreach copy and awesome-list pitch: [docs/outreach.md](docs/outreach.md)\n\n## Uninstall\n\n```bash\nrm -f ~/.local/bin/ccs\nrm -rf ~/.config/ccs\n# Optional: remove managed ANTHROPIC_* env from ~/.claude/settings.json\n```\n\n## Exit Codes\n\n| Code | Meaning |\n|---|---|\n| 0 | Success |\n| 1 | User error, verify failure, or invalid input |\n\n## License\n\nGPL-3.0 - see [LICENSE](LICENSE).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fike-li%2Fccs","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fike-li%2Fccs","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fike-li%2Fccs/lists"}