Start with the automated checks:
oc-doctor
OPENCODE_SYNC_VERBOSE=1 sync-modelscurl -fsSL https://opencode.ai/install | bash
exec "$SHELL" -l
opencode --versionThe setup installer does not silently install or downgrade OpenCode.
Re-run the installer, then reload the active shell:
./scripts/install.sh
exec "$SHELL" -lThe installer updates ~/.zshrc for Zsh and ~/.bashrc otherwise. It replaces only the block between the opencode-local-setup markers.
Confirm the server and model are loaded:
curl -fsS http://127.0.0.1:1234/v1/models | jqCommon endpoints:
| Server | URL |
|---|---|
| LM Studio | http://127.0.0.1:1234/v1 |
| Ollama | http://127.0.0.1:11434/v1 |
| vLLM | http://127.0.0.1:8000/v1 |
| llama.cpp | http://127.0.0.1:8080/v1 |
Increase the timeout only for genuinely slow links:
OPENCODE_SYNC_TIMEOUT_MS=10000 sync-modelsCheck the exact config path and provider IDs:
echo "${OPENCODE_CONFIG:-$HOME/.config/opencode/opencode.json}"
opencode models
opencode models --refreshA project-level opencode.json can override global settings. A custom path set with OPENCODE_CONFIG is loaded in OpenCode's documented precedence order.
JSONC is supported. The synchronizer accepts line comments, block comments, and trailing commas. After writing, it normalizes the file to strict JSON. Invalid syntax still fails without changing the original file.
Current model metadata uses tool_call:
{
"my-model": {
"name": "My Model",
"tool_call": true
}
}Run sync-models to migrate discovered models automatically. Agent-level tool policy is separate and belongs under current OpenCode agent.permission configuration.
A model limit must include both context and output:
{
"limit": {
"context": 131072,
"output": 8192
}
}The synchronizer omits incomplete limits rather than writing invalid config.
For built-in providers:
opencode auth login
opencode auth listFor a custom server, verify the env variable is available in the same shell:
export REMOTE_API_KEY='...'
REMOTE_API_KEY="$REMOTE_API_KEY" \
LOCAL_API_BASE=http://100.100.100.100:8000/v1 \
OPENCODE_PROVIDER_ID=gpu-box \
node scripts/sync-provider.mjsNever place a raw API key in a committed config. oc-doctor reports literal keys and Authorization headers.
Discovery is opt-in:
export OPENCODE_TAILSCALE_DISCOVERY=1
export OPENCODE_TAILSCALE_PORTS=1234,8000,8080,11434
tailscale status
OPENCODE_SYNC_VERBOSE=1 sync-modelsOnly online peers are considered. Explicitly configured remote providers are more predictable and do not require discovery.
The wrapper only refreshes before launch by default. Reduce the custom endpoint timeout or disable an offline provider:
export OPENCODE_SYNC_TIMEOUT_MS=1000Remove OPENCODE_SYNC_AFTER_EXIT=1 and OPENCODE_TAILSCALE_DISCOVERY=1 unless needed. The default discovery state is off.
By default, stale entries are pruned. To merge without pruning:
OPENCODE_SYNC_PRUNE=0 sync-modelsThe writer uses a temporary file and atomic rename, so a failed write should leave the original intact. Before major manual edits:
cp ~/.config/opencode/opencode.json ~/.config/opencode/opencode.json.backupThen validate:
oc-doctor
opencode models