OpenCode: technical tutorial
OpenCode: ReviewInstall & set upNewsTechnical tutorial
As of September 2026, compiled from our own notes and news archive; text machine-generated and editorially checked. Check versions and commands in the official documentation.
This tutorial covers setting up OpenCode for serious work: configuration layers, custom and local model providers (including via your own router), custom agents, pattern-based permissions, MCP servers and unattended use via opencode run, opencode serve and GitHub Actions. Keys and commands have been checked against the official documentation (as of September 2026).
Configuration: files and order
OpenCode reads opencode.json or opencode.jsonc (JSON with comments). The layers are merged, not replaced; a later layer wins for the same field:
- Remote configuration (
.well-known/opencode, for organisations). - Global:
~/.config/opencode/opencode.json. - A custom path via the environment variable
OPENCODE_CONFIG. - Project:
opencode.jsonin the root. - Inline configuration.
- Managed configuration files and, on macOS, managed preferences (the highest priority).
Always put the schema line at the top for autocomplete and validation in your editor. Two types of variables keep secrets out of your files:
{env:NAAM}: the value of an environment variable.{file:pad/naar/bestand}: the contents of a file.
{
"$schema": "https://opencode.ai/config.json",
"model": "anthropic/claude-opus-5-5",
"small_model": "anthropic/claude-haiku-4-5",
"instructions": ["./docs/conventies.md", "packages/*/AGENTS.md"],
"share": "disabled",
"autoupdate": "notify"
}
- Model IDs have the form
provider/model; you can see the exact IDs per provider in OpenCode's model picker. small_modelis used for light tasks, such as session titles. A cheap model is enough here.instructionsadds extra instruction files alongsideAGENTS.md; paths and globs are allowed.share: "disabled"prevents sessions from being shared. Sensible for company code.
Custom, local and router providers
You add any service with an OpenAI-compatible API via the @ai-sdk/openai-compatible package. First the key: /connect → Other → a custom ID → paste the key. Then in the configuration:
{
"provider": {
"mijnrouter": {
"npm": "@ai-sdk/openai-compatible",
"name": "Eigen LLM-router",
"options": { "baseURL": "https://router.example.com/v1" },
"models": {
"code": { "name": "Router: code" },
"goedkoop": { "name": "Router: goedkoop" }
}
}
},
"model": "mijnrouter/code",
"small_model": "mijnrouter/goedkoop"
}
This way, all OpenCode traffic goes through a single router, which manages the providers' keys itself and can track costs per client. The model names are then aliases that the router translates.
Locally with Ollama:
{
"provider": {
"ollama": {
"npm": "@ai-sdk/openai-compatible",
"name": "Ollama (lokaal)",
"options": { "baseURL": "http://localhost:11434/v1" },
"models": { "qwen3-coder:30b": { "name": "Qwen3 Coder 30B" } }
}
}
}
For LM Studio, use http://127.0.0.1:1234/v1 as the baseURL. You must list models manually for both. Small local models often handle tool calls poorly; test a model first with a small task in Plan mode.
Agents
OpenCode has two main agents, which you switch between with Tab:
- Build: all tools.
- Plan: analysis without code changes.
There are also subagents that you invoke with @:
- General: multi-step tasks, with full access.
- Explore: fast, read-only search through the codebase.
- Scout: read-only research into dependencies and documentation.
You define custom agents as a markdown file in .opencode/agents/ (per project) or ~/.config/opencode/agents/ (global). An example, .opencode/agents/reviewer.md:
---
description: Beoordeelt code op beveiliging en onderhoudbaarheid
mode: subagent
model: anthropic/claude-opus-5-5
temperature: 0.1
permission:
edit: deny
bash: deny
---
Je bent een strenge code-reviewer. Zoek naar injectie, lekken van
geheimen en ontbrekende foutafhandeling. Noem per bevinding het
bestand en de regel. Wijzig zelf niets.
modecan beprimary(via Tab),subagent(via@) orall.- The same can be done in
opencode.jsonunder theagentkey. - With
opencode agent create, you can create one interactively.
Pattern-based permissions
Every tool has a permission with the value allow, ask or deny. Known keys are read, edit, glob, grep, bash, task, skill, webfetch, websearch, external_directory and doom_loop. Most default to allow. Exceptions: external_directory (working outside your project) and doom_loop (an agent stuck in a loop) are set to ask, and read denies .env files by default.
For bash and other tools, you can choose per pattern. The last matching rule wins, so put the general rule at the top:
{
"permission": {
"*": "ask",
"read": "allow",
"grep": "allow",
"bash": {
"*": "ask",
"git *": "allow",
"npm test": "allow",
"rm *": "deny",
"git push *": "deny"
},
"webfetch": "ask"
}
}
* stands for any characters, ? for exactly one character.
MCP servers
In opencode.json under mcp. A local server; note that command is an array:
{
"mcp": {
"database": {
"type": "local",
"command": ["npx", "-y", "mijn-db-mcp"],
"environment": { "DATABASE_URL": "{env:DATABASE_URL}" },
"enabled": true
}
}
}
A remote server:
{
"mcp": {
"docs": {
"type": "remote",
"url": "https://docs.example.com/mcp",
"headers": { "Authorization": "Bearer {env:DOCS_TOKEN}" },
"enabled": true
}
}
}
OAuth is automatically detected for external servers. Set "oauth": false if you don't want that, for example because you're working with a fixed header. With "enabled": false you temporarily disable a server without removing the configuration. Every server adds tools to the context, so only enable what you need for the project.
Unattended: run, serve and GitHub
opencode run executes a single command without an interface:
opencode run --agent plan -m anthropic/claude-opus-5-5 \
"Beschrijf de architectuur van dit project in vijf punten"
opencode run --format json "Draai de tests en repareer wat faalt" > run.jsonl
--format jsonoutputs the raw events as JSON.- With
-cor--continueyou continue with the previous session, with-s <id>with a specific session.
opencode serve starts a headless HTTP server, so that you can control OpenCode from other programs. Always set a password:
OPENCODE_SERVER_PASSWORD="sterk-wachtwoord" opencode serve
Never expose that server to a network without a password: anyone who can access it can run commands on your machine.
GitHub Actions: opencode github install sets up a workflow in your repository. In the action, opencode github run runs the agent, for example in response to a comment in an issue or pull request. Set the keys as repository secrets and do not give the agent broader permissions than necessary in CI.
Troubleshooting
- "Provider not found": the ID in
model(provider/model) does not match the key underprovider, or you have not yet linked a credential with/connect. - Local model does not call tools: the model has poor support for function calling; choose a model that is trained for it, or use it only in Plan.
- A rule in
permissionseems to be ignored: a later, more general rule wins. Put the specific rules at the bottom. - MCP server does not start:
commandis a string instead of an array, or a variable after{env:...}is missing. - Instructions are missing: check whether
AGENTS.mdhas been committed and whether the paths ininstructionsare correct, as seen from the project root.
Documentation: opencode.ai/docs.