docs
Configuration
One config file, one precedence order, one selection knob.
dex doctor prints every resolved value with where it came
from — when anything feels off, that is the ground truth.
Precedence
| Layer (wins first) | Example |
|---|---|
| CLI flags | --model, --base-url |
| Environment variables | DEX_MODEL, OPENCODE_API_KEY, DEX_HEADERS |
| Config file | $XDG_CONFIG_HOME/dex/config.yaml (or $DEX_CONFIG) |
Nothing hardcodes a model: if no layer selects one, dex refuses to start
and prints a setup guide instead of guessing. The only built-in default is
the provider landing URL for a bare model id
(model: m with no provider/ prefix) — opencode's
gateway, so a bare id has somewhere to ride.
The selection knob: model:
model: names provider and model:
<provider>/<model>. An <endpoint>/<model>
forces an endpoint; a bare provider name just switches provider. Write-back
keeps that form — a /model or /provider pick
updates model: in the file, so the switch becomes the default
for later runs. Session state still re-applies the exact provider/model on
/resume.
A file naming only a provider also works (model: anthropic
plus ANTHROPIC_API_KEY) — but a bare provider pick names no
model, so export the provider's key and pass an id:
DEX_MODEL=opencode/<model-id> dex.
Minimal config
providers:
opencode:
api_key: sk-... # the deposit place for this provider's key
model: zen/gpt-5.6-luna # endpoint-or-provider / model Catalog, endpoints, and wire protocol
Endpoints, model lists, pricing, and context windows come from the
models.dev
catalog. A fresh daemon bootstraps it in the background;
dex update --models is a manual refresh. After the cache
exists, a bare /model <id> moves base_url
to the endpoint serving that id.
The wire protocol follows the same way: a first /responses
failure falls back to chat-completions once and is remembered (per
endpoint+model in learned-apis.json), so per-model knowledge
never needs configuring. Escape hatches, in order of narrowing scope:
-
DEX_MODEL_APIS="id=openai-completions,..."seeds a model's protocol (a fullendpoint/idkey beats a bare id). -
providers.<name>.api:pins the protocol for one provider entry. - Do not set a global
api:to fix one model — it pins every model and disables the automatic fallback. -
--base-urlpins the endpoint; routing prefixes become naming only and are stripped.
Other OpenAI-compatible providers
Any models.dev provider with an OpenAI-style endpoint works without dedicated integration:
model: zai/glm-5.3-flash
providers:
zai:
api_key: zsk-... # or export ZHIPU_API_KEY
# base_url: ... # optional; defaults to the catalog endpoint
# api: openai-completions # optional protocol pin; learned otherwise
# headers: {X-Custom: ...} # optional; sent only to this provider
Anthropic is built in as its own provider —
model: anthropic/claude-sonnet-4-5 (or
--model anthropic) with ANTHROPIC_API_KEY. It
speaks the native Messages wire (anthropic-messages):
x-api-key auth, anthropic-version header,
block-shaped tool calls, and thinking blocks replayed with their
signatures. Any other provider entry can pin that wire too:
api: anthropic-messages.
Headers
Extra provider headers merge per-key in this order (later wins):
provider-scoped headers: beats a global file
headers:, env ANTHROPIC_CUSTOM_HEADERS <
OPENAI_HEADERS < DEX_HEADERS, and
--header beats all env vars. Syntax is a JSON object or
Name: Value / Name=Value pairs,
comma/newline-separated. authorization can't be overridden.
Deprecated keys
Deprecated file keys are still honored with a one-time warning — move them to the canonical spots:
| Deprecated | Replacement |
|---|---|
active_provider: / provider: | put the provider in model: as provider/model |
top-level base_url: | base_url: under the provider's entry in providers: |
top-level api: | api: under the provider's entry in providers: |
top-level headers: / http_headers: | headers: under the provider's entry (provider-scoped) or DEX_HEADERS (global) |
DEX_PROVIDER env | not supported — model selection is DEX_MODEL=<provider>/<model> |
OPENAI_HEADERS / ANTHROPIC_CUSTOM_HEADERS env | DEX_HEADERS (same syntax) |
Valid keys & diagnostics
The file accepts: model, providers,
context_window, thinking_effort,
system_prompt, system_prompt_file,
mcp_servers, agent_wake,
cache_warming, extensions, harness,
harness_profile, harness_profiles,
jev (+ the deprecated ones above). Unknown keys are called out by name
(dex: unknown config key(s) …); other keys are preserved
untouched. dex doctor shows every resolved value with its
origin, and DEX_LOG=debug covers provider requests/responses.