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 variablesDEX_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 full endpoint/id key 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-url pins 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:

DeprecatedReplacement
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 envnot supported — model selection is DEX_MODEL=<provider>/<model>
OPENAI_HEADERS / ANTHROPIC_CUSTOM_HEADERS envDEX_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.