Configure
Tools, rules, agents, models, themes, and more.
Tools
Manage the tools an LLM can use.
Tools enable LLMs to perform actions in your codebase. OpenCode includes built-in tools, extensible through custom tools or MCP servers. By default, all tools are enabled without requiring permission, though behavior can be controlled via permissions settings.
Configure
Use the permission field to manage tool behavior with allow, deny, or ask (approval required) options.
{
"$schema": "https://opencode.ai/config.json",
"permission": {
"edit": "deny",
"bash": "ask",
"webfetch": "allow"
}
}Wildcards enable controlling multiple tools simultaneously, such as mymcp_* for MCP server tools.
Built-in Tools
The following are the built-in tools.
bash
Execute shell commands in your project environment. Allows running terminal commands like npm install or git status.
edit
Modify existing files using exact string replacements. Performs precise edits through exact text matching.
write
Create new files or overwrite existing ones. The write tool operates under the edit permission setting.
read
Read file contents from your codebase. Supports reading specific line ranges for large files.
grep
Search file contents using regular expressions. Offers fast content searching with full regex syntax support.
glob
Find files by pattern matching. Uses glob patterns like **/*.js returning results sorted by modification time.
lsp (experimental)
Interacts with LSP servers for code intelligence features. Requires OPENCODE_EXPERIMENTAL_LSP_TOOL=true. Supports goToDefinition, findReferences, hover, documentSymbol, and other operations.
apply_patch
Apply patches to files. Controlled by the edit permission alongside file modifications.
skill
Load a skill (a SKILL.md file) and return its content in the conversation.
todowrite
Manage todo lists during coding sessions. Disabled for subagents by default.
webfetch
Fetch web content. Enables retrieving and reading web pages for documentation or research.
websearch
Search the web for information. Available with OpenCode provider or OPENCODE_ENABLE_EXA environment variable. Performs searches via Exa AI without API key requirements.
question
Ask the user questions during execution. Useful for gathering preferences, clarifying instructions, or obtaining implementation decisions.
Custom tools
Enable defining custom functions callable by the LLM through configuration files. See the Custom Tools section for details.
MCP servers
Model Context Protocol servers allow you to integrate external tools and services including databases, APIs, and third-party services. See the MCP Servers section for details.
Internals
Ignore patterns
Tools like grep and glob use ripgrep, respecting .gitignore patterns. Create a .ignore file to explicitly allow certain paths:
!node_modules/
!dist/
!build/Rules
Set custom instructions for OpenCode.
You can provide custom instructions to opencode by creating an AGENTS.md file. This is similar to Cursor's rules. It contains instructions that will be included in the LLM's context to customize its behavior for your specific project.
Initialize
To create a new AGENTS.md file, you can run the /init command in opencode.
You should commit your project's AGENTS.md file to Git.
/init scans the important files in your repo, may ask a couple of targeted questions when the codebase cannot answer them, and then creates or updates AGENTS.md with concise project-specific guidance.
It focuses on the things future agent sessions are most likely to need:
- build, lint, and test commands
- command order and focused verification steps when they matter
- architecture and repo structure that are not obvious from filenames alone
- project-specific conventions, setup quirks, and operational gotchas
- references to existing instruction sources like Cursor or Copilot rules
If you already have an AGENTS.md, /init will improve it in place instead of blindly replacing it.
Example
You can also just create this file manually. Here's an example:
# SST v3 Monorepo Project
This is an SST v3 monorepo with TypeScript. The project uses bun workspaces for package management.
## Project Structure
- `packages/` - Contains all workspace packages (functions, core, web, etc.)
- `infra/` - Infrastructure definitions split by service (storage.ts, api.ts, web.ts)
- `sst.config.ts` - Main SST configuration with dynamic imports
## Code Standards
- Use TypeScript with strict mode enabled
- Shared code goes in `packages/core/` with proper exports configuration
- Functions go in `packages/functions/`
- Infrastructure should be split into logical files in `infra/`
## Monorepo Conventions
- Import shared modules using workspace names: `@my-app/core/example`We are adding project-specific instructions here and this will be shared across your team.
Types
opencode also supports reading the AGENTS.md file from multiple locations. And this serves different purposes.
Project
Place an AGENTS.md in your project root for project-specific rules. These only apply when you are working in this directory or its sub-directories.
Global
You can also have global rules in a ~/.config/opencode/AGENTS.md file. This gets applied across all opencode sessions. Since this isn't committed to Git or shared with your team, we recommend using this to specify any personal rules that the LLM should follow.
Claude Code Compatibility
For users migrating from Claude Code, OpenCode supports Claude Code's file conventions as fallbacks:
- Project rules:
CLAUDE.mdin your project directory (used if noAGENTS.mdexists) - Global rules:
~/.claude/CLAUDE.md(used if no~/.config/opencode/AGENTS.mdexists) - Skills:
~/.claude/skills/-- see Agent Skills for details
To disable Claude Code compatibility, set one of these environment variables:
export OPENCODE_DISABLE_CLAUDE_CODE=1 # Disable all .claude support
export OPENCODE_DISABLE_CLAUDE_CODE_PROMPT=1 # Disable only ~/.claude/CLAUDE.md
export OPENCODE_DISABLE_CLAUDE_CODE_SKILLS=1 # Disable only .claude/skillsPrecedence
When opencode starts, it looks for rule files in this order:
- Local files by traversing up from the current directory (
AGENTS.md,CLAUDE.md) - Global file at
~/.config/opencode/AGENTS.md - Claude Code file at
~/.claude/CLAUDE.md(unless disabled)
The first matching file wins in each category.
Custom Instructions
You can specify custom instruction files in your opencode.json or the global ~/.config/opencode/opencode.json.
{
"$schema": "https://opencode.ai/config.json",
"instructions": ["CONTRIBUTING.md", "docs/guidelines.md", ".cursor/rules/*.md"]
}You can also use remote URLs:
{
"$schema": "https://opencode.ai/config.json",
"instructions": ["https://raw.githubusercontent.com/my-org/shared-rules/main/style.md"]
}Remote instructions are fetched with a 5 second timeout. All instruction files are combined with your AGENTS.md files.
Referencing External Files
While opencode doesn't automatically parse file references in AGENTS.md, you can achieve similar functionality in two ways:
Using opencode.json
The recommended approach is to use the instructions field:
{
"$schema": "https://opencode.ai/config.json",
"instructions": ["docs/development-standards.md", "test/testing-guidelines.md", "packages/*/AGENTS.md"]
}Manual Instructions in AGENTS.md
You can teach opencode to read external files by providing explicit instructions. Example:
# TypeScript Project Rules
## External File Loading
CRITICAL: When you encounter a file reference (e.g., @rules/general.md), use your Read tool to load it on a need-to-know basis.
Instructions:
- Do NOT preemptively load all references - use lazy loading based on actual need
- When loaded, treat content as mandatory instructions that override defaults
- Follow references recursively when needed
## Development Guidelines
For TypeScript code style and best practices: @docs/typescript-guidelines.md
For React component architecture and hooks patterns: @docs/react-patterns.md
For REST API design and error handling: @docs/api-standards.md
For testing strategies and coverage requirements: @test/testing-guidelines.md
## General Guidelines
Read the following file immediately as it's relevant to all workflows: @rules/general-guidelines.md.This approach allows you to: Create modular, reusable rule files; Share rules across projects via symlinks or git submodules; Keep AGENTS.md concise while referencing detailed guidelines; Ensure opencode loads files only when needed.
For monorepos or projects with shared standards, using opencode.json with glob patterns (like packages/*/AGENTS.md) is more maintainable than manual instructions.
Agents
Configure and use specialized agents.
Agents are specialized AI assistants that can be configured for specific tasks and workflows. They allow you to create focused tools with custom prompts, models, and tool access.
Use the plan agent to analyze code and review suggestions without making any code changes.
You can switch between agents during a session or invoke them with the @ mention.
Types
There are two types of agents in OpenCode; primary agents and subagents.
Primary agents
Primary agents are the main assistants you interact with directly. You can cycle through them using the Tab key, or your configured switch_agent keybind. These agents handle your main conversation.
You can use the Tab key to switch between primary agents during a session.
Subagents
Subagents are specialized assistants that primary agents can invoke for specific tasks. You can also manually invoke them by @ mentioning them in your messages. OpenCode comes with three built-in subagents: General, Explore, and Scout.
Built-in
OpenCode comes with two built-in primary agents and three built-in subagents.
Use build
Mode: primary - Build is the default primary agent with all tools enabled.
Use plan
Mode: primary - A restricted agent designed for planning and analysis. By default, file edits and bash are set to ask.
Use general
Mode: subagent - A general-purpose agent for researching complex questions and executing multi-step tasks. Has full tool access except todo.
Use explore
Mode: subagent - A fast, read-only agent for exploring codebases. Cannot modify files.
Use scout
Mode: subagent - A read-only agent for external docs and dependency research.
Use compaction
Mode: primary - Hidden system agent that compacts long context. Not selectable in the UI.
Use title
Mode: primary - Hidden system agent that generates session titles. Not selectable in the UI.
Use summary
Mode: primary - Hidden system agent that creates session summaries. Not selectable in the UI.
Usage
- For primary agents, use the Tab key to cycle through them.
- Subagents can be invoked automatically by primary agents or manually by @ mentioning a subagent. Example:
@general help me search for this function - Navigation between sessions: When subagents create child sessions, use
session_child_first(default: Leader+Down) to enter the first child session. - In child sessions:
session_child_cycle(Right) to cycle next,session_child_cycle_reverse(Left) to cycle previous,session_parent(Up) to return to parent.
Configure
You can customize agents or create new ones through configuration.
JSON
Configure agents in your opencode.json:
{
"$schema": "https://opencode.ai/config.json",
"agent": {
"build": {
"mode": "primary",
"model": "anthropic/claude-sonnet-4-20250514",
"prompt": "{file:./prompts/build.txt}",
"permission": {
"edit": "allow",
"bash": "allow"
}
},
"plan": {
"mode": "primary",
"model": "anthropic/claude-haiku-4-20250514",
"permission": {
"edit": "deny",
"bash": "deny"
}
},
"code-reviewer": {
"description": "Reviews code for best practices and potential issues",
"mode": "subagent",
"model": "anthropic/claude-sonnet-4-20250514",
"prompt": "You are a code reviewer. Focus on security, performance, and maintainability.",
"permission": {
"edit": "deny"
}
}
}
}Markdown
Define agents using markdown files placed in ~/.config/opencode/agents/ (global) or .opencode/agents/ (per-project):
---
description: Reviews code for quality and best practices
mode: subagent
model: anthropic/claude-sonnet-4-20250514
temperature: 0.1
permission:
edit: deny
bash: deny
---
You are in code review mode. Focus on:
- Code quality and best practices
- Potential bugs and edge cases
- Performance implications
- Security considerations
Provide constructive feedback without making direct changes.The markdown file name becomes the agent name.
Options
Description
Required. Brief description of what the agent does.
Temperature
Control randomness. 0.0-0.2 = focused, 0.3-0.5 = balanced, 0.6-1.0 = creative. Default: 0 for most models, 0.55 for Qwen.
Max steps
Control max agentic iterations. Use the steps field.
The legacy maxSteps field is deprecated.
Disable
Set to true to disable the agent.
Prompt
Specify a custom system prompt file. Path relative to config location.
Model
Override the model for this agent.
If you don't specify a model, primary agents use the globally configured model while subagents use the model of the invoking primary agent.
Tools (deprecated)
Deprecated. Prefer the permission field. Controls tool availability.
Permissions
Configure per-agent permissions with ask, allow, deny.
| Key | Tools it gates |
|---|---|
read | read |
edit | write, edit, apply_patch |
glob | glob |
grep | grep |
list | list |
bash | bash |
task | task |
external_directory | Any tool that reads/writes outside project |
todowrite | todowrite, todoread |
webfetch | webfetch |
websearch | websearch |
lsp | lsp |
skill | skill |
question | question |
doom_loop | Recovery prompts when agent appears stuck |
JSON permission example:
{
"agent": {
"my-agent": {
"permission": {
"edit": "allow",
"bash": "ask",
"webfetch": "deny"
}
}
}
}Markdown permission example:
---
permission:
edit: allow
bash: ask
webfetch: deny
---Bash permission with glob patterns:
{
"agent": {
"my-agent": {
"permission": {
"bash": "allow",
"bash(npm *)": "deny",
"bash(git push *)": "ask"
}
}
}
}Mode
primary, subagent, or all. Defaults to all.
Hidden
Hide from @ autocomplete. Only for mode: subagent agents.
Only affects user visibility.
Task permissions
Control which subagents can be invoked via the Task tool.
{
"agent": {
"build": {
"permission": {
"task": "allow",
"task(explore)": "allow",
"task(general)": "deny"
}
}
}
}Rules are evaluated in order: more specific patterns override broader ones. Users can always override agent permissions interactively.
Color
Customize UI appearance. Hex or theme color values.
Top P
Control response diversity. Values 0.0-1.0.
Additional
Extra options passed through to the provider.
Create agents
Use the opencode agent create command. It will interactively guide you through naming, describing, selecting mode, and configuring your new agent.
Use cases
- Build - Full-powered coding assistant with all tools enabled.
- Plan - Read-only analysis and planning without code changes.
- Review - Code review agent focused on quality and best practices.
- Debug - Debugging assistant with access to logs and shell.
- Docs - Documentation writer with restricted file access.
Examples
Do you have an agent you'd like to share? Submit a PR.
Documentation agent
{
"agent": {
"docs": {
"description": "Documentation writer",
"mode": "subagent",
"model": "anthropic/claude-sonnet-4-20250514",
"prompt": "You are a documentation specialist. Write clear, concise docs. Focus on API references, guides, and examples.",
"permission": {
"edit": "allow",
"bash": "deny"
}
}
}
}Security auditor
{
"agent": {
"security": {
"description": "Security auditor",
"mode": "subagent",
"model": "anthropic/claude-sonnet-4-20250514",
"prompt": "You are a security auditor. Review code for vulnerabilities, injection attacks, auth issues, and data exposure. Never modify code directly.",
"permission": {
"edit": "deny",
"bash": "deny"
}
}
}
}Models
Configuring an LLM provider and model.
OpenCode uses the AI SDK and Models.dev to support 75+ LLM providers and local models.
Providers
Most popular providers are preloaded. Use /connect to add credentials.
Select a model
Use the /models command to browse and select from available models.
Recommended models
Consider using one of the models we recommend.
- GPT 5.2
- GPT 5.1 Codex
- Claude Opus 4.5
- Claude Sonnet 4.5
- Minimax M2.1
- Gemini 3 Pro
Set a default
{
"$schema": "https://opencode.ai/config.json",
"model": "lmstudio/google/gemma-3n-e4b"
}Format is provider_id/model_id.
Configure models
You can configure model-specific options in your opencode.json:
{
"$schema": "https://opencode.ai/config.json",
"provider": {
"openai": {
"model": {
"gpt-5.2": {
"temperature": 0.2,
"max_tokens": 16384
}
}
},
"anthropic": {
"model": {
"claude-sonnet-4-20250514": {
"temperature": 0,
"max_tokens": 8192
}
}
}
}
}Variants
Variants let you group models by provider. This is useful when providers offer the same model under different names.
Built-in variants
- Anthropic: claude-sonnet-4-20250514, claude-haiku-4-20250514, claude-opus-4-20250514
- OpenAI: gpt-5.2, gpt-5.1-codex, o3, o4-mini
- Google: gemini-3-pro, gemini-3-flash
Custom variants
{
"provider": {
"my-provider": {
"variant": {
"claude-sonnet-4-20250514": "my-custom-sonnet-name"
}
}
}
}Cycle variants
When multiple providers offer the same model, use the /models command to cycle between variants.
Loading models
Models are loaded in the following priority order:
- CLI flag -
--modelflag takes highest priority. - Config - The
modelfield inopencode.json. - Last used - The model from your most recent session.
- Internal priority - OpenCode's default model selection.
Themes
Select a built-in theme or define your own.
Terminal Requirements
Themes rely on true color (24-bit) support. Most modern terminals support this. If your theme colors look wrong, ensure your terminal supports true color.
Built-in Themes
| Theme | Description |
|---|---|
opencode | Default theme with warm tones |
catppuccin | Soothing pastel theme |
dracula | Dark theme with vibrant colors |
tokyonight | Clean dark theme inspired by Tokyo at night |
gruvbox | Retro groove color scheme |
solarized | Precision colors for readability |
nord | Arctic, north-bluish color palette |
monokai | Iconic warm dark theme |
onedark | Atom-inspired dark theme |
System Theme
By default, OpenCode uses the opencode theme. The system theme adapts to your terminal's light or dark mode if your terminal reports its background color.
Using a Theme
{
"$schema": "https://opencode.ai/config.json",
"theme": "catppuccin"
}Custom Themes
Hierarchy
Custom themes can be defined at two levels:
- Global:
~/.config/opencode/themes/ - Project:
.opencode/themes/
Project themes take priority over global themes with the same name.
Creating a Theme
Create a JSON file in one of the theme directories. The file name (without extension) becomes the theme name.
JSON Format
A theme file defines color values for the TUI components:
{
"primary": "#88C0D0",
"secondary": "#81A1C1",
"accent": "#5E81AC",
"error": "#BF616A",
"warning": "#EBCB8B",
"success": "#A3BE8C",
"muted": "#4C566A",
"text": "#ECEFF4",
"background": "#2E3440",
"border": "#3B4252"
}Color Definitions
- primary - Main accent color used for highlights and focus indicators
- secondary - Supporting accent color
- accent - Additional accent for interactive elements
- error - Error states and destructive actions
- warning - Warning messages and caution indicators
- success - Success states and positive actions
- muted - Subtle text and disabled elements
- text - Primary text color
- background - Base background color
- border - Border and divider color
Terminal Defaults
If a color is not specified in the theme file, OpenCode falls back to your terminal's default ANSI colors.
Nord Example
Here is a complete Nord theme example:
{
"primary": "#88C0D0",
"secondary": "#81A1C1",
"accent": "#5E81AC",
"error": "#BF616A",
"warning": "#EBCB8B",
"success": "#A3BE8C",
"muted": "#4C566A",
"text": "#ECEFF4",
"background": "#2E3440",
"border": "#3B4252"
}Keybinds
Customize your keybinds.
Leader Key
The leader key is a prefix key that starts key sequences. By default, the leader key is ctrl+x. You can customize it:
{
"$schema": "https://opencode.ai/config.json",
"keybind": {
"leader": "ctrl+a"
}
}Binding Values
Keybinds are specified as strings with modifier keys joined by +. Available modifiers: ctrl, alt, shift. Examples:
ctrl+s- Control + Salt+enter- Alt + Enterctrl+shift+p- Control + Shift + Pleader n- Leader key followed by N
{
"keybind": {
"submit": "ctrl+s",
"new_session": "leader n",
"switch_agent": "tab",
"session_list": "leader l"
}
}Disable Keybind
Set a keybind to an empty string to disable it:
{
"keybind": {
"help": ""
}
}Desktop Prompt Shortcuts
| Action | Default |
|---|---|
| Submit | enter |
| Newline | shift+enter |
| Paste | ctrl+v |
| History back | alt+up |
| History forward | alt+down |
| Switch agent | tab |
| New session | leader n |
| Session list | leader l |
| Help | leader ? |
| Interrupt | esc |
Shift+Enter
Shift+Enter inserts a newline. Some terminals may not send this correctly. If Shift+Enter does not work, configure your terminal to send the correct escape sequence.
Windows Terminal config
Add this to your Windows Terminal settings.json:
{
"actions": [
{
"command": {
"action": "sendInput",
"input": "[13;2u"
},
"keys": "shift+enter"
}
]
}On Windows, some default keybinds may conflict with the terminal emulator. Check your terminal's settings if a keybind doesn't work as expected.
Commands
Custom commands for the TUI.
Commands let you create reusable prompts and workflows accessible via the / prefix in the TUI.
Create Command Files
Commands are stored as files in:
- Global:
~/.config/opencode/commands/ - Project:
.opencode/commands/
The file name (without extension) becomes the command name, accessible as /command-name.
Configure
JSON
{
"command": {
"review": {
"description": "Review code changes",
"prompt": "Review the current diff for bugs, style issues, and improvements."
},
"test": {
"description": "Generate tests",
"prompt": "Generate comprehensive tests for $ARGUMENTS"
}
}
}Markdown
Create a markdown file in your commands directory:
---
description: Review code for quality
agent: plan
---
Review the current git diff. Focus on:
1. Potential bugs
2. Performance issues
3. Code style violations
Provide specific, actionable feedback.Prompt Config
Arguments
Use $ARGUMENTS in your prompt to accept user input. When a user runs /review src/main.ts, the text after the command replaces $ARGUMENTS.
Shell Output
Use $(command) syntax to include shell output in your prompt:
---
description: Review recent changes
---
Review the following diff:
$(git diff HEAD~1)File References
Use {file:path} to include file contents in your prompt:
---
description: Apply project standards
---
Follow these coding standards:
{file:./docs/standards.md}
Now review: $ARGUMENTSOptions
Template
The prompt template string. Supports $ARGUMENTS, $(command), and {file:path} substitutions.
Description
Brief description shown in the command list.
Agent
Specify which agent should handle the command. Example: "agent": "plan" routes the command to the plan agent.
Subtask
Set to true to run the command as a subtask (child session) rather than in the main conversation.
Model
Override the model used for this command.
Built-in commands like /init, /models, /connect, /compact, and /help cannot be overridden by custom commands.
Formatters
Language-specific formatters.
OpenCode automatically formats code after edits using language-specific formatters.
Built-in formatters
| Language | Formatter |
|---|---|
| Go | goimports |
| JavaScript | prettier |
| TypeScript | prettier |
| JSX | prettier |
| TSX | prettier |
| CSS | prettier |
| HTML | prettier |
| JSON | prettier |
| YAML | prettier |
| Markdown | prettier |
| Python | ruff |
| Rust | rustfmt |
| Zig | zig fmt |
| C | clang-format |
| C++ | clang-format |
| Java | google-java-format |
| Kotlin | ktfmt |
| Swift | swift-format |
| Ruby | rubocop |
| PHP | php-cs-fixer |
| Elixir | mix format |
| Dart | dart format |
| Lua | stylua |
| Nix | nixfmt |
| Terraform | terraform fmt |
| SQL | sql-formatter |
How it works
When a file is edited, OpenCode checks if a formatter is available for that language. If the formatter binary is found in your PATH, it runs automatically after the edit. If the formatter is not installed, the edit proceeds without formatting.
Configure
Enable
Formatters are enabled by default. No configuration is needed if the formatter binary is in your PATH.
Disable
To disable formatting entirely:
{
"$schema": "https://opencode.ai/config.json",
"format": false
}Custom formatters
Override or add formatters for specific file extensions:
{
"$schema": "https://opencode.ai/config.json",
"format": {
".ts": ["dprint", "fmt", "--stdin", "typescript"],
".py": ["black", "-"],
".rb": false
}
}Set an extension to false to disable formatting for that language. The formatter command receives file content on stdin and should output the formatted content on stdout.
Permissions
Control which actions require approval.
Actions
Permissions control whether a tool action is automatically allowed, denied, or requires user approval. Each action can be set to one of three values:
allow- Action runs without askingdeny- Action is blockedask- User must approve each invocation
Configuration
{
"$schema": "https://opencode.ai/config.json",
"permission": {
"edit": "allow",
"bash": "ask",
"webfetch": "deny"
}
}Granular Rules
For bash, you can define granular rules using argument patterns:
{
"permission": {
"bash": "ask",
"bash(npm test *)": "allow",
"bash(rm *)": "deny",
"bash(git push *)": "ask"
}
}Wildcards
Use * to match any characters. This works for both tool names and argument patterns:
mymcp_*- Match all tools frommymcpMCP serverbash(npm *)- Match all npm commandsbash(git push *)- Match git push with any arguments
Home Directory Expansion
Use ~ in patterns to match the user's home directory. OpenCode expands ~ to the actual home path for matching.
External Directories
The external_directory permission controls access to files outside the current project. By default, this is set to ask.
{
"permission": {
"external_directory": "allow"
}
}Available Permissions
| Key | Tools it gates |
|---|---|
read | read |
edit | write, edit, apply_patch |
glob | glob |
grep | grep |
list | list |
bash | bash |
task | task |
external_directory | Any tool that reads/writes outside project |
todowrite | todowrite, todoread |
webfetch | webfetch |
websearch | websearch |
lsp | lsp |
skill | skill |
question | question |
doom_loop | Recovery prompts when agent appears stuck |
Defaults
By default, all tools are set to allow except:
external_directory- defaults toasktodowrite- disabled for subagents by default
What "Ask" Does
When a tool is set to ask, OpenCode pauses execution and displays a prompt asking you to approve or deny the action. You can approve once, approve for the session, or deny.
Agents
Each agent can have its own permission overrides that take precedence over global permissions. See the Agents section for per-agent permission configuration.
Policies
Control which resources OpenCode may use.
Configuration
Policies are configured in your opencode.json under the policy key:
{
"$schema": "https://opencode.ai/config.json",
"policy": {
"model": {
"allow": ["anthropic/*", "openai/gpt-5*"],
"deny": ["openai/o3"]
},
"provider": {
"allow": ["anthropic", "openai"],
"deny": ["ollama"]
},
"mcp": {
"allow": ["sentry", "context7"],
"deny": ["*"]
}
}
}Available Policies
| Policy | Description |
|---|---|
model | Control which models can be used |
provider | Control which providers can be used |
mcp | Control which MCP servers can be connected |
Matching
Policy patterns support wildcards (*) for flexible matching:
anthropic/*- Match all Anthropic modelsopenai/gpt-5*- Match all GPT-5 variants*- Match everything
Rule Order
When both allow and deny are specified:
denyrules are evaluated first- If denied, the resource is blocked regardless of allow rules
- If not denied,
allowrules are checked - If no rules match, the resource is allowed by default
Provider Lists
Use the provider policy to restrict which providers are visible in the /models and /connect commands. Denied providers are hidden from the UI.
LSP Servers
Language Server Protocol integration.
Built-in LSP Servers
OpenCode includes built-in support for the following LSP servers:
- gopls - Go
- typescript-language-server - TypeScript/JavaScript
- pyright - Python
- rust-analyzer - Rust
- lua-language-server - Lua
- zls - Zig
- intelephense - PHP
How It Works
LSP servers provide code intelligence features like go-to-definition, find references, hover information, and diagnostics. OpenCode starts the appropriate LSP server when you open a project with supported languages.
The LSP integration feeds diagnostic information (errors, warnings) to the LLM so it can understand and fix issues in your code.
Best Practices
- Ensure the LSP server binary is installed and available in your
PATH - For Go projects, run
go mod tidybefore starting OpenCode - For TypeScript projects, ensure
node_modulesis installed - For Python projects, ensure your virtual environment is activated
Configuration
{
"$schema": "https://opencode.ai/config.json",
"lsp": {
"gopls": {
"enabled": true,
"command": ["gopls", "serve"],
"args": ["-rpc.trace"]
}
}
}Disabling LSP
To disable LSP entirely:
{
"lsp": false
}To disable a specific LSP server:
{
"lsp": {
"gopls": {
"enabled": false
}
}
}Custom LSP Servers
Add custom LSP servers for languages not included by default:
{
"lsp": {
"clangd": {
"enabled": true,
"command": ["clangd"],
"languages": ["c", "cpp"],
"extensions": [".c", ".h", ".cpp", ".hpp"]
}
}
}PHP Intelephense
For PHP projects, OpenCode supports Intelephense. Install it globally:
npm install -g intelephenseNo additional configuration is needed. OpenCode detects PHP files and starts Intelephense automatically.
MCP Servers
Add local and remote MCP tools.
Model Context Protocol (MCP) servers let you extend OpenCode with external tools and services.
Enable
Configure MCP servers in your opencode.json:
{
"$schema": "https://opencode.ai/config.json",
"mcp": {
"sentry": {
"type": "remote",
"url": "https://mcp.sentry.dev/sse"
}
}
}Overriding Remote Defaults
When connecting to remote MCP servers, you can override default headers and parameters:
{
"mcp": {
"my-server": {
"type": "remote",
"url": "https://my-mcp-server.com/sse",
"headers": {
"Authorization": "Bearer ${MCP_TOKEN}"
}
}
}
}Local MCP Servers
Run MCP servers locally as subprocesses:
{
"mcp": {
"my-local-server": {
"type": "local",
"command": ["node", "path/to/server.js"],
"args": ["--port", "3000"],
"env": {
"API_KEY": "${MY_API_KEY}"
}
}
}
}Key options for local servers:
command- Command to start the serverargs- Arguments passed to the commandenv- Environment variables for the server processcwd- Working directory for the server
Remote MCP Servers
Connect to remote MCP servers via SSE or HTTP:
{
"mcp": {
"my-remote-server": {
"type": "remote",
"url": "https://my-server.com/mcp",
"headers": {
"Authorization": "Bearer ${TOKEN}"
}
}
}
}Key options for remote servers:
url- Server endpoint URLheaders- Custom headers (supports environment variable expansion)transport- Transport type (sseorhttp)
OAuth Authentication
Automatic
Remote MCP servers can use OAuth for authentication. OpenCode handles the OAuth flow automatically when the server requires it.
Pre-registered
For pre-registered OAuth applications, provide the client credentials:
{
"mcp": {
"my-oauth-server": {
"type": "remote",
"url": "https://my-server.com/mcp",
"oauth": {
"client_id": "${OAUTH_CLIENT_ID}",
"client_secret": "${OAUTH_CLIENT_SECRET}"
}
}
}
}Commands
Use /mcp to manage MCP server connections. Use /mcp login <server> to re-authenticate with an OAuth server.
Disabling
To disable an MCP server without removing its configuration:
{
"mcp": {
"my-server": {
"type": "remote",
"url": "https://my-server.com/mcp",
"enabled": false
}
}
}Management
Global
Configure MCP servers globally in ~/.config/opencode/opencode.json to make them available across all projects.
Per-agent
MCP tools can be controlled per-agent using the permission field with the mcp_servername_* pattern:
{
"agent": {
"build": {
"permission": {
"mcp_sentry_*": "allow",
"mcp_context7_*": "ask"
}
}
}
}Glob patterns
Use glob patterns in permissions to control groups of MCP tools: mcp_servername_* matches all tools from a specific server.
Examples
Sentry
{
"mcp": {
"sentry": {
"type": "remote",
"url": "https://mcp.sentry.dev/sse"
}
}
}Context7
{
"mcp": {
"context7": {
"type": "local",
"command": ["npx", "-y", "@upstash/context7-mcp@latest"]
}
}
}Grep by Vercel
{
"mcp": {
"grep": {
"type": "remote",
"url": "https://mcp.grep.dev/sse"
}
}
}ACP Support
Agent Client Protocol integration.
OpenCode supports the Agent Client Protocol (ACP), allowing it to work as an AI backend for editors and IDEs.
Configuration
Enable ACP support in your opencode.json:
{
"$schema": "https://opencode.ai/config.json",
"acp": {
"enabled": true,
"port": 9100
}
}Editor-Specific Setup
Zed
Configure Zed to use OpenCode as the AI backend in your Zed settings.json:
{
"agent": {
"default_profile": "opencode",
"profiles": {
"opencode": {
"provider": "opencode",
"url": "http://localhost:9100"
}
}
}
}JetBrains
Use the ACP plugin for JetBrains IDEs. Configure the server URL to http://localhost:9100 in the plugin settings.
Avante.nvim
Configure Avante.nvim to connect to OpenCode's ACP server:
require("avante").setup({
provider = "opencode",
opencode = {
endpoint = "http://localhost:9100",
},
})CodeCompanion.nvim
Configure CodeCompanion.nvim to use OpenCode:
require("codecompanion").setup({
adapters = {
opencode = function()
return require("codecompanion.adapters").extend("openai_compatible", {
url = "http://localhost:9100/v1/chat/completions",
})
end,
},
})Features & Support
- Chat completions API (
/v1/chat/completions) - Streaming responses
- Tool use / function calling
- Multi-turn conversations
- Model listing (
/v1/models)
Some editor-specific commands (like inline completions or code actions) may not be supported through the ACP interface. Use OpenCode's TUI for the full feature set.
Agent Skills
Reusable instructions for agents.
Skills are reusable instruction files (SKILL.md) that agents can load on demand. They provide focused guidance for specific tasks without cluttering the main system prompt.
Place files
Skills can be placed in any of the following locations:
.opencode/skills/- Project-level skills~/.config/opencode/skills/- Global user skills.claude/skills/- Claude Code compatible (project)~/.claude/skills/- Claude Code compatible (global)- Any directory, referenced by path in agent config
- Nested subdirectories within any of the above
Understand discovery
OpenCode discovers skills at startup by scanning the skill directories. Skills are indexed by name and made available to agents through the skill tool. When an agent invokes a skill, its content is loaded into the conversation context.
Write frontmatter
Skills use YAML frontmatter to define metadata:
---
name: typescript-testing
description: Guidelines for writing TypeScript tests
glob: "**/*.test.ts"
---
# TypeScript Testing Guidelines
Write tests using vitest. Always include:
- Unit tests for pure functions
- Integration tests for API endpoints
- Edge case coverageAvailable frontmatter fields:
- name - Unique identifier for the skill (auto-derived from filename if omitted)
- description - Brief description shown in skill listings
- glob - File pattern that triggers automatic skill loading
Validate names
Skill names must follow these rules:
- Lowercase letters, numbers, and hyphens only
- Must start with a letter
- Must not exceed 64 characters
- Must be unique across all skill directories
Regex: ^[a-z][a-z0-9-]{0,63}$
Follow length rules
Keep skills focused and concise. The recommended maximum length is 4000 tokens. Longer skills consume context window space and may be truncated.
Use an example
---
name: react-components
description: Guidelines for React component development
glob: "**/*.tsx"
---
# React Component Guidelines
## Structure
- Use functional components with hooks
- Export components as named exports
- Co-locate tests with components
## Naming
- PascalCase for component names
- camelCase for hooks (useXxx)
- kebab-case for file names
## State Management
- Prefer local state with useState
- Use context for shared state
- Avoid prop drilling beyond 2 levelsRecognize tool description
When the skill tool is available, agents see a description listing all available skills. The agent can then invoke specific skills by name when it determines the skill's guidance would be helpful.
Configure permissions
Control skill access with the skill permission key:
| Value | Effect |
|---|---|
allow | Agent can load skills without asking |
ask | User must approve each skill load |
deny | Agent cannot load skills |
Override per agent
{
"agent": {
"build": {
"permission": {
"skill": "allow"
}
},
"explore": {
"permission": {
"skill": "deny"
}
}
}
}Disable the skill tool
To globally disable skills:
{
"permission": {
"skill": "deny"
}
}Troubleshoot loading
- Verify the skill file is in a recognized directory
- Check that the file name ends with
.md - Ensure the frontmatter YAML is valid
- Confirm the skill name is unique across all directories
- Check that the
skillpermission is not set todeny - Use
/skillsto list discovered skills and verify your skill appears
References
Access directories outside the current project.
References allow OpenCode to access files and directories outside your current project. This is useful for monorepos, shared libraries, or referencing external documentation.
Configuration Methods
Local Directories
Reference local directories by path:
{
"$schema": "https://opencode.ai/config.json",
"reference": {
"shared-lib": {
"path": "../shared-library",
"description": "Shared utility library"
},
"docs": {
"path": "~/docs/api-specs",
"description": "API specification documents"
}
}
}Git Repositories
Reference remote Git repositories. OpenCode clones them locally:
{
"reference": {
"design-system": {
"git": "https://github.com/my-org/design-system.git",
"branch": "main",
"description": "Company design system components"
}
}
}Key Features
Descriptions
Add descriptions to help the LLM understand when to use each reference. The description is included in the tool context so the agent knows what each reference contains.
Visibility Control
References are visible to agents through the read tool. The agent can browse referenced directories just like project files.
Usage in TUI
Use /references to list all configured references and their status.
Permission Handling
References bypass the external_directory permission check. Any directory configured as a reference is treated as a trusted path. This means agents can read referenced files without triggering the external directory approval prompt.
Custom Tools
Create tools the LLM can call.
Custom tools let you define new functions that the LLM can invoke during sessions. Tools are defined as executable scripts with a TypeScript configuration.
Creating a Tool
Location
Custom tools are defined in:
.opencode/tools/- Project-level tools~/.config/opencode/tools/- Global tools
Structure
Each tool consists of a TypeScript definition file that uses the tool() helper:
import { tool } from "opencode/tool"
import { z } from "zod"
export default tool({
name: "hello",
description: "Say hello to someone",
parameters: z.object({
name: z.string().describe("The name to greet"),
}),
execute: async ({ name }) => {
return `Hello, ${name}!`
},
})Multiple Tools Per File
You can export multiple tools from a single file:
import { tool } from "opencode/tool"
import { z } from "zod"
export const greet = tool({
name: "greet",
description: "Greet someone",
parameters: z.object({ name: z.string() }),
execute: async ({ name }) => `Hello, ${name}!`,
})
export const farewell = tool({
name: "farewell",
description: "Say goodbye to someone",
parameters: z.object({ name: z.string() }),
execute: async ({ name }) => `Goodbye, ${name}!`,
})Name Collisions
If a custom tool has the same name as a built-in tool, the custom tool takes precedence. This allows you to override built-in tool behavior.
Arguments
Tool arguments are defined using Zod schemas. The schema defines both the type validation and the description shown to the LLM:
parameters: z.object({
path: z.string().describe("File path to read"),
lines: z.number().optional().describe("Number of lines to read"),
encoding: z.enum(["utf-8", "ascii"]).default("utf-8").describe("File encoding"),
})Context
The execute function receives the parsed arguments and a context object with access to project information:
export default tool({
name: "project-info",
description: "Get project information",
parameters: z.object({}),
execute: async (_args, ctx) => {
return JSON.stringify({
cwd: ctx.cwd,
projectRoot: ctx.projectRoot,
})
},
})Examples
Write a Tool in Python
You can write the tool logic in any language and call it from the TypeScript definition. Here is an example using Python:
Python script (.opencode/tools/analyze.py):
import sys
import json
def analyze(file_path):
with open(file_path, 'r') as f:
content = f.read()
lines = content.split('\n')
return {
"lines": len(lines),
"characters": len(content),
"words": len(content.split()),
}
if __name__ == "__main__":
result = analyze(sys.argv[1])
print(json.dumps(result))TypeScript definition (.opencode/tools/analyze.ts):
import { tool } from "opencode/tool"
import { z } from "zod"
import { execSync } from "child_process"
export default tool({
name: "analyze",
description: "Analyze a file's statistics",
parameters: z.object({
path: z.string().describe("Path to the file to analyze"),
}),
execute: async ({ path }) => {
const result = execSync(`python .opencode/tools/analyze.py "${path}"`, {
encoding: "utf-8",
})
return result
},
})