OpenCode¶
Snapshot date: 8 October 2026. OpenCode ships releases very frequently and V2 is now the default on the website (binaries at 2.0.6 at time of writing), while V1 docs and installs remain widely used. This guide covers V2 first and calls out V1 differences where they matter. Always check
opencode --versionand the matching docs.
TL;DR¶
- What: An open-source (MIT) AI coding agent — a terminal UI, desktop app, and web client — that reads your codebase, edits files, runs commands and chains multi-step tasks.
- Why people use it: It's model-agnostic — 75+ providers via the models.dev catalog, plus local models (Ollama, LM Studio, vLLM). Same workflow whether you use Claude, GPT, Gemini, DeepSeek, Qwen or a model on your own GPU.
- Who: Built by Anomaly (the team behind SST and OpenNext). Repo:
anomalyco/opencode. - Scale: Over 200K GitHub stars as of early September 2026; the company reported more than 16 million monthly developers in August 2026.
- Key concepts: primary agents (
build,plan), subagents (general,explore,scout),AGENTS.mdproject rules, a JSON/JSONC config, fine-grained permissions, MCP servers, skills, custom commands, and a client/server architecture.
Table of contents¶
- What OpenCode is
- V1 vs V2
- Installation
- First run
- Providers and models
- Configuration
- Agents
- Permissions
- Project instructions: AGENTS.md
- MCP servers
- Custom commands and skills
- Everyday TUI usage
- Automation, server mode and CI
- Homelab recipe: OpenCode + local models
- OpenCode vs Claude Code vs Codex
- Gotchas and troubleshooting
- Cheat sheet
- Sources
1. What OpenCode is¶
OpenCode is an agent harness: the loop, tools, context management and UI that turn an LLM into a coding agent. The LLM is pluggable.
┌────────────┐ ┌──────────────┐ ┌───────────────────────────┐
│ Clients │──▶│ OpenCode │──▶│ Providers │
│ TUI, mini, │ │ server │ │ Anthropic, OpenAI, │
│ desktop, │◀──│ sessions, │◀──│ Google, Bedrock, Vertex, │
│ web, IDE, │ │ tools, perms,│ │ Azure, OpenRouter, │
│ ACP, SDK │ │ MCP, agents │ │ Ollama, vLLM, LM Studio… │
└────────────┘ └──────────────┘ └───────────────────────────┘
Built-in capabilities: file read/write/edit/patch, glob and grep, shell execution, web fetch and web search, todo lists, sub-agent delegation (task/subagent tool), snapshots with undo/redo, context compaction, image attachments, MCP tools, skills, and custom tools via plugins.
Interfaces:
- TUI — the full-screen terminal interface (
opencode). - Mini — a minimal interactive interface (
opencode mini, V2). - Desktop app — macOS, Windows, Linux (.deb, .rpm, AppImage).
- Web — browser client (
opencode pairin V2;opencode webin V1). - IDE / ACP — any editor speaking the Agent Client Protocol can drive OpenCode (
opencode acp). - SDK / HTTP API — embed the agent server in your own tools.
Business model: The agent is free. Anomaly sells optional model access:
- OpenCode Zen / Console — a curated, pay-as-you-go gateway to models the OpenCode team has tested for coding agents.
- OpenCode Go — a $10/month subscription with access to leading open-source coding models.
2. V1 vs V2¶
Both versions use the opencode command and do not install side by side by default. The V2 curl installer replaces the V1 binary; remove a package-managed V1 install first.
What changed in V2¶
| Area | V1 | V2 |
|---|---|---|
| Architecture | Each TUI starts its own server | One shared background service per user; all local clients connect to it (--standalone for a private server) |
| Web client | opencode web |
opencode pair (needs the shared service) |
| TUI settings | Layered tui.json files |
Single global ~/.config/opencode/cli.json (auto-migrated) |
| Plugins | V1 plugin API | New plugin API — V1 plugins do not run |
| Server API | V1 API | New API + @opencode/client package |
| Permissions | permission map grouped by tool |
Ordered permissions array of {action, resource, effect} |
| Agents | agent map, prompt, disable |
agents map, system, disabled, model#variant |
| Providers | provider, npm, api, options |
providers, package, settings.baseURL, headers, body |
| MCP | mcp.<name>, enabled, single timeout |
mcp.servers.<name>, disabled, timeout.catalog / timeout.execution |
| LSP | Runs language servers, LSP diagnostics | Config accepted but LSP is not run — use lint/typecheck commands instead |
| Instructions | AGENTS.md, plus CLAUDE.md fallback |
AGENTS.md only |
small_model |
Top-level key | agents.title.model |
autoupdate |
true/false/"notify" |
update: "auto" \| "notify" \| "disable" |
Good news: V2 reads the same config locations and normalises supported V1 fields in memory without rewriting them. You can keep V1 config and convert gradually. The docs even suggest asking OpenCode itself to do the migration:
Migrate my OpenCode configuration, including file-based definitions, from the V1
format to the native V2 format. Preserve its behavior and all unrelated settings.
Don't point V1 at a config you've converted to V2-only syntax.
3. Installation¶
V2 (current)¶
# Install script (Linux/macOS)
curl -fsSL https://opencode.ai/v2/install | bash
# Verify
opencode --version
V2 is also available via npm, bun, pnpm, yarn, Homebrew and the AUR (see the install page for exact package names), plus standalone binaries for macOS, Windows and Linux (glibc and musl), and versioned Docker images such as ghcr.io/anomalyco/opencode:2.0.0. The npm package uses a postinstall script to fetch the native binary for your platform. Windows package managers are not supported in V2.
V1 (still common)¶
curl -fsSL https://opencode.ai/install | bash # install script
npm install -g opencode-ai # Node
brew install anomalyco/tap/opencode # Homebrew tap (more current than core formula)
sudo pacman -S opencode # Arch stable
paru -S opencode-bin # Arch AUR latest
mise use -g github:anomalyco/opencode # mise
docker run -it --rm ghcr.io/anomalyco/opencode # Docker
On Windows, V1 recommends WSL; Chocolatey and Scoop also work.
Terminal¶
Use a modern, truecolor terminal — Ghostty, WezTerm, Alacritty or Kitty are the recommended options.
Uninstall¶
opencode uninstall --dry-run # preview
opencode uninstall # V2 keeps session data, config and state
4. First run¶
cd ~/code/my-project
opencode
Inside the TUI:
/connect # pick a provider and enter credentials
/models # choose a model
/init # analyse the repo and generate AGENTS.md
Commit the generated AGENTS.md — it's how OpenCode (and other agents) learn your build commands and conventions.
A first useful session¶
- Press Tab to switch to the Plan agent (read-only).
- Describe the change. Reference files with
@(fuzzy file search). Drag images into the terminal to attach them. - Iterate on the plan.
- Press Tab again to return to Build and tell it to implement.
- Didn't like it?
/undo(repeatable). Changed your mind?/redo.
5. Providers and models¶
Model references always use provider/model format, e.g. anthropic/claude-sonnet-5-5, openai/gpt-6-sol, ollama/qwen3:8b, openrouter/<vendor>/<model>. List what you have:
opencode models # all configured providers
opencode models anthropic # filter
opencode models --refresh # refresh catalog from models.dev (V1)
Connecting cloud providers¶
- TUI:
/connect - CLI (V1):
opencode auth login— credentials live in~/.local/share/opencode/auth.json. OpenCode also picks up provider keys from environment variables and a project.env.
Enterprise clouds (V2 syntax)¶
{
"$schema": "https://opencode.ai/config.json",
"providers": {
// AWS Bedrock — uses the default AWS credential chain
"amazon-bedrock": {
"settings": { "profile": "work", "region": "us-east-1" }
},
// Azure — needs the resource name; supports API key or Entra ID via `az login`
"azure": {
"settings": { "resourceName": "my-models" }
},
// Google Vertex — uses ADC (`gcloud auth application-default login`)
"google-vertex": {
"settings": { "project": "my-project", "location": "us-central1" }
}
}
}
Azure notes: OpenCode lists your resource's deployments rather than the whole catalog. Your identity needs Cognitive Services OpenAI User (Azure OpenAI) or Cognitive Services User (other Foundry models). In V2, the old azure-cognitive-services and google-vertex-anthropic IDs are replaced by azure and google-vertex.
Local models (V2)¶
V2 has built-in discovery for local runtimes:
| Runtime | Default endpoint | Notes |
|---|---|---|
| Ollama | http://127.0.0.1:11434 |
Auto-discovered; only models with the completion capability appear |
| LM Studio | http://127.0.0.1:1234/v1 |
Reads /api/v1/models |
| vLLM | http://127.0.0.1:8000/v1 |
Checks /health then /v1/models; tools start disabled because discovery can't infer tool support |
Pointing at a remote box:
{
"$schema": "https://opencode.ai/config.json",
"providers": {
"ollama": { "settings": { "baseURL": "http://gpu-host:11434/v1" } },
"lmstudio": { "settings": { "baseURL": "http://gpu-host:1234/v1" } },
"vllm": { "settings": { "baseURL": "http://gpu-host:8000/v1" } }
}
}
Any OpenAI-compatible endpoint (V2)¶
{
"$schema": "https://opencode.ai/config.json",
"model": "company/coder",
"providers": {
"company": {
"name": "Company Gateway",
"env": ["COMPANY_GATEWAY_KEY"],
"package": "@opencode/ai/providers/openai-compatible",
"settings": { "baseURL": "https://gateway.example.com/v1" },
"models": {
"coder": {
"modelID": "upstream/coder-v2",
"name": "Coder v2",
"limit": { "context": 200000, "output": 32000 }
}
}
}
}
}
The same file in V1 syntax for comparison:
{
"$schema": "https://opencode.ai/config.json",
"provider": {
"company": {
"npm": "@ai-sdk/openai-compatible",
"api": "https://gateway.example.com/v1",
"options": { "apiKey": "{env:COMPANY_GATEWAY_KEY}" },
"models": { "coder": {} }
}
}
}
Proxies, headers and timeouts (V2)¶
{
"providers": {
"anthropic": {
"settings": {
"baseURL": "https://llm-proxy.example.com/anthropic",
"headerTimeout": 600000, // ms; default 5 min
"chunkTimeout": false // disable inter-chunk timeout
},
"headers": { "X-Gateway-Tenant": "engineering" }
}
}
}
Timed-out requests are retried up to three times. OpenAI, xAI and supported Azure Responses models can reuse a WebSocket per session to avoid resending the whole prompt each step (settings.transport: "websocket" | "http").
A note on subscriptions¶
Model vendors' consumer subscriptions generally aren't valid for third-party harnesses. In particular, Claude Pro/Max subscriptions can't be used through OpenCode — use an Anthropic API key, Bedrock/Vertex/Foundry, or another provider. GitHub Copilot is supported via device OAuth (/connect → GitHub Copilot) if your account has Copilot Chat access.
6. Configuration¶
Files and precedence¶
| Scope | Location |
|---|---|
| Global | ~/.config/opencode/opencode.json or .jsonc |
| Project | <project>/opencode.json(c) and/or <project>/.opencode/opencode.json(c) |
| TUI/CLI client (V2) | ~/.config/opencode/cli.json (global only) |
| TUI (V1) | ~/.config/opencode/tui.json, project tui.json |
| File-based definitions | .opencode/agents/, commands/, skills/, plugins/, themes/ (plural preferred) and the same under ~/.config/opencode/ |
| Managed (admin) | /etc/opencode/ (Linux), /Library/Application Support/opencode/ (macOS), %ProgramData%\opencode (Windows); macOS MDM via ai.opencode.managed |
Configs merge; later layers override only conflicting keys. In V2, OpenCode walks from the current directory up to the filesystem root, merging direct opencode.json(c) files from farthest to closest, then .opencode/ files in the same order — so any .opencode/ config beats any direct one.
Useful environment overrides (V1 names; most remain): OPENCODE_CONFIG, OPENCODE_CONFIG_DIR, OPENCODE_CONFIG_CONTENT, OPENCODE_PERMISSION, OPENCODE_DISABLE_AUTOUPDATE, OPENCODE_SERVER_PASSWORD.
Always add the schema for editor validation:
{ "$schema": "https://opencode.ai/config.json" }
Variable substitution¶
{
"model": "{env:OPENCODE_MODEL}",
"providers": {
"openai": { "settings": { "apiKey": "{file:~/.secrets/openai-key}" } }
}
}
{env:NAME} becomes an empty string if unset; {file:path} paths are relative to the config file or absolute (/, ~). This plays nicely with pass-style secret files.
A solid V2 global config¶
// ~/.config/opencode/opencode.jsonc
{
"$schema": "https://opencode.ai/config.json",
"model": "anthropic/claude-sonnet-5-5",
"default_agent": "build",
"update": "notify",
"share": "disabled",
"snapshots": true,
"formatter": true,
"compaction": {
"auto": true,
"keep": { "tokens": 15000 },
"buffer": 20000
},
"watcher": { "ignore": ["target/**", "node_modules/**", "dist/**", ".git/**"] },
"tool_output": { "max_lines": 2000, "max_bytes": 51200 },
"agents": {
"title": { "model": "anthropic/claude-haiku-5-5" }
},
"permissions": [
{ "action": "shell", "resource": "*", "effect": "ask" },
{ "action": "shell", "resource": "git status*", "effect": "allow" },
{ "action": "shell", "resource": "git diff*", "effect": "allow" },
{ "action": "shell", "resource": "cargo check*", "effect": "allow" },
{ "action": "shell", "resource": "cargo test*", "effect": "allow" },
{ "action": "shell", "resource": "git push *", "effect": "ask" },
{ "action": "shell", "resource": "rm -rf *", "effect": "deny" },
{ "action": "edit", "resource": "*", "effect": "allow" }
]
}
Notable V2 options¶
| Key | What it does |
|---|---|
warming |
Keeps recently active sessions' prompt caches warm with periodic tiny requests (off by default; costs tokens) |
references |
Expose other local dirs or Git repos as named, read-only supporting context |
worktree.directory |
Where new git worktrees for parallel sessions are created |
websearch.provider |
Choose web search backend ("random" picks an available one) |
media.image |
Resize/reject oversized images before sending |
experimental.policies |
Hard allow/deny of providers or permissions (enterprise guardrails) |
skills |
Extra skill directories or URLs |
7. Agents¶
Built-in agents¶
| Agent | Mode | Purpose |
|---|---|---|
| build | primary (default) | Full tool access for development |
| plan | primary | Planning/analysis; edits and shell set to ask |
| general | subagent | Research and multi-step work; can edit; good for parallel work |
| explore | subagent | Fast, read-only codebase search |
| scout | subagent | Read-only external docs/dependency research; can clone dependency repos into a managed cache |
| compaction, title, summary | hidden | System agents for compaction, session titles and summaries |
- Tab cycles primary agents.
@nameinvokes a subagent manually (@explore where is auth handled?).- Primary agents also call subagents automatically based on their
description. - Sub-agent child sessions are navigable from the parent session (V1 defaults: Leader+Down to enter, Left/Right to cycle, Up to return).
Defining agents in Markdown¶
~/.config/opencode/agents/<name>.md (global) or .opencode/agents/<name>.md (project). The filename becomes the agent name; the body is the system prompt.
---
description: Reviews Rust changes for correctness, safety and missing tests
mode: subagent
model: anthropic/claude-opus-5-5
permission:
edit: deny
bash:
"*": ask
"git diff*": allow
"cargo clippy*": allow
"cargo test*": allow
---
You are a senior Rust reviewer. Focus on:
- ownership/borrowing mistakes, unnecessary clones, panics in library code
- error handling (prefer `thiserror`/`anyhow` patterns already in the repo)
- missing tests for new branches
- clippy warnings (`-D warnings` is enforced in CI)
Never edit files. Report findings as a prioritised list with file:line references.
(That frontmatter is V1-style and is auto-translated by V2. Native V2 would use permissions: as an ordered list and model: provider/model#variant.)
Defining agents in JSON (V2)¶
{
"agents": {
"reviewer": {
"description": "Review changes without editing files",
"mode": "subagent",
"model": "anthropic/claude-opus-5-5#high",
"system": "Focus on correctness, security and missing tests.",
"steps": 30,
"permissions": [
{ "action": "edit", "resource": "*", "effect": "deny" }
]
},
"plan": {
"model": "openai/gpt-6-sol"
}
}
}
Agent options worth knowing¶
| Option | Notes |
|---|---|
description |
Required; drives automatic delegation |
mode |
primary, subagent or all (default) |
model |
Override per agent; subagents otherwise inherit the caller's model |
steps |
Cap agentic iterations (cost control); the agent then summarises remaining work |
hidden |
Hide a subagent from @ autocomplete (still callable by other agents) |
| Task permissions | Control which subagents an agent may delegate to (task in V1, subagent in V2) |
color |
UI colour |
| Sampling / provider options | temperature, top_p, reasoningEffort etc. — under request.body in V2 |
Interactive scaffolding:
opencode agent create # asks scope, description, permissions; writes a .md file
opencode agent list
Sub-agent nesting depth defaults to 1 (subagents can't spawn subagents); V2 sets it via experimental.subagent_depth.
8. Permissions¶
Default is permissive — OpenCode allows all operations unless you configure otherwise. Set permissions before pointing it at anything important.
V2: ordered rules¶
{
"permissions": [
{ "action": "shell", "resource": "*", "effect": "ask" },
{ "action": "shell", "resource": "git status*", "effect": "allow" },
{ "action": "edit", "resource": "*", "effect": "allow" },
{ "action": "websearch", "resource": "*", "effect": "deny" }
]
}
Action names changed in V2: bash → shell, task → subagent, write/patch → edit.
V1: per-tool map¶
{
"permission": {
"edit": "ask",
"bash": {
"*": "ask",
"git status *": "allow",
"rm -rf *": "deny"
},
"webfetch": "deny",
"external_directory": "ask"
}
}
V1 permission keys: read, edit, glob, grep, list, bash, task, external_directory, todowrite, webfetch, websearch, lsp, skill, question, doom_loop. Keys are wildcard-matched against tool names, so "mymcp_*": "deny" blocks every tool from an MCP server.
Precedence rules¶
- Last matching rule wins — put broad
*rules first and specific exceptions after. - Agent-level permissions override global ones.
--autoonopencode/opencode runauto-approves anything not explicitly denied — useful in sandboxes and CI, dangerous on your workstation.- Organisations can enforce non-overridable rules via managed config or
experimental.policies.
9. Project instructions: AGENTS.md¶
/init generates an AGENTS.md in the project root. V2 discovers:
~/.config/opencode/AGENTS.md(global, personal preferences)AGENTS.mdfiles from the current directory up to$HOME(or the project root for projects outside home)
V2 does not read CLAUDE.md — move that content into AGENTS.md. (V1 had a CLAUDE.md fallback and could read .claude/skills; disable with OPENCODE_DISABLE_CLAUDE_CODE* env vars.)
Example for a Rust CLI project:
# AGENTS.md
## Build & test
- Build: `cargo build`
- Lint: `cargo fmt --check && cargo clippy --all-targets -- -D warnings`
- Test: `cargo test`
- Pre-commit hooks enforce fmt + clippy + test; never bypass with `--no-verify`.
## Conventions
- Binary name matches crate name; subcommands via `clap` derive.
- Errors: `anyhow` in the binary, `thiserror` in library modules.
- Credentials come from `pass`; never hard-code or log secrets.
- Config lives in `~/.config/<tool>/config.toml`.
## CI
- GitLab CI; shared includes come from the `skel` repo — do not edit the include header by hand.
## Don'ts
- Don't add dependencies without saying why.
- Don't modify `.gitlab-ci.yml` include/stages blocks.
10. MCP servers¶
MCP tools appear alongside built-in tools. Every enabled server costs context — the docs specifically warn that servers like GitHub's can add a lot of tokens. Enable sparingly and per agent where possible.
V2¶
{
"mcp": {
"servers": {
"playwright": {
"type": "local",
"command": ["npx", "-y", "@playwright/mcp"],
"disabled": false,
"timeout": { "catalog": 30000, "execution": 30000 }
},
"sentry": {
"type": "remote",
"url": "https://mcp.sentry.dev/mcp",
"oauth": {}
},
"context7": {
"type": "remote",
"url": "https://mcp.context7.com/mcp",
"headers": { "CONTEXT7_API_KEY": "{env:CONTEXT7_API_KEY}" }
}
}
}
}
V1¶
{
"mcp": {
"playwright": {
"type": "local",
"command": ["npx", "-y", "@playwright/mcp"],
"enabled": true,
"environment": { "DEBUG": "0" },
"timeout": 30000
},
"gitlab": {
"type": "remote",
"url": "https://gitlab.example.com/api/v4/mcp",
"oauth": false,
"headers": { "Authorization": "Bearer {env:GITLAB_TOKEN}" }
}
}
}
Remote OAuth is automatic (including Dynamic Client Registration). Manage it with:
opencode mcp add # interactive
opencode mcp list
opencode mcp auth <name> # browser OAuth flow
opencode mcp logout <name>
opencode mcp debug <name> # connectivity + OAuth discovery diagnostics
V1 stores MCP tokens in ~/.local/share/opencode/mcp-auth.json. In V2, OAuth fields are snake_case (client_id, client_secret).
11. Custom commands and skills¶
Commands¶
Reusable prompt templates invoked as /name. Markdown version — .opencode/commands/review.md:
---
description: Review the current diff
agent: plan
model: anthropic/claude-opus-5-5
---
Review the current `git diff` for correctness, security issues and missing
tests. Group findings by severity. Focus area: $ARGUMENTS
JSON version (V2):
{
"commands": {
"release-notes": {
"description": "Draft release notes since the last tag",
"template": "Summarise commits since the last git tag as release notes grouped by feat/fix/chore.",
"subagent": true
}
}
}
$ARGUMENTS receives whatever follows the command. In V2, subagent: true (V1: subtask) runs the command in the background and reports back to the parent session.
Skills¶
Skills are folders with a SKILL.md plus any scripts/references, loaded on demand by the agent:
.opencode/skills/
└── helm-chart/
├── SKILL.md
└── templates/
Keep the directory name stable — it's the skill ID. Extra skill locations or URLs go in the skills config array.
12. Everyday TUI usage¶
| Action | How |
|---|---|
| Switch primary agent | Tab |
| Reference a file | @ + fuzzy search |
| Invoke a subagent | @explore …, @general … |
| Attach an image | Drag and drop into the terminal |
| Undo / redo agent changes | /undo, /redo (snapshots must be enabled) |
| Connect provider / pick model | /connect, /models |
| Generate AGENTS.md | /init |
| Share a session link | /share (sessions are not shared by default; V2 accepts the setting but sharing isn't supported yet) |
| Command palette | command_list keybind (configurable, e.g. ctrl+p) |
Keybinds are configurable (V1: tui.json → keybinds; V2: cli.json).
13. Automation, server mode and CI¶
One-shot runs¶
opencode run "Explain this repository"
opencode run -m openai/gpt-6-luna --agent plan "List TODOs in src/"
opencode run --format json "Summarise the last 10 commits" | jq .
opencode run --continue "Now write tests for that"
opencode run -f error.log "What's causing this?"
Useful flags (V1): --model/-m, --agent, --file/-f, --format json, --continue/-c, --session/-s, --fork, --variant (reasoning effort), --thinking, --auto, --attach <url>.
Shared server (avoid MCP cold starts)¶
# V1
opencode serve --port 4096
opencode run --attach http://localhost:4096 "Explain async/await"
opencode attach http://10.20.30.40:4096 # TUI against a remote backend
# V2 — a shared background service is started automatically
opencode --standalone # private server instead
opencode --server http://localhost:4096 # connect to a specific server
opencode service set disabled true # opt out of the shared service
opencode pair # web UI (URL + generated credentials)
Set OPENCODE_SERVER_PASSWORD (and optionally OPENCODE_SERVER_USERNAME) before exposing a server beyond localhost. mDNS discovery (--mdns) lets other devices on the LAN find it.
Sessions and stats¶
opencode session list -n 20
opencode export <sessionID> --sanitize > session.json
opencode import session.json
opencode stats --days 30 --models 5 # token & cost usage
opencode debug paths # V2: where db/config/cache/log live
GitHub / GitLab¶
opencode github install # sets up a GitHub Actions workflow
opencode pr 123 # check out a PR branch and start OpenCode
OpenCode also documents a GitLab integration. A generic GitLab CI job using run:
opencode-review:
image: ghcr.io/anomalyco/opencode:2.0.0
stage: test
rules:
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
variables:
ANTHROPIC_API_KEY: $ANTHROPIC_API_KEY
script:
- git fetch origin "$CI_MERGE_REQUEST_TARGET_BRANCH_NAME"
- >
opencode run --agent plan --format json
"Review the diff against origin/$CI_MERGE_REQUEST_TARGET_BRANCH_NAME.
Report bugs, security issues and missing tests."
> review.json
artifacts:
paths: [review.json]
Use the plan agent (or a custom read-only agent) in CI unless the job is meant to push changes, and never use --auto with write permissions on untrusted MR content — that's a prompt-injection path straight into your runner.
14. Homelab recipe: OpenCode + local models¶
Goal: routine work on a local open model, frontier model only when needed.
1. Serve a model on the GPU box
# Option A: Ollama
ollama serve
ollama pull qwen3:32b
# Option B: vLLM (better throughput; enable tool calling)
vllm serve Qwen/Qwen3-32B \
--host 0.0.0.0 --port 8000 \
--max-model-len 32768 \
--enable-auto-tool-choice --tool-call-parser hermes
2. Point OpenCode at it and keep a frontier fallback
// ~/.config/opencode/opencode.jsonc (V2)
{
"$schema": "https://opencode.ai/config.json",
"model": "ollama/qwen3:32b",
"providers": {
"ollama": { "settings": { "baseURL": "http://gpu-host:11434/v1" } },
"vllm": {
"settings": { "baseURL": "http://gpu-host:8000/v1" },
"models": {
"Qwen/Qwen3-32B": {
"name": "Qwen3 32B (vLLM)",
"capabilities": { "tools": true }
}
}
}
},
"agents": {
"architect": {
"description": "Hard design questions and tricky refactors",
"mode": "primary",
"model": "anthropic/claude-opus-5-5"
}
}
}
Tab between build (local) and architect (frontier) as needed.
3. Tips for local models
- Tool calling quality varies a lot between models and quantisations — test a multi-step task before trusting it. vLLM-discovered models start with tools disabled; enable them explicitly as above.
- Keep context realistic (32K–64K) on consumer GPUs; enable compaction.
- Smaller models benefit from a tighter
AGENTS.mdand fewer MCP servers. - Behind a reverse proxy with TLS, use the
https://…/v1URL and pass an API key viasettings.apiKeywith{env:…}.
15. OpenCode vs Claude Code vs Codex¶
| OpenCode | Claude Code | Codex | |
|---|---|---|---|
| Vendor | Anomaly | Anthropic | OpenAI |
| Licence | MIT, open source | Proprietary | CLI open source; service proprietary |
| Models | Any (75+ providers, local) | Claude | GPT |
| Subscription use | Its own Zen/Go; vendor subs generally not allowed | Claude Pro/Max/Team/Enterprise | ChatGPT plans |
| Interfaces | TUI, mini, desktop, web, ACP, SDK | Terminal, IDE, desktop, web, mobile | Terminal, IDE, cloud, ChatGPT |
| Config | opencode.json(c), AGENTS.md |
settings.json, CLAUDE.md |
config.toml, AGENTS.md |
| Agents/subagents | build/plan + general/explore/scout + custom | Subagents, plugins, hooks | Agents |
| MCP | Yes (local + remote OAuth) | Yes | Yes |
| Skills | Yes | Yes | Yes |
| Strengths | Portability, local models, inspectable, client/server | Tightest integration with Claude, polish | Tightest integration with GPT/Codex cloud |
| Weaknesses | Integration burden, fast-moving (occasional regressions), V1→V2 transition | Single vendor | Single vendor |
Pick OpenCode when you want one workflow across many models, need local/air-gapped models, want to inspect or extend the agent, or want to avoid vendor lock-in. Pick the vendor agent when you're committed to one model family and want the most tuned experience, or want to use a consumer subscription.
16. Gotchas and troubleshooting¶
- Wrong docs for your version. V1 and V2 configs differ; check
opencode --versionand use/docs(V1) or/v2/docs(V2). - V1 plugins silently don't work in V2. Port them via the V2 plugin migration guide.
- LSP diagnostics disappeared after upgrading to V2. Expected — V2 doesn't run language servers. Put lint/typecheck commands in
AGENTS.md. CLAUDE.mdignored in V2. Move it toAGENTS.md.- Model not in the list.
opencode models --refresh(V1), or add it explicitly under the provider'smodelsmap. Check the exactprovider/modelID. - Ollama shows no models. Ensure
/api/tagsand/api/showare reachable at thebaseURL-derived path and that the model reports thecompletioncapability (embedding models are hidden). - Context fills quickly. Disable unused MCP servers, enable compaction, use
exploresubagents for searches. - Large monorepos are slow / disk-hungry. Snapshots use an internal git repo; tune
watcher.ignoreor disable snapshots (you lose/undo). - Agent did something you didn't expect. Default permissions are allow-all — configure
askfor shell and edits. - Shared service confusion (V2).
opencode --standalonefor an isolated run;opencode service set disabled trueto stop using it by default. - Inspecting effective config:
opencode debug config(V1);opencode debug paths(V2). - Resource usage: Community reports note RAM use above 1GB; release velocity is high, so pin versions in CI.
17. Cheat sheet¶
# install / update
curl -fsSL https://opencode.ai/v2/install | bash
opencode upgrade
opencode --version
# start
opencode # TUI in cwd
opencode ~/code/project # TUI in another dir
opencode mini # minimal UI (V2)
opencode -c # continue last session
opencode -m anthropic/claude-sonnet-5-5 --agent plan
# headless
opencode run "prompt"
opencode run --format json -f file.txt "prompt"
# providers / models
opencode auth login # V1
opencode models [provider]
# agents / mcp
opencode agent create | list
opencode mcp add | list | auth <n> | logout <n> | debug <n>
# server
opencode serve # V1 headless API
opencode attach <url>
opencode pair # V2 web UI
opencode --standalone # V2 private server
# sessions
opencode session list
opencode export <id> --sanitize
opencode import <file|share-url>
opencode stats --days 7
TUI: Tab = switch agent @ = file/subagent /init /connect /models
/undo /redo /share
18. Sources¶
- OpenCode docs (V1)
- OpenCode V2 docs — Intro
- OpenCode V2 — Migrate from V1
- OpenCode V2 — Config
- OpenCode V2 — Providers
- OpenCode V2 — CLI
- OpenCode V1 — Config
- OpenCode V1 — Agents
- OpenCode V1 — CLI
- OpenCode V1 — MCP servers
- GitHub — anomalyco/opencode
- AI Engineer — OpenCode organisation profile
- Remio — OpenCode on GitHub Trending
- Olostep — OpenCode vs Claude Code
- Never Code Alone — OpenCode overview
- models.dev