Skip to content

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.

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):

  1. Per-agent binding — an entry under agents: in models.yaml for this agent, naming a profile and optionally a model.
  2. Global default — the default: profile in models.yaml.

If neither resolves, muaz errors with a clear message telling you to set a default or bind the agent to a profile.

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:

Terminal window
muaz models add --list # what this build offers
muaz models add anthropic # guided: model, endpoint, key — then it becomes the default

Either 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.

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.

~/.muaz/models.yaml
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-work

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 — run muaz 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, and POST /api/providers/{name}/test probes 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-main

The 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.

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.

typeNotes
anthropicNative Anthropic Messages API, with automatic prompt caching
openai-compatibleOpenAI, Together.ai, Groq, vLLM, LM Studio, and any OpenAI-compatible endpoint
bedrockAWS Bedrock (uses ambient AWS credentials)
geminiGoogle Gemini (generativelanguage.googleapis.com)
ollamaLocally-running Ollama server
type: anthropic
default_model: claude-sonnet-5
api_key: "${ANTHROPIC_API_KEY}"
timeout_secs: 300 # optional; thinking models can run long
adaptive_thinking: true # optional; extended thinking, on by default
effort: high # optional; low | medium | high | xhigh | max
cache: true # optional; prompt caching, on by default

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:

Terminal window
muaz models tune main # what this profile's type accepts, and where it stands
muaz models tune main effort=high cache=false
muaz models tune main --unset effort # back to the provider's default

Both 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.

typeTunable
anthropicadaptive_thinking (on), effort (the API’s own), cache (on), timeout_secs (300)
openai-compatiblereasoning_effort (the model’s own), timeout_secs (30)
bedrockregion, profile, cache (off), additional_model_request_fields, endpoint_url, timeout_secs (60)
geminithinking_mode (off), thinking_budget (off), timeout_secs (60)
ollamathink (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.

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:

ValueWhereWhat it means
directDesktop install (the default)Loopback is your machine — local presets work as written
host_gatewayBoth container images (set in the image)Loopback is the container; your machine is host.docker.internal, and local presets are pre-filled with it
noneHosted 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-compatible
base_url: "http://host.docker.internal:1234" # LM Studio on the host
default_model: local-model

Two 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 run needs --add-host=host.docker.internal:host-gateway.
  • The server must listen beyond loopback. On Linux host-gateway is the bridge address, so a model server bound to 127.0.0.1 still 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.

  • CLI — manage models.yaml without hand-editing YAML:

    Terminal window
    muaz models add --list # the presets this build ships
    muaz models add anthropic # guided setup from a preset
    muaz models list # profiles, default, and bindings
    muaz 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 model
    muaz models tune openai-main # what this profile's type can be tuned to
    muaz models tune openai-main reasoning_effort=high # (--unset <key> restores the default)
    muaz models default anthropic-main # set the global default
    muaz models bind coding --profile bedrock-work --model claude-3-7-sonnet
    muaz models unbind coding
    muaz models remove openai-main

    muaz agents create also 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/presets returns the preset table this build ships (already filtered for what the deployment can reach); GET /api/providers/types returns the provider types and what each can be tuned to; PUT /api/providers/{name} / DELETE manage profiles; PUT /api/bindings/default, PUT /api/bindings/agents/{agent}, and DELETE /api/bindings/agents/{agent} manage the mapping.

  • File — or just edit ~/.muaz/models.yaml directly.

# models.yaml — add the profile once, make it the default
profiles:
anthropic-main: { type: anthropic, default_model: claude-sonnet-5, api_key: ${ANTHROPIC_API_KEY} }
default: anthropic-main

Every 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.