6.7 KiB
OpenCode CLI
Source of truth: OpenCode v2 docs for config keys; the overview for the gateway endpoint and context size. If this page disagrees with them, they win. The v1 config is deprecated but kept for installs that haven't migrated.
OpenCode is anomalyco/opencode (renamed from sst/opencode). Don't confuse it with the unrelated opencode-ai/opencode Go TUI. It speaks plain OpenAI Chat Completions, so it talks to the gateway like any other OpenAI-compatible client.
Install
curl -fsSL https://opencode.ai/v2/install | bash
Homebrew, npm, bun, pnpm, yarn and AUR also work. See the v2 docs.
Config (v2)
opencode.json or opencode.jsonc, in the project root (or .opencode/) or globally at ~/.config/opencode/opencode.json. OpenCode searches upward from the current directory and merges, closest file wins.
{
"$schema": "https://opencode.ai/config.json",
"providers": {
"omniroute": {
"name": "OmniRoute",
"package": "aisdk:@ai-sdk/openai-compatible",
"settings": {
"baseURL": "https://<YOUR-OMNIROUTE-PROXY>/v1",
"apiKey": "<token>"
},
"models": {
"qwen3.8-27b": {
"modelID": "qwen3.8-27b-local//models/Qwen3.8-27B-UD-Q4_K_XL.gguf",
"name": "Qwen3.8-27B",
"capabilities": { "tools": true, "input": ["text"], "output": ["text"] },
"compatibility": { "reasoningField": "reasoning_content" },
"limit": { "context": 260000, "output": 32000 },
"cost": { "input": 0.4, "output": 3 },
"body": {
"temperature": 1,
"top_p": 0.95,
"top_k": 20,
"min_p": 0,
"presence_penalty": 0,
"chat_template_kwargs": { "reasoning_effort": "xhigh" }
},
"variants": [
{ "id": "medium", "body": { "chat_template_kwargs": { "reasoning_effort": "medium" } } },
{ "id": "fast", "body": { "chat_template_kwargs": { "reasoning_effort": "low" } } },
{
"id": "instruct",
"body": {
"temperature": 0.7,
"top_p": 0.8,
"presence_penalty": 1.5,
"chat_template_kwargs": { "enable_thinking": false }
}
}
]
}
}
}
}
}
What each part does
| Key | Purpose |
|---|---|
providers |
Plural in v2 (v1: provider). The key (omniroute) is the prefix in model references. |
package |
The adapter for the API shape. This stack uses an OpenAI-compatible one. |
settings.baseURL |
The gateway URL, up to and including /v1. |
settings.apiKey |
The gateway API key issued to OpenCode (gateway → API keys). The v2 docs' own examples use an env list instead, to keep the key out of the file. |
models.<key> |
The short name you select. modelID is the id the gateway exposes, which the key doesn't have to match. |
capabilities |
Declares tool calling and input/output modalities. |
compatibility.reasoningField |
Where the backend returns reasoning text. llama.cpp uses reasoning_content. |
limit |
OpenCode's own context bookkeeping. The server doesn't read it. See overview for the number to use. |
body |
Extra request fields, sent on every call. Sampling values and chat_template_kwargs go here. |
variants |
Named overrides on top of body. |
Selecting a model and variant
Format: provider/model#variant. The provider ends at the first /.
opencode run --model omniroute/qwen3.8-27b # default: xhigh reasoning
opencode run --model omniroute/qwen3.8-27b#medium
opencode run --model omniroute/qwen3.8-27b#fast # low reasoning effort
opencode run --model omniroute/qwen3.8-27b#instruct # thinking off, instruct sampling
Notes
- Unverified keys: the v2 docs show
"package": "@opencode/ai/providers/openai-compatible"for custom providers, while this config uses theaisdk:@ai-sdk/openai-compatibleform. The docs pages I could read don't confirm that prefix. If OpenCode rejects the provider, switchpackageto the documented value. - Variants: the v2 docs' own variant example puts settings under
settings. This config usesbody, which the models page lists as valid for provider-specific request fields. limit.context: overview explains how per-slot context is derived. The example above uses a larger value than a plain per-slot division gives.
OpenCode-specific risks
On top of the shared Qwen3.8-27B tool-calling risk (see overview):
- Relies on the backend's
--jinjaflag (architecture → llama-server). Without it, OpenCode's unconditional tool-call scaffolding gets a 500. - anomalyco/opencode#20669 (closed as "not planned", so a live, unfixed risk): OpenCode's
bashtool crashes if the model omits the optionaldescriptionfield on a tool call. Some local backends returnfinish_reason: tool_callswith an empty array, which can hang the agent loop instead of stopping it. - Reasoning control goes through
chat_template_kwargsinbody, not OpenCode's nativereasoningEffort. The native key has no effect against llama.cpp.
V1 config (deprecated)
Use this only on OpenCode v1. It is no longer maintained here. Differences from v2: provider (singular), npm instead of package, options instead of settings, and a flat reasoning / interleaved block instead of capabilities / compatibility, and no variants or body in this config.
{
"$schema": "https://opencode.ai/config.json",
"model": "omniroute/qwen3.8-27b-local//models/Qwen3.8-27B-UD-Q4_K_XL.gguf",
"provider": {
"omniroute": {
"npm": "@ai-sdk/openai-compatible",
"name": "OmniRoute",
"options": { "baseURL": "https://<YOUR-OMNIROUTE-PROXY>/v1" },
"models": {
"qwen3.8-27b-local//models/Qwen3.8-27B-UD-Q4_K_XL.gguf": {
"name": "Qwen3.8-27B",
"reasoning": true,
"interleaved": { "field": "reasoning_content" },
"limit": { "context": 131000, "output": 65536 },
"cost": { "input": 0.4, "output": 3.0, "cache": { "read": 0.04, "write": 0 } }
}
}
}
}
}
Select the model with omniroute/<model-key>. The v1 install script is curl -fsSL https://opencode.ai/install | bash.
Further reading
research/opencode-cli-setup.md (v1-era, base URL predates the gateway), research/opencode-auto-compact.md.