OpenCode Config Reference (opencode.json)
Updated by Alex Sorokoletov
Independent reference, not affiliated with Anomaly. Tables are generated from the OpenCode source at v1.18.33 (v1.18.33). Official documentation: opencode.ai.
OpenCode reads opencode.json or opencode.jsonc from ~/.config/opencode, from every directory between the project root and the working directory, and from .opencode/ folders, then deep-merges them with the nearest file winning. Both names are parsed as JSONC. The schema is published at https://opencode.ai/config.json, and unknown keys are silently ignored.
Where is opencode.json located?#
Sources merge from lowest to highest precedence, so a later row overrides an earlier one:
| Order (low → high) | Source | Where |
|---|---|---|
| 1 | Remote well-known config | `<url>/.well-known/opencode` for each org you logged in to with `opencode auth login <url>` |
| 2 | Global config | ~/.config/opencode/config.json, then opencode.json, then opencode.jsonc |
| 3 | OPENCODE_CONFIG | the file the variable points to |
| 4 | Project config | opencode.json and opencode.jsonc from the worktree root down to the working directory; nearer files win |
| 5 | .opencode directories | opencode.json then opencode.jsonc in each .opencode/ up to the worktree root, ~/.opencode and $OPENCODE_CONFIG_DIR |
| 6 | OPENCODE_CONFIG_CONTENT | inline JSON in the variable |
| 7 | Console organization config | config of the active OpenCode Console organization |
| 8 | Managed config directory | /Library/Application Support/opencode (macOS), %ProgramData%\opencode (Windows), /etc/opencode (Linux) |
| 9 | macOS managed preferences | MDM-deployed .mobileconfig profile; overrides everything above |
The global directory is $XDG_CONFIG_HOME/opencode, ~/.config/opencode by default. Project files are looked up from the working directory up to the worktree root and applied from the root down. Within one directory opencode.jsonc loads after opencode.json, so it wins when both exist. The same config directories also supply Markdown agents from agent/ or agents/, Markdown commands from command/ or commands/, and plugin files from plugin/ or plugins/.
Merging is a deep merge: nested objects combine key by key and arrays are replaced, except instructions, which concatenates and removes duplicates, and plugin, which collects entries from every file and keeps one copy per package.
Which environment variables change config loading?#
| Variable | Effect |
|---|---|
OPENCODE_CONFIG | path of an extra config file merged after the global config |
OPENCODE_CONFIG_CONTENT | inline JSON config merged after all files |
OPENCODE_CONFIG_DIR | extra config directory (agents, commands, plugins, opencode.json) |
OPENCODE_DISABLE_PROJECT_CONFIG | skip project opencode.json files and project .opencode directories |
OPENCODE_PERMISSION | JSON merged into `permission` after every config source |
OPENCODE_DISABLE_AUTOCOMPACT | forces `compaction.auto` to false |
OPENCODE_DISABLE_PRUNE | forces `compaction.prune` to false |
Two substitutions run on the raw text of every config file before parsing: {env:NAME} inserts an environment variable (empty when unset) and {file:path} inserts a file's contents.
opencode.json vs opencode.jsonc#
Both are parsed by the same JSONC parser, which accepts comments and trailing commas, so the extension changes nothing about syntax. The difference is precedence within a directory (.jsonc wins) and how OpenCode writes settings changed from the app: global changes go to the first of opencode.jsonc, opencode.json, config.json that exists, and a .jsonc file is edited in place so its comments survive.
What are all the opencode.json keys?#
| Key | Type | Description |
|---|---|---|
$schema | string | JSON schema reference for configuration validation |
agent | object (agent name → agent) | Agent configuration, see https://opencode.ai/docs/agents |
attachment | object | Attachment processing configuration, including image size limits and resizing behavior |
attachment.image | object | — |
attachment.image.auto_resize | boolean | — |
attachment.image.max_base64_bytes | integer | — |
attachment.image.max_height | integer | — |
attachment.image.max_width | integer | — |
autoshare | boolean | Deprecated. Use 'share' field instead. Share newly created sessions automatically |
autoupdate | boolean | notify | Automatically update to the latest version. Set to true to auto-update, false to disable, or 'notify' to show update notifications |
command | object (command name → command) | Command configuration, see https://opencode.ai/docs/commands |
compaction | object | — |
compaction.auto | boolean | Enable automatic compaction when context is full (default: true) |
compaction.preserve_recent_tokens | integer | Maximum number of tokens from recent turns to preserve verbatim after compaction |
compaction.prune | boolean | Enable pruning of old tool outputs (default: false) |
compaction.reserved | integer | Token buffer for compaction. Leaves enough window to avoid overflow during compaction. |
compaction.tail_turns | integer | Maximum number of recent user turns, including their following assistant/tool responses, to keep verbatim during compaction. By default retention is limited only by the preserved token budget. |
default_agent | string | Default agent to use when none is specified. Must be a primary agent. Falls back to 'build' if not set or if the specified agent is invalid. |
disabled_providers | string[] | Disable providers that are loaded automatically |
enabled_providers | string[] | When set, ONLY these providers will be enabled. All other providers will be ignored |
enterprise | object | — |
enterprise.url | string | Enterprise URL |
experimental | object | — |
experimental.batch_tool | boolean | Enable the batch tool |
experimental.continue_loop_on_deny | boolean | Continue the agent loop when a tool call is denied |
experimental.disable_paste_summary | boolean | — |
experimental.mcp_timeout | integer | Timeout in milliseconds for model context protocol (MCP) requests |
experimental.openTelemetry | boolean | Enable OpenTelemetry spans for AI SDK calls (using the 'experimental_telemetry' flag) |
experimental.policies | object[] | Policy statements applied to supported resources, such as provider access |
experimental.primary_tools | string[] | Tools that should only be available to primary agents. |
formatter | boolean | object | Enable or configure formatters. Omit or set to false to disable, true to enable built-ins, or an object to enable built-ins with overrides. |
instructions | string[] | Additional instruction files or patterns to include |
layout | auto | stretch | Deprecated. Always uses stretch layout. |
logLevel | DEBUG | INFO | WARN | ERROR | Log level |
lsp | boolean | object | Enable or configure LSP servers. Omit or set to false to disable, true to enable built-ins, or an object to enable built-ins with overrides. |
mcp | object (server name → server) | MCP (Model Context Protocol) server configurations |
mode | object (agent name → agent) | Deprecated. Use `agent` field instead. |
model | string | Model to use in the format of provider/model, eg anthropic/claude-2 |
permission | ask | allow | deny | object | — |
plugin | (string | [string, object])[] | — |
provider | object (provider id → provider) | Custom provider configurations and model overrides |
reference | object | Deprecated. Use 'references' field instead. Named git or local directory references |
references | object | Named git or local directory references |
server | object | Server configuration for opencode serve and web commands |
server.cors | string[] | — |
server.hostname | string | — |
server.mdns | boolean | — |
server.mdnsDomain | string | — |
server.port | integer | — |
share | manual | auto | disabled | Control sharing behavior:'manual' allows manual sharing via commands, 'auto' enables automatic sharing, 'disabled' disables all sharing |
shell | string | Default shell to use for terminal and bash tool |
skills | object | Additional skill folder paths |
skills.paths | string[] | — |
skills.urls | string[] | — |
small_model | string | Small model to use for tasks like title generation in the format of provider/model |
snapshot | boolean | Enable or disable snapshot tracking. When false, filesystem snapshots are not recorded and undoing or reverting will not undo/redo file changes. Defaults to true. |
subagent_depth | integer | Maximum subagent nesting depth. Defaults to 1, which prevents subagents from launching subagents. |
tool_output | object | Thresholds for truncating tool output. When output exceeds either limit, the full text is written to the truncation directory and a preview is returned. |
tool_output.max_bytes | integer | Maximum bytes of tool output before it is truncated and saved to disk (default: 51200) |
tool_output.max_lines | integer | Maximum lines of tool output before it is truncated and saved to disk (default: 2000) |
tools | object (tool → boolean) | — |
username | string | Custom username to display in conversations instead of system username |
watcher | object | — |
watcher.ignore | string[] | — |
theme, keybinds and tui are not opencode.json keys in this release: OpenCode drops them when it loads the file and migrates them to a tui.json beside it.
| tui.json key | Description |
|---|---|
theme | — |
keybinds | — |
plugin | — |
plugin_enabled | — |
leader_timeout | Leader key timeout in milliseconds |
attention | Attention notification and sound settings |
prompt | Prompt size settings |
scroll_speed | TUI scroll speed |
scroll_acceleration | Scroll acceleration settings |
diff_style | Control diff rendering style: 'auto' adapts to terminal width, 'stacked' always shows single column |
cursor | Terminal cursor settings |
mouse | Enable or disable mouse capture (default: true) |
How do I configure agents?#
Each entry under agent is keyed by agent name. A name matching a built-in agent overrides it; any other name creates an agent. Keys OpenCode does not recognise inside an agent are moved into its options.
| Key | Type | Description |
|---|---|---|
color | string | primary | secondary | accent | success | warning | error | info | Hex color code (e.g., #FF5733) or theme color (e.g., primary) |
description | string | Description of when to use the agent |
disable | boolean | — |
hidden | boolean | Hide this subagent from the @ autocomplete menu (default: false, only applies to mode: subagent) |
maxSteps | integer | Deprecated. Use 'steps' field instead. |
mode | subagent | primary | all | — |
model | string | — |
options | object | — |
permission | ask | allow | deny | object | — |
prompt | string | — |
steps | integer | Maximum number of agentic iterations before forcing text-only response |
temperature | number | — |
tools | object | Deprecated. Use 'permission' field instead |
top_p | number | — |
variant | string | Default model variant for this agent (applies only when using the agent's configured model). |
How do I add a provider or a custom model?#
Each entry under provider is keyed by provider id. options accepts any extra keys beyond the ones listed; models is keyed by model id and accepts the model fields (name, limit, cost, modalities, options, headers, variants and others).
| Key | Type | Description |
|---|---|---|
api | string | — |
blacklist | string[] | — |
env | string[] | — |
id | string | — |
models | object | — |
name | string | — |
npm | string | — |
options | object | — |
options.apiKey | string | — |
options.baseURL | string | — |
options.chunkTimeout | integer | false | Timeout in milliseconds between streamed SSE chunks for this provider (default: 300000). If no chunk arrives within this window, the request is aborted. Set to false to disable timeout. |
options.enterpriseUrl | string | GitHub Enterprise URL for copilot authentication |
options.headerTimeout | integer | false | Timeout in milliseconds to wait for response headers (default: 300000). Set to false to disable timeout. |
options.setCacheKey | boolean | Enable promptCacheKey for this provider (default false) |
options.timeout | integer | false | Timeout in milliseconds for full requests to this provider. Set to false to disable timeout. |
whitelist | string[] | — |
{
"$schema": "https://opencode.ai/config.json",
"provider": {
"local": {
"npm": "@ai-sdk/openai-compatible",
"options": { "baseURL": "http://localhost:11434/v1" },
"models": { "qwen3-coder": { "name": "Qwen3 Coder" } }
}
},
"model": "local/qwen3-coder"
}
How do I configure MCP servers?#
Each entry under mcp is keyed by server name and is either a local server started as a subprocess or a remote server reached over HTTP. { "enabled": false } on its own disables a server defined in another config file.
| Key | Type | Required | Description |
|---|---|---|---|
command | string[] | yes | Command and arguments to run the MCP server |
cwd | string | no | Working directory for the MCP server process. Relative paths resolve from the workspace directory. |
enabled | boolean | no | Enable or disable the MCP server on startup |
environment | object | no | Environment variables to set when running the MCP server |
timeout | integer | no | Timeout in ms for MCP server requests. Defaults to 5000 (5 seconds) if not specified. |
type | local | yes | Type of MCP server connection |
| Key | Type | Required | Description |
|---|---|---|---|
enabled | boolean | no | Enable or disable the MCP server on startup |
headers | object | no | Headers to send with the request |
oauth | object | false | no | OAuth authentication configuration for the MCP server. Set to false to disable OAuth auto-detection. |
timeout | integer | no | Timeout in ms for MCP server requests. Defaults to 5000 (5 seconds) if not specified. |
type | remote | yes | Type of MCP server connection |
url | string | yes | URL of the remote MCP server |
Can OpenCode 1.x read an OpenCode 2 config?#
Partly. 1.x lowers several OpenCode 2 keys to their 1.x names, ignores keys with no 1.x meaning, and refuses a v2 permissions array outright.
| OpenCode 2 key | 1.x key | What 1.x does |
|---|---|---|
permissions | — | config rejected with an error: "V2 permissions are not supported by OpenCode V1" |
snapshots | snapshot | translated; the v1 key wins if both are set |
media | attachment | translated; the v1 key wins if both are set |
compaction.keep.tokens | compaction.preserve_recent_tokens | translated; the v1 key wins if both are set |
compaction.buffer | compaction.reserved | translated; the v1 key wins if both are set |
experimental.subagent_depth | subagent_depth | translated; the v1 key wins if both are set |
agents | agent | translated; entries already under the v1 key win |
commands | command | translated; entries already under the v1 key win |
mcp.timeout | experimental.mcp_timeout | translated; the v1 key wins if both are set |
plugins | — | ignored with a warning (no v1 equivalent) |
providers | — | ignored with a warning (no v1 equivalent) |
websearch | — | ignored with a warning (no v1 equivalent) |
warming | — | ignored with a warning (no v1 equivalent) |
Frequently asked questions#
Where is the OpenCode config file?#
The global file is ~/.config/opencode/opencode.json (or opencode.jsonc, or the older config.json). A project file is opencode.json or opencode.jsonc in the repository, at any level from the root to the working directory, or inside a .opencode/ folder. OPENCODE_CONFIG adds one more file and OPENCODE_CONFIG_DIR one more directory.
Should I use opencode.json or opencode.jsonc?#
Either. OpenCode parses both as JSONC, so comments and trailing commas work in both. If a directory has both, opencode.jsonc is merged last and wins on conflicting keys. Editing settings from the app preserves comments only in a .jsonc file, because a .json file is rewritten as plain JSON.
What is the OpenCode config merge order?#
From lowest to highest: remote well-known config from opencode auth login, the global config, OPENCODE_CONFIG, project files from the repository root down to the working directory, .opencode/ folders, OPENCODE_CONFIG_CONTENT, Console organization config, the system managed directory, and finally macOS MDM managed preferences, which override everything.
Where is the OpenCode config schema?#
At https://opencode.ai/config.json. OpenCode writes "$schema": "https://opencode.ai/config.json" into any config file it loads that lacks one, and creates the global file with only that line on first run, so editors that read $schema get completion and validation without setup. Keybinds and themes are validated against a separate schema, https://opencode.ai/tui.json, in tui.json.
Why does OpenCode ignore a key in opencode.json?#
Unknown keys are dropped silently when the file is decoded, so a typo produces no error. theme, keybinds and tui moved to tui.json. OpenCode 2 names such as plugins, providers, websearch and warming are ignored with a warning in the log, while permissions makes the whole file fail to load.
How do I configure MCP servers in opencode.json?#
Add an entry under mcp: { "type": "local", "command": ["npx", "-y", "my-server"] } for a subprocess, or { "type": "remote", "url": "https://..." } for HTTP. The default request timeout is 5000 ms, enabled: false keeps a server defined but stopped, and remote servers detect OAuth automatically unless oauth is false.
Sources
- OpenCode official documentation
- OpenCode release notes
packages/sdk/openapi.json: OpenAPI document: generated Config schema (types) (at v1.18.33)packages/core/src/v1/config/config.ts: Config schema (keys and descriptions) (at v1.18.33)packages/core/src/v1/config/agent.ts: agent config schema (at v1.18.33)packages/core/src/v1/config/provider.ts: provider config schema (at v1.18.33)packages/core/src/v1/config/mcp.ts: MCP server config schema (at v1.18.33)packages/opencode/src/config/config.ts: config loader: merge order (at v1.18.33)packages/opencode/src/config/paths.ts: project file and .opencode directory discovery (at v1.18.33)packages/opencode/src/config/managed.ts: managed config directories and macOS MDM preferences (at v1.18.33)packages/opencode/src/config/v2-compat.ts: v2 config keys lowered, ignored or rejected by 1.x (at v1.18.33)packages/tui/src/config/index.tsx: tui.json schema (at v1.18.33)packages/opencode/src/config/parse.ts: JSONC parsing and excess-key handling (at v1.18.33)packages/opencode/src/config/variable.ts: {env:} and {file:} substitution (at v1.18.33)packages/opencode/src/config/tui-migrate.ts: theme/keybinds/tui migration to tui.json (at v1.18.33)packages/opencode/src/config/agent.ts: Markdown agents from agent/ and agents/ (at v1.18.33)packages/opencode/src/config/command.ts: Markdown commands from command/ and commands/ (at v1.18.33)
Release-by-release changes: OpenCode version tracker. All OpenCode pages: OpenCode reference index.