Skip to main content

Model Registry & Routing

Canonical model policy stays in the existing YAML and per-harness configs. Generated mirrors project that policy into one machine-readable view without becoming a competing source of truth.

This is the model-side counterpart to the MCP registry. Use it when adding a model, changing reasoning/cost metadata, checking live catalog drift, or understanding how a model reaches Pi, OpenCode, and provider launchers.

Mental model​

PieceRole
home/.chezmoidata/ai_models/Canonical model registry and policy sections, split across three files
scripts/ai_models.pyDependency-free parser for the registry sections
home/dot_config/ai/readonly_model-mirrors.v1.jsonCommitted generated mirror deployed to ~/.config/ai/model-mirrors.v1.json
scripts/model_mirrors.pyGenerates/verifies the static mirror and runs explicit live drift probes

Registry: .chezmoidata/ai_models/​

Source of truth: home/.chezmoidata/ai_models/. The sections are split across three files for navigation only β€” chezmoi merges every file under .chezmoidata/ (subdirectories included) into one flat data namespace, so templates still read .cursor_models and .category_models directly. scripts/ai_models.py holds the section β†’ file map (SECTION_FILES) and takes the registry directory, never a single file.

SectionFileCanonical policy
cursor_modelsharness-catalogs.yamlCurated Cursor aliases; recommended: true is the narrower preferred set
pi_extra_modelsharness-catalogs.yamlPi's curated picker; every entry is provider-routed through Pi's built-in OpenRouter provider
copilot_modelsharness-catalogs.yamlProbed Copilot CLI catalog; the mirror's copilot available set
provider_modelsprovider-routes.yamlStatic provider-route choices for shell completion; Vertex entries also own adapter wire/capability metadata
review_model_overridestiering.yamlSparse review selector overrides (inherit, pro) for harnesses whose review roles cannot be derived from category_models
agent_categoriestiering.yamlPortable category β†’ {family, contract}; the same table on every harness
agent_bindingstiering.yamlEvery delegable agent name β†’ its category, built-ins included
category_modelstiering.yamlPer-harness category picks; see Model tiering for policy and rationale

Adding a section means adding it to SECTION_FILES as well: the parser resolves a section by name, so an unmapped section raises rather than being searched for across files.

Recommended Cursor entries use recommendation_rank to preserve the deliberate TUI picker order independently of the broader curated registry order.

Using it​

Static generation has no network path:

python3 scripts/model_mirrors.py generate
python3 scripts/model_mirrors.py verify

The stable launcher adapter emits consumer_view.v1 fields:

schema_version, consumer, harness, set, status, complete, models, reason, provenance

Example adapter call:

python3 scripts/model_mirrors.py adapt \
--mirror home/dot_config/ai/readonly_model-mirrors.v1.json \
--consumer launcher --harness cursor --set available

Live catalog access exists only behind the explicit probe subcommand:

python3 scripts/model_mirrors.py probe \
--mirror home/dot_config/ai/readonly_model-mirrors.v1.json \
--target harness:cursor --target provider:openrouter

Generators​

GeneratorOutput
scripts/model_mirrors.pyGenerates/verifies the v1 static mirror and runs explicit live drift probes

Pi and OpenCode no longer generate model blocks: both harnesses resolve openrouter/ selectors through their own built-in provider, so run_onchange_after_07-merge-pi-config.sh.tmpl installs the profile's static models.json and run_onchange_after_07-merge-opencode-config.sh.tmpl only injects MCP servers.

The mirror is a committed generated artifact verified by tests and make check. Diagnostic probes are operator initiated. See Tool configs.

Generated mirror v1​

home/dot_config/ai/readonly_model-mirrors.v1.json deploys to ~/.config/ai/model-mirrors.v1.json.

It is generated from the registry, harness configs, and the versioned installed-harness evidence in scripts/model_capabilities.v1.json.

observed_at is the verification date for that evidence snapshot, not a claim about the currently installed binaries. Refresh the identities and their catalog/capability claims together before advancing it; a newer --version alone is not equivalent evidence.

Every harness and provider route has three catalogs:

CatalogMeaning
availableWhat fixed installed-source evidence or configured capability data establishes; may be incomplete
curatedOperator-owned IDs allowed by current policy
recommendedDeliberate subset shown as preferred choices; availability alone never promotes a model into this set

Each catalog carries status, models, complete, reason, and provenance. Status is known, unknown, or error.

unknown/error catalogs must have no models, complete: null, and a reason, so a failed probe can never look like a successful empty catalog.

Provenance enumerates every contributing config or registry source. Registry entries also name sections, such as agent_bindings, agent_categories, category_models, and review_model_overrides for Copilot review-policy routing.

The mirror also records exact installed harness identity/version evidence and consumer adapters.

Generation fails closed when the canonical cursor_models section is missing, empty, unrecognized, duplicated, or contains an invalid ID. Curated catalogs must contain only recognized, non-duplicated IDs; generation cannot publish a known mirror with a stale fallback.

Launcher consumption​

The deployed ,ai launcher consumes the shared consumer_view.v1 module with the available set.

A known, complete catalog rejects an absent explicit model. Incomplete or unknown catalogs preserve low-level explicit model control.

The plan exposes bounded catalog status, count, and provenance without embedding the full model list, and planning performs no network access.

Omitting --set in the repo-side adapter still selects the documented launcher default, recommended. __comma_provider_models.fish consumes provider curated catalogs.

Command consumers keep policy in their own config and use the mirror only for bounded availability/provenance checks.

Opt-in live drift​

Locally verified adapters cover Cursor (cursor-agent --list-models), Pi (pi --offline --list-models), OpenCode (opencode models), OpenRouter, Vertex, and llama.cpp.

Claude, Codex, Antigravity, and Copilot remain explicitly unsupported until a complete local adapter is verified.

Probe limits and failure rules:

Probe typeCap
Command probes20 seconds and 4 MiB
HTTP probes10 seconds and 8 MiB

Results never include stderr, response headers, credentials, or exception text.

Every provider model ID in an HTTP payload must be a string accepted by MODEL_ID_RE. One malformed or non-string ID makes the whole payload unknown, never known drift.

Missing credentials, authentication/command failures, timeouts, oversized/empty/unparseable output, and unsupported adapters also return unknown.

A known result reports stale_curated, new_available, and recommended_unavailable, but never mutates the static mirror or auto-promotes a live ID.

Fixture probes use a JSON target_cases map such as scripts/tests/fixtures/model_probe_cases.json. Providing a fixture without a matching target fails closed instead of falling through to a live call.

The same mirror/probe seam is available for non-mutating live catalog diagnostics.

OpenRouter routing​

OPENROUTER_API_KEY comes from the openrouter/api/token pass entry, exported by home/dot_config/fish/readonly_config.fish.tmpl. Both Pi and OpenCode resolve openrouter/ selectors through their own built-in provider, so neither carries a generated provider block.

Upstream provider routing is model-specific (user calls 2026-08-07; uptime-aware default load balancing 2026-08-17): every moonshotai/kimi-k3 route sends provider: { only: ["fireworks", "together", "baseten"], max_price: { completion: 16 } }, while every z-ai/glm-5.3-flash route sends provider: { quantizations: ["fp8", "fp16", "bf16", "fp32"], preferred_min_throughput: 24 }; z-ai/glm-5.2 carries the same FP8-or-higher, 24 t/s floor policy (GLM 5.3 Flash replaced deepseek/deepseek-v4-flash-0731 on 2026-09-10, user call); deepseek/deepseek-v4.1-flash sends provider: { preferred_min_throughput: 35, max_price: { completion: 1.2 } } (user call 2026-09-11: the $1.20/M completion cap is a hard filter, the 35 t/s floor only deprioritizes, and there is no quantization filter because few DeepSeek endpoints declare one). None of these objects set sort or order: OpenRouter's default load balancer then skips providers with significant outages in the last 30 seconds and price-weights the rest. The GLM allowlist excludes INT4/INT8/FP4/FP6 providers; preferred_min_throughput deprioritizes endpoints below 24 t/s rather than excluding them. See Provider routing.

The policies have three carriers. Pi 0.84.0 sends each object through modelOverrides.compat.openRouterRouting, which its runtime copies as-is into the request's provider field. OMP 17.2.9's typed openrouter transport drops modelOverrides…compat.extraBody.provider from the wire (verified 2026-08-08: the merged catalog entry carries no extraBody and a live request with an impossible quantization succeeds), so OMP and OpenCode carry the policy in the model slug through workspace *-lanes-* presets. The eight kimi-lanes* presets preserve their effort-specific reasoning.effort values (including none, which disables reasoning) and carry the Kimi object; the eight glm-lanes* presets do the same for GLM, including the FP8-or-higher quantization allowlist. Those presets pin z-ai/glm-5.2, but the request model overrides the preset's model (live-probed 2026-09-10: z-ai/glm-5.3-flash@preset/glm-lanes-high answered as z-ai/glm-5.3-flash on an FP8 endpoint), so GLM 5.3 Flash rides the same slugs. The eight deepseek-lanes* presets carry the DeepSeek object (35 t/s preferred floor, $1.20/M completion cap, no quantization filter, no sort) and pin deepseek/deepseek-v4.1-flash; each got a new designated version on 2026-09-11 through POST /presets/{slug}/chat/completions, which keeps version history for rollback (the request model overrides the pin anyway, live-probed 2026-09-11: deepseek/deepseek-v4.1-flash@preset/deepseek-lanes-max answered as deepseek/deepseek-v4.1-flash on an FP8 endpoint). The four *-openrouter wrappers compose effort only: <model>@preset/effort-<level> for every --model. ,cursor-openrouter reaches OpenRouter through Cursor's agent-cli-local flavor (--base-url OpenAI-compatible), which the regular cursor-agent build rejects; its provider config is baseUrl+apiKey only, so effort rides the effort-<level> slug. Every session runs through the loopback shim, which both strips strict:true from openai/* tool schemas (cursor-agent-local's reasoning predicate matches those ids and the bundled Shell schema's optional debounce_ms fails OpenAI strict validation; see other harnesses) and enforces a wire-level model allowlist: the launcher exports the pinned wire id as CURSOR_AGENT_ALLOWED_MODEL and the shim returns 403 for any /chat/completions whose model differs, so no subagent or profile can route a different model on the session. The wrappers default to z-ai/glm-5.3-flash@preset/effort-max. Each wrapper first checks the active account for effort-<level> and creates it with only reasoning.effort when absent; existing presets are never rewritten. Inside an interactive session /model accepts a free-text id verbatim, so a typed model@preset/effort-<level> keeps the effort slug while a bare model does not.

  • OpenCode: both profiles run main, every configured worker, and small_model on openrouter/z-ai/glm-5.3-flash@preset/glm-lanes-high at high effort. DeepSeek V4.1 Flash stays selectable through openrouter/deepseek/deepseek-v4.1-flash@preset/deepseek-lanes-max, Kimi through openrouter/moonshotai/kimi-k3@preset/kimi-lanes, and GLM-5.2 through openrouter/z-ai/glm-5.2@preset/glm-lanes-max.
  • Pi: defaultProvider is anthropic in both profiles, defaultModel is claude-fable-5.1, and defaultThinkingLevel is high, so the T1 lanes ride the native Anthropic route. pi_extra_models exposes the strict Pi OpenRouter set: openrouter/openai/gpt-5.6-sol (recommended OpenRouter route; T2 implement at :high and the refute counter at :xhigh β€” one id, two efforts, after it superseded openrouter/openai/gpt-5.5 on 2026-09-07), openrouter/z-ai/glm-5.3-flash (mechanical since 2026-09-10), openrouter/deepseek/deepseek-v4.1-flash (V4 Flash carried mechanical until then; the id moved to V4.1 on 2026-09-11, still selectable), openrouter/google/gemini-3.8-flash (memory), openrouter/anthropic/claude-sonnet-4.6 (former counter, still selectable), openrouter/moonshotai/kimi-k3 (selectable), openrouter/z-ai/glm-5.2 (selectable), and openrouter/openai/gpt-6-astra (selectable; pinned to OpenAI's Flex service tier through only: ["openai/flex"], which bills $5/$25 per M against $10/$50 on the standard endpoint, live-probed 2026-09-11, user call; service-tier endpoints are never matched by the base openai slug). The gated Kimi, GLM 5.3 Flash, DeepSeek V4.1 Flash, GLM-5.2, and GPT-6 Astra provider policies still live in modelOverrides.

Local inference​

The local-inference backend is llama.cpp via ,llama-cpp; see llama.cpp local inference.