Skip to content

Providers and models

The unit that travels is the workflow, not the runtime. The same YAML can run a step on any of three kinds of provider, all declared in registries.json and resolved by internal/catalog:

Kind What it is Examples from the registry
http An OpenAI-compatible chat endpoint. The credential is an env var name (apiKeyEnv), never a value. openrouter, anthropic, groq, ollama-http, lmstudio, vllm
cli A local agent CLI driven one prompt at a time. claude-cli, codex-cli, copilot-cli, opencode
acp A local agent spoken to over the Agent Client Protocol. devin, opencode-acp, codex-acp

The provider registry page lists every entry, generated from the file. A step picks one with provider: and optionally a model:.

  • WFX_DEFAULT_PROVIDER: the provider for every step that names none. wfx doctor prints it on its first line and flags it when it is not ready.
  • WFX_DEFAULT_CLASSIFIER: the classifier for decide: steps that name none, and for proposal reviews.

Both are server configuration, and ScrubServerEnv removes them from the environment a run sees. See Env store and secrets.

agentadapter/ makes a local agent CLI usable as a model. There are four presets (ACPPresets):

Adapter Command Mode Provider
devin devin acp (model via --model) bypass devin
opencode opencode acp (model over the protocol) build opencode-acp
claude npx -y @agentclientprotocol/claude-agent-acp (uses claude’s own login) default add an entry with "kind": "acp", "preset": "claude"
codex npx -y @zed-industries/codex-acp full-access codex-acp

A fresh session every turn. Every ACP provider opens a new session for each turn, in the same process. Each turn’s prompt is already the complete request, so a kept session only accumulates copies of it and every turn pays for all the earlier ones again. A registry entry can opt out with "keepSession": true; do that only for an agent you have measured to need it.

Terminal window
wfx adapters # each adapter, whether it is installed, and how to install it
wfx models opencode-acp # the models the agent offers, asked live
wfx models opencode-acp --free # only the free ones

The platform’s own loop executes the tools, because that is the only place a step’s tool allowlist and guardrails apply. The adapter therefore refuses the agent’s own native tools by default. When a turn ends empty after refusals, the adapter hands the platform the equivalent call instead (read, grep, glob, bash), but only for tools the step offers. An edit, a fetch or a sub-task has no safe equivalent and stays refused.

The default opencode entry is a cli provider: one fresh opencode run --standalone -m <model> process per turn, with the prompt on stdin. --standalone gives each turn a private opencode server instead of opencode’s shared background service, which sits on one fixed port for the whole machine; with it, two users or two steps on one box no longer collide.

A provider that cannot be reached does not have to fail the step. A registry entry can name providers to try next, in order:

"openrouter": {
"kind": "http",
"apiKeyEnv": "OPENROUTER_API_KEY",
"fallback": ["opencode"]
}

The server can also name a list that applies to every step, after the step’s provider and that provider’s own fallback: model.fallback in config.yaml, or WFX_FALLBACK_PROVIDERS (comma separated). That is the one place an operator fixes a broken provider for every workflow at once.

A step falls back only when nothing was answered: its provider does not resolve (key unset, binary missing) or its first call fails before the model has said anything. A step that got any answer is never re-run elsewhere, because its working directory may already have changed.

An http entry names its key by apiKeyEnv, never by value. The engine looks that name up in the step’s environment, which includes the env store, and then in the server process’s own environment. The env store is the recommended place:

Terminal window
wfx env set OPENROUTER_API_KEY # read without echoing, stored encrypted
wfx doctor # says which providers are ready and which key is missing

--free does not guess. A model counts as free only if its id ends in -free (opencode Zen) or :free (OpenRouter). The default opencode cli entry runs opencode/ling-3.1-flash-free; opencode-acp is no longer the default because opencode now refuses free models over ACP. opencode-acp used opencode/space-bunny-free, which needs no key. Its registry description records why: it was the fastest of the free models that scored 7 out of 7 on a commit-classification check on 2026-09-27.