Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

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:

  1. --profile <name> flag (explicit, always works)
  2. --<name> shortcut (auto-generated from profile names)
  3. default_profile from 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-control does not accept custom permission flags (--dangerously-skip-permissions or --permission-mode auto). Combining --control with --auto or --yolo will 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.