Every model provider lives at [providers.models.<type>.<alias>]. <type> is a canonical family slot (see the Catalog for every slot with its endpoint). <alias> is your operator-assigned instance name, pick any descriptive name (home, work, cn, gpt5, ...).
The smallest config that loads clean has four section headers: a provider entry, an agent that references it, and a risk profile the agent gates against. Configure them through the gateway, zerocode, or zeroclaw config set; the config reference has the full field index.
Almost every family also takes the shared fields from ModelProviderConfig:
api_key: credential for providers that use bearer or subscription-style API keys.uri: full endpoint override. Leave unset to use the family's endpoint resolver.model: model identifier sent to the provider.temperature: optional sampling temperature.timeout_secs: HTTP request timeout in seconds.max_tokens: optional response length cap.extra_headers: extra HTTP headers for custom gateways or auth bridges.fallback_models: alternate model IDs on the same provider alias.fallback: ordered list of other dotted provider aliases to try after this alias fails.wire_api,native_tools,provider_extra,think, andchat_template_kwargs: advanced protocol and request-body overrides.vision: override the provider's image-input (vision) capability. Leave unset to use the family's built-in default. Setfalsefor a text-only model served by a vision-capable family (for example, a text model behind llama.cpp) so image messages route to a configured[multimodal] vision_model_providerinstead of erroring; settrueto force it on.tls_ca_cert_path: absolute path to a PEM-encoded CA certificate for TLS connections to this provider (a per-provider trust override, distinct from the gateway TLSca_cert_path). Shell expansion such as~is not performed; leave unset to use the system trust store.
Family-specific entries add their own typed fields on top of these shared fields.
For most families, the URL is resolved in this order:
- Operator override:
urifield on the alias entry, if set. - Family endpoint: the family's
*Endpointenum supplies the URL (e.g.OpenAIEndpoint::Default->https://api.openai.com/v1). Multi-region families have anendpointfield on the alias entry that picks the variant (e.g.endpoint = "cn"for Moonshot). - Templated families: Azure takes typed inputs (
resource,deployment,api_version) and substitutes them into the family's URI template. Missing fields fail loud at runtime.
Bedrock is an exception: its endpoint hostname is constructed at request time from the signing region resolved through the AWS credential chain (AWS_REGION, AWS_DEFAULT_REGION, or the region from the active credential_process or IMDS profile). The uri alias field and the schema-level providers.models.bedrock.<alias>.region field have no effect in the current implementation.
Every slot, its default endpoint, and whether it runs locally is in the Catalog. There is one canonical key per vendor: no synonyms.
Supported credential input and storage forms:
- Inline
api_key = "..."in the alias entry (fine for dev, risky for checked-in configs). - 1Password references: set a secret field to
op://vault/item/field. ZeroClaw keeps the reference in config and resolves it at runtime withop read, so the 1Password CLI must be installed and signed in. - Config-level secrets store: encrypted at
~/.zeroclaw/secretsvia a local key file. - Generic env override:
ZEROCLAW_providers__models__<type>__<alias>__api_key=...setsproviders.models.<type>.<alias>.api_keyat startup. See Environment variables for the full grammar.
Schema-mirror env overrides win at startup. They replace the in-memory credential for that process without rewriting the stored inline, encrypted, or op:// value on disk.
zeroclaw quickstart writes credentials to the secrets store by default. Configs you commit should not contain inline keys. For ecosystem-default names you already export in your shell ($ANTHROPIC_API_KEY, $OPENROUTER_API_KEY, …), the env-vars reference shows the one-line bash expansions that point a schema-mirror name at the existing value.
Several providers accept OAuth or subscription-style tokens instead of raw API keys. Get the token from the vendor's own dashboard or CLI flow, then drop it into the alias entry the same way you would an API key:
- Anthropic / Claude: Console API keys and tokens generated by
claude setup-tokenfor Claude Max go inapi_keyon[providers.models.anthropic.<alias>]. In Quickstart, pickapi_keyorsetup_token; the saved provider entry is still the canonicalanthropicslot. - OpenAI Codex subscription: run
zeroclaw auth login --model-provider openai-codex(or import an existing Codex CLI login with--import ~/.codex/auth.json), then setrequires_openai_auth = trueand leaveapi_keyunset on[providers.models.openai.<alias>]; the runtime reads ZeroClaw's storedopenai-codexauth profile. - Gemini CLI:
[providers.models.gemini_cli.<alias>]shells out to thegeminiCLI; use the CLI's own auth flow. - Grok Build CLI:
[providers.models.grok_cli.<alias>]shells out through the documentedgrok agent stdioACP surface. The assembled prompt is JSON-RPC on stdin, never argv or a prompt file. Auth uses the CLI login cache by default. For API-key auth, exportXAI_API_KEYinto the daemon environment and explicitly addenv_passthrough = ["XAI_API_KEY"]to the alias; the typed aliasapi_keyremains unsupported. An existing absoluteworking_directoryis required and defines both the child cwd and ACP session boundary. The child environment is cleared before spawn, andenv_passthroughdefaults to empty. Other provider-ownedXAI_*names and allGROK_*names are rejected. ZeroClaw defaults to--sandbox strict,--permission-mode dontAsk, an empty built-in tool set, and fail-closed ACP permission responses.extra_argsis the explicit per-alias opt-in for relaxing those controls. The bypass flags--always-approve,--dangerously-skip-permissions,--yolo, and--permission-mode=bypassPermissionsmake the headless ACP client selectallow_once; other permission modes continue to selectreject_once. ACP transport/model/session/cwd flags plus positional and short arguments are reserved; unknown value-taking long options use--flag=value. Aliasvision = trueonly opts ZeroClaw into sending ACP image blocks; Grok still advertisespromptCapabilities.image = falsethrough 0.2.118 and does not reliably use the image content - leave unset for production; see ACP vision / image input. - Qwen / MiniMax: set
auth_mode = "o_auth"on the alias entry plus the relevantoauth_*fields (see env-vars → OAuth and CLI-path fields).
When ZeroClaw runs inside a container and a provider is on the host (e.g. Ollama), set uri to a host-reachable address. The generic env-override mechanism (ZEROCLAW_<dotted_path_with_double_underscores>=<value>) can set the same field at runtime without editing config:
{{#env-var container}}
The __ is the path separator; the example above sets providers.models.ollama.home.uri. See Environment variables for the full grammar.
Use vision when a provider family can serve both multimodal and text-only
models. The value belongs to the provider alias, so routing and fallback paths
resolve it together with that alias's endpoint, credentials, and model:
[providers.models.openai.vision]
model = "gpt-4o"
wire_api = "responses"
vision = true
[providers.models.llamacpp.text]
model = "qwen3-4b"
vision = falseLeaving vision unset preserves the provider family's built-in default. For
OpenAI Responses aliases, set vision = true for models that accept image
input; this opt-in keeps text-only Responses models from receiving image
payloads accidentally.
Setting vision = true is an explicit operator assertion that the selected
alias accepts image input. It changes image routing: ZeroClaw keeps image
attachments on that alias instead of treating it as text-only or routing them
to multimodal.vision_model_provider. Set it only for a tested provider and
model combination. For grok_cli, the same field only controls whether
ZeroClaw sends ACP image blocks; it does not rewrite Grok's
promptCapabilities.image advertise (still false through 0.2.118) and does
not make the CLI reliably describe the image. See
ACP vision / image input.
When [multimodal] vision_model_provider names a dotted provider alias, its
model is used automatically. An explicit [multimodal] vision_model takes
precedence over the alias model; if neither is set, the primary turn model is
used for backward compatibility.
Ollama defaults to the local endpoint, so a local alias only needs the model name:
[providers.models.ollama.local]
model = "llama3.1"Set uri when ZeroClaw is not running on the same host as Ollama:
[providers.models.ollama.host]
model = "llama3.1"
uri = "http://host.docker.internal:11434"Ollama-specific optional fields are num_ctx, num_predict, and temperature_override.
Azure OpenAI computes its endpoint from the typed Azure fields:
[providers.models.azure.work]
api_key = "op://platform/azure-openai/api-key"
model = "gpt-4o"
resource = "example-resource"
deployment = "gpt-4o-prod"
api_version = "2024-10-21"The resource, deployment, and api_version values live in this typed config, they are not read from Azure-specific environment variables. Use uri only when you need to override the computed endpoint completely.
Bedrock needs an alias with a model; endpoint region currently comes from the Bedrock auth environment/profile path:
[providers.models.bedrock.work]
model = "anthropic.claude-sonnet-4-6"The Bedrock provider uses the credential paths implemented in crates/zeroclaw-providers/src/bedrock.rs:
api_keyon the Bedrock alias, orBEDROCK_API_KEY, uses Bedrock bearer-token auth and takes precedence over SigV4 credentials.AWS_ACCESS_KEY_IDplusAWS_SECRET_ACCESS_KEYuses SigV4.AWS_SESSION_TOKENis optional.AWS_REGIONorAWS_DEFAULT_REGIONselects the signing region and falls back tous-east-1.credential_processin the active profile from~/.aws/config, or fromAWS_CONFIG_FILE, uses SigV4.AWS_PROFILEselects the profile and defaults todefault.- EC2 IMDSv2 instance credentials are the final SigV4 fallback.
The config schema additionally defines a providers.models.bedrock.<alias>.region
field, but the current implementation does not read it. The endpoint region is
always resolved from the AWS credential chain (environment variables,
credential_process, or IMDS) as described above.
A normal static profile in ~/.aws/credentials is not read by the current Bedrock implementation. ~/.zeroclaw/secrets only stores ZeroClaw config secrets such as an alias api_key; it does not export AWS_* variables for the provider.
To reuse an AWS CLI profile through the implemented profile path, put a credential_process in ~/.aws/config:
[profile zeroclaw-bedrock]
credential_process = /usr/bin/aws configure export-credentials --profile my-existing-profile
region = us-east-1/usr/bin/aws is the default path on Debian and Ubuntu. On other systems,
use the absolute path from command -v aws.
Then run ZeroClaw with AWS_PROFILE=zeroclaw-bedrock. For a systemd user service, see Service management.
One type per family; pick the region via the typed endpoint field on the alias entry.
The custom slot requires uri. See Custom providers.
Agents reference a provider by dotted alias. Provider entries on their own do nothing.
risk_profile and runtime_profile reference independent alias maps, so their names need not match (runtime_profile is also optional). Config::validate() fails loud at startup if model_provider doesn't resolve to a configured [providers.models.<type>.<alias>] entry, or if risk_profile doesn't resolve to a configured [risk_profiles.<alias>] entry.
For multiple agents pointing at different providers, see Routing.
When a request to a provider fails after exhausting its retries (provider down, key rate-limited, model unavailable), the alias can fall over to alternatives you declare on the alias entry. Two independent, ordered axes:
fallback_models: alternate model IDs tried on this provider, using the same endpoint, key, and headers. Only the model identifier changes. Use it when a provider serves a backup model (a smaller or older variant) that should be tried before leaving the provider entirely.fallback: an ordered list of other provider aliases (dotted<type>.<alias>references into[providers.models]). Each fallback alias resolves with its own credentials, endpoint, and model, a fallback never inherits the failing alias's key.
The walk is depth-first: an alias's entire model list is exhausted before leaving
it, then each fallback alias is descended in turn, applying that alias's own
fallback_models and fallback recursively. Suppose anthropic.prod serves
claude-sonnet-4-5, lists claude-haiku-4-5 in its fallback_models, and
names openai.backup (serving gpt-4.1) in its fallback. The attempt order
is then:
anthropic.prod/claude-sonnet-4-5
-> anthropic.prod/claude-haiku-4-5
-> openai.backup/gpt-4.1
-> (request fails)
Fallback aliases can themselves declare fallback, so the chain is as long as
your config makes it, up to a maximum depth of 3 aliases. A chain that loops
back on itself (a -> b -> a) is detected and the cycle edge is pruned, and
an acyclic chain deeper than the limit has its remaining links pruned; neither
ever loops, hangs, or overflows the stack.
A fallback entry that names an alias which is not configured, one that closes a
cycle, or a chain that exceeds the maximum depth is non-fatal:
Config::validate() still succeeds, the offending edge is skipped at runtime, and
the issue is surfaced as a validation warning (dangling_fallback_ref /
fallback_cycle / max_fallback_depth_exceeded) on the CLI and in the dashboard.
A fallback_models entry that is blank or duplicates the alias's primary model
is likewise skipped at runtime and surfaced (empty_fallback_model /
fallback_model_duplicates_primary). A bad fallback link degrades gracefully, it
never prevents the agent from running.
- Overview
- Provider catalog: concrete config example for every family
- Streaming
- Routing
- Custom providers