opencode
7 min read

opencode is an open-source AI coding agent for the terminal. It runs as a TUI (also available as a desktop app and IDE extension), understands project context, and can read/write files and run shell commands. It is provider-agnostic — works with 75+ LLM providers via the AI SDK and Models.dev, including local models — and is heavily configurable through JSON config, custom agents, commands, and plugins.

sh
opencode # start the TUI in the current project
opencode run "fix the failing test in @src/api.ts" # one-shot, non-interactive
opencode serve # headless HTTP server

Install

sh
curl -fsSL https://opencode.ai/install | bash # install script

npm install -g opencode-ai # or bun/pnpm/yarn
brew install anomalyco/tap/opencode # Homebrew (most up-to-date tap)
sudo pacman -S opencode # Arch

On Windows, WSL is recommended. opencode auto-updates on startup by default ("autoupdate": false or "notify" to change).

Getting started

1. Connect a provider — run /connect in the TUI and add an API key (or use OpenCode Zen, a curated set of tested models).
2. Initialize the project — run /init to have opencode analyze the repo and generate an AGENTS.md (commit this to Git).
3. Work — ask questions, reference files with @ fuzzy-search, drag-and-drop images into the terminal for visual context.

Plan vs. Build

opencode ships two primary agents you toggle with Tab:

• Plan — restricted; file edits and bash default to ask, so it analyzes and proposes without changing anything.
• Build — the default; full tool access for actually making changes.

The typical flow: draft an approach in Plan, iterate on it, then switch to Build to implement. Use /undo and /redo (repeatable) to roll changes back and forth.

Agents

Agents are specialized assistants with their own prompt, model, and tool permissions. Two kinds:

• Primary — the assistant you talk to directly (Build, Plan, or custom); cycle with Tab.
• Subagents — invoked by primary agents for focused work, or manually via @mention. Built-ins: General (full-access multi-step work), Explore (fast read-only codebase search), Scout (read-only external docs/dependency research).

Hidden system agents (compaction, title, summary) run automatically.

Define agents in opencode.json or as markdown files in ~/.config/opencode/agents/ (global) or .opencode/agents/ (project). The filename becomes the agent name.

markdown
---
description: Reviews code for quality and best practices
mode: subagent
model: anthropic/claude-sonnet-4-5
temperature: 0.1
permission:
edit: deny
bash: deny
---

You are in code review mode. Focus on bugs, edge cases,
performance, and security. Suggest changes without making them.

Key options: description (required), mode (primary/subagent/all), model, prompt ({file:./prompt.txt}), temperature/top_p, steps (max agentic iterations), permission, color, hidden, disable. Run opencode agent create for an interactive scaffold. Control which subagents an agent may spawn with permission.task.

Configuration

Config is JSON/JSONC validated against https://opencode.ai/config.json. Files are merged (not replaced), later sources overriding earlier ones:

1. Remote (.well-known/opencode) — org defaults
2. Global — ~/.config/opencode/opencode.json
3. Custom — OPENCODE_CONFIG env var
4. Project — opencode.json in repo (walks up to nearest Git dir)
5. .opencode/ directories — agents, commands, plugins
6. Inline — OPENCODE_CONFIG_CONTENT
7. Managed — /etc/opencode/, macOS .mobileconfig via MDM (highest, not user-overridable)

jsonc
{
"$schema": "https://opencode.ai/config.json",
"model": "anthropic/claude-sonnet-4-5",
"small_model": "anthropic/claude-haiku-4-5", // cheap model for titles etc.
"autoupdate": true,
"instructions": ["CONTRIBUTING.md", ".cursor/rules/*.md"],
"permission": { "edit": "ask", "bash": "ask" }
}

TUI-specific settings live in a separate tui.json (theme, keybinds, scroll, notifications). Inspect the fully resolved config with opencode debug config.

Variable substitution

• {env:VAR} — substitute an environment variable
• {file:path} — inline a file's contents (great for keeping API keys out of config)

jsonc
{ "provider": { "anthropic": { "options": { "apiKey": "{file:~/.secrets/anthropic}" } } } }

Other notable keys

compaction (auto context compaction), snapshot (file-change tracking for undo; disable on huge repos), watcher.ignore (glob ignore patterns), share (manual/auto/disabled), shell, attachment.image (resize limits), disabled_providers/enabled_providers.

Models

Model IDs are provider/model-id (e.g. anthropic/claude-sonnet-4-5, opencode/gpt-5.1-codex). Pick one in the TUI with /models, set a default via the model key, or override per-invocation with --model. Models that are strong at both code generation and tool-calling work best (Claude Opus/Sonnet 4.5, GPT 5.x, Gemini 3 Pro, etc.).

Per-model options and variants are configured under provider.<id>.models:

jsonc
{
"provider": {
"anthropic": {
"models": {
"claude-sonnet-4-5": { "options": { "thinking": { "type": "enabled", "budgetTokens": 16000 } } }
}
}
}
}

Variants (e.g. Anthropic high/max thinking budgets, OpenAI reasoning-effort levels) are cycled in the TUI with variant_cycle. Local models run via providers like LM Studio or Ollama.

Tools

Tools are the actions the LLM can take. Built-ins: bash, edit, write, read, grep, glob, apply_patch, lsp (experimental), skill, todowrite, webfetch, websearch, question. Internally grep/glob use ripgrep, so .gitignore is respected (add a .ignore file to override).

Extend with custom tools (functions defined in config) or MCP servers (Model Context Protocol — external tools, DB access, API integrations) via the mcp key. Plugins add tools, hooks, and integrations from .opencode/plugins/ or npm (plugin key).

Permissions

Permissions decide whether a tool runs automatically (allow), prompts (ask), or is blocked (deny). Defaults are permissive — most allow, but doom_loop and external_directory default to ask, and .env reads are denied.

jsonc
{
"permission": {
"*": "ask",
"edit": "deny",
"bash": { "*": "ask", "git *": "allow", "npm *": "allow", "rm *": "deny" },
"external_directory": { "~/projects/personal/**": "allow" }
}
}

Object syntax matches against tool input (bash commands, file paths, URLs…) with glob wildcards (*, ?); the last matching rule wins, so put "*" first and specific rules after. Permission keys: read, edit (covers write/apply_patch), glob, grep, bash, task, skill, lsp, question, webfetch, websearch, plus the guards external_directory (paths outside the workspace) and doom_loop (same call repeated 3×). Agents can override globally-set permissions, and the same pattern syntax gates MCP tools ("mymcp_*": "deny"). The legacy boolean tools config is deprecated in favor of permission.

Policies

Separate from permissions: experimental.policies controls which resources (currently LLM providers) opencode may use — useful for org-level provider allow/deny lists. Statements have effect (allow/deny), action (provider.use), and a wildcard resource; last match wins, global config beats project config.

jsonc
{
"experimental": {
"policies": [
{ "effect": "deny", "action": "provider.use", "resource": "*" },
{ "effect": "allow", "action": "provider.use", "resource": "anthropic" }
]
}
}

Rules (AGENTS.md)

Project-specific instructions live in AGENTS.md (like Cursor rules). /init generates it from your repo — build/test commands, structure, conventions, gotchas — and improves an existing one in place. Lookup precedence: local AGENTS.md (walking up) → global ~/.config/opencode/AGENTS.md → ~/.claude/CLAUDE.md (Claude Code compatibility fallback). Pull in extra files via the instructions array (supports globs and remote URLs).

Custom commands

Reusable prompts triggered with /name, alongside built-ins like /init, /undo, /redo, /share, /help. Define in config or as markdown in ~/.config/opencode/commands/ (global) or .opencode/commands/ (project).

markdown
---
description: Run tests with coverage
agent: build
model: anthropic/claude-haiku-4-5
---

Run the full test suite with coverage. Recent commits: !`git log --oneline -10`
Focus on failing tests in @src/ and suggest fixes for $ARGUMENTS.

Placeholders: $ARGUMENTS (all args), $1/$2/… (positional), !`cmd` (inject shell output), @file (inline file contents). subtask: true forces the command to run as a subagent so it doesn't pollute primary context.

Formatters

opencode runs language-specific formatters after writing/editing files. Disabled by default — enable with "formatter": true, or use an object to configure overrides and custom formatters. Built-ins include prettier, biome, gofmt, rustfmt, ruff, shfmt, nixfmt, clang-format, and many more (each requires its tool/config present).

jsonc
{
"formatter": {
"prettier": { "disabled": true },
"custom-md": { "command": ["deno", "fmt", "$FILE"], "extensions": [".md"] }
}
}

$FILE is replaced with the file path. (LSP servers are similarly configured under the lsp key.)

Themes & keybinds (TUI)

Set the theme in tui.json ("theme": "tokyonight") or pick one with /theme. Built-ins include tokyonight, catppuccin, gruvbox, nord, everforest, one-dark, matrix, and system (adapts to your terminal). Truecolor (24-bit) is recommended. Custom themes go in ~/.config/opencode/themes/*.json.

Keybinds are customized in tui.json under keybinds (merged with defaults — only override what you change). They use a leader key (default ctrl+x). Notable defaults:

ActionKeybindActionKeybind
agent_cycletabcommand_listctrl+p
session_new<leader>nsession_list<leader>l
messages_undo<leader>umessages_redo<leader>r
model_list<leader>mtheme_list<leader>t
session_interruptescapesession_compact<leader>c
editor_open<leader>eapp_exitctrl+c/ctrl+d

Sharing

/share creates a link to the current conversation (off by default; the share config key sets manual/auto/disabled).


opencode is one of several terminal AI tools tracked here — see also crush and mods. It is developed under the Anomaly/SST umbrella.