Usage
Basic usage
# Launch with default profile
ccode
# Launch with a specific profile
ccode --bedrock
ccode --deepseek
ccode --openrouter
ccode --openrouter-preset
ccode --zai
ccode --kimi
ccode --qwen
ccode --minimax
ccode --some-other-custom-profile
# There's also a longer form for profiles
# (in case they'd add a --bedrock flag and you couldn't use such a shorthand)
ccode --profile bedrock
# Pass arguments through to Claude Code
ccode --deepseek --ide
ccode --deepseek -p "Fix the bug in auth.py"
Profile selection
Profiles are selected in this priority order:
--profile <name>flag (explicit, always works)--<name>shortcut (auto-generated from profile names)default_profilefrom config
Since 1.3.0 you can build profiles without hand-editing YAML using ccode add-profile (interactive, --from-file, or --from-url), ccode remove-profile, and ccode set-default-profile. See the Commands section below for each one, or Importing configuration for hosted example YAMLs you can pull in directly.
Profile shortcuts
Every profile name automatically becomes a --<name> shortcut. If you have a profile called deepseek, then --deepseek works.
If a profile name collides with a Claude Code flag (e.g. you named a profile model), the shortcut is disabled and ccode will warn you. Use --profile model instead.
Practical examples
One of ccode’s features is the split config - a global user config that can hold your API keys, plus optional per-project configs that can override pieces of it. You can find the merge rules on the Configuration page, but here’s a few practical scenarios.
Example 1: a different default profile per project
If you mostly want everything in one place, you can keep all your providers and API keys in your user config and just use default_profile in each project’s ccode.yaml to pick which one runs there.
User config (~/.config/ccode/config.yaml on Linux/macOS, %APPDATA%\ccode\config.yaml on Windows, you can just use ccode edit-config to open it):
default_profile: "default"
profiles:
# Passthrough - launches Claude Code as-is with your subscription
default: {}
# Anthropic API - pay-per-token billing
anthropic:
anthropic_api_key: "YOUR_ANTHROPIC_API_KEY_HERE"
# DeepSeek - https://platform.deepseek.com/
deepseek:
anthropic_base_url: "https://api.deepseek.com/anthropic"
anthropic_auth_token: "YOUR_DEEPSEEK_API_KEY_HERE"
# OpenRouter - https://openrouter.ai/
openrouter:
anthropic_base_url: "https://openrouter.ai/api"
anthropic_auth_token: "YOUR_OPENROUTER_API_KEY_HERE"
models:
model:
model: "anthropic/claude-sonnet-4.6"
name: "Claude Sonnet 4"
description: "Anthropic Claude Sonnet via OpenRouter"
Local config (./ccode.yaml lives in the project directory and can be created per-project as needed):
ccode init-config --minimal .
ccode edit-config .
init-config accepts either a file path or a directory; passing . (or any directory) drops a ccode.yaml in there. edit-config does the same in reverse - pass a directory and it opens the project config inside it.
Project A - personal hobby project, use your Anthropic subscription:
# ./ccode.yaml
default_profile: "default"
Project B - work project, use the work-issued API key:
# ./ccode.yaml
default_profile: "anthropic"
Project C - cost-sensitive project, use DeepSeek:
# ./ccode.yaml
default_profile: "deepseek"
Project D - want to try OpenRouter for this one:
# ./ccode.yaml
default_profile: "openrouter"
In each project, ccode (no flags) just picks the right provider. The API keys never leave your user config, and you can still override per-launch with ccode --deepseek or ccode --profile anthropic if you want.
Example 2: different DeepSeek models per project
Same provider, different models. Maybe you want DeepSeek V4 Pro for a complex codebase and V4 Flash for a tiny utility script.
User config (the API key lives here, never in the project):
profiles:
# DeepSeek - https://platform.deepseek.com/
deepseek:
anthropic_base_url: "https://api.deepseek.com/anthropic"
anthropic_auth_token: "YOUR_DEEPSEEK_API_KEY_HERE"
Project A - bigger model, longer thinking:
# ./ccode.yaml
default_profile: "deepseek"
profiles:
deepseek:
models:
model:
model: "deepseek-v4-pro[1m]"
opus:
model: "deepseek-v4-pro[1m]"
name: "DeepSeek V4 Pro"
capabilities:
adaptive_thinking: false
sonnet:
model: "deepseek-v4-pro[1m]"
name: "DeepSeek V4 Pro (Sonnet tier)"
capabilities:
adaptive_thinking: false
haiku:
model: "deepseek-v4-flash"
name: "DeepSeek V4 Flash"
capabilities:
adaptive_thinking: false
subagent:
model: "deepseek-v4-flash"
name: "DeepSeek V4 Flash (subagent)"
claude_code_effort_level: "max"
Project B - cheaper, faster model for trivial work:
# ./ccode.yaml
default_profile: "deepseek"
profiles:
deepseek:
models:
model:
model: "deepseek-v4-flash"
opus:
model: "deepseek-v4-flash"
name: "DeepSeek V4 Flash"
capabilities:
adaptive_thinking: false
sonnet:
model: "deepseek-v4-flash"
capabilities:
adaptive_thinking: false
haiku:
model: "deepseek-v4-flash"
capabilities:
adaptive_thinking: false
subagent:
model: "deepseek-v4-flash"
name: "DeepSeek V4 Flash (subagent)"
Because the API key only lives in the user config, both project files are safe to commit - your team can clone the repo and ccode just works as long as they have their own DeepSeek key set up.
The same trick works with OpenRouter, where you get access to a much wider model catalog (Claude, GPT, Gemini, Mistral, Qwen, etc.) and can switch per-project without touching the user config.
Example 3: different environment and telemetry settings per project
Project configs can also flip the always-on launch modes and tweak environment variables. Useful when one repo wants telemetry off, or you want auto-permissions only in a sandbox project.
Project A - sandbox, always launch in yolo mode (--dangerously-skip-permissions, just shorter):
# ./ccode.yaml
default_profile: "default"
always_yolo: true
env:
DISABLE_TELEMETRY: "1"
DISABLE_ERROR_REPORTING: "1"
Project B - real codebase, leave permissions strict but always use auto-mode:
# ./ccode.yaml
default_profile: "anthropic"
always_auto: true
Project C - turn off the autoupdater and disable cost warnings here:
# ./ccode.yaml
default_profile: "deepseek"
env:
DISABLE_AUTOUPDATER: "1"
DISABLE_COST_WARNINGS: "1"
The env: block is also handy when you want to set Claude Code variables that ccode doesn’t have a first-class field for yet, or for OpenTelemetry exporters in a specific project.
Commands
ccode install
Installs the ccode binary to your PATH. See the Installation page for full details.
ccode install # User-level install (no admin/sudo required)
ccode install --system # System-wide install (requires admin/sudo)
ccode init-config
Creates a configuration file and prints its path.
ccode init-config # Create user config (fails if exists)
ccode init-config --minimal # Create minimal user config (Anthropic only)
ccode init-config --reset # Overwrite existing config with defaults
ccode init-config --minimal --reset # Reset with minimal config
ccode init-config ccode.yaml # Create config at a custom file path
ccode init-config --minimal ccode.yaml # Create minimal config at custom file path
ccode init-config . # Create ./ccode.yaml in current dir (project config)
ccode init-config --minimal . # Same, but with the minimal template
ccode init-config --minimal some-project/ # Create some-project/ccode.yaml
The --minimal flag creates a smaller configuration with only the top-level settings and Anthropic direct profiles (no cloud providers, third-party providers, or local model examples). Useful for quick setup or project-level configs.
If you pass a directory (or .) as the path argument, ccode creates ccode.yaml inside it. This is the easiest way to scaffold a project-level config: cd into your project and run ccode init-config --minimal ..
ccode edit-config
Opens a config file in a text editor. By default it opens the user config; pass a directory to open the project config inside it. If no user config exists yet, it’s created automatically.
ccode edit-config # Open user config in default editor
ccode edit-config vim # Open user config in a specific editor
ccode edit-config nano
ccode edit-config zed
ccode edit-config . # Open ./ccode.yaml (project config) in default editor
ccode edit-config some-project/ # Open some-project/ccode.yaml
The editor is resolved in this order: command argument > $EDITOR > $VISUAL > platform default (notepad on Windows, nano on Linux/macOS).
The editor names above (vim, nano, zed) work on Windows and Linux as long as the editor is on PATH. On Mac, sometimes commands will be a bit different - for example, Zed only registers a zed CLI on PATH if you run “Install CLI” from the Zed menu; otherwise you’d point at the actual binary inside the .app bundle:
# Zed on macOS without "Install CLI" run from the menu
ccode edit-config /Applications/Zed.app/Contents/MacOS/cli
The rule is: pass whatever you’d type in your terminal to launch the editor. GUI editors like Zed/VS Code/Sublime hand off to the running app and exit immediately, which is fine - ccode doesn’t need to wait for the editor to close, you just edit and save whenever, and the next ccode launch picks up the new config.
If you pass a directory and there’s no ccode.yaml (or .claude/ccode.yaml) inside it, ccode warns you and suggests running ccode init-config --minimal <dir> to create one - it won’t silently fall back to the user config in that case.
ccode profiles
Lists all available profiles from the merged configuration.
$ ccode profiles
User config: C:\Users\you\AppData\Roaming\ccode\config.yaml
Default profile: default
Always control: false (shortcuts: --control or --no-control)
Always auto: false (shortcuts: --auto or --no-auto)
Always yolo: false (shortcuts: --yolo or --no-yolo)
Available profiles:
> default
type: subscription passthrough
shortcut: --default
deepseek
type: https://api.deepseek.com/anthropic (deepseek-v4-pro[1m])
shortcut: --deepseek
openrouter
type: https://openrouter.ai/api (anthropic/claude-sonnet-4.6) [no auth]
shortcut: --openrouter
ccode add-profile
Build a new profile from scratch (interactively), or import one from a local YAML file or an https URL. Each call adds exactly one profile.
# Interactive: walks through name, base URL, auth token, model overrides.
# Press ENTER to skip any field that doesn't apply.
ccode add-profile
# From a local YAML file (or stdin via `-`):
ccode add-profile --from-file ./team-deepseek.yaml
cat profile.yaml | ccode add-profile --from-file -
# From an https URL (refuses http:// without --allow-http):
ccode add-profile --from-url https://ccode.kronis.dev/configuration-examples/deepseek.yaml
# Add and set as default in one go:
ccode add-profile --from-url https://... --set-default
# Replace an existing profile of the same name:
ccode add-profile --from-url https://... --overwrite
By default the profile lands in your user-level config. To target a project config instead, pass a directory or . as a positional argument:
ccode add-profile . # writes to ./ccode.yaml
ccode add-profile some-project/ # writes to some-project/ccode.yaml
ccode add-profile some-project/foo.yaml # writes to some-project/foo.yaml
The target file must already exist - if it doesn’t, ccode prints the exact init-config command to scaffold it.
ccode shows what’s about to be written and asks for confirmation before touching the file. Comments in your config are preserved.
Where API keys live (split-key prompt). When the target is a project config and the profile carries a real auth token, ccode asks where the key should be saved:
Where should the API key go?
If you intend to commit project files, the separate user config is safer.
1) Your user config: /home/you/.config/ccode/config.yaml
2) This project file: ./ccode.yaml
Pick a choice [default 1]:
Picking 1 writes the auth fields to your user config and the rest of the profile to the project file. The two combine at runtime via ccode’s normal field-level merge.
Unattended use (CI / scripts). Two flags bypass the interactive prompts that come from a profile’s prompt: field:
# Pre-fill specific prompt slots. Repeat for multiple fields.
ccode add-profile --from-url https://... --value anthropic_auth_token=$DEEPSEEK_KEY
# Skip prompts entirely; the prompted fields stay unset.
ccode add-profile --from-url https://... --no-prompts
A --value whose name isn’t in the source YAML’s prompt: list is rejected.
Profile name rules. Names must be non-empty, contain no whitespace, not start with a hyphen, and not collide with a Claude Code or ccode flag (so the auto-generated --<name> shortcut keeps working). A name like model or init-config is rejected with a clear error.
For the hosted YAML examples and guidance on hosting your own profile YAMLs for your team or org, see Importing configuration.
ccode remove-profile
Remove a profile from a config file. Asks for confirmation by default (defaults to yes).
ccode remove-profile my-custom-profile
ccode remove-profile deepseek . # from ./ccode.yaml
ccode remove-profile deepseek --yes # skip the confirmation prompt
If the profile being removed is the file’s default_profile, ccode warns you so you don’t end up pointing at a profile that no longer exists.
ccode set-default-profile
Set default_profile in a config file without opening an editor.
ccode set-default-profile deepseek
ccode set-default-profile default . # in ./ccode.yaml
ccode set-default-profile foo some-project/ # in some-project/ccode.yaml
The named profile must already exist in the target file. If it doesn’t, ccode lists what’s available and exits without changes. If default_profile is already set to the chosen name, the command is a no-op.
ccode --help
Shows ccode’s own help, including the current config paths, available profiles, and ccode-specific commands and flags.
ccode --help
Since ccode wraps Claude Code, it overrides the default claude --help. The original Claude Code help is always available directly:
claude --help
ccode uninstall
Removes ccode binaries, PATH entries, and optionally the configuration directory. You are prompted before each deletion - nothing is removed without your confirmation. See the Installation page for full details.
ccode uninstall
Launch modes
ccode can automatically enable Claude Code’s launch modes. Set always_control, always_auto, or always_yolo in your config, or use CLI flags to override per-launch:
# Remote control - sessions show up at claude.ai/code
ccode --control # Enable for this session
ccode --no-control # Disable for this session
# Auto permissions - Claude handles permission prompts automatically
ccode --auto # Enable for this session
ccode --no-auto # Disable for this session
# Skip permissions - bypass all permission prompts (be careful!)
ccode --yolo # Enable for this session
ccode --no-yolo # Disable for this session
# Combine modes
ccode --control --yolo # Remote control + skip permissions
# Combine with profiles
ccode --deepseek --auto
ccode --deepseek --yolo
ccode --deepseek --control
always_yolo takes priority over always_auto (they’re mutually exclusive permission modes). always_control can be combined with either.
Note: At the time of writing,
claude remote-controldoes not accept custom permission flags (--dangerously-skip-permissionsor--permission-mode auto). Combining--controlwith--autoor--yolowill print a warning but still attempt to pass the flags, in case a future Claude Code update enables it. Auto permissions can be set in the Claude app/web UI instead.
New Claude Code versions breaking Remote Control with 3rd party models
Some Claude Code version after 2.1.138 seems to have introduced a check that blocks remote-control whenever ANTHROPIC_API_KEY or ANTHROPIC_AUTH_TOKEN is set in the environment.
Every ccode profile that points at a third-party provider (OpenRouter, DeepSeek, a local proxy, etc.) sets one of those variables to route inference, so on that version ccode --control / always_control: true no longer works with those profiles. The previous versions allowed it and it doesn’t really seem like they have a good reason for doing this - since you need a subscription for Remote Control anyway.
Depending on which variable the profile populates, the error looks like one of these:
ccode: using profile "openrouter-deepseek" -- https://openrouter.ai/api (@preset/deep-seek-v4-pro-official-only), remote-control
Error: Remote Control requires claude.ai subscription auth. ANTHROPIC_AUTH_TOKEN is set, so this session is using API-key auth - unset it (or run in a shell without it) to use Remote Control.
ccode: using profile "example-local-proxy" -- http://127.0.0.1:11434 (example-local-model), remote-control
Error: Remote Control requires claude.ai subscription auth. ANTHROPIC_API_KEY is set, so this session is using API-key auth - unset it (or run in a shell without it) to use Remote Control.
I noticed this after deploying ccode on a new computer and could reproduce the issue after an update:
C:\Users\lokalna>claude update
Current version: 2.1.138
Checking for updates to latest version...
Successfully updated from 2.1.138 to version 2.1.141
Running claude /login or claude setup-token does not seem to help - the check fires on the presence of the env variable, not on whether subscription OAuth exists alongside it.
I wrote about it on Itch.io and made a GitHub issue as well.
Starting with version 2.0.0, ccode ships a Local proxy as the fix for this.
Passthrough
We have a few commands/flags of our own, but all other flags are passed through to Claude Code. We try not to have naming conflicts.
All Claude Code flags and arguments work as expected:
ccode --deepseek --continue # Resume last conversation
ccode --deepseek -r # Interactive session picker
ccode --deepseek --worktree # New git worktree
ccode --deepseek --debug # Debug mode
Use -- to force everything after it to be passed through:
ccode --deepseek -- --some-future-flag
Known limitations
So far, most of the issues I’ve run into are related to Remote Control (which is extremely cool when it works) not always working consistently. Sometimes I’ll start a Remote Control session, even with regular Claude, and it’ll just sit there and do nothing instead of showing up in the web/desktop app. ccode is just a launcher, so there’s not much it can do about that.
There’s also the issue of Remote Control not letting me set the permissions reliably. Even when Remote Control itself works, I’ll usually have to open the session in the app and use the dropdown to change permissions to what I want (for example, Auto mode). The --auto and --yolo flags don’t always survive into a claude remote-control session at the time of writing - see the warning ccode prints when you combine them.
macOS code signing is now in place as of 1.2.0. The macOS binary ships as a signed and notarized universal binary (Intel + Apple Silicon in one file), and there’s also a signed and notarized .pkg installer for one-click installs. The previous xattr -d com.apple.quarantine ./ccode workaround is no longer needed.