Settings & Config
Command Code stores configuration in two main kinds of JSON file: config.json for your personal preferences, and the settings.json family for how the agent behaves in a project. A few smaller files hold MCP servers, keybindings, credentials, and scheduled jobs. This page is the complete reference - every key, where it lives, how it's resolved, and its default.
No file is created just by launching Command Code. Files appear the first time something is written - your first model or theme change creates config.json, and approving a command for a project creates settings.local.json. Until then, built-in defaults apply.
~/.commandcode/config.json is a single user-level file. It's yours: it never lives in a repository, and Command Code updates it for you as you use the CLI (for example when you pick a model with /model or switch themes with /theme). It's written with 0600 permissions.
| Key | Type | What it does | Default |
|---|---|---|---|
provider | string | Selected auth provider: anthropic, github-copilot, codex, or command-code | - |
model | string | Default model for new sessions | Curated default model |
theme | dark | light | auto | Terminal theme. auto automatically detects your terminal background and uses light or dark to match | auto |
compactMode | default | fast | Auto-compact aggressiveness | default |
reasoningEffort | object | Per-model reasoning effort, keyed by model id. Values: low, medium, high, xhigh, max | Provider default |
featureModels | object | Model overrides for background features, keyed by feature. Keys: titleGeneration, compaction, toolDescription, tasteOnboarding, tasteLearning, branchSummarization. Managed by /config | Curated defaults |
collapsePastedText | boolean | Collapse long pasted/dictated text (>300 chars) into a [first words… +NL] token | true |
tasteLearning | boolean | Global toggle for taste learning | true |
ideContextEnabled | boolean | IDE context integration | true |
autoInstallExtension | boolean | Auto-install the IDE extension on startup | true |
defaultExportFormat | html | jsonl | md | Format a bare /export writes | html |
defaultShareGistFormat | html | jsonl | md | Format a bare /share gist posts | html |
treeFilterMode | string | Default /tree filter: default, no-tools, user-only, labeled-only, all | default |
branchSummarySkipPrompt | boolean | Never prompt for a branch summary in /tree | false |
onDemandToolDescriptions | boolean | Generate the permission prompt's command explanation only on ctrl+e | true |
installed | boolean | First-install detection (machine-written) | - |
firstMessageSent | boolean | First-message detection (machine-written) | - |
You rarely need to edit this file directly - slash commands like /model, /theme, /effort, and /config manage it for you.
Settings files hold the things that shape how the agent behaves: model, permissions, hooks, MCP servers, skills, and mods. Unlike config.json, they exist at multiple scopes and are deep-merged.
| Scope | File | Use it for |
|---|---|---|
| Project local | <project>/.commandcode/settings.local.json | Personal overrides for one project. Approved permissions are saved here. Add it to .gitignore. |
| Project | <project>/.commandcode/settings.json | Team-shared rules. Commit it so everyone gets the same hooks and permissions. |
| User | ~/.commandcode/settings.json | Your defaults across every project. |
The legacy ~/.commandcode/config.json also feeds this layer as the lowest-precedence source for six overlapping keys (model, theme, compactMode, tasteLearning, featureModels, reasoningEffort).
| Key | Type | What it does | Default |
|---|---|---|---|
model | string | Main model id for the session | Curated default |
effort | string | Global reasoning effort | - |
reasoningEffort | object | Per-model reasoning effort override | - |
permissions | object | Permission rules and toggles (see below) | {} |
permissionMode | string | Legacy default mode; superseded by permissions.defaultMode | default |
hooks | object | Lifecycle hooks (see below) | - |
theme | string | Terminal theme | - |
tasteLearning | boolean | Taste-learning gate (per-project override) | true |
compactMode | default | fast | Auto-compact aggressiveness | default |
featureModels | object | Per-feature model overrides, including the planning and implementation models | - |
providers | object | Bring-your-own provider configuration | - |
plugins | string[] | Plugin list | - |
skills | string[] | Extra skill directories (~/ expands; relative paths resolve to the project root) | - |
disableSkillShellExecution | boolean | Disable dynamic !`…` shell placeholders in skill bodies | false |
disableScratchpad | boolean | Disable the per-session scratchpad directory | false |
mcp | object | Inline MCP servers: { "servers": [ … ] } | - |
mods | object | Declarative mod config: { sources?, paths?, disabled? } | - |
disabledSkills | string[] | Skill names to disable (unioned across layers) | - |
attribution | object | Commit co-author (attribution) | CommandCodeBot Coauthor trailer |
featureModels also carries the two main-loop lanes: the model the conversation itself runs on, chosen by which phase of a planning round you are in.
- Planning runs while the session is in plan mode (shift+tab,
/plan, or the model'senter_plan_modetool): exploring the codebase and writing the plan. - Implementation takes over when you approve a plan, and drives the execution phase that follows. Leaving plan mode without approving a plan (a plain shift+tab or
/mode) does not switch to it; you stay on the session model.
Set either one, or both, in ~/.commandcode/config.json or any settings.json layer:
Or pick them interactively in /config → Feature models → Planning / Implementation, which opens the same searchable model picker /model uses.
A phase model only ever applies inside a planning round. Concretely:
| Situation | Model used |
|---|---|
| Session that never plans or approves a plan | your session model (/model), always |
| In plan mode | planning, if set |
| After you approve a plan | implementation, if set |
| Leaving plan mode without approving | session model (no switch) |
After you pick a model with /model | your pick, until the next planning round |
Sub-agents (task tool) | their own model: if set, otherwise the active lane |
The bottom status row shows a chip naming the phase and its model: planning: GLM-5.3 in plan mode, then implementing: DeepSeek V4 Pro (latest) once you approve. Approving a plan also posts a one-line notice, Plan handoff — now implementing with deepseek-v4-pro., since that handoff is the one model change that lands silently mid-turn.
- Both feature models are optional and off by default: An unset lane, or one whose id is unknown or not covered by your plan, runs on the session model rather than failing the turn.
- The switch lands mid-run:
exit_plan_modeis a tool call, so approval happens inside a turn; the implementation model picks up the very next turn of that same run, not just your next message. /modelwins: Picking a model, including re-picking the one you are already on, stands both lanes down until the next planning round. Your saved config is untouched.- Reasoning effort follows the model through the existing per-model
reasoningEffortmap./efforttargets the model actually running, so a pick made during a phase applies to the phase model, not the session model on the banner. - ZDR mode: Pick any model that works in ZDR. A saved phase model with no ZDR route (for example, one picked before launching with
CMD_ZDR=1) is paused, and that phase runs on your session model instead. /clearends the phase: It starts a fresh session, so the next turn runs on your session model until you enter plan mode again.
Controls the Co-authored-by: CommandCodeBot <noreply@commandcode.ai> trailer appended to commits. Configure it with:
- commit: a non-empty value replaces the default trailer. It must be a single-line
Co-authored-by: Name <email>trailer (max 200 characters); values that are not a co-author trailer are ignored. Empty string""turns the trailer off entirely. - Precedence:
settings.local.json> projectsettings.json> usersettings.json.
Examples for valid/invalid commit values:
- allowed
"Co-authored-by: My Bot <bot@example.com>" - allowed
"Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>" - blocked
"Signed-off-by: Me <me@example.com>", not a Co-authored-by trailer - blocked
"Co-authored-by: My Bot <not an email>", no valid email address
Rules that allow, ask, or deny operations, plus a few related toggles.
| Key | Type | What it does |
|---|---|---|
allow | string[] | Rules that auto-approve matching operations |
ask | string[] | Rules that always prompt |
deny | string[] | Rules that always block |
defaultMode | string | Default permission mode: default, accept-edits, plan, yolo, or dont-ask (auto-accept and bypass are accepted aliases) |
additionalDirectories | string[] | Extra in-workspace directories (~/ expands; relative paths resolve to the project root) |
disableBypass | boolean | string | true (or "disable") makes yolo (permission bypass) unenterable |
The four rule lists (allow, ask, deny, additionalDirectories) union across every scope rather than being overwritten, so a rule added at any level always applies. When you approve a command with "don't ask again for this project," it's written to settings.local.json.
This section is the file format only. The complete guide covers what each rule matches, wildcards and shell patterns, the five modes, and the decision ladder behind every prompt.
Hooks run shell scripts at lifecycle events. Only four events are recognized: PreToolUse, PostToolUse, Stop, and SessionStart.
Each handler must be { "type": "command", "command": "…" }, with an optional timeout (in seconds, 0–600), async, and failClosed.
Every event and its stdin payload, exit-code semantics, the block/halt matrix, execution ordering and timeouts, plus runnable example scripts.
Complete guideMCP Servers
The entry schema for every transport, scopes and precedence, OAuth and
API-key auth, the /mcp menu, and worked configs for popular servers.
| Path | Contents | Edit by hand? |
|---|---|---|
~/.commandcode/providers.json | Custom BYOK providers - endpoints, key references, models | Yes - or via /connect |
~/.commandcode/auth.json | Command Code login, subscription tokens, and keys pasted in /connect for custom providers - written 0600 | No - managed by /login, /logout, and /connect |
~/.commandcode/keybindings.json | Keybinding overrides, merged over the defaults (id → key or id → key[]) | Yes - see Keybindings |
~/.commandcode/mcp.json (or .mcp.json) | User-scope MCP servers: { "mcpServers": { … } } | Yes |
<project>/.mcp.json | Project-scope MCP servers (commit this) | Yes |
~/.commandcode/projects/{project}/mcp.json | Local (per-project) MCP servers | Via CLI |
~/.commandcode/cron/jobs.json | Durable scheduled / cron jobs | No - machine-managed |
~/.commandcode/telemetry-install-id | Anonymous per-machine telemetry id | No - machine-managed |
MCP scope precedence (low → high): settings.json mcp.servers < user mcp.json < project .mcp.json < local projects/{project}/mcp.json.
Command Code also reads a handful of environment variables as configuration:
| Variable | What it does |
|---|---|
COMMAND_CODE_API_KEY | Command-provider API key; overrides auth.json when set |
CMD_ZDR | 1 enables Zero-Data-Retention mode (pauses ZDR-incompatible feature models) |
COMMANDCODE_SKIP_UPDATES | Skip the auto-updater |
COMMANDCODE_SCRATCHPAD / COMMANDCODE_SCRATCHPAD_BASE | Override the per-session scratchpad location or base directory |
MCP_TOOL_TIMEOUT | Per-request MCP tool timeout, in milliseconds |
MAX_MCP_OUTPUT_TOKENS | Cap on MCP tool output tokens (default 25000) |
DO_NOT_TRACK | Standard opt-out that disables telemetry |
HOME / USERPROFILE | Home directory used to resolve ~/.commandcode |
When the same setting is defined in more than one place, the more specific scope wins:
<project>/.commandcode/settings.local.json- highest<project>/.commandcode/settings.json~/.commandcode/settings.json~/.commandcode/config.json(legacy fields only) - lowest
Maps are deep-merged and scalars overwrite, except the permission rule lists (allow, ask, deny, additionalDirectories), which union across all layers.
The model for a session is resolved separately, since it can be set in more ways:
--modelflag - highest/modelpicked during the sessionmodelin settings.json /config.json- Built-in default - lowest
A running session reads its default model from config.json once at startup. Changing the default in another terminal (or editing the file by hand) doesn't affect sessions that are already running - new sessions pick it up.
- Commit
<project>/.commandcode/settings.jsonso your team shares hooks and permission rules, and code review sees changes to them. - Gitignore
settings.local.json- it holds your personal approvals and overrides:
- Never commit
~/.commandcodefiles. They're user-level by design;auth.jsonholds credentials. - Let slash commands manage
config.jsonrather than editing it by hand.
~/.commandcode/projects/{project}/config.json holds machine-written state for each project you use Command Code in - currently taste onboarding progress (tasteOnboarding: completed/skipped flags, learned and skipped sessions, last learning date). It lives in your home directory, not the repository, and Command Code manages it entirely - you never need to edit it.