OpenCode — Configuration Reference

Complete OpenCode 2 configuration reference. Covers opencode.jsonc settings, providers, permissions, MCP servers, skills, plugins, and the V1 compatibility mapping.

October 20, 2026
opencodeconfigurationmcpskillssettings

OpenCode — Configuration Reference

OpenCode 2 uses opencode.json or opencode.jsonc for server and project settings, and ~/.config/opencode/ for global configuration. The .opencode/ directory stores project-specific agents, commands, skills, and plugins.

V1 configuration is still loaded and normalized in memory, so an existing opencode.json keeps working. The native V2 shapes below are what new configuration should use.

opencode.jsonc

Project root, .opencode/opencode.jsonc, or ~/.config/opencode/opencode.jsonc:

{
  "$schema": "https://opencode.ai/config.json",
  "model": "anthropic/claude-sonnet-5-5",
  "permissions": [
    { "action": "shell", "resource": "*", "effect": "ask" },
    { "action": "shell", "resource": "git status *", "effect": "allow" },
    { "action": "shell", "resource": "git diff *", "effect": "allow" }
  ],
  "mcp": {
    "servers": {}
  }
}

Most providers are auto-detected from /connect credentials or their environment variables, so a providers block is only required for custom endpoints, local runtimes, or non-default options.

Precedence

OpenCode searches from the current directory to the filesystem root, merges direct opencode.json(c) files from farthest to closest, then merges .opencode/opencode.json(c) files in the same order. Every discovered .opencode config overrides every direct config.

Precedence, highest last:

  1. ~/.config/opencode/opencode.json(c)
  2. ancestor project configs
  3. the current project's opencode.json(c)
  4. /etc/opencode/opencode.json(c) (or the macOS equivalent)

Managed preferences deployed by MDM override everything. They are the only reliable way to enforce restrictions; ordinary settings cannot stop a user from adding providers or MCP servers. Use policies for that.

Variables

{env:NAME} substitutes an environment variable and {file:path} substitutes file contents. Both resolve inside JSON strings:

{
  "providers": {
    "acme": {
      "settings": {
        "apiKey": "{env:ACME_API_KEY}"
      }
    }
  }
}

Providers

V2 keys providers under providers. The old singular provider map is V1 syntax.

{
  "$schema": "https://opencode.ai/config.json",
  "providers": {
    "anthropic": {
      "settings": {
        "apiKey": "{env:ANTHROPIC_API_KEY}"
      }
    },
    "acme": {
      "name": "Acme",
      "env": ["ACME_API_KEY"],
      "package": "@opencode/ai/providers/openai-compatible",
      "settings": {
        "baseURL": "https://llm.acme.example/v1"
      },
      "models": {
        "qwen3-coder": {
          "name": "Qwen 3 Coder"
        }
      }
    }
  }
}
KeyDescription
nameDisplay name in the UI
envOrdered environment variable names that can supply the credential
packageRuntime provider package, such as @opencode/ai/providers/openai-compatible
canonicalBuilt-in provider ID whose catalog defaults this provider inherits
compatibilityAPI quirks shared by every model of the provider
settingsProvider package options such as baseURL, apiKey, and timeouts
headersExtra HTTP headers on every request
bodyJSON fields merged into every request body
modelsModels to add or override, keyed by the OpenCode model ID

settings.apiKey accepts {env:VAR} or {file:path}. settings.baseURL points a catalog provider at a proxy or compatible endpoint.

Models

Models live under a provider's models map. The map key is the ID you select; modelID is the ID sent to the provider.

KeyDescription
modelIDModel or deployment ID sent upstream
nameDisplay name
capabilitiesTool support, input/output media, reasoning controls
limitContext, input, and output token limits
costInput, output, and cache pricing per million tokens
settings / headers / bodyRequest overrides for this model
variantsNamed option sets, selected as provider/model#variant
disabledHides the model from selection

Local runtimes are discovered automatically: Ollama on 127.0.0.1:11434, LM Studio on 127.0.0.1:1234, and vLLM on 127.0.0.1:8000. Point them elsewhere with providers.<id>.settings.baseURL.

Permissions

V2 replaces per-tool permission maps with one ordered permissions array. The last matching rule wins.

{
  "$schema": "https://opencode.ai/config.json",
  "permissions": [
    { "action": "shell", "resource": "*", "effect": "ask" },
    { "action": "shell", "resource": "git *", "effect": "allow" },
    { "action": "shell", "resource": "git commit *", "effect": "deny" },
    { "action": "shell", "resource": "git push *", "effect": "deny" },
    { "action": "shell", "resource": "npm run *", "effect": "allow" },
    { "action": "shell", "resource": "rm *", "effect": "deny" },
    { "action": "edit", "resource": "*", "effect": "deny" },
    { "action": "edit", "resource": "packages/web/src/content/docs/*.mdx", "effect": "allow" }
  ]
}

Each rule has three string fields:

FieldMeaning
actionTool or permission action
resourcePath, command, URL, query, skill ID, or agent ID
effectallow, deny, or ask

Built-in actions use read, edit, glob, grep, shell, subagent, skill, webfetch, websearch, external_directory, and question. V1 names changed: bash is now shell, task is now subagent, and write and patch are now edit.

A shell pattern ending in * also matches the command without arguments, so git status * covers both git status and git status --short.

Defaults

Every agent starts with this base policy:

[
  { "action": "*", "resource": "*", "effect": "allow" },
  { "action": "read", "resource": "*.env", "effect": "ask" },
  { "action": "read", "resource": "*.env.*", "effect": "ask" },
  { "action": "read", "resource": "*.env.example", "effect": "allow" }
]

External paths are allowed by default in V2; V1 asked first. To restore the V1 prompt:

{
  "permissions": [
    { "action": "external_directory", "resource": "*", "effect": "ask" }
  ]
}

Agents

V2 replaces the singular agent map and the deprecated mode map with agents:

{
  "$schema": "https://opencode.ai/config.json",
  "agents": {
    "reviewer": {
      "description": "Review changes without editing files",
      "mode": "subagent",
      "system": "Focus on correctness, security, and missing tests.",
      "model": "anthropic/claude-sonnet-5-5#high",
      "permissions": [
        { "action": "edit", "resource": "*", "effect": "deny" }
      ]
    }
  }
}

prompt becomes system, disable becomes disabled, maxSteps becomes steps, and a separate variant joins the model reference after #. File-based agents live in .opencode/agents/<name>.md; the Markdown body is the system prompt.

Commands

The singular command map becomes commands, subtask becomes subagent, and a separate model variant joins the model reference:

{
  "commands": {
    "review": {
      "description": "Review the current changes",
      "template": "Review the current diff for correctness and missing tests.",
      "model": "anthropic/claude-sonnet-5-5#high",
      "subagent": true
    }
  }
}

Markdown command files live in .opencode/commands/<name>.md.

MCP Server Configuration

V2 groups servers under mcp.servers and uses disabled instead of enabled. V2 does not accept server names directly under mcp.

{
  "$schema": "https://opencode.ai/config.json",
  "mcp": {
    "servers": {
      "everything": {
        "type": "local",
        "command": ["npx", "-y", "@modelcontextprotocol/server-everything"],
        "environment": {
          "LOG_LEVEL": "info"
        }
      },
      "context7": {
        "type": "remote",
        "url": "https://mcp.context7.com/mcp",
        "headers": {
          "CONTEXT7_API_KEY": "{env:CONTEXT7_API_KEY}"
        }
      }
    }
  }
}
FieldApplies toDescription
typebothlocal or remote
commandlocalExecutable followed by arguments
cwdlocalWorking directory; defaults to the workspace
environmentlocalExtra environment variables
urlremoteAbsolute Streamable HTTP endpoint
headersremoteHTTP headers
oauthremoteOAuth settings, or false to disable OAuth
disabledbothPrevents connection when true
codemodebothSet false to expose tools directly instead of through Code Mode
timeoutbothPer-server startup, catalog, and execution overrides

Remote servers use OAuth by default. Run /mcps to sign in, or opencode mcp auth <name>. Add servers with opencode mcp add and list them with opencode mcp list.

Code Mode is on by default: MCP tools are grouped as tools.<server>.<tool> inside a JavaScript interpreter, so large servers do not bloat the provider tool list. Set codemode: false on a server that must stay on the native tool list.

Skills System

Skills are instruction bundles OpenCode loads on demand. Each skill is a folder containing SKILL.md, placed in .opencode/skills/ or ~/.config/opencode/skills/:

.opencode/skills/
└── git-release/
    ├── SKILL.md
    ├── scripts/
    └── references/
---
name: Git Release
description: Create consistent releases and changelogs from merged PRs.
---

## What I do
- Draft release notes from merged PRs
- Propose a version bump
- Provide a copy-pasteable `gh release create` command

The file path determines the skill ID. OpenCode advertises permitted skills with a description and loads one when the model calls the skill tool, or when you mention it as @skill-id.

OpenCode also discovers .claude/skills/ and .agents/skills/. Add extra directories or HTTP catalogs with the skills array:

{
  "skills": ["./team-skills", "https://example.com/opencode/skills/"]
}

Control which skills an agent can load with skill permissions:

{
  "permissions": [
    { "action": "skill", "resource": "*", "effect": "allow" },
    { "action": "skill", "resource": "internal-*", "effect": "deny" },
    { "action": "skill", "resource": "experimental-*", "effect": "ask" }
  ]
}

Plugins

V2 replaces the plugin array with plugins and drops the tuple form:

{
  "plugins": [
    "opencode-example-plugin",
    {
      "package": "./plugins/local",
      "options": { "enabled": true }
    }
  ]
}

V1 plugin implementations do not run in V2. They use a new @opencode/plugin API with Plugin.define({ id, setup(ctx) }) and hooks registered on context domains. Local V2 plugins live in .opencode/plugins/<name>/index.ts.

Compaction

V2 groups the retained-context budget under keep and renames reserved to buffer:

{
  "compaction": {
    "auto": true,
    "keep": {
      "tokens": 15000
    },
    "buffer": "15%"
  }
}

buffer accepts a token count or a percentage of the model's context window. V2 has no native tail_turns or prune field; both are ignored with a warning.

Other Renames

V1V2
snapshotsnapshots
attachmentmedia
referencereferences
small_modelagents.title.model
autoupdateupdate ("disable", "notify", "auto")
enabled_providers / disabled_providerspolicies
agent / mode mapsagents
command mapcommands
plugin arrayplugins

Terminal preferences are no longer stored in opencode.json. Themes, keybinds, tabs, and alerts live in the global ~/.config/opencode/cli.json.

.opencode/ Directory

.opencode/
├── agents/                # Agent definitions
├── commands/              # Slash commands
├── plugins/               # Project plugins
└── skills/                # Project-specific skills

Environment Variables

VariablePurpose
ANTHROPIC_API_KEYAnthropic provider
OPENAI_API_KEYOpenAI provider
GOOGLE_API_KEYGoogle Gemini provider
DEEPSEEK_API_KEYDeepSeek provider
OPENROUTER_API_KEYOpenRouter provider
OPENCODE_API_KEYOpenCode Console account
OPENCODE_LOG_LEVELServer log level (DEBUG for diagnostics)
OPENCODE_PASSWORDServer password when exposing the API
OPENCODE_DBDatabase path override

Sources