# Opencode Config

> |

- **Type:** Skill
- **Install:** `agentstack add skill-timmy6942025-opencode-builder-skill-opencode-config`
- **Verified:** Yes — security-reviewed for prompt injection and unsafe behavior
- **Seller:** [Timmy6942025](https://agentstack.voostack.com/s/timmy6942025)
- **Installs:** 0
- **Category:** [Agent Skills](https://agentstack.voostack.com/c/agent-skills)
- **Latest version:** 0.1.0
- **License:** MIT
- **Upstream author:** [Timmy6942025](https://github.com/Timmy6942025)
- **Source:** https://github.com/Timmy6942025/opencode-builder-skill/tree/main/skills/opencode-config

## Install

```sh
agentstack add skill-timmy6942025-opencode-builder-skill-opencode-config
```

Requires the [AgentStack CLI](https://agentstack.voostack.com/docs/cli). Works with Claude Code, Cursor, and any MCP-compatible agent.

## About

# OpenCode Configuration

> **📚 Official Docs:** For the latest information, always refer to the official documentation:
> [https://opencode.ai/docs/config/](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](#format)
- [Config Locations & Precedence](#config-locations--precedence)
- [Config Merging Behavior](#config-merging-behavior)
- [All Config Fields](#all-config-fields)
- [TUI Config (tui.json)](#tui-config-tuijson)
- [Variable Substitution](#variable-substitution)
- [Managed Settings (Enterprise)](#managed-settings-enterprise)
- [Provider-Specific Options](#provider-specific-options)
- [Environment Variables](#environment-variables)
- [Debugging & Verification](#debugging--verification)
- [Troubleshooting](#troubleshooting)

---

## 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"`

```jsonc
{
  "$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):

| Priority | Source | Description |
|----------|--------|-------------|
| 1 (lowest) | **Remote config** | Organizational defaults from `.well-known/opencode` |
| 2 | **Global config** | User preferences at `~/.config/opencode/opencode.json` |
| 3 | **Custom config** | Custom overrides via `OPENCODE_CONFIG` env var |
| 4 | **Project config** | Project-specific settings at `opencode.json` in project root |
| 5 | **`.opencode` directories** | Agents, commands, modes, plugins, skills, tools, themes |
| 6 | **Inline config** | Runtime overrides via `OPENCODE_CONFIG_CONTENT` env var |
| 7 | **Managed config files** | Admin-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.

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

Override in your local config:

```jsonc
// 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:

```bash
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:

```bash
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:

```bash
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.

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

### `model`

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

```jsonc
{
  "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.

```jsonc
{
  "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`).

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

**Provider options:**

| Option | Type | Default | Description |
|--------|------|---------|-------------|
| `timeout` | number \| false | 300000 | Request timeout in milliseconds. Set to `false` to disable. |
| `chunkTimeout` | number | — | Timeout in ms between streamed response chunks. Aborts if no chunk arrives in time. |
| `setCacheKey` | boolean | — | Ensure a cache key is always set for the provider. |
| `baseURL` | string | — | Custom base URL for the provider (useful for proxies, gateways, local servers). |
| `headers` | object | — | Custom HTTP headers sent with provider requests. |

**Custom provider (npm):**

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

```jsonc
{
  "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:

```jsonc
{
  "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:

```jsonc
{
  "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:**

| Option | Type | Required | Description |
|--------|------|----------|-------------|
| `type` | `"local"` | Yes | Must be `"local"` |
| `command` | array | Yes | Command and arguments to run the MCP server |
| `environment` | object | No | Environment variables for the server process |
| `enabled` | boolean | No | Enable/disable the server on startup |
| `timeout` | number | No | Timeout in ms for fetching tools (default: 5000) |

**Remote MCP options:**

| Option | Type | Required | Description |
|--------|------|----------|-------------|
| `type` | `"remote"` | Yes | Must be `"remote"` |
| `url` | string | Yes | URL of the remote MCP server |
| `enabled` | boolean | No | Enable/disable the server on startup |
| `headers` | object | No | HTTP headers for the request |
| `oauth` | object \| false | No | OAuth config or `false` to disable OAuth auto-detection |
| `timeout` | number | No | Timeout in ms for fetching tools (default: 5000) |

**Remote MCP OAuth options:**

| Option | Type | Description |
|--------|------|-------------|
| `clientId` | string | OAuth client ID. If not provided, dynamic client registration is attempted. |
| `clientSecret` | string | OAuth client secret, if required. |
| `scope` | string | OAuth scopes to request. |

### `tools`

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

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

Glob patterns are supported for MCP tool names:

```jsonc
{
  "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.

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

**Permission values:**

| Value | Description |
|-------|-------------|
| `"allow"` | Run without approval |
| `"ask"` | Prompt user for approval |
| `"deny"` | Block the action |

**Available permission keys:**

| Key | Matches |
|-----|---------|
| `read` | File reads (matches file path) |
| `edit` | All file modifications (edit, write, patch) |
| `glob` | File globbing (matches glob pattern) |
| `grep` | Content search (matches regex pattern) |
| `bash` | Shell commands (matches parsed commands) |
| `task` | Subagent launches (matches subagent type) |
| `skill` | Skill loading (matches skill name) |
| `lsp` | LSP queries (currently non-granular) |
| `question` | User questions during execution |
| `webfetch` | URL fetching (matches URL) |
| `websearch` | Web search (matches query) |
| `external_directory` | Tool calls touching paths outside project root |
| `doom_loop` | Triggered 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:

```jsonc
{
  "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:

```jsonc
{
  "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:

```jsonc
{
  "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.

```jsonc
{
  "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/`:

```markdown
---
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.

```jsonc
{
  "default_agent": "plan"
}
```

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

### `share`

Configure the conversation sharing feature:

```jsonc
{
  "share": "manual"
}
```

| Value | Description |
|-------|-------------|
| `"manual"` | Allow manual sharing via `/share` command (d

…

## Source & license

This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.

- **Author:** [Timmy6942025](https://github.com/Timmy6942025)
- **Source:** [Timmy6942025/opencode-builder-skill](https://github.com/Timmy6942025/opencode-builder-skill)
- **License:** MIT

Install and usage instructions live in the source repository linked above.

## Pricing

- **Free** — Free

## Security capabilities

Automated source analysis of v0.1.0 — what this tool can access:

- **Network access:** no
- **Filesystem access:** no
- **Shell / process execution:** no
- **Environment & secrets:** yes
- **Dynamic code execution:** no

*"Yes" means the capability is present in the source — more access means more to trust, not that it is unsafe.*


## Versions

- **0.1.0** — security scan: passed — Imported from the upstream source.

## Links

- Listing page: https://agentstack.voostack.com/l/skill-timmy6942025-opencode-builder-skill-opencode-config
- Seller: https://agentstack.voostack.com/s/timmy6942025
- Browse the marketplace: https://agentstack.voostack.com/browse

---
Listed on AgentStack — the marketplace for AI agent skills and MCP servers. Every listing is security-reviewed. Creators keep 70%.
