OpenCode (sst/opencode)
is a terminal AI coding agent. It talks to this server's
/v1/chat/completions endpoint directly via the Vercel AI SDK
(@ai-sdk/openai-compatible). No proxy, no LiteLLM, no translation
layer.
There are two repos with confusingly similar names. Use the first one.
sst/opencode(this doc), actively maintained by the SST team. Latest is v1.14.x (May 2026). Docs at opencode.ai. npm package:opencode-ai. Yes, the npm name reuses the older fork's slug; the GitHub repo is what tells you which project you're on.opencode-ai/opencode(the older Go-based fork acquired by Charm) , not what this doc covers. If you cloned that repo, the config schema below will not match.
If you don't specifically want OpenCode, the easier path is one of these clients, all of which work with this server out of the box:
- Claude Code: see
CLAUDE_CODE.md. Native/v1/messages, no setup beyond a base URL. - Cline, Cursor, Continue, KiloCode: point the OpenAI-compatible base
URL at
http://127.0.0.1:5001/v1and pick any model name. - Codex CLI: see
CODEX.md. Slightly fiddlier (Responses API, role aliasing). - Qwen Code: see
QWEN_CLI.md.
Pick one. All resolve to the same binary.
# Windows: Scoop is the cleanest path, handles PATH automatically
scoop install extras/opencode
# Or npm (any platform with Node 20+)
npm install -g opencode-ai@latest
# Or Chocolatey
choco install opencodeThe curl -fsSL https://opencode.ai/install | bash one-liner is
macOS/Linux only; on Windows use one of the above. If a package
manager ships an older version, npm install -g opencode-ai@latest
forces the current release. Confirm with opencode --version.
Pick any snapshot in the launcher (the default is start_speed on
port 5001), or run headless:
start.bat --headless --snapshot start_speedWait until the log shows Application startup complete. The
single-GPU snapshots all listen on port 5001. Only start_pp2_160k
uses port 5002.
Verify the server's served-model-name with:
curl http://127.0.0.1:5001/v1/modelsThe patched wheel uses a wildcard served-model-name, so any string
works as the model id in opencode.json. The shipped snapshots
declare qwen3.6-27b-autoround (or qwen3.6-27b-nvfp4 on the
Blackwell NVFP4 snapshot) as the canonical id, but "any" also
works.
OpenCode reads config from one of:
- Project root:
./opencode.json(per-repo override). - Global:
%USERPROFILE%\.config\opencode\opencode.jsonon Windows,~/.config/opencode/opencode.jsonon macOS/Linux.
If the global directory does not exist, run opencode once to let it
create the parent dirs, then drop this file in:
{
"$schema": "https://opencode.ai/config.json",
"provider": {
"vllm-local": {
"npm": "@ai-sdk/openai-compatible",
"name": "Local vLLM",
"options": {
"baseURL": "http://127.0.0.1:5001/v1",
"apiKey": "sk-no-key-required"
},
"models": {
"qwen3.6-27b-autoround": {
"name": "Qwen3.6 27B (local vLLM)",
"limit": {
"context": 90000,
"output": 8192
}
}
}
}
},
"model": "vllm-local/qwen3.6-27b-autoround"
}A few things that bite people:
baseURLmust end in/v1. Without the path, the AI SDK builds wrong URLs and every request 404s.- The model key under
modelsmust match whatGET /v1/modelsreturns (or you can use"any"since the wildcard accepts any string). A mismatch fails silently rather than logging a useful error. apiKeycannot be empty. vLLM does not validate it, but the SDK requires the field non-empty. Any string works (sk-no-key-required,none,dummy, etc.). You can also use"$ENV_VAR"to read from the environment.limit.contextshould match your snapshot's--max-model-len. On the Ampere/Ada zip:start_72tps32000,start_speed90000,start_127k/ Unsloth tunes 127000,start_pp2_160k160000,start_gpu0_50k50000. On the Blackwell zip:rtx5090_nvfp4200000 (NVFP4, default and sole 5090 text path since v1.3.7) andrtx5090_nvfp4_vision180000 (NVFP4, image and video input, experimental, port 5004).
@ai-sdk/openai-compatible is the right adapter here because the
shipped snapshots serve /v1/chat/completions. The other adapter,
@ai-sdk/openai, is for the Responses API (/v1/responses) and is
what Codex CLI and OpenCode Zen's Codex models route through. The
bundled wheel implements both endpoints, but for OpenCode the
chat-completions path is simpler and avoids the developer-role
issues described in CODEX.md.
From any project directory:
opencodeThe default model from opencode.json should be selected. If not,
press / to open the picker and pick vllm-local/qwen3.6-27b-autoround,
or run /model vllm-local/qwen3.6-27b-autoround to pin it for the
session.
Every snapshot ships the tool-calling fix baked in:
- vLLM PR #35687:
treats
<tool_call>as an implicit</think>. - vLLM PR #40861: streaming-path fixes for split tags, dropped parameters, multi-call drops under speculative decoding, and structural delimiters appearing as literal text inside parameter values.
qwen3.5-enhanced.jinjachat template undertemplates/.--tool-call-parser=qwen3_coderand--reasoning-parser=qwen3.
So OpenCode's read / edit / shell tool calls round-trip cleanly
without per-snapshot tweaking. Reports of OpenCode tool calls
breaking against local LLMs are usually Ollama-side parsing bugs
(Ollama serialises tool calls as plain text under some chat
templates); none of that applies here because vLLM hands back
proper structured tool_calls JSON.
OpenCode reads AGENTS.md for persistent, project-specific
instructions. It also falls back to CLAUDE.md if no AGENTS.md
exists, which is handy if you already wrote rules for Claude Code.
Two scopes:
- Project-local (recommended): drop an
AGENTS.mdin your project root. Only applies when OpenCode is run from that directory or below. - Global:
%USERPROFILE%\.config\opencode\AGENTS.mdapplies to every project on the machine.
To bootstrap one, run /init inside OpenCode. It scans the repo and
either creates a starter file or improves the existing one in place
(it does not overwrite).
Qwen3.6 sometimes emits a single backslash inside JSON tool-call
arguments (C:\Users\... instead of C:\\Users\\...), which makes
the call fail to parse. This is a model-side issue, not OpenCode-
or Windows-specific (it also reproduces on Linux vLLM and llama.cpp),
but Windows users hit it more because their paths are full of
backslashes.
The cheap fix is a one-liner in AGENTS.md:
On Windows, always use Windows-style paths (C:\path\to\file) in tool
calls. When a path appears inside a JSON argument, escape backslashes
as needed (C:\\path\\to\\file).
Once the model knows the target, it escapes correctly. Reported and confirmed by a Reddit user running OpenCode against this server.
- "model not found", the model key in
opencode.jsondoesn't match what/v1/modelsreturns. Re-runcurl http://127.0.0.1:5001/v1/modelsand copy theidfield verbatim, or use"any". - Every request 404s,
baseURLis missing the/v1path. /connectasks for an API key, vLLM doesn't validate it, but the SDK requires the field non-empty. Any string works.- Empty response, finish_reason length, the thinking block ate
max_tokens. Qwen3.6 is a thinking model; with the budget under about 1500 the entire allowance can go into<think>. OpenCode defaults are fine, but if you script your own calls, setmax_tokensto 2000+ for short Q&A. - Tool calls fail or stop mid-task, almost always a server-side
issue rather than OpenCode. Run
python windows_tools\check_coherence.py --port 5001to confirm the server itself is healthy. If coherence passes but tool calls still fail, capture the request/response and open an issue. - First request after boot takes longer. vLLM compiles attention kernels lazily on first request. Subsequent requests are fast.
- Wrong model selected, pin per-session with
/model vllm-local/qwen3.6-27b-autoround, or set the top-level"model"field inopencode.jsonas shown above.
CLAUDE_CODE.md, the easiest integration overall.CODEX.md, Responses-API client notes.QWEN_CLI.md, Qwen Code (Alibaba's fork of gemini-cli) setup.PI.md, Pi coding agent setup.COHERENCE.md, the validator to run if OpenCode sees garbage output.- OpenCode docs: Config, Rules, and Providers.