OpenCode OpenCode

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.

opencode.json
{
  "$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:

.ignore
!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.

Tip

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:

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:

markdown
# 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:

To disable Claude Code compatibility, set one of these environment variables:

Terminal window
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/skills

Precedence

When opencode starts, it looks for rule files in this order:

  1. Local files by traversing up from the current directory (AGENTS.md, CLAUDE.md)
  2. Global file at ~/.config/opencode/AGENTS.md
  3. 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.

opencode.json
{
  "$schema": "https://opencode.ai/config.json",
  "instructions": ["CONTRIBUTING.md", "docs/guidelines.md", ".cursor/rules/*.md"]
}

You can also use remote URLs:

opencode.json
{
  "$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:

opencode.json
{
  "$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:

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

Tip

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.

Tip

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.

Tip

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

  1. For primary agents, use the Tab key to cycle through them.
  2. Subagents can be invoked automatically by primary agents or manually by @ mentioning a subagent. Example: @general help me search for this function
  3. Navigation between sessions: When subagents create child sessions, use session_child_first (default: Leader+Down) to enter the first child session.
  4. 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:

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):

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

Warning

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.

Tip

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.

KeyTools it gates
readread
editwrite, edit, apply_patch
globglob
grepgrep
listlist
bashbash
tasktask
external_directoryAny tool that reads/writes outside project
todowritetodowrite, todoread
webfetchwebfetch
websearchwebsearch
lsplsp
skillskill
questionquestion
doom_loopRecovery prompts when agent appears stuck

JSON permission example:

opencode.json
{
  "agent": {
    "my-agent": {
      "permission": {
        "edit": "allow",
        "bash": "ask",
        "webfetch": "deny"
      }
    }
  }
}

Markdown permission example:

markdown
---
permission:
  edit: allow
  bash: ask
  webfetch: deny
---

Bash permission with glob patterns:

opencode.json
{
  "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.

Note

Only affects user visibility.

Task permissions

Control which subagents can be invoked via the Task tool.

opencode.json
{
  "agent": {
    "build": {
      "permission": {
        "task": "allow",
        "task(explore)": "allow",
        "task(general)": "deny"
      }
    }
  }
}
Tip

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

Examples

Tip

Do you have an agent you'd like to share? Submit a PR.

Documentation agent

opencode.json
{
  "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

opencode.json
{
  "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

Tip

Consider using one of the models we recommend.

Set a default

opencode.json
{
  "$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:

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

Custom variants

opencode.json
{
  "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:

  1. CLI flag - --model flag takes highest priority.
  2. Config - The model field in opencode.json.
  3. Last used - The model from your most recent session.
  4. 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

ThemeDescription
opencodeDefault theme with warm tones
catppuccinSoothing pastel theme
draculaDark theme with vibrant colors
tokyonightClean dark theme inspired by Tokyo at night
gruvboxRetro groove color scheme
solarizedPrecision colors for readability
nordArctic, north-bluish color palette
monokaiIconic warm dark theme
onedarkAtom-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

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

Custom Themes

Hierarchy

Custom themes can be defined at two levels:

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:

tui.json
{
  "primary": "#88C0D0",
  "secondary": "#81A1C1",
  "accent": "#5E81AC",
  "error": "#BF616A",
  "warning": "#EBCB8B",
  "success": "#A3BE8C",
  "muted": "#4C566A",
  "text": "#ECEFF4",
  "background": "#2E3440",
  "border": "#3B4252"
}

Color Definitions

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:

tui.json
{
  "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:

opencode.json
{
  "$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:

opencode.json
{
  "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:

opencode.json
{
  "keybind": {
    "help": ""
  }
}

Desktop Prompt Shortcuts

ActionDefault
Submitenter
Newlineshift+enter
Pastectrl+v
History backalt+up
History forwardalt+down
Switch agenttab
New sessionleader n
Session listleader l
Helpleader ?
Interruptesc

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:

opencode.json
{
  "actions": [
    {
      "command": {
        "action": "sendInput",
        "input": ""
      },
      "keys": "shift+enter"
    }
  ]
}
Note

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:

The file name (without extension) becomes the command name, accessible as /command-name.

Configure

JSON

opencode.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:

markdown
---
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:

markdown
---
description: Review recent changes
---

Review the following diff:

$(git diff HEAD~1)

File References

Use {file:path} to include file contents in your prompt:

markdown
---
description: Apply project standards
---

Follow these coding standards:
{file:./docs/standards.md}

Now review: $ARGUMENTS

Options

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.

Note

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

LanguageFormatter
Gogoimports
JavaScriptprettier
TypeScriptprettier
JSXprettier
TSXprettier
CSSprettier
HTMLprettier
JSONprettier
YAMLprettier
Markdownprettier
Pythonruff
Rustrustfmt
Zigzig fmt
Cclang-format
C++clang-format
Javagoogle-java-format
Kotlinktfmt
Swiftswift-format
Rubyrubocop
PHPphp-cs-fixer
Elixirmix format
Dartdart format
Luastylua
Nixnixfmt
Terraformterraform fmt
SQLsql-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:

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

Custom formatters

Override or add formatters for specific file extensions:

opencode.json
{
  "$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:

Configuration

opencode.json
{
  "$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:

opencode.json
{
  "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:

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.

opencode.json
{
  "permission": {
    "external_directory": "allow"
  }
}

Available Permissions

KeyTools it gates
readread
editwrite, edit, apply_patch
globglob
grepgrep
listlist
bashbash
tasktask
external_directoryAny tool that reads/writes outside project
todowritetodowrite, todoread
webfetchwebfetch
websearchwebsearch
lsplsp
skillskill
questionquestion
doom_loopRecovery prompts when agent appears stuck

Defaults

By default, all tools are set to allow except:

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:

opencode.json
{
  "$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

PolicyDescription
modelControl which models can be used
providerControl which providers can be used
mcpControl which MCP servers can be connected

Matching

Policy patterns support wildcards (*) for flexible matching:

Rule Order

When both allow and deny are specified:

  1. deny rules are evaluated first
  2. If denied, the resource is blocked regardless of allow rules
  3. If not denied, allow rules are checked
  4. 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:

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

Configuration

opencode.json
{
  "$schema": "https://opencode.ai/config.json",
  "lsp": {
    "gopls": {
      "enabled": true,
      "command": ["gopls", "serve"],
      "args": ["-rpc.trace"]
    }
  }
}

Disabling LSP

To disable LSP entirely:

opencode.json
{
  "lsp": false
}

To disable a specific LSP server:

opencode.json
{
  "lsp": {
    "gopls": {
      "enabled": false
    }
  }
}

Custom LSP Servers

Add custom LSP servers for languages not included by default:

opencode.json
{
  "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:

Terminal window
npm install -g intelephense

No 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:

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:

opencode.json
{
  "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:

opencode.json
{
  "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:

Remote MCP Servers

Connect to remote MCP servers via SSE or HTTP:

opencode.json
{
  "mcp": {
    "my-remote-server": {
      "type": "remote",
      "url": "https://my-server.com/mcp",
      "headers": {
        "Authorization": "Bearer ${TOKEN}"
      }
    }
  }
}

Key options for remote servers:

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:

opencode.json
{
  "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:

opencode.json
{
  "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:

opencode.json
{
  "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

opencode.json
{
  "mcp": {
    "sentry": {
      "type": "remote",
      "url": "https://mcp.sentry.dev/sse"
    }
  }
}

Context7

opencode.json
{
  "mcp": {
    "context7": {
      "type": "local",
      "command": ["npx", "-y", "@upstash/context7-mcp@latest"]
    }
  }
}

Grep by Vercel

opencode.json
{
  "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:

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:

opencode.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:

lua
require("avante").setup({
  provider = "opencode",
  opencode = {
    endpoint = "http://localhost:9100",
  },
})

CodeCompanion.nvim

Configure CodeCompanion.nvim to use OpenCode:

lua
require("codecompanion").setup({
  adapters = {
    opencode = function()
      return require("codecompanion.adapters").extend("openai_compatible", {
        url = "http://localhost:9100/v1/chat/completions",
      })
    end,
  },
})

Features & Support

Note

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:

  1. .opencode/skills/ - Project-level skills
  2. ~/.config/opencode/skills/ - Global user skills
  3. .claude/skills/ - Claude Code compatible (project)
  4. ~/.claude/skills/ - Claude Code compatible (global)
  5. Any directory, referenced by path in agent config
  6. 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:

markdown
---
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 coverage

Available frontmatter fields:

Validate names

Skill names must follow these rules:

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

markdown
---
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 levels

Recognize 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:

ValueEffect
allowAgent can load skills without asking
askUser must approve each skill load
denyAgent cannot load skills

Override per agent

opencode.json
{
  "agent": {
    "build": {
      "permission": {
        "skill": "allow"
      }
    },
    "explore": {
      "permission": {
        "skill": "deny"
      }
    }
  }
}

Disable the skill tool

To globally disable skills:

opencode.json
{
  "permission": {
    "skill": "deny"
  }
}

Troubleshoot loading


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:

opencode.json
{
  "$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:

opencode.json
{
  "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:

Structure

Each tool consists of a TypeScript definition file that uses the tool() helper:

TypeScript
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:

TypeScript
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:

TypeScript
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:

TypeScript
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):

Python
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):

TypeScript
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
  },
})