Every model provider lives at [providers.models.<type>.<alias>] in ~/.zeroclaw/config.toml. <type> is the canonical family slot (anthropic, openai, azure, gemini, groq, moonshot, ...). <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:
{{#include ../_snippets/minimal-config.toml}}The aliases (home, assistant) above are example names β substitute whatever suits your install.
[providers.models.<type>.<alias>]
model = "<model-id>" # passed to the provider as the model selectorAlmost every family also takes:
api_key = "..." # or use the secrets store, or a provider-specific env var
uri = "https://..." # optional operator override; otherwise the family's typed endpoint enum supplies the URLFor every family, 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 and Bedrock take typed inputs (
resource,deployment,api_versionfor Azure;regionfor Bedrock) and substitute them into the family's URI template. Missing fields fail loud at runtime.
Run cargo doc --open -p zeroclaw-config (or read crates/zeroclaw-config/src/providers.rs) for the complete list. Highlights:
| Slot | Notes |
|---|---|
anthropic |
API key or OAuth (sk-ant-oat-*) |
openai |
GPT, o-series; the OpenAI Codex subscription variant is providers.models.openai.<alias> with wire_api = "responses" and requires_openai_auth = true |
azure |
Typed: resource, deployment, api_version β all set on the alias entry |
gemini |
Google's API; gemini_cli is the CLI-shells-out variant |
bedrock |
AWS-credentials chain, region template |
ollama |
Local inference; uri defaults to http://localhost:11434 |
openrouter |
Multi-vendor routing layer (treated as a single provider; see Routing) |
groq, mistral, xai, deepseek, ... |
OpenAI-compatible endpoints, each with its own canonical slot |
moonshot, qwen, glm, minimax, zai, doubao, ... |
Multi-region families; pick the region with endpoint = "<variant>" on the alias entry |
lmstudio, llamacpp, sglang, vllm, osaurus, litellm |
Local-server defaults (http://localhost:<port>/v1) |
custom |
Catch-all for OpenAI-compatible endpoints not covered above; uri is required |
There is one canonical key per vendor β no synonyms.
Three ways to supply credentials, in resolution order:
- Inline
api_key = "..."in the alias entry (fine for dev, risky for checked-in configs). - 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.
zeroclaw onboard 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 β
sk-ant-oat-*OAuth tokens (from Claude Pro/Team) go inapi_keyon[providers.models.anthropic.<alias>]. - OpenAI Codex subscription β set
requires_openai_auth = trueand leaveapi_keyunset on[providers.models.openai.<alias>]; the runtime reads the stored Codex login. - Gemini CLI β
[providers.models.gemini_cli.<alias>]shells out to thegeminiCLI; use the CLI's own auth flow. - Qwen / MiniMax β set
auth_mode = "oauth"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:
[providers.models.ollama.local]
uri = "http://host.docker.internal:11434"
model = "qwen3.6:35b-a3b"The generic env-override mechanism (ZEROCLAW_<dotted_path_with_double_underscores>=<value>) can set the same field at runtime without editing config.toml:
ZEROCLAW_providers__models__ollama__home__uri=http://ollama:11434 zeroclaw agent -a assistantThe __ is the path separator; the example above sets providers.models.ollama.home.uri. See Environment variables for the full grammar.
[providers.models.ollama.local]
uri = "http://localhost:11434"
model = "qwen3.6:35b-a3b"
think = false # disable reasoning mode for faster output
reasoning_effort = "none" # same intent, passed as a top-level field
options = { temperature = 0, num_ctx = 32768 }[providers.models.azure.work]
resource = "my-resource" # template var: https://{resource}.openai.azure.com/...
deployment = "gpt-4o"
api_version = "2024-10-01-preview"
api_key = "..."The resource, deployment, and api_version values live in this typed config β they are not read from environment variables.
Pick the region with the typed endpoint field on the alias entry:
[providers.models.moonshot.cn]
api_key = "..."
endpoint = "cn" # MoonshotEndpoint::Cn -> https://api.moonshot.cn/v1
[providers.models.moonshot.intl]
api_key = "..."
endpoint = "intl" # MoonshotEndpoint::Intl -> https://api.moonshot.ai/v1One type per family; region picks via the endpoint field on the alias entry.
[providers.models.custom.gateway]
uri = "https://my-gateway.example.com/v1"
model = "my-model-id"
api_key = "..."The custom slot requires uri. See Custom providers.
Agents reference a provider by dotted alias. Provider entries on their own do nothing.
[agents.assistant]
model_provider = "anthropic.home" # `<type>.<alias>` into providers.models
risk_profile = "hardened" # alias into risk_profiles.<alias>
runtime_profile = "deep" # alias into runtime_profiles.<alias>; independent of risk_profilerisk_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.
- Overview
- Provider catalog β concrete config example for every family
- Streaming
- Routing
- Custom providers