cc-switch
Generate ~/.claude/settings.json from saved provider/model configs —
a small CLI that mirrors the credstore pattern.
Non-secret provider shape lives in ~/.claude/cc-switch.json. API
keys are never stored there — the config keeps the key's name,
and the value is read from credstore at activate time and injected into
the system environment as ANTHROPIC_AUTH_TOKEN. The generated
settings.json contains no credential line.
Install
cc-switch is a standalone PyPI package, installed independently of Slife — it was originally extracted from that repository, but neither package pulls in the other. It depends on credstore, which is pulled in automatically.
uv tool install --force --python '>=3.13' cc-switch
# or, in this repo (dev):
uv sync
--python '>=3.13'is not optional. Without ituvbuilds the tool environment on whichever interpreter it prefers; cc-switch needs ≥ 3.13, so an older environment has no compatible release to install at all. With the constraint, uv fetches a suitable interpreter or fails loudly.
One-click installers (install uv if needed, then uv tool install --force --python '>=3.13' cc-switch):
# macOS / Linux / WSL
curl -fsSL https://raw.githubusercontent.com/juzcn/cc-switch/main/install.sh | bash
# Windows PowerShell
powershell -ExecutionPolicy Bypass -Command "irm https://raw.githubusercontent.com/juzcn/cc-switch/main/install.ps1 | iex"
The installers and the --force form are idempotent — the first run
installs, re-running updates to the latest PyPI release. A plain
uv tool install cc-switch no-ops when the tool is already installed.
Uninstall with uninstall.sh / uninstall.ps1 (config under
~/.claude/cc-switch.json is left in place).
Commands
cc-switch set <provider-name>
Create or edit a provider. Prompts for:
- Base URL (required)
- API key name — the credstore key holding the secret (required)
- Supported models (optional; comma, space, or semicolon separated)
If the provider already exists this edits it; otherwise it adds it. When editing, a blank answer keeps the current value. The models prompt toggles against the provider's current list: a model you type that is already listed is removed, one that isn't is added (symmetric difference). A blank answer leaves the list unchanged, and typing the same list again undoes the change.
cc-switch set deepseek
# Base URL [..]: https://api.deepseek.com/anthropic
# API key name (credstore key): DEEPSEEK_API_KEY
# Supported models (comma separated; toggles against the current list): deepseek-chat,deepseek-reasoner
No secret value is ever asked for or written — store it first with:
credstore set DEEPSEEK_API_KEY
cc-switch activate <provider-name/model-name>
Writes ~/.claude/settings.json with stock Claude Code defaults, and
injects the API key from credstore into the system environment as
ANTHROPIC_AUTH_TOKEN (mirroring credstore inject — registry on
Windows, shell profile on Unix), so a freshly launched Claude Code
session inherits it. The settings file contains no credential.
settings.json is written first, then the secret is resolved from
credstore. If the key is missing — or credstore itself is not
installed — activate fails loudly with the appropriate hint, leaving
the generated settings file on disk but not injecting a token.
On success, the activated provider/model is recorded in the top-level
active field of ~/.claude/cc-switch.json, so the list view can show
which model is currently active.
cc-switch activate deepseek/deepseek-chat
If the model is omitted and the provider has exactly one model, it is used; if several, you are prompted to pick one.
cc-switch activate <provider-name/model-name> --custom
Like activate, but lets you override each model slot first —
ANTHROPIC_DEFAULT_HAIKU_MODEL, ANTHROPIC_DEFAULT_SONNET_MODEL,
ANTHROPIC_DEFAULT_OPUS_MODEL, ANTHROPIC_CLAUDE_CODE_SUBAGENT_MODEL,
and ANTHROPIC_CLAUDE_CODE_EFFORT_LEVEL — one at a time. Enter a value
to override, or Enter to keep the default. The main model slot
(ANTHROPIC_MODEL) is chosen on the command line, not here. Overrides
are one-shot: they never touch the stored provider config.
cc-switch
With no command, lists every configured provider/model pair, one per
line. The currently active model is marked (active):
deepseek/deepseek-chat
deepseek/deepseek-reasoner
scnet/scnet-1m (active)
cc-switch list
Shows provider metadata (base URL, API key name, models) — one block per provider.
cc-switch remove <provider-name>
Deletes a provider config. Does not touch credstore or settings.json.
Files
| Path | Purpose |
|---|---|
~/.claude/cc-switch.json |
Provider/model shapes + the active spec (no secrets) |
~/.claude/settings.json |
Generated by activate |
credstore (DEEPSEEK_API_KEY, …) |
The actual API key values |
CC_SWITCH_FILE overrides the config path; the settings path can be
overridden for tests.
Security notes
- The config file holds only metadata — the API key is referenced by name.
activatereads the secret from credstore and injects it into the system environment asANTHROPIC_AUTH_TOKEN(registry on Windows / shell profile on Unix), mirroringcredstore inject; it is never written to settings.json.- A provider's
extra_env(settable via the Python API) may not containANTHROPIC_MODEL,ANTHROPIC_BASE_URL, orANTHROPIC_AUTH_TOKEN— cc-switch owns those slots, and a secret must never reach the plaintext config. - On a TTY,
activateprints an activation hint without echoing the secret; when stdout is piped it emits the shell export line foreval. - Restart your shell (or start a new terminal) after activating for the env change to take effect in the current session.
- Secrets are immutable Python
str— cc-switch follows credstore's practice ofdel-ing the reference immediately after use.
Development
Requires uv.
uv sync --locked # create .venv with runtime + dev dependencies
uv run pytest # run the test suite
uv run ruff check # lint
uv run ruff format # format
uv run pyright # type-check
CI runs the suite on Windows, macOS, and Linux (.github/workflows/ci.yml), plus lint and type-check jobs.
Releasing
Bump version in pyproject.toml, commit, then push a tag with the same
version:
git tag -a v0.9.12 -m "cc-switch 0.9.12" && git push origin v0.9.12
.github/workflows/publish.yml fails unless the tag matches the package
version exactly, then uploads to PyPI via trusted publishing.
License
MIT
Metadata
Release files for cc-switch 0.9.11
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| cc_switch-0.9.11.tar.gz | 59.1 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| cc_switch-0.9.11-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 75.2 kB
Release files / cc_switch-0.9.11.tar.gz
| Download URL | cc_switch-0.9.11.tar.gz |
|---|---|
| Size | 59.1 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
5f28c8e11f62c34d1ae2c3a6f3e1a909977dc173a535f6e281d4b89a12d76bb4
|
|
BLAKE2b-256 checksum How to use checksums |
f7134d53a09ecb08b2bedad27cf95194bec51c493a41f46f24f61350dda1adfb
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
Release files / cc_switch-0.9.11-py3-none-any.whl
| Download URL | cc_switch-0.9.11-py3-none-any.whl |
|---|---|
| Size | 16.1 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
5c911b1d05c1767d07e95d365d34a1ffdfa057f38aa1729c763de9691cc001e1
|
|
BLAKE2b-256 checksum How to use checksums |
af929763e2e2fb0572102917830e6e7fed56d29e97feb666128b688858c2a659
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|