Skip to content

Configuration

Anode reads JSON config plus environment variables. The important rule: the main config file is first-valid, not layered.

Anode loads the first candidate that exists, passes safety checks, and parses:

  1. $ANODE_CONFIG
  2. ~/.config/anode/config.json
  3. ./anode.json

Earlier files with errors are skipped. anode config list shows each candidate’s status, and anode config doctor exits nonzero when any candidate cannot be safely read or parsed.

Inspect the current discovery order and effective file:

anode config list

Print only the effective config path for scripts or editor integrations:

anode config path

When $ANODE_CONFIG is set but cannot be loaded, stdout still prints the fallback effective path and stderr carries the warning.

Use anode config doctor in CI or release checks; it exits nonzero when a config file cannot be parsed or safely read, and successful checks end with Config doctor passed..

Run a command with a specific config:

ANODE_CONFIG="$PWD/anode.json" anode -x "summarize this repository"
{
"model": "anthropic/claude-sonnet-4-6",
"profile": "craft",
"providers": {
"anthropic": {
"apiKey": "{env:ANTHROPIC_API_KEY}"
}
}
}

You often do not need a config file. If you set a supported provider environment variable, Anode auto-registers that provider.

KeyUse
modelDefault model in provider/model format.
profileDefault profile. Defaults to craft. Aliases: smart -> craft, rush -> quick, deep -> study, search -> find.
providersProvider map.
profilesCustom or overridden agent profiles.
permissionsUser-level permission rules.
permissionPresetunrestricted, careful, or strict; yolo is an alias for unrestricted.
contextContext window and compaction settings.
toolsTool limits, disabled tools, toolbox dirs.
shellShell tool environment and blocked command substrings.
uiTUI appearance and status display.
webWeb tool controls.
mcpWorkspace MCP trust and connection timeout.
pluginsProcess plugin paths and timeout.
skillsParsed skill settings. See Agents and skills.
sessionLocal session storage settings.
{
"providers": {
"work": {
"type": "openai-compatible",
"apiKey": "{env:WORK_LLM_KEY}",
"baseURL": "https://llm.example.com/v1",
"models": ["fast", "large"],
"timeoutSec": 180,
"maxRetries": 3
}
},
"model": "work/fast"
}

Provider fields:

KeyDefaultUse
typeprovider IDProvider type, such as anthropic, openai, zai, openai-compatible, custom, ollama, azure-openai, or bedrock.
apiFormatopenaiCustom endpoint wire format: openai, anthropic, gemini, or generic. Only used with type: "custom".
apiKey-Key value or resolver.
baseURLprovider defaultOverride endpoint. Required for many custom endpoints.
modelsprovider defaultAllowed model names. Required for useful custom endpoints.
modelDefaultsPer-model BYOK overrides: display name, reasoning capability, thinking budgets, token limits, vision support. See Per-Model Defaults.
timeoutSec120Model request timeout in seconds.
maxRetries2Transient retry count. Negative disables retries.

Transient retries cover retryable HTTP statuses such as rate limits and server errors. When a provider returns Retry-After, Anode honors seconds or HTTP-date headers and caps the sleep at 30 seconds so a single request cannot stall the agent indefinitely. Successful retries are still recorded in the run harness ledger as provider retry telemetry with provider, model, attempt, status, Retry-After, sleep duration, and transport error fields when available.

apiKey supports:

FormatMeaning
"{env:VAR}"Read environment variable VAR.
"VAR_NAME"If the value is all-caps style, read that environment variable.
"!command"Run a shell command and use stdout.
"literal"Use the literal value.

Anode ships a built-in registry of model reasoning capabilities (effort range, thinking requirements, defaults) for the public model catalogues of every auto-detected provider. The TUI /effort, the --reasoning-effort flag, and the model picker all consult this registry. Models the registry doesn’t know fall back to a zero capability — meaning reasoning controls are hidden, no display label is shown, and defaultEffort is ignored.

When you connect to a custom provider that exposes private aliases, preview names, BYOK wrappers, or any model the public registry doesn’t list yet, declare its defaults locally under providers[*].modelDefaults. This gives Anode the same per-model knowledge a hosted UI like droid would carry, without requiring a source fork.

{
"providers": {
"my-proxy": {
"type": "openai-compatible",
"baseURL": "http://localhost:9000/v1",
"apiKey": "{env:MY_PROXY_KEY}",
"models": ["opus-latest", "preview-fast", "image-only"],
"modelDefaults": {
"opus-latest": {
"displayName": "Opus Latest",
"supportsReasoning": true,
"defaultEffort": 4,
"minEffort": 1,
"maxEffort": 5,
"thinkingRequired": true,
"thinkingMaxTokens": 64000,
"maxOutputTokens": 128000,
"maxContextTokens": 1000000
},
"preview-fast": {
"displayName": "Preview Fast",
"supportsReasoning": true,
"defaultEffort": 2,
"minEffort": 1,
"maxEffort": 4
},
"image-only": {
"displayName": "Image Only",
"supportsReasoning": false,
"supportsVision": true
}
}
}
}
}

Fields (every field optional):

KeyUse
displayNameFriendly label shown in the model picker. Falls back to the wire model name.
supportsReasoningTrue if the model accepts reasoning effort at all.
defaultEffortEffort level 1–5 used when none is supplied.
minEffortLowest effort the model accepts. Effort is clamped to this.
maxEffortHighest effort the model accepts. Effort is clamped to this.
thinkingRequiredTrue when the model requires explicit thinking tokens (Anthropic-style).
thinkingMaxTokensUpper bound on the thinking budget when reasoning is enabled.
maxOutputTokensCap on completion length.
maxContextTokensTotal context window the model accepts.
supportsVisionSet false for text-only models. Omit for the default (vision-capable when the provider supports it).

Rules:

  • Built-in registry entries always win. Overrides only fill in gaps for models the upstream registry does not list, so upstream updates remain authoritative.
  • A defaults entry that is entirely zero/false is ignored — it would just shadow the default zero capability.
  • Keys are wire model names (no provider/ prefix). The same model name may appear under multiple providers with different defaults; the last one loaded wins.
  • Entries from every configured provider’s modelDefaults are merged into a single runtime override map at startup.
  • The legacy field name modelCapabilities is still accepted as an alias for modelDefaults so older configs keep working.

Anode auto-registers providers when these variables are set:

VariableProvider ID
ANTHROPIC_API_KEYanthropic
OPENAI_API_KEYopenai
ZAI_API_KEYzai
ZAI_CODING_API_KEYzai-coding
GEMINI_API_KEYgemini
GROQ_API_KEYgroq
DEEPSEEK_API_KEYdeepseek
MISTRAL_API_KEYmistral
FIREWORKS_API_KEYfireworks
XAI_API_KEYxai
OPENROUTER_API_KEYopenrouter
TOGETHER_API_KEYtogether
CEREBRAS_API_KEYcerebras
DEEPINFRA_API_KEYdeepinfra
HUGGINGFACE_API_KEYhuggingface
OLLAMA_HOSTollama

Default model selection prefers Anthropic, then OpenAI, then Z.ai Coding, then Z.ai. Otherwise Anode uses the first configured provider model it can find.

{
"profiles": {
"security-review": {
"model": "anthropic/claude-sonnet-4-6",
"promptKind": "review",
"readOnly": true,
"tools": ["read", "finder", "web_search", "todo_read"],
"maxTurns": 15,
"defaultEffort": 4
}
}
}

Profile fields:

KeyUse
modelProfile model override.
promptKindchat, quick, study, review, oracle, find, or aggman. Aliases: rush -> quick, deep -> study, search -> find.
promptPathExtra prompt text from a file, relative to workspace when not absolute.
systemPromptInline extra prompt text.
toolsAllowed tool names or glob patterns.
readOnlyHide mutation tools from the model.
maxTurnsTurn limit.
defaultEffortReasoning effort level from 1 to 5, clamped by model capability.

See Profiles.

Canonical built-in profile names are craft, quick, study, review, oracle, find, and aggman. See Profiles for aliases and custom profile configuration.

{
"context": {
"window": 200000,
"reserveTokens": 16384,
"keepRecent": 20000,
"compactPercent": 0.85,
"compactEnabled": true,
"maxOutputTokens": 16384
}
}
KeyDefaultUse
window200000Approximate model context window. A per-model maxContextTokens (under providers[*].modelDefaults) wins for that model.
reserveTokens16384Space reserved for response when compactPercent is unset.
keepRecent20000Recent tokens preserved during compaction.
compactPercent0.85Share of the effective context window allowed before auto-compaction fires. Set to a value in (0, 0.99]; values are clamped. Pass a negative value (-1) to fall back to the legacy window - reserveTokens cutoff.
compactEnabledtrueEnable automatic compaction.
maxOutputTokens16384Max response tokens sent to provider.

If a model accepts a larger or smaller window than the global default, set it on the provider entry instead of the global context.window:

{
"providers": {
"anthropic": {
"modelDefaults": {
"claude-opus-4-7": { "maxContextTokens": 1000000 },
"claude-haiku-4-5": { "maxContextTokens": 200000 }
}
}
}
}

Resolution order when the agent picks the effective window: per-model maxContextTokenscontext.window → built-in default (200000). The compactPercent knob is then applied to whichever window won, so a 1M token model auto-compacts around 850k tokens with the default 85% trigger.

{
"tools": {
"bashTimeout": 60,
"externalTimeout": 30,
"maxResultSize": 20000,
"finderResultLimit": 100,
"disabled": ["web_*"],
"toolboxDirs": ["./tools"]
}
}
KeyDefaultUse
bashTimeout30Shell timeout in seconds.
externalTimeout20MCP/toolbox/plugin timeout in seconds.
maxResultSize20000Max tool result characters passed back to the model.
finderResultLimit50Default finder result limit.
disabled[]Tool names or glob patterns to disable globally.
toolboxDirs[]Executable tool directories.
{
"shell": {
"defaultShell": "bash",
"loginShell": false,
"env": ["NODE_ENV=test"],
"blockedCmds": ["rm -rf /"]
}
}

Shell commands use non-login -c execution by default so validation and benchmark runs do not load user startup files. Set loginShell to true only when commands intentionally depend on login-shell initialization.

blockedCmds are substring matches applied before shell execution.

{
"ui": {
"theme": "dark",
"showTokens": true,
"showElapsed": true,
"showGitStats": true,
"composerHeight": 3,
"startScreen": "chat"
}
}

startScreen accepts chat, plan, diff, terminal, files, connections, settings, or logs. dashboard is an alias for Chat. Unknown values fall back to Chat.

{
"web": {
"enabled": true,
"maxBytes": 50000,
"blockedHosts": ["internal.example.com"],
"userAgent": "Anode/0.4"
}
}

ANODE_WEB_ENABLED is used only when web.enabled is not set. Values 0, false, no, off, and disabled disable web access.

{
"mcp": {
"allowWorkspace": false,
"connectTimeout": 10
}
}

Workspace MCP config requires trust unless allowWorkspace is true or ANODE_ENABLE_WORKSPACE_MCP=true is set.

See MCP.

{
"plugins": {
"enabled": true,
"paths": ["~/.config/anode/plugins/my-plugin"],
"timeoutSeconds": 5
}
}

See Hooks and plugins.

{
"skills": {
"dirs": ["~/.config/anode/skills"],
"maxSize": 65536,
"allowMCP": false
}
}

dirs adds extra skill roots to scan. Relative entries resolve from the workspace root. maxSize reads up to 65,536 bytes of SKILL.md content by default; longer files end with ...[truncated] after that prefix. allowMCP enables skill-local MCP activation; profile and tool policy still apply.

{
"session": {
"autoSave": true,
"maxSessions": 100,
"storePath": "~/.config/anode/sessions"
}
}

maxSessions default is 0, meaning no configured retention limit.

Subsystems have their own files:

AreaFiles
MCP~/.config/anode/mcp.json, trusted anode.json, trusted .mcp.json
LSP~/.config/anode/lsp.json, .lsp.json, .anode/lsp.json
Hooks~/.config/anode/hooks.json, .anode/hooks.json, hooks.json
Permissionspermissions in main config, .agents/permissions.json, .anode/permissions.json