Model Registry

Agents don't name a model. They name a registry key, and the key points at the model. That one layer of indirection is what makes provider churn survivable: when Anthropic, OpenAI or Google renames or retires a model id โ€” which happens continuously โ€” you edit one entry in ~/.mur/models.yaml and every agent pointing at that key moves with it. No per-agent migration.

mur model connect anthropic    # one key, many models (see below)
mur model list                 # every registered key
mur model show claude_opus     # provider, model, effective cost, context window
mur model doctor               # offline audit โ€” see below

API keys are stored as SecretRefs (env:, keychain:, file:, cmd:), never written to config in plaintext.

Connecting a provider

You rarely want to register models one at a time. mur model connect onboards a credential, then lets you pick from that provider's models:

mur model connect anthropic                  # prompts for the key โ†’ macOS Keychain,
                                             #   lists the models, you pick
mur model connect openai --all               # take everything, no prompt
mur model connect deepseek --base-url https://api.deepseek.com --pick 1,3-5
mur model connect                            # no vendor: probe local runtimes
                                             #   (Ollama ยท MLX ยท LM Studio)

Picked models are written with pricing and context window already filled in. If the provider already has a key in the registry, connect reuses that reference instead of asking again.

Where the model list comes from depends on what the endpoint can answer:

You connectList comes fromWhy
A known cloud vendor (anthropic, openai, deepseek, โ€ฆ)the models.dev catalogA vendor's configured endpoint is often a chat-only proxy that forwards /v1/models untouched โ€” probing it returns an auth error even with a valid key
A custom endpoint (--base-url, unknown vendor)live GET /v1/modelsOnly that endpoint knows which models it actually serves
No vendor at alllocal runtime probeOllama, MLX and LM Studio answer on well-known ports

A vendor that isn't anthropic or openai needs --base-url, because those two are the only wire protocols the runtime speaks natively. Everything else is registered as provider: openai โ€” the protocol โ€” with the vendor recorded alongside it:

deepseek_deepseek_chat:
  provider: openai                    # how MUR dials it
  vendor: deepseek                    # who makes it โ€” what pricing looks up
  model: deepseek-chat
  base_url: https://api.deepseek.com

Two fields because they answer two questions. provider: picks a client, and the runtime ships four (local, ollama, anthropic, openai); putting a vendor name there gives you an entry nothing can dial. vendor: is what the models.dev catalog is keyed by, and it is why the entry above arrives priced.

It is written only when the two differ โ€” for Anthropic, OpenAI and Ollama the protocol already names the vendor. Entries written before the field carry neither problem nor benefit: the vendor is inferred from the endpoint host instead, so older registries keep pricing correctly.

Pointing an agent at a key

An agent's profile.yaml carries model_ref โ€” the registry key it resolves at run time:

model_ref: claude_sonnet
fallback_chain: [claude_sonnet, gpt5]   # tried in order when the primary fails

Renaming a model is therefore a registry edit, not a fleet-wide change:

# provider renamed claude-sonnet-4-6 โ†’ claude-sonnet-5
mur model add claude_sonnet --provider anthropic --model claude-sonnet-5
# every agent with model_ref: claude_sonnet now runs the new id

mur model doctor

An offline, read-only audit of the registry and every installed agent. It runs against the cached price catalog and makes no network calls.

mur model doctor
# ok โ€” 6 registry entries, 27 agents, nothing inconsistent

It reports three kinds of divergence:

FindingLevelMeaning
model_ref '<key>' is not in models.yamlerrorthe agent cannot dial at all
profile.yaml model: says X but model_ref resolves to Ywarnthe ref is what runs; the legacy block is stale
<id> is not in the price catalog under <vendor>warnlikely a typo, or provider: naming the wrong vendor

It never rewrites a model id. Which model an agent runs is a cost and behaviour decision you made, and silently "upgrading" a renamed id would change your spend and your output quality without asking. The doctor tells you; the edit stays yours.

What the catalog check does not prove

It is not a deprecation check. The models.dev catalog keeps historical entries โ€” at the time of writing it lists claude-sonnet-4-6 and claude-sonnet-5 side by side โ€” so an id still appearing there says nothing about whether the provider still serves it. Answering that would need a live /v1/models call against every endpoint, which this command deliberately does not make.

What it does catch is an id the catalog has never carried: a typo, a copied-wrong id, or a provider: field used as a vendor name when it is really a wire protocol. That last case is common โ€” DeepSeek is reached over the OpenAI protocol, so its entry reads provider: openai while the catalog files it under vendor deepseek. The check reads the entry's recorded vendor: first, falls back to inferring one from base_url, and only then tries provider, so OpenAI-compatible third parties are not flagged wholesale.

Two blind spots worth knowing:

  • An entry pointed at a local proxy (such as the Model Gateway on 127.0.0.1:8088) is exempt from the catalog check, because the proxy hides which vendor is upstream. A retired id behind one is invisible here.
  • A local runtime (Ollama, MLX, LM Studio) is in no public catalog by definition, so it is never flagged for being absent from one.

Pricing

Cost per 1k tokens and the context window are auto-filled from the models.dev catalog when you add an entry:

mur model add gpt5 --provider openai --model gpt-5.2      # auto-filled
mur model add local --provider openai --model qwen --no-fetch   # skip the lookup
mur model prices refresh                                   # refresh the cache
mur model prices show

Set them by hand with --input-cost / --output-cost when the catalog has no entry. A model with no price shows no price in the agent CLI footer rather than a blank โ€” "we cannot price this" and "this cost nothing" are different things, and the footer says which one you are looking at.

Moving a registry to another machine

models.yaml holds secret references, never key material, so the file is safe to copy, commit, or sync. Setting up a second machine is two steps:

scp ~/.mur/models.yaml newmachine:~/            # the "export" is a copy
mur model import ~/models.yaml                  # on the new machine

Import merges models and roles into whatever is already there. It never deletes, and it skips keys that already exist locally unless you pass --force. Because the keys themselves did not travel, it finishes by listing the secret references that do not resolve on this machine โ€” those are exactly what you still need to re-key, with mur model connect <vendor> or by recreating the env var or file the reference points at.

Hub Model Library

The MUR Hub desktop app manages all of this without YAML: connect a cloud provider (the key goes to the macOS Keychain), auto-detect local runtimes, discover their models via /v1/models, and add them as registry keys. It shares the Keychain service with mur model connect, so a key stored by either surface is visible to the other.