Model routing
The models.* block controls which OpenCode model each bundled agent should use. It is optional. If you omit it, or if a selector cannot resolve, OpenCode can continue using its current/default model.
Model routing has three layers:
models.providersdefine named model pools.models.handlersroute workload types to provider pools or direct model IDs.models.agentsoptionally overrides individual registered agents.
Prefer providers and handlers first. Per-agent overrides are powerful, but most users do not need them.
Selector syntax
A selector is a string or an ordered array of strings:
| Form | Meaning |
|---|---|
"<provider/model>" |
Concrete OpenCode model ID. |
"@provider/<name>" |
Reference to models.providers.<name>. |
"@handler/<name>" |
Reference to models.handlers.<name>. |
Arrays are tried in order. Under the default selection strategy, the first currently available candidate wins.
Providers
Provider pools give names to model candidates:
{
"models": {
"providers": {
"main": ["<provider/model-strong>"],
"fast": ["<provider/model-fast>"],
"review": ["<provider/model-review>"],
"fallback": ["<provider/model-backup-1>", "<provider/model-backup-2>"]
}
}
}
Use concrete IDs that OpenCode actually exposes in your environment. The names main, fast, review, and fallback are examples; pool names are yours.
Handlers
Handlers route workload categories used by bundled agents:
{
"models": {
"handlers": {
"primary": "@provider/main",
"developer": "@provider/main",
"coordinator": "@provider/main",
"code_analyzer": "@provider/review",
"scout": "@provider/fast"
}
}
}
Common handler names:
| Handler | Typical users |
|---|---|
primary |
Selectable primary agents, Configuru, Retitler. |
primary_beta |
/beta second opinion. |
developer |
Implementation-focused project developer. |
coordinator |
Orchestration, codebase coordination, code review coordination, council coordination. |
code_analyzer |
Codebase analysis, pattern finding, review analysis. |
small_document_analyzer |
Short documentation Q&A. |
big_document_analyzer |
Long-form documentation work. |
scout |
Web, repository, locator, and discovery agents. |
See Agents for the user-facing agent inventory.
Beta as a separate perspective
/beta is useful only when it resolves to a different concrete model than the normal primary route. Configure that through primary_beta:
{
"models": {
"providers": {
"main": ["<provider/model-primary>"],
"second_opinion": ["<provider/model-alternative>"]
},
"handlers": {
"primary": "@provider/main",
"primary_beta": "@provider/second_opinion"
}
}
}
If both routes resolve to the same model, /beta is not registered because it would not provide an independent review.
Per-agent overrides
Use models.agents only when a specific agent must be pinned differently from its workload handler:
{
"models": {
"agents": {
"codebase/analyzer": "@provider/review",
"primary/alpha": "<provider/model-primary>"
}
}
}
Prefer stable agent keys such as primary/alpha, squad/beta, or codebase/analyzer over display-name aliases.
Fallback and selection
models.fallback is a final safety net when a selector cannot resolve:
{
"models": {
"fallback": ["@provider/main", "@provider/fallback"]
}
}
models.selection controls availability behavior:
{
"models": {
"selection": {
"availability": "opencode",
"strategy": "first_available",
"cacheTtlMs": 1800000,
"refreshTimeoutMs": 3000
}
}
}
The defaults are right for most users. Change them only when you need deterministic configured order, custom availability behavior, or different cache timing.