Providers & models
muaz separates what an agent is (its prompt, tools, and behaviour) from which model it talks to. Agents are provider-agnostic: they never hard-code a provider. The model is chosen separately, so you can say “use GPT for everything” — or point one agent at a different model — without editing the agent.
How a model gets bound to an agent
Section titled “How a model gets bound to an agent”Agents never carry a provider. Everything about model routing lives in one file,
~/.muaz/models.yaml, which muaz re-reads on every resolution — so changing a
model takes effect immediately, with no restart.
When an agent runs, muaz resolves its provider in this order (first match wins):
- Per-agent binding — an entry under
agents:inmodels.yamlfor this agent, naming a profile and optionally a model. - Global default — the
default:profile inmodels.yaml.
If neither resolves, muaz errors with a clear message telling you to set a
default or bind the agent to a profile.
Starting from a preset
Section titled “Starting from a preset”A fresh install has no profiles — models.yaml is written once, on first
run, and never rewritten by an upgrade, so anything shipped in it would be
frozen into your install forever. The provider presets live in the binary
instead, which means an upgrade brings current model ids for free.
Pick one from the browser UI’s first-run screen or the Providers page, or from the terminal:
muaz models add --list # what this build offersmuaz models add anthropic # guided: model, endpoint, key — then it becomes the defaultEither way you end up with a profile in models.yaml you can edit like any
other. The worked examples below are the same shapes, spelled
out.
models.yaml
Section titled “models.yaml”The single file has three parts: named connection profiles, the global
default, and per-agent agents overrides. A profile is a named, reusable
model connection — define it once and reference it by name everywhere.
profiles: anthropic-main: type: anthropic # native Anthropic provider (prompt caching on) default_model: claude-sonnet-5 api_key: ${ANTHROPIC_API_KEY} openai-main: type: openai-compatible base_url: https://api.openai.com default_model: gpt-4o api_key: ${OPENAI_API_KEY} bedrock-work: type: bedrock region: us-east-1 default_model: anthropic.claude-3-5-sonnet-20241022-v2:0 profile: work local: type: ollama default_model: qwen3
default: anthropic-main # every unbound agent uses this profile
agents: # per-agent overrides (agent name or @plugin/agent) coding: profile: bedrock-workAPI keys & authentication
Section titled “API keys & authentication”The API-key providers (openai-compatible, gemini) authenticate with a key
you get from the provider’s dashboard. Rather than reference ${OPENAI_API_KEY}
and hope it’s exported in every shell that launches muaz, you can store the key
with muaz — it goes to your OS keychain (macOS Keychain, Windows Credential
Manager, or the Linux Secret Service), falling back to a chmod 600
~/.muaz/secrets.json when no keychain is available (headless Linux, CI).
Keep the api_key: ${OPENAI_API_KEY} reference in the profile as-is — it names
the secret. When the key is needed, muaz resolves ${OPENAI_API_KEY} from the
store first, then the environment, so a stored key wins over a stale shell value.
Store a key any of these ways:
- CLI —
muaz auth [profile]prompts for the key (input hidden) and saves it, without starting a chat. With no argument it targets the default binding. This is the way to authenticate before your first chat: if a profile’s key is unset, agent startup fails while resolving${VAR}, so the REPL never reaches its prompt — runmuaz auth <profile>first. It also accepts a piped key for scripting:printf %s "$KEY" | muaz auth openai-main. - REPL —
/auth [profile]does the same from inside a running chat. With no argument it targets the current session’s profile. - Browser UI — the Providers page shows a status pill (Key set / From environment / Not set) next to each key-based profile, a masked Set key field, and a Test button that validates the credentials with a minimal request.
- Gateway API —
PUT /api/secrets/{name}sets a value (write-only — secret values are never returned over HTTP),DELETE /api/secrets/{name}removes it, andPOST /api/providers/{name}/testprobes a profile’s credentials.
Bedrock uses the ambient AWS credential chain (profile/region), and local Ollama / LM Studio need no key, so neither uses the secret store.
Binding models (the default + agents sections)
Section titled “Binding models (the default + agents sections)”# ~/.muaz/models.yaml (default + agents sections)
# Profile used by every agent that isn't bound below:default: anthropic-main
# Bind specific agents to a different profile (and optionally a different model):agents: coding: profile: bedrock-work model: anthropic.claude-3-7-sonnet-20250219-v1:0 # optional model swap "@web-research/researcher": # plugin agents use their qualified name profile: openai-mainThe binding key is the agent name (or a fully-qualified @plugin/agent name for
a plugin agent). model is optional — omit it to use the profile’s model.
Provider types
Section titled “Provider types”muaz supports five provider types. Each accepts only its own fields — unknown
fields are rejected with a clear error. Every tab below is a complete, working
profile: paste it under profiles: with a name of your choosing.
type | Notes |
|---|---|
anthropic | Native Anthropic Messages API, with automatic prompt caching |
openai-compatible | OpenAI, Together.ai, Groq, vLLM, LM Studio, and any OpenAI-compatible endpoint |
bedrock | AWS Bedrock (uses ambient AWS credentials) |
gemini | Google Gemini (generativelanguage.googleapis.com) |
ollama | Locally-running Ollama server |
type: anthropicdefault_model: claude-sonnet-5api_key: "${ANTHROPIC_API_KEY}"timeout_secs: 300 # optional; thinking models can run longadaptive_thinking: true # optional; extended thinking, on by defaulteffort: high # optional; low | medium | high | xhigh | maxcache: true # optional; prompt caching, on by defaulttype: openai-compatible# `/v1/chat/completions` is appended for you — do not include `/v1` here.base_url: "https://api.openai.com"default_model: gpt-5.1api_key: "${OPENAI_API_KEY}"timeout_secs: 60reasoning_effort: "medium" # for o-series / thinking modelsThe same shape covers a local OpenAI-compatible server, which needs no key:
type: openai-compatiblebase_url: "http://localhost:1234" # LM Studiodefault_model: openai/gpt-oss-20btimeout_secs: 60type: bedrockdefault_model: us.anthropic.claude-sonnet-4-6-20251001-v1:0region: us-east-1 # optional; falls back to AWS_DEFAULT_REGION → AWS_REGION → us-east-1timeout_secs: 120 # optionalprofile: my-aws-profile # optional; AWS credential profileendpoint_url: "https://vpce-xxx.bedrock-runtime.us-east-1.vpce.amazonaws.com" # optional; VPC endpointtype: geminidefault_model: gemini-3.5-flashapi_key: "${GEMINI_API_KEY}"timeout_secs: 60thinking_budget: 8192 # token budget for extended thinking (0 = off)# thinking_mode: "medium" # alternative: low / medium / high / maxtype: ollamabase_url: "http://localhost:11434"default_model: llama3.2timeout_secs: 120keep_alive: "5m" # optional; how long Ollama keeps the model loadedthink: "high" # optional; thinking mode: enabled / high / medium / lowTuning a profile
Section titled “Tuning a profile”The fields above the key — thinking, caching, timeouts — are optional. Leave one out and the provider’s own default applies, which is usually what you want: a default that improves in a later release reaches every profile that never overrode it.
When you do want to change one, you do not have to hand-edit YAML. The
Providers page renders a Settings section per profile, and the CLI has
muaz models tune:
muaz models tune main # what this profile's type accepts, and where it standsmuaz models tune main effort=high cache=falsemuaz models tune main --unset effort # back to the provider's defaultBoth read one table shipped in the binary, so they always offer exactly the fields the build supports — and a value the field cannot hold is refused when you set it, not at the next agent run.
type | Tunable |
|---|---|
anthropic | adaptive_thinking (on), effort (the API’s own), cache (on), timeout_secs (300) |
openai-compatible | reasoning_effort (the model’s own), timeout_secs (30) |
bedrock | region, profile, cache (off), additional_model_request_fields, endpoint_url, timeout_secs (60) |
gemini | thinking_mode (off), thinking_budget (off), timeout_secs (60) |
ollama | think (off), keep_alive (Ollama’s own 5m), timeout_secs (120) |
Parenthesised values are what applies when the field is absent. default_model,
base_url and api_key are not in this list — they define the connection, so
they live in the main form and in muaz models set.
Local models when muaz runs elsewhere
Section titled “Local models when muaz runs elsewhere”localhost and 127.0.0.1 inside a container are the container, so a
base_url that works on your laptop points at nothing once muaz is running as
the server image or a hosted sandbox.
muaz does not guess. The deployment declares what it can reach through
MUAZ_LOCAL_MODEL_ACCESS, and the presets, the hints and muaz doctor all
follow it:
| Value | Where | What it means |
|---|---|---|
direct | Desktop install (the default) | Loopback is your machine — local presets work as written |
host_gateway | Both container images (set in the image) | Loopback is the container; your machine is host.docker.internal, and local presets are pre-filled with it |
none | Hosted sandboxes (set by the control plane) | Your machine is not reachable at all; local presets are not offered |
Under host_gateway, use the host’s gateway address:
type: openai-compatiblebase_url: "http://host.docker.internal:1234" # LM Studio on the hostdefault_model: local-modelTwo things have to be true for that to resolve:
- The container needs the name. Sandboxes started by the control plane get
it automatically; a hand-run
docker runneeds--add-host=host.docker.internal:host-gateway. - The server must listen beyond loopback. On Linux
host-gatewayis the bridge address, so a model server bound to127.0.0.1still refuses the connection — enable its “serve on local network” option. (Docker Desktop on macOS and Windows proxies host loopback, so it works there either way.)
muaz doctor names this explicitly: it probes every profile with a live call,
and one whose endpoint is loopback and whose probe failed reports the
host.docker.internal fix rather than a bare connection error.
Under none there is no address that would work — a hosted sandbox runs in
someone else’s data centre, not on your network. Use a hosted provider
(Anthropic, OpenAI, Gemini, Bedrock) there, or run muaz locally.
Managing providers
Section titled “Managing providers”-
CLI — manage
models.yamlwithout hand-editing YAML:Terminal window muaz models add --list # the presets this build shipsmuaz models add anthropic # guided setup from a presetmuaz models list # profiles, default, and bindingsmuaz models set openai-main --type openai-compatible --model gpt-4o --api-key '${OPENAI_API_KEY}'muaz models set-model openai-main gpt-4o-mini # change just a profile's modelmuaz models tune openai-main # what this profile's type can be tuned tomuaz models tune openai-main reasoning_effort=high # (--unset <key> restores the default)muaz models default anthropic-main # set the global defaultmuaz models bind coding --profile bedrock-work --model claude-3-7-sonnetmuaz models unbind codingmuaz models remove openai-mainmuaz agents createalso offers to bind a profile to the new agent. -
Browser UI — the Providers page manages profiles and the default; the Agents page edits per-agent bindings. See Browser UI.
-
Gateway API —
GET /api/providers/presetsreturns the preset table this build ships (already filtered for what the deployment can reach);GET /api/providers/typesreturns the provider types and what each can be tuned to;PUT /api/providers/{name}/DELETEmanage profiles;PUT /api/bindings/default,PUT /api/bindings/agents/{agent}, andDELETE /api/bindings/agents/{agent}manage the mapping. -
File — or just edit
~/.muaz/models.yamldirectly.
Switching everything to a new model
Section titled “Switching everything to a new model”# models.yaml — add the profile once, make it the defaultprofiles: anthropic-main: { type: anthropic, default_model: claude-sonnet-5, api_key: ${ANTHROPIC_API_KEY} }default: anthropic-mainEvery agent — the built-in starter and codebase, the code-review step
agents, and any plugin agent you install — now uses that model. No agent files
were touched.