agentsclimarketplace

Opencode config

Skill Timmy6942025/opencode-builder-skill/skills/opencode-config

Kilo/agent skill for building OpenCode extensions, plugins, and integrations

Install
npx -y skills add Timmy6942025/opencode-builder-skill --skill opencode-config

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

One thing to look at

  • 1 stars1 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.

What its author says it does

Copied from the file, not written here

Use this skill when configuring OpenCode's opencode.json or tui.json files, setting up config precedence, managing provider credentials, using variable substitution, deploying managed settings via MDM, or troubleshooting configuration issues. Covers all config options, schema validation, remote/global/project config layers, environment variables, file references, and enterprise managed preferences.

SKILL.md

43.7 KB, as published. Nobody here has run it

OpenCode Configuration

๐Ÿ“š Official Docs: For the latest information, always refer to the official documentation: https://opencode.ai/docs/config/

OpenCode uses JSON-based configuration files to control runtime behavior, TUI appearance, server settings, tool permissions, agent definitions, and provider connections. This skill covers every aspect of configuration: file format, locations, precedence, merging, all available fields, TUI config, variable substitution, enterprise managed settings, environment variables, and troubleshooting.


Table of Contents


Format

OpenCode supports both JSON and JSONC (JSON with Comments) formats for all configuration files.

Schema

Every config file should include a $schema field for editor validation and autocomplete:

  • Server/runtime config: "$schema": "https://opencode.ai/config.json"
  • TUI config: "$schema": "https://opencode.ai/tui.json"
{
  "$schema": "https://opencode.ai/config.json",
  "model": "anthropic/claude-sonnet-4-5",
  "autoupdate": true,
  "server": {
    "port": 4096
  }
}

Schemas enable autocompletion in VS Code, JetBrains editors, and other JSON-aware editors. Omitting the schema is valid but not recommended.


Config Locations & Precedence

Configuration files are merged together, not replaced. Settings from multiple locations are combined. Later sources override earlier ones only for conflicting keys. Non-conflicting settings from all configs are preserved.

Precedence Order (lowest to highest)

Config sources are loaded in this order (later sources override earlier ones):

PrioritySourceDescription
1 (lowest)Remote configOrganizational defaults from .well-known/opencode
2Global configUser preferences at ~/.config/opencode/opencode.json
3Custom configCustom overrides via OPENCODE_CONFIG env var
4Project configProject-specific settings at opencode.json in project root
5.opencode directoriesAgents, commands, modes, plugins, skills, tools, themes
6Inline configRuntime overrides via OPENCODE_CONFIG_CONTENT env var
7Managed config filesAdmin-controlled files in platform-specific directories
8 (highest)macOS managed preferences.mobileconfig via MDM โ€” not user-overridable

For example, if your global config sets autoupdate: true and your project config sets model: "anthropic/claude-sonnet-4-5", the final configuration will include both settings. If both set the same key, the project config wins.

Remote Config

Organizations can provide default configuration via the .well-known/opencode endpoint. This is fetched automatically when you authenticate with a provider that supports it.

Remote config is loaded first, serving as the base layer. All other config sources (global, project, managed) can override these defaults.

// Remote config from .well-known/opencode
{
  "mcp": {
    "jira": {
      "type": "remote",
      "url": "https://jira.example.com/mcp",
      "enabled": false
    }
  }
}

Override in your local config:

// opencode.json (project or global)
{
  "mcp": {
    "jira": {
      "type": "remote",
      "url": "https://jira.example.com/mcp",
      "enabled": true
    }
  }
}

Global Config

Place your global OpenCode config in ~/.config/opencode/opencode.json. Use global config for user-wide server/runtime preferences like providers, models, and permissions.

For TUI-specific settings, use ~/.config/opencode/tui.json.

Global config overrides remote organizational defaults.

Project Config

Add opencode.json in your project root. Project config has the highest precedence among standard config files โ€” it overrides both global and remote configs.

When OpenCode starts up, it first looks for a config file in the current directory, then traverses up to the nearest Git directory. This file is safe to check into Git and uses the same schema as the global one.

Custom Config Path (OPENCODE_CONFIG)

Specify a custom config file path using the OPENCODE_CONFIG environment variable:

export OPENCODE_CONFIG=/path/to/my/custom-config.json
opencode run "Hello world"

Custom config is loaded between global and project configs in the precedence order.

Custom Config Directory (OPENCODE_CONFIG_DIR)

Specify a custom config directory using the OPENCODE_CONFIG_DIR environment variable. This directory will be searched for agents, commands, modes, and plugins just like the standard .opencode directory:

export OPENCODE_CONFIG_DIR=/path/to/my/config-directory
opencode run "Hello world"

The custom directory is loaded after the global config and .opencode directories, so it can override their settings.

.opencode Directories

The .opencode and ~/.config/opencode directories use plural names for subdirectories: agents/, commands/, modes/, plugins/, skills/, tools/, and themes/. Singular names (e.g., agent/) are also supported for backwards compatibility.

Inline Config (OPENCODE_CONFIG_CONTENT)

Pass configuration directly as a JSON string via the OPENCODE_CONFIG_CONTENT environment variable. Useful for runtime overrides without touching files:

export OPENCODE_CONFIG_CONTENT='{"model": "anthropic/claude-sonnet-4-5"}'
opencode run "Hello world"

Config Merging Behavior

Configs are merged, not replaced. When two config sources define the same key, the merge behavior depends on the value type:

  • Scalar values (strings, numbers, booleans): later source wins
  • Objects: recursively merged; later source keys override earlier ones
  • Arrays: later source replaces the entire array (not appended)

Example flow:

  1. Global sets autoupdate: true
  2. Project sets model: "anthropic/claude-sonnet-4-5"
  3. Final config: both autoupdate: true AND model: "anthropic/claude-sonnet-4-5" are present

Example with arrays (important caveat):

  1. Global sets instructions: ["CONTRIBUTING.md"]
  2. Project sets instructions: ["docs/guidelines.md"]
  3. Final config: instructions: ["docs/guidelines.md"] โ€” the global array is replaced, not merged

All Config Fields

$schema

JSON Schema URL for editor validation and autocomplete.

{
  "$schema": "https://opencode.ai/config.json"
}

model

The primary LLM model used for conversations. Format: provider/model-name.

{
  "model": "anthropic/claude-sonnet-4-5"
}

small_model

A separate model for lightweight tasks like title generation and compaction summaries. By default, OpenCode tries to use a cheaper model from your provider, falling back to the main model.

{
  "small_model": "anthropic/claude-haiku-4-5"
}

provider

Provider configuration with API keys, endpoints, and options. Each key is a provider ID (e.g., anthropic, openai, amazon-bedrock, ollama).

{
  "provider": {
    "anthropic": {
      "models": {},
      "options": {
        "apiKey": "{env:ANTHROPIC_API_KEY}",
        "timeout": 600000,
        "chunkTimeout": 30000,
        "setCacheKey": true
      }
    }
  }
}

Provider options:

OptionTypeDefaultDescription
timeoutnumber | false300000Request timeout in milliseconds. Set to false to disable.
chunkTimeoutnumberโ€”Timeout in ms between streamed response chunks. Aborts if no chunk arrives in time.
setCacheKeybooleanโ€”Ensure a cache key is always set for the provider.
baseURLstringโ€”Custom base URL for the provider (useful for proxies, gateways, local servers).
headersobjectโ€”Custom HTTP headers sent with provider requests.

Custom provider (npm):

Use any OpenAI-compatible provider by specifying an npm package:

{
  "provider": {
    "ollama": {
      "npm": "@ai-sdk/openai-compatible",
      "name": "Ollama (local)",
      "options": {
        "baseURL": "http://localhost:11434/v1"
      },
      "models": {
        "llama2": {
          "name": "Llama 2"
        }
      }
    }
  }
}

plugin

Load plugins from npm packages or local paths:

{
  "plugin": ["opencode-helicone-session", "@my-org/custom-plugin"]
}

Plugins can also be placed in .opencode/plugins/ or ~/.config/opencode/plugins/ as JavaScript/TypeScript files, which are loaded automatically at startup.

mcp

MCP (Model Context Protocol) server configurations for adding external tools:

{
  "mcp": {
    "my-local-server": {
      "type": "local",
      "command": ["npx", "-y", "@my-org/mcp-server"],
      "enabled": true,
      "environment": {
        "MY_ENV_VAR": "value"
      }
    },
    "my-remote-server": {
      "type": "remote",
      "url": "https://mcp.example.com",
      "enabled": true,
      "headers": {
        "Authorization": "Bearer {env:MY_API_KEY}"
      }
    }
  }
}

Local MCP options:

OptionTypeRequiredDescription
type"local"YesMust be "local"
commandarrayYesCommand and arguments to run the MCP server
environmentobjectNoEnvironment variables for the server process
enabledbooleanNoEnable/disable the server on startup
timeoutnumberNoTimeout in ms for fetching tools (default: 5000)

Remote MCP options:

OptionTypeRequiredDescription
type"remote"YesMust be "remote"
urlstringYesURL of the remote MCP server
enabledbooleanNoEnable/disable the server on startup
headersobjectNoHTTP headers for the request
oauthobject | falseNoOAuth config or false to disable OAuth auto-detection
timeoutnumberNoTimeout in ms for fetching tools (default: 5000)

Remote MCP OAuth options:

OptionTypeDescription
clientIdstringOAuth client ID. If not provided, dynamic client registration is attempted.
clientSecretstringOAuth client secret, if required.
scopestringOAuth scopes to request.

tools

Enable/disable tools globally. Set a tool to false to disable it, or true to enable it:

{
  "tools": {
    "write": false,
    "bash": false
  }
}

Glob patterns are supported for MCP tool names:

{
  "tools": {
    "my-mcp*": false
  }
}

As of v1.1.1, the legacy tools boolean config is deprecated and has been merged into permission.

permission

Granular permission rules for tool execution. Controls whether actions require user approval, are auto-approved, or are blocked.

{
  "permission": {
    "*": "ask",
    "bash": "ask",
    "edit": "allow",
    "bash": {
      "*": "ask",
      "git *": "allow",
      "rm *": "deny"
    },
    "edit": {
      "*": "deny",
      "packages/web/src/*.mdx": "allow"
    }
  }
}

Permission values:

ValueDescription
"allow"Run without approval
"ask"Prompt user for approval
"deny"Block the action

Available permission keys:

KeyMatches
readFile reads (matches file path)
editAll file modifications (edit, write, patch)
globFile globbing (matches glob pattern)
grepContent search (matches regex pattern)
bashShell commands (matches parsed commands)
taskSubagent launches (matches subagent type)
skillSkill loading (matches skill name)
lspLSP queries (currently non-granular)
questionUser questions during execution
webfetchURL fetching (matches URL)
websearchWeb search (matches query)
external_directoryTool calls touching paths outside project root
doom_loopTriggered when same tool call repeats 3x with identical input
*Catch-all for any permission

Granular rules (object syntax):

Rules are evaluated by pattern match, with the last matching rule winning. Use "*" as catch-all first, then specific patterns after.

  • * matches zero or more of any character
  • ? matches exactly one character
  • All other characters match literally

Home directory expansion:

Use ~ or $HOME at the start of a pattern to reference your home directory:

  • ~/projects/* โ†’ /Users/username/projects/*
  • $HOME/projects/* โ†’ /Users/username/projects/*

External directory access:

Use external_directory to allow tool calls that touch paths outside the working directory:

{
  "permission": {
    "external_directory": {
      "~/projects/personal/**": "allow"
    }
  }
}

Defaults (if nothing is specified):

  • Most permissions default to "allow"
  • doom_loop and external_directory default to "ask"
  • read defaults to "allow" but .env files are denied:
{
  "permission": {
    "read": {
      "*": "allow",
      "*.env": "deny",
      "*.env.*": "deny",
      "*.env.example": "allow"
    }
  }
}

What "Ask" does:

When OpenCode prompts for approval, three outcomes are offered:

  • once โ€” approve just this request
  • always โ€” approve future requests matching suggested patterns (rest of session)
  • reject โ€” deny the request

Agent-level permissions:

Permissions can be overridden per agent. Agent permissions merge with global config, and agent rules take precedence:

{
  "permission": {
    "bash": {
      "*": "ask",
      "git *": "allow"
    }
  },
  "agent": {
    "build": {
      "permission": {
        "bash": {
          "*": "ask",
          "git commit *": "ask",
          "git push *": "deny"
        }
      }
    }
  }
}

agent

Define specialized agents for specific tasks. Each agent can have its own model, prompt, tools, permissions, and other settings.

{
  "agent": {
    "code-reviewer": {
      "description": "Reviews code for best practices and potential issues",
      "model": "anthropic/claude-sonnet-4-5",
      "prompt": "You are a code reviewer. Focus on security, performance, and maintainability.",
      "tools": {
        "write": false,
        "edit": false
      },
      "permission": {
        "edit": "deny"
      }
    }
  }
}

Agents can also be defined as markdown files in ~/.config/opencode/agents/ or .opencode/agents/:

---
description: Code review without edits
mode: subagent
permission:
  edit: deny
  bash: ask
  webfetch: deny
---
Only analyze code and suggest changes.

default_agent

Set the default agent used when none is explicitly specified. Must be a primary agent (not a subagent). Can be a built-in agent ("build", "plan") or a custom agent. Falls back to "build" with a warning if the specified agent doesn't exist or is a subagent.

{
  "default_agent": "plan"
}

This setting applies across all interfaces: TUI, CLI (opencode run), desktop app, and GitHub Action.

share

Configure the conversation sharing feature:

{
  "share": "manual"
}
ValueDescription
"manual"Allow manual sharing via /share command (default)
"auto"Automatically share new conversations
"disabled"Disable sharing entirely

command

Define custom slash commands for repetitive tasks:

{
  "command": {
    "test": {
      "template": "Run the full test suite with coverage report and show any failures.\nFocus on the failing tests and suggest fixes.",
      "description": "Run tests with coverage",
      "agent": "build",
      "model": "anthropic/claude-haiku-4-5"
    },
    "component": {
      "template": "Create a new React component named $ARGUMENTS with TypeScript support.\nInclude proper typing and basic structure.",
      "description": "Create a new component"
    }
  }
}

Commands can also be defined as markdown files in ~/.config/opencode/commands/ or .opencode/commands/.

formatter

Enable and configure code formatters. Omit to keep formatters disabled.

{
  "formatter": true
}

Use an object to keep built-ins enabled while configuring overrides or custom formatters:

{
  "formatter": {
    "prettier": {
      "disabled": true
    },
    "custom-prettier": {
      "command": ["npx", "prettier", "--write", "$FILE"],
      "environment": {
        "NODE_ENV": "development"
      },
      "extensions": [".js", ".ts", ".jsx", ".tsx"]
    }
  }
}

lsp

Enable and configure LSP (Language Server Protocol) servers. Omit to keep LSP disabled.

{
  "lsp": true
}

Use an object to keep built-ins enabled while configuring overrides:

{
  "lsp": {
    "typescript": {
      "disabled": true
    }
  }
}

snapshot

OpenCode uses snapshots to track file changes during agent operations, enabling undo/revert within a session. Snapshots are enabled by default.

For large repositories or projects with many submodules, disable snapshots to avoid slow indexing and significant disk usage:

{
  "snapshot": false
}

Disabling snapshots means changes made by the agent cannot be rolled back through the UI.

autoupdate

OpenCode automatically downloads new updates on startup.

{
  "autoupdate": false
}
ValueDescription
trueAuto-download updates (default)
falseDisable auto-updates
"notify"Notify without auto-downloading (only works if not installed via package manager like Homebrew)

instructions

Point to instruction/rule files using paths and glob patterns. These files are loaded as system instructions for the LLM:

{
  "instructions": ["CONTRIBUTING.md", "docs/guidelines.md", ".cursor/rules/*.md"]
}

disabled_providers

Disable specific providers that would otherwise be loaded automatically:

{
  "disabled_providers": ["openai", "gemini"]
}

When a provider is disabled:

  • It won't be loaded even if environment variables are set
  • It won't be loaded even if API keys are configured via /connect
  • The provider's models won't appear in the model selection list

enabled_providers

Allowlist specific providers. When set, only the specified providers will be enabled and all others will be ignored:

{
  "enabled_providers": ["anthropic", "openai"]
}

disabled_providers takes priority over enabled_providers. If a provider appears in both, it is disabled.

experimental

Options under active development. Not stable โ€” may change or be removed without notice.

{
  "experimental": {
    "policies": [
      {
        "effect": "deny",
        "action": "provider.use",
        "resource": "openai"
      }
    ]
  }
}

Policies allow or deny OpenCode actions on configured resources. Currently, policies can control which providers OpenCode may use.

attachment.image

Configure image attachment limits. OpenCode normalizes images before sending to the model. By default, images are resized when they exceed 2000x2000 pixels or 5242880 base64 bytes.

{
  "attachment": {
    "image": {
      "auto_resize": true,
      "max_width": 2000,
      "max_height": 2000,
      "max_base64_bytes": 5242880
    }
  }
}
OptionTypeDescription
auto_resizebooleanResize images exceeding limits. Set to false to reject oversized images instead.
max_widthnumberMaximum image width in pixels before resizing or rejection.
max_heightnumberMaximum image height in pixels before resizing or rejection.
max_base64_bytesnumberMaximum encoded image payload size (base64 bytes, not original file size).

If an image still cannot fit after resizing, OpenCode omits oversized tool-result images or fails oversized user-provided images with an image size error.

compaction

Control context compaction behavior:

{
  "compaction": {
    "auto": true,
    "prune": true,
    "reserved": 10000
  }
}
OptionTypeDefaultDescription
autobooleantrueAutomatically compact the session when context is full.
prunebooleantrueRemove old tool outputs to save tokens.
reservednumberโ€”Token buffer for compaction. Leaves enough window to avoid overflow during compaction.

watcher

Configure file watcher ignore patterns:

{
  "watcher": {
    "ignore": ["node_modules/**", "dist/**", ".git/**"]
  }
}

Patterns follow glob syntax. Use this to exclude noisy directories from file watching.

shell

Configure the shell used for the interactive terminal and agent tool calls:

{
  "shell": "pwsh"
}

If not specified, OpenCode automatically discovers a sensible default based on your OS (pwsh or cmd.exe on Windows, /bin/zsh or /bin/bash on macOS/Linux). You can provide an absolute path or a short name.

server

Configure server settings for opencode serve and opencode web commands:

{
  "server": {
    "port": 4096,
    "hostname": "0.0.0.0",
    "mdns": true,
    "mdnsDomain": "myproject.local",
    "cors": ["http://localhost:5173"]
  }
}
OptionTypeDescription
portnumberPort to listen on.
hostnamestringHostname to listen on. When mdns is enabled and no hostname is set, defaults to 0.0.0.0.
mdnsbooleanEnable mDNS service discovery. Allows other devices on the network to discover your OpenCode server.
mdnsDomainstringCustom domain name for mDNS service. Defaults to opencode.local. Useful for running multiple instances on the same network.
corsarrayAdditional origins to allow for CORS. Values must be full origins (scheme + host + optional port), e.g., https://app.example.com.

TUI Config (tui.json)

Use a dedicated tui.json (or tui.jsonc) file for TUI-specific settings. This is separate from opencode.json, which configures server/runtime behavior.

{
  "$schema": "https://opencode.ai/tui.json",
  "theme": "tokyonight",
  "leader_timeout": 2000,
  "scroll_speed": 3,
  "scroll_acceleration": {
    "enabled": false
  },
  "diff_style": "auto",
  "mouse": true,
  "keybinds": {
    "leader": "ctrl+x",
    "command_list": "ctrl+p"
  },
  "attention": {
    "enabled": true,
    "notifications": true,
    "sound": true,
    "volume": 0.4,
    "sound_pack": "opencode.default",
    "sounds": {
      "error": "./sounds/error.mp3"
    }
  }
}

Use OPENCODE_TUI_CONFIG to point to a custom TUI config file.

Legacy theme, keybinds, and tui keys in opencode.json are deprecated and automatically migrated when possible.

TUI Options

OptionTypeDescription
themestringSets your UI theme.
keybindsobjectCustomizes keyboard shortcuts. Merged with built-in defaults, so only configure shortcuts you want to change.
leader_timeoutnumberHow long OpenCode waits after the leader key. Defaults to 2000 ms.
scroll_speednumberHow fast the TUI scrolls (minimum: 0.001, supports decimals). Defaults to 3. Ignored if scroll_acceleration.enabled is true.
scroll_acceleration.enabledbooleanEnable macOS-style scroll acceleration. When enabled, scroll speed increases with rapid scrolling gestures. Takes precedence over scroll_speed.
diff_stylestringControls diff rendering. "auto" adapts to terminal width, "stacked" always shows single-column layout.
mousebooleanEnable or disable mouse capture in the TUI (default: true). When disabled, terminal's native mouse selection/scrolling behavior is preserved.
attentionobjectConfigures TUI desktop notifications and sounds. Disabled by default.

Keybinds

All customizable keybinds with their defaults:

{
  "keybinds": {
    "leader": "ctrl+x",
    "app_exit": "ctrl+c,ctrl+d,<leader>q",
    "app_debug": "none",
    "app_console": "none",
    "app_heap_snapshot": "none",
    "app_toggle_animations": "none",
    "app_toggle_file_context": "none",
    "app_toggle_diffwrap": "none",
    "app_toggle_paste_summary": "none",
    "app_toggle_session_directory_filter": "none",
    "command_list": "ctrl+p",
    "help_show": "none",
    "docs_open": "none",
    "editor_open": "<leader>e",
    "theme_list": "<leader>t",
    "theme_switch_mode": "none",
    "theme_mode_lock": "none",
    "sidebar_toggle": "<leader>b",
    "scrollbar_toggle": "none",
    "status_view": "<leader>s",
    "session_export": "<leader>x",
    "session_copy": "none",
    "session_new": "<leader>n",
    "session_list": "<leader>l",
    "session_timeline": "<leader>g",
    "session_fork": "none",
    "session_rename": "ctrl+r",
    "session_delete": "ctrl+d",
    "session_share": "none",
    "session_unshare": "none",
    "session_interrupt": "escape",
    "session_compact": "<leader>c",
    "session_toggle_timestamps": "none",
    "session_toggle_generic_tool_output": "none",
    "session_child_first": "<leader>down",
    "session_child_cycle": "right",
    "session_child_cycle_reverse": "left",
    "session_parent": "up",
    "stash_delete": "ctrl+d",
    "model_provider_list": "ctrl+a",
    "model_favorite_toggle": "ctrl+f",
    "model_list": "<leader>m",
    "model_cycle_recent": "f2",
    "model_cycle_recent_reverse": "shift+f2",
    "model_cycle_favorite": "none",
    "model_cycle_favorite_reverse": "none",
    "mcp_list": "none",
    "provider_connect": "none",
    "console_org_switch": "none",
    "agent_list": "<leader>a",
    "agent_cycle": "tab",
    "agent_cycle_reverse": "shift+tab",
    "variant_cycle": "ctrl+t",
    "variant_list": "none",
    "messages_page_up": "pageup,ctrl+alt+b",
    "messages_page_down": "pagedown,ctrl+alt+f",
    "messages_line_up": "ctrl+alt+y",
    "messages_line_down": "ctrl+alt+e",
    "messages_half_page_up": "ctrl+alt+u",
    "messages_half_page_down": "ctrl+alt+d",
    "messages_first": "ctrl+g,home",
    "messages_last": "ctrl+alt+g,end",
    "messages_next": "none",
    "messages_previous": "none",
    "messages_last_user": "none",
    "messages_copy": "<leader>y",
    "messages_undo": "<leader>u",
    "messages_redo": "<leader>r",
    "messages_toggle_conceal": "<leader>h",
    "tool_details": "none",
    "display_thinking": "none",
    "prompt_submit": "none",
    "prompt_editor_context_clear": "none",
    "prompt_skills": "none",
    "prompt_stash": "none",
    "prompt_stash_pop": "none",
    "prompt_stash_list": "none",
    "workspace_set": "none",
    "input_clear": "ctrl+c",
    "input_paste": {
      "key": "ctrl+v",
      "preventDefault": false
    },
    "input_submit": "return",
    "input_newline": "shift+return,ctrl+return,alt+return,ctrl+j",
    "input_move_left": "left,ctrl+b",
    "input_move_right": "right,ctrl+f",
    "input_move_up": "up",
    "input_move_down": "down",
    "input_select_left": "shift+left",
    "input_select_right": "shift+right",
    "input_select_up": "shift+up",
    "input_select_down": "shift+down",
    "input_line_home": "ctrl+a",
    "input_line_end": "ctrl+e",
    "input_select_line_home": "ctrl+shift+a",
    "input_select_line_end": "ctrl+shift+e",
    "input_visual_line_home": "alt+a",
    "input_visual_line_end": "alt+e",
    "input_select_visual_line_home": "alt+shift+a",
    "input_select_visual_line_end": "alt+shift+e",
    "input_buffer_home": "home",
    "input_buffer_end": "end",
    "input_select_buffer_home": "shift+home",
    "input_select_buffer_end": "shift+end",
    "input_delete_line": "ctrl+shift+d",
    "input_delete_to_line_end": "ctrl+k",
    "input_delete_to_line_start": "ctrl+u",
    "input_backspace": "backspace,shift+backspace",
    "input_delete": "ctrl+d,delete,shift+delete",
    "input_undo": "ctrl+-,super+z",
    "input_redo": "ctrl+.,super+shift+z",
    "input_word_forward": "alt+f,alt+right,ctrl+right",
    "input_word_backward": "alt+b,alt+left,ctrl+left",
    "input_select_word_forward": "alt+shift+f,alt+shift+right",
    "input_select_word_backward": "alt+shift+b,alt+shift+left",
    "input_delete_word_forward": "alt+d,alt+delete,ctrl+delete",
    "input_delete_word_backward": "ctrl+w,ctrl+backspace,alt+backspace",
    "input_select_all": "super+a",
    "history_previous": "up",
    "history_next": "down",
    "dialog.select.prev": "up,ctrl+p",
    "dialog.select.next": "down,ctrl+n",
    "dialog.select.page_up": "pageup",
    "dialog.select.page_down": "pagedown",
    "dialog.select.home": "home",
    "dialog.select.end": "end",
    "dialog.select.submit": "return",
    "dialog.prompt.submit": "return",
    "dialog.mcp.toggle": "space",
    "prompt.autocomplete.prev": "up,ctrl+p",
    "prompt.autocomplete.next": "down,ctrl+n",
    "prompt.autocomplete.hide": "escape",
    "prompt.autocomplete.select": "return",
    "prompt.autocomplete.complete": "tab",
    "permission.prompt.fullscreen": "ctrl+f",
    "plugins.toggle": "space",
    "dialog.plugins.install": "shift+i",
    "terminal_suspend": "ctrl+z",
    "terminal_title_toggle": "none",
    "tips_toggle": "<leader>h",
    "plugin_manager": "none",
    "plugin_install": "none",
    "which_key_toggle": "ctrl+alt+k",
    "which_key_layout_toggle": "ctrl+alt+shift+k",
    "which_key_pending_toggle": "ctrl+alt+shift+p",
    "which_key_group_previous": "ctrl+alt+left,ctrl+alt+[",
    "which_key_group_next": "ctrl+alt+right,ctrl+alt+]",
    "which_key_scroll_up": "ctrl+alt+up,ctrl+alt+p",
    "which_key_scroll_down": "ctrl+alt+down,ctrl+alt+n",
    "which_key_page_up": "ctrl+alt+pageup",
    "which_key_page_down": "ctrl+alt+pagedown",
    "which_key_home": "ctrl+alt+home",
    "which_key_end": "ctrl+alt+end"
  }
}

Windows defaults differ for:

  • input_undo defaults to ctrl+z,ctrl+-,super+z (adds ctrl+z because Windows terminals don't support POSIX suspend)
  • terminal_suspend is forced to none (native Windows terminals don't support POSIX suspend)

Binding values:

A string can contain one shortcut or multiple comma-separated shortcuts. Use an array for multiple shortcuts:

{
  "keybinds": {
    "messages_copy": ["<leader>y", "ctrl+shift+c"]
  }
}

For advanced cases, use an object with key, event, preventDefault, or fallthrough:

{
  "keybinds": {
    "input_paste": {
      "key": "ctrl+v",
      "preventDefault": false
    }
  }
}

Disable a keybind by setting it to "none" or false:

{
  "keybinds": {
    "session_compact": "none"
  }
}

Attention (Notifications & Sound)

The attention section controls TUI desktop notifications and sounds. Disabled by default.

{
  "attention": {
    "enabled": true,
    "notifications": true,
    "sound": true,
    "volume": 0.4,
    "sound_pack": "opencode.default",
    "sounds": {
      "default": "./sounds/default.mp3",
      "question": "./sounds/question.mp3",
      "permission": "./sounds/permission.mp3",
      "error": "./sounds/error.mp3",
      "done": "./sounds/done.mp3",
      "subagent_done": "./sounds/subagent_done.mp3"
    }
  }
}
OptionTypeDefaultDescription
enabledbooleanfalseMaster switch for all attention features.
notificationsbooleantrueAllow terminal-mediated desktop notifications when attention is enabled.
soundbooleantrueAllow attention sounds when attention is enabled.
volumenumber0.4Sound volume from 0 to 1.
sound_packstring"opencode.default"Sound pack ID to use.
soundsobject{}Override individual sound files for default, question, permission, error, done, or subagent_done. Paths can be absolute, file:// URLs, or relative to tui.json.

Built-in events play sounds when triggered, and non-subagent events request desktop notifications only when the terminal is blurred.


Variable Substitution

Use variable substitution in config files to reference environment variables and file contents.

Environment Variables

Use {env:VARIABLE_NAME} to substitute environment variables:

{
  "$schema": "https://opencode.ai/config.json",
  "model": "{env:OPENCODE_MODEL}",
  "provider": {
    "anthropic": {
      "options": {
        "apiKey": "{env:ANTHROPIC_API_KEY}"
      }
    }
  }
}

If the environment variable is not set, it is replaced with an empty string.

File Contents

Use {file:path/to/file} to substitute the contents of a file:

{
  "$schema": "https://opencode.ai/config.json",
  "instructions": ["./custom-instructions.md"],
  "provider": {
    "openai": {
      "options": {
        "apiKey": "{file:~/.secrets/openai-key}"
      }
    }
  }
}

File paths can be:

  • Relative to the config file directory
  • Absolute paths starting with / or ~

Useful for:

  • Keeping sensitive data like API keys in separate files
  • Including large instruction files without cluttering your config
  • Sharing common configuration snippets across multiple config files

Managed Settings (Enterprise)

Organizations can enforce configuration that users cannot override. Managed settings are loaded at the highest priority tier (tier 7-8), overriding everything else.

File-based

Drop an opencode.json or opencode.jsonc file in the system managed config directory:

PlatformPath
macOS/Library/Application Support/opencode/
Linux/etc/opencode/
Windows%ProgramData%\opencode

These directories require admin/root access to write, so users cannot modify them.

macOS Managed Preferences (.mobileconfig via MDM)

On macOS, OpenCode reads managed preferences from the ai.opencode.managed preference domain. Deploy a .mobileconfig via MDM (Jamf, Kandji, FleetDM) and the settings are enforced automatically.

OpenCode checks these paths:

  1. /Library/Managed Preferences/<user>/ai.opencode.managed.plist
  2. /Library/Managed Preferences/ai.opencode.managed.plist

The plist keys map directly to opencode.json fields. MDM metadata keys (PayloadUUID, PayloadType, etc.) are stripped automatically.

Creating a .mobileconfig:

Use the ai.opencode.managed PayloadType. The OpenCode config keys go directly in the payload dict:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN"
  "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
  <key>PayloadContent</key>
  <array>
    <dict>
      <key>PayloadType</key>
      <string>ai.opencode.managed</string>
      <key>PayloadIdentifier</key>
      <string>com.example.opencode.config</string>
      <key>PayloadUUID</key>
      <string>GENERATE-YOUR-OWN-UUID</string>
      <key>PayloadVersion</key>
      <integer>1</integer>
      <key>share</key>
      <string>disabled</string>
      <key>server</key>
      <dict>
        <key>hostname</key>
        <string>127.0.0.1</string>
      </dict>
      <key>permission</key>
      <dict>
        <key>*</key>
        <string>ask</string>
        <key>bash</key>
        <dict>
          <key>*</key>
          <string>ask</string>
          <key>rm -rf *</key>
          <string>deny</string>
        </dict>
      </dict>
    </dict>
  </array>
  <key>PayloadType</key>
  <string>Configuration</string>
  <key>PayloadIdentifier</key>
  <string>com.example.opencode</string>
  <key>PayloadUUID</key>
  <string>GENERATE-YOUR-OWN-UUID</string>
  <key>PayloadVersion</key>
  <integer>1</integer>
</dict>
</plist>

Generate unique UUIDs with uuidgen. Customize the settings to match your organization's requirements.

Deploying via MDM:

  • Jamf Pro: Computers > Configuration Profiles > Upload > scope to target devices or smart groups
  • Kandji: Custom Profiles > upload the .mobileconfig
  • FleetDM: Add the .mobileconfig to your gitops repo under mdm.macos_settings.custom_settings and run fleetctl apply

Verifying on a device:

opencode debug config

All managed preference keys appear in the resolved config and cannot be overridden by user or project configuration.


Provider-Specific Options

Amazon Bedrock

Amazon Bedrock supports AWS-specific configuration:

{
  "provider": {
    "amazon-bedrock": {
      "options": {
        "region": "us-east-1",
        "profile": "my-aws-profile",
        "endpoint": "https://bedrock-runtime.us-east-1.vpce-xxxxx.amazonaws.com"
      }
    }
  }
}
OptionDescription
regionAWS region for Bedrock (defaults to AWS_REGION env var or us-east-1).
profileAWS named profile from ~/.aws/credentials (defaults to AWS_PROFILE env var).
endpointCustom endpoint URL for VPC endpoints. Alias for generic baseURL using AWS-specific terminology. If both specified, endpoint takes precedence.

Authentication methods:

  • AWS_ACCESS_KEY_ID / AWS_SECRET_ACCESS_KEY: IAM user access keys
  • AWS_PROFILE: Named profiles from ~/.aws/credentials
  • AWS_BEARER_TOKEN_BEDROCK: Long-term API keys from the Bedrock console
  • AWS_WEB_IDENTITY_TOKEN_FILE / AWS_ROLE_ARN: EKS IRSA (IAM Roles for Service Accounts)

Authentication precedence:

  1. Bearer Token โ€” AWS_BEARER_TOKEN_BEDROCK environment variable or token from /connect command
  2. AWS Credential Chain โ€” Profile, access keys, shared credentials, IAM roles, Web Identity Tokens (EKS IRSA), instance metadata

Bearer tokens take precedence over all AWS credential methods including configured profiles.

Custom inference profiles:

{
  "provider": {
    "amazon-bedrock": {
      "models": {
        "anthropic-claude-sonnet-4.5": {
          "id": "arn:aws:bedrock:us-east-1:xxx:application-inference-profile/yyy"
        }
      }
    }
  }
}

Generic Provider Options (All Providers)

OptionTypeDescription
baseURLstringCustom base URL for the provider. Useful for proxies, gateways, or local servers.
timeoutnumber | falseRequest timeout in milliseconds (default: 300000). Set to false to disable.
chunkTimeoutnumberTimeout between streamed response chunks.
setCacheKeybooleanEnsure a cache key is always set.
headersobjectCustom HTTP headers for requests.

Environment Variables

VariablePurpose
OPENCODE_CONFIGPath to custom config file
OPENCODE_CONFIG_DIRPath to custom config directory
OPENCODE_CONFIG_CONTENTInline JSON config string
OPENCODE_TUI_CONFIGPath to custom TUI config file
OPENCODE_SERVER_PASSWORDPassword for server authentication
OPENCODE_SERVER_USERNAMEUsername for server authentication
OPENCODE_PORTPort for the server
OPENCODE_ENABLE_EXAEnable Exa integration
OPENCODE_EXPERIMENTAL_LSP_TOOLEnable experimental LSP tool
OPENCODE_EXPERIMENTALEnable experimental features
OPENCODE_DISABLE_LSP_DOWNLOADDisable automatic LSP server downloads
OPENCODE_DISABLE_CLAUDE_CODEDisable Claude Code integration
OPENCODE_DISABLE_CLAUDE_CODE_PROMPTDisable Claude Code prompt
OPENCODE_DISABLE_CLAUDE_CODE_SKILLSDisable Claude Code skills
AUTO_SHAREEnable automatic sharing
AWS_REGIONAWS region for Bedrock
AWS_PROFILEAWS profile for Bedrock
AWS_BEARER_TOKEN_BEDROCKBearer token for Bedrock
AWS_ACCESS_KEY_IDAWS access key ID
AWS_SECRET_ACCESS_KEYAWS secret access key
AWS_WEB_IDENTITY_TOKEN_FILEWeb identity token file for EKS IRSA
AWS_ROLE_ARNRole ARN for EKS IRSA
ANTHROPIC_API_KEYAnthropic API key
OPENAI_API_KEYOpenAI API key
AZURE_RESOURCE_NAMEAzure OpenAI resource name
AZURE_COGNITIVE_SERVICES_RESOURCE_NAMEAzure Cognitive Services resource name
GOOGLE_CLOUD_PROJECTGoogle Cloud project ID for Vertex AI
GOOGLE_APPLICATION_CREDENTIALSPath to service account JSON key for Vertex AI
VERTEX_LOCATIONRegion for Vertex AI (defaults to global)
GITLAB_INSTANCE_URLGitLab instance URL for self-hosted
GITLAB_TOKENGitLab personal access token
GITLAB_AI_GATEWAY_URLCustom AI Gateway URL for self-hosted GitLab
GITLAB_OAUTH_CLIENT_IDOAuth client ID for self-hosted GitLab
DIGITALOCEAN_ACCESS_TOKENDigitalOcean Model Access Key
CLOUDFLARE_ACCOUNT_IDCloudflare account ID
CLOUDFLARE_API_KEYCloudflare API key
CLOUDFLARE_GATEWAY_IDCloudflare AI Gateway ID
CLOUDFLARE_API_TOKENCloudflare API token
NVIDIA_API_KEYNVIDIA API key
AICORE_SERVICE_KEYSAP AI Core service key JSON
AICORE_DEPLOYMENT_IDSAP AI Core deployment ID
AICORE_RESOURCE_GROUPSAP AI Core resource group
CONTEXT7_API_KEYContext7 MCP API key

Debugging & Verification

Use the debug command to verify your resolved configuration:

opencode debug config

This displays the fully merged configuration from all sources, including managed preferences. Useful for:

  • Troubleshooting precedence issues
  • Confirming that MDM-deployed settings are active
  • Verifying variable substitution resolved correctly
  • Checking which providers are enabled/disabled
  • Inspecting resolved permission rules

Troubleshooting

IssueSolution
Config not taking effectRun opencode debug config to see the resolved configuration and verify precedence.
Managed settings not applyingCheck that the .mobileconfig is installed (System Settings > Privacy & Security > Profiles on macOS) and that the PayloadType is ai.opencode.managed.
Provider not loadingCheck disabled_providers and enabled_providers โ€” disabled_providers takes priority. Also verify API keys are set via /connect or environment variables.
Variable not resolvingEnsure the environment variable is set in the same shell session. {env:VAR} replaces with empty string if unset.
File reference failingVerify the path is relative to the config file directory, or use an absolute path starting with / or ~.
TUI theme not applyingUse tui.json, not opencode.json. Legacy theme key in opencode.json is deprecated.
MCP server tools not appearingCheck tools config โ€” MCP tools can be disabled globally with glob patterns like "my-mcp*": false.
Permission denied for external pathsAdd external_directory rules to allow access to paths outside the project root.
Array config not merging as expectedArrays are replaced, not appended. Later config sources replace entire arrays from earlier sources.
Plugins not loadingCheck that npm plugins are in the plugin array and local plugins are in .opencode/plugins/ or ~/.config/opencode/plugins/.
Keybind not workingVerify the keybind value is not set to "none". Check for conflicts with terminal keybindings.
Agent not showing upEnsure it's defined as a primary agent (not a subagent) if using default_agent. Check that agent markdown files have valid frontmatter.

Keep looking

Skills are one crate of 328,083. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.