Model catalog
September 1, 2026 · View on GitHub
llmux exposes the known models — a curated set plus the live grok and
openrouter pins — as a machine-readable catalog. This is deliberately not an
exhaustive list of everything routable: at request time the grok provider
forwards ANY grok-* id verbatim and the openrouter provider forwards any
or-<vendor>/<slug> verbatim (see alias semantics), so a
request or config pin naming an id outside the curated set still works. Such an
out-of-catalog pin appears here as a synthesized row with null metadata (see
out-of-catalog grok pin and
out-of-catalog openrouter pin).
Endpoints
GET /modelsGET /llmux/models
Both return the same payload and sit behind the same loopback + proxy api-key gate as every other route:
{ "models": [ /* ModelEntry, ... */ ] }
Registering root /models reserves a path that previously fell through to the
upstream proxy fallback. Anthropic exposes no root /models, and /v1/models
is left untouched (still proxied upstream), so nothing regresses.
Response schema
Each element of models is a ModelEntry:
| Key | Type | Meaning |
|---|---|---|
id | string | Concrete upstream model id. |
aliases | array of strings | Extra request slugs that resolve to this id (may be empty). |
name | string | Human-facing display name. |
efforts | array of strings | Accepted reasoning.effort values, low→high (may be empty). |
max_context | integer or null | Context window in tokens; null when unpublished. |
group | string | Backend group: claude, codex, grok, or openrouter. |
max_context: null means the context window is not published for that id —
not that it is zero.
Alias semantics
-
grok family alias —
"grok"is dynamic: it attaches to whichever grok id is the current live pin (POST /llmux/grok/config.grok.default_model). A baregrokrequest routes to that pin, so the catalog advertises the alias on exactly the pinned entry. Anygrok-*id also passes through verbatim. -
codex variant aliases —
sol/terra/lunaresolve to the latest gpt generation of that variant (gpt-5.6-sol/-terra/-luna), and the baregpt-5.6id resolves to thesolflagship. These are advertised statically on the corresponding entries. -
claude aliases — the claude rows carry short user-curated aliases that both ROUTE to the claude group and are RESOLVED by the proxy: a bare alias is rewritten to its catalog id before the request leaves llmux, so the alias
GET /modelsadvertises is actually honored upstream.request slug catalog id model on the wire fable,fable-5-1claude-fable-5-1[1m]claude-fable-5-1opus,opus-5claude-opus-5[1m]claude-opus-5sonnet,sonnet-5claude-sonnet-5[1m]claude-sonnet-5haikuclaude-haiku-4-5claude-haiku-4-5Matching is trimmed and case-insensitive (
" OPUS "resolves), and an alias may carry the client-side[1m]context suffix —fable[1m]resolves exactly likefable, because alias resolution runs before the suffix strip. That strip is syntactic only — it does not promise a 1M-capable target (haiku[1m]resolves to the ordinaryclaude-haiku-4-5row). Only aliases are rewritten: a real catalog id is not an alias and passes through untouched — the[1m]suffix strip is a separate, subsequent step, which is whyclaude-opus-5[1m]still reaches upstream asclaude-opus-5— and foreign slugs (grok-4.6,gpt-5.6-sol) are never rewritten. The mapping has a single source, theCLAUDE_MODELSconst insrc/catalog.rsbehindresolve_claude_alias; adding a curated row carries its aliases automatically. llmux still does not otherwise shape claude requests, and theeffortsmenu on claude rows is the Claude Code/effortlevel list, per the user contract. -
openrouter
or-aliases — the openrouter rows advertise the id a client SENDS (or-ox-alpha); the OpenRouter slug it is rewritten to on the wire (stealth/ox-alpha) is a different string, because the advertised id has to carry theor-prefix that routes the request to the openrouter group in the first place. The curated mapping:request slug model on the wire or-ox-alphastealth/ox-alphaor-freeopenrouter/freeor-glm-5.2z-ai/glm-5.2:freeor-nemotron-3-ultranvidia/nemotron-3-ultra-550b-a55b:freeor-nemotron-3.5-lightningnvidia/nemotron-3.5-lightning:freeor-dots-3-notedots-studio/dots-3-note-preview:freeor-laguna-s-2.1poolside/laguna-s-2.1:freeor-north-mini-codecohere/north-mini-code:freeor-gemma-4-31bgoogle/gemma-4-31b-it:freeor-gpt-oss-20bopenai/gpt-oss-20b:freeThree rules sit around that table, and the table is a convenience layer, not a gate:
- bare
or— like baregrok, it resolves to the live pin (config.openrouter.default_model, defaultstealth/ox-alpha), and so does a request that names no model at all. or-<vendor>/<slug>escape hatch — anything containing a/is used VERBATIM minus theor-selector, so the ~400 OpenRouter models outside the curated set are reachable:or-openai/gpt-oss-20b:free→openai/gpt-oss-20b:free. A bareopenrouter/…slug also routes here and rides through unchanged.- no silent substitution — an uncurated bare name passes through as it was typed, so OpenRouter's own 404 reaches the user instead of llmux answering from a model nobody asked for.
Matching is trimmed and case-insensitive, and one trailing
[1m]is stripped first, exactly as on the claude and codex paths. - bare
-
alias stability — aliases float to the current generation, ids do not.
opustracks the newest curated Opus and moved fromclaude-opus-4-8[1m]toclaude-opus-5[1m]on 2026-07-27 (4.8 stays in the catalog; it just no longer owns an alias). Anyone who needs one specific model must send its full catalog id — that is the stable handle. Usage and pricing are booked against the resolved id, not the alias, so alias traffic lands on the same row as id traffic.
Out-of-catalog grok pin
The curated grok set is grok-4.6 (the default pin) and grok-4.5.
config.grok.default_model may pin ANY
grok-* slug — including ids not in the curated table below (e.g.
grok-4.3, grok-code-fast-1). Because the provider forwards such ids
verbatim, the pin is real and routable, so the "grok" family alias must have
an owner. When the pin matches no curated id, the catalog appends a
synthesized grok row: id = the pin, name = the pin verbatim, aliases
= ["grok"], efforts from the thinking-level lookup (empty unless the id is a
known reasoner — e.g. pinning grok-4.3 yields none, low, medium, high), and
max_context = null. The null metadata reflects that llmux has no published
context/name for an id it does not curate.
Out-of-catalog openrouter pin
config.openrouter.default_model may pin ANY OpenRouter slug, including one
outside the curated table below — the provider forwards it verbatim, so the pin
is real and routable and the bare or alias must have an owner. When the pin
matches no curated row's wire slug, the catalog appends a synthesized
openrouter row: id = or-<pin> (the string a client can actually type),
name = the pin verbatim, aliases = ["or"], efforts = empty, and
max_context = null — llmux has no published context or effort menu for a
model it does not curate.
Current catalog
| id | aliases | name | efforts | max_context | group |
|---|---|---|---|---|---|
| claude-fable-5-1[1m] | fable, fable-5-1 | Claude Fable 5.1 | low, medium, high, xhigh, max | 1000000 | claude |
| claude-fable-5[1m] | — | Claude Fable 5 | low, medium, high, xhigh, max | 1000000 | claude |
| claude-opus-5[1m] | opus, opus-5 | Claude Opus 5 [1M] | low, medium, high, xhigh, max | 1000000 | claude |
| claude-opus-5 | — | Claude Opus 5 | low, medium, high, xhigh, max | 200000 | claude |
| claude-opus-4-8[1m] | — | Claude Opus 4.8 | low, medium, high, xhigh, max | 1000000 | claude |
| claude-opus-4-6[1m] | — | Claude Opus 4.6 | low, medium, high, xhigh, max | 1000000 | claude |
| claude-sonnet-5[1m] | sonnet, sonnet-5 | Claude Sonnet 5 [1M] | low, medium, high, xhigh, max | 1000000 | claude |
| claude-sonnet-5 | — | Claude Sonnet 5 | low, medium, high, xhigh, max | 200000 | claude |
| claude-haiku-4-5 | haiku | Claude Haiku 4.5 | low, medium, high, xhigh, max | 200000 | claude |
| gpt-5.6-sol[1m] | — | GPT-5.6-Sol [1M] | low, medium, high, xhigh, max, ultra | 1000000 | codex |
| gpt-5.6-sol | sol, gpt-5.6 | GPT-5.6-Sol | low, medium, high, xhigh, max, ultra | 372000 | codex |
| gpt-5.6-terra[1m] | — | GPT-5.6-Terra [1M] | low, medium, high, xhigh, max, ultra | 1000000 | codex |
| gpt-5.6-terra | terra | GPT-5.6-Terra | low, medium, high, xhigh, max, ultra | 372000 | codex |
| gpt-5.6-luna | luna | GPT-5.6-Luna | low, medium, high, xhigh, max | 372000 | codex |
| gpt-5.5 | — | GPT-5.5 | low, medium, high, xhigh | 272000 | codex |
| grok-4.6 | grok (pinned) | Grok 4.6 | low, medium, high, xhigh | 500000 | grok |
| grok-4.5 | — | Grok 4.5 | low, medium, high | 500000 | grok |
| or-ox-alpha | or (pinned) | Ox Alpha (free) | low, high, max | 1048576 | openrouter |
| or-free | — | OpenRouter Free Models Router | — | 200000 | openrouter |
| or-glm-5.2 | — | Z.ai GLM 5.2 (free) | high, xhigh | 256000 | openrouter |
| or-nemotron-3-ultra | — | NVIDIA Nemotron 3 Ultra (free) | medium, high | 1000000 | openrouter |
| or-nemotron-3.5-lightning | — | NVIDIA Nemotron 3.5 Lightning (free) | — | 1000000 | openrouter |
| or-dots-3-note | — | Dots3-Note Preview (free) | — | 512000 | openrouter |
| or-laguna-s-2.1 | — | Poolside Laguna S 2.1 (free) | — | 262144 | openrouter |
| or-north-mini-code | — | Cohere North Mini Code (free) | — | 256000 | openrouter |
| or-gemma-4-31b | — | Google Gemma 4 31B (free) | — | 262144 | openrouter |
| or-gpt-oss-20b | — | OpenAI gpt-oss-20b (free) | low, medium, high | 131072 | openrouter |
"grok (pinned)" means the grok alias appears on that row only while it is the
live grok pin; any other pinned grok-* id appears instead as a synthesized row
(see Out-of-catalog grok pin). "or (pinned)" reads
the same way for the openrouter pin (see
Out-of-catalog openrouter pin); with the
default pin it sits on or-ox-alpha. The openrouter ids are what a client
sends — the slug that reaches OpenRouter is the one in the
alias table, and every curated openrouter row is a free
model (priced $0 in and out; an UNCURATED openrouter model has no known
rate and is reported unpriced, never as a free $0).
The codex [1m] rows
gpt-5.6-sol[1m] / gpt-5.6-terra[1m] are the codex side of the same [1m]
convention the claude rows use: the suffix is a client-side context-denominator
opt-in, not a different upstream model. Claude Code parses it out of the
configured model string to size its context readout; llmux strips one trailing
[1m] before resolving the model, so upstream never sees it and
gpt-5.6-sol[1m] reaches the backend as gpt-5.6-sol. The strip happens ahead
of every resolution rule, so a suffixed alias works too (sol[1m] →
gpt-5.6-sol), and it applies to routing as well (sol[1m] classifies to the
codex group exactly like sol). A client that sends the id verbatim — curl, an
SDK — gets the model it asked for instead of falling back to the configured pin.
The advertised 1000000 is the opt-in denominator; the measured upstream input
ceiling is close to it. Probes 2026-08-21 against the ChatGPT-account codex
backend accepted 555,029 / ~801k / ~869k / 910,229 input tokens on
gpt-5.6-sol and were rejected at ~936k with Your input exceeds the context window of this model (gpt-5.6-terra accepted 555,029). OpenAI publishes
1,050,000 total for the gpt-5.6 family. The base rows keep the openai/codex
catalog's 372000 — the window a client gets without opting in — exactly as the
claude base rows keep 200000 next to their [1m] twins. There is deliberately
no gpt-5.6-luna[1m] (luna still returns "Model not found" upstream) and no
gpt-5.5[1m] row (272k family).
Sources
Evidence gathered 2026-07-14; the claude rows and their aliases were re-curated 2026-07-27, the codex context windows were re-probed 2026-08-21 (the codex effort menus are unchanged from 2026-07-14), and the grok rows were re-probed 2026-08-26 (unchanged — see below).
- Claude rows — user-curated 2026-07-27 from the Claude Code model picker.
The
[1m]suffix marks the 1M-context variant ids. Effort menus are the Claude Code/effortlevels (low, medium, high, xhigh, max), applied per the user contract; llmux does not itself shape claude requests. The claude rows now live as theCLAUDE_MODELSconst insrc/catalog.rs, which is also the source for alias→id resolution insrc/provider/anthropic.rs. - Codex effort menus and base context windows — the openai/codex model
catalog (
models-manager/models.json), fetched 2026-07-14.gpt-5.6-sol/-terrasupport low→ultra;gpt-5.6-lunalow→max;gpt-5.5low→xhigh (context 272000). The legacygpt-5.5-codex/gpt-5-codexids are no longer curated. - Codex
[1m]context window — live probes through the daemon against the ChatGPT-account codex backend, 2026-08-21:gpt-5.6-solaccepted 910,229 input tokens and was rejected at ~936k (Your input exceeds the context window of this model);gpt-5.6-terraaccepted 555,029. This supersedes the earlier "369,755 pass / ~380k rejected" note that made 372000 look probe-confirmed. - OpenRouter rows — the live
GET https://openrouter.ai/api/v1/modelsprobe on 2026-08-21: 420 models, 21 of them withpricing.prompt == "0"; the ten curated rows take their wire slug, display name,max_context, and effort menu (reasoning.supported_efforts, re-sorted low→high) from that response. They are theOPENROUTER_MODELSconst insrc/catalog.rs, which is also the source foror-…→ slug resolution insrc/provider/openrouter.rs. The design record, including the probe evidence that OpenRouter serves a NATIVE Anthropic Messages endpoint, isopenrouter/spec.md. - Grok context window / name — the live
cli-chat-proxy/v1/modelsprobe 2026-07-14 (grok-4.5ctx 500000). Thegrok-4.6row was verified the same way against the livecli-chat-proxy/v1/modelson 2026-08-13 (ctx 500000, effortslow, medium, high, xhigh) and re-probed unchanged on 2026-08-26 with a real subscription token:grok-4.6reasoning_effortsxhigh, high, medium, low(upstream defaulthigh, ctx 500000),grok-4.5high, medium, low— noxhigh— ctx 500000. That asymmetry is why an above-highrequest keepsxhighongrok-4.6and clamps tohighongrok-4.5. Grok effort menus come from the provider's per-model thinking-level table. The curated grok set isgrok-4.6(the default pin) andgrok-4.5; other known grok ids (grok-4.3,grok-3-mini, …) pass through at request time and synthesize a null-metadata row when pinned.