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 /models
  • GET /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:

KeyTypeMeaning
idstringConcrete upstream model id.
aliasesarray of stringsExtra request slugs that resolve to this id (may be empty).
namestringHuman-facing display name.
effortsarray of stringsAccepted reasoning.effort values, low→high (may be empty).
max_contextinteger or nullContext window in tokens; null when unpublished.
groupstringBackend 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 bare grok request routes to that pin, so the catalog advertises the alias on exactly the pinned entry. Any grok-* id also passes through verbatim.

  • codex variant aliasessol / terra / luna resolve to the latest gpt generation of that variant (gpt-5.6-sol / -terra / -luna), and the bare gpt-5.6 id resolves to the sol flagship. 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 /models advertises is actually honored upstream.

    request slugcatalog idmodel on the wire
    fable, fable-5-1claude-fable-5-1[1m]claude-fable-5-1
    opus, opus-5claude-opus-5[1m]claude-opus-5
    sonnet, sonnet-5claude-sonnet-5[1m]claude-sonnet-5
    haikuclaude-haiku-4-5claude-haiku-4-5

    Matching is trimmed and case-insensitive (" OPUS " resolves), and an alias may carry the client-side [1m] context suffix — fable[1m] resolves exactly like fable, 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 ordinary claude-haiku-4-5 row). 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 why claude-opus-5[1m] still reaches upstream as claude-opus-5 — and foreign slugs (grok-4.6, gpt-5.6-sol) are never rewritten. The mapping has a single source, the CLAUDE_MODELS const in src/catalog.rs behind resolve_claude_alias; adding a curated row carries its aliases automatically. llmux still does not otherwise shape claude requests, and the efforts menu on claude rows is the Claude Code /effort level 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 the or- prefix that routes the request to the openrouter group in the first place. The curated mapping:

    request slugmodel on the wire
    or-ox-alphastealth/ox-alpha
    or-freeopenrouter/free
    or-glm-5.2z-ai/glm-5.2:free
    or-nemotron-3-ultranvidia/nemotron-3-ultra-550b-a55b:free
    or-nemotron-3.5-lightningnvidia/nemotron-3.5-lightning:free
    or-dots-3-notedots-studio/dots-3-note-preview:free
    or-laguna-s-2.1poolside/laguna-s-2.1:free
    or-north-mini-codecohere/north-mini-code:free
    or-gemma-4-31bgoogle/gemma-4-31b-it:free
    or-gpt-oss-20bopenai/gpt-oss-20b:free

    Three rules sit around that table, and the table is a convenience layer, not a gate:

    • bare or — like bare grok, it resolves to the live pin (config.openrouter.default_model, default stealth/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 the or- selector, so the ~400 OpenRouter models outside the curated set are reachable: or-openai/gpt-oss-20b:freeopenai/gpt-oss-20b:free. A bare openrouter/… 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.

  • alias stability — aliases float to the current generation, ids do not. opus tracks the newest curated Opus and moved from claude-opus-4-8[1m] to claude-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

idaliasesnameeffortsmax_contextgroup
claude-fable-5-1[1m]fable, fable-5-1Claude Fable 5.1low, medium, high, xhigh, max1000000claude
claude-fable-5[1m]Claude Fable 5low, medium, high, xhigh, max1000000claude
claude-opus-5[1m]opus, opus-5Claude Opus 5 [1M]low, medium, high, xhigh, max1000000claude
claude-opus-5Claude Opus 5low, medium, high, xhigh, max200000claude
claude-opus-4-8[1m]Claude Opus 4.8low, medium, high, xhigh, max1000000claude
claude-opus-4-6[1m]Claude Opus 4.6low, medium, high, xhigh, max1000000claude
claude-sonnet-5[1m]sonnet, sonnet-5Claude Sonnet 5 [1M]low, medium, high, xhigh, max1000000claude
claude-sonnet-5Claude Sonnet 5low, medium, high, xhigh, max200000claude
claude-haiku-4-5haikuClaude Haiku 4.5low, medium, high, xhigh, max200000claude
gpt-5.6-sol[1m]GPT-5.6-Sol [1M]low, medium, high, xhigh, max, ultra1000000codex
gpt-5.6-solsol, gpt-5.6GPT-5.6-Sollow, medium, high, xhigh, max, ultra372000codex
gpt-5.6-terra[1m]GPT-5.6-Terra [1M]low, medium, high, xhigh, max, ultra1000000codex
gpt-5.6-terraterraGPT-5.6-Terralow, medium, high, xhigh, max, ultra372000codex
gpt-5.6-lunalunaGPT-5.6-Lunalow, medium, high, xhigh, max372000codex
gpt-5.5GPT-5.5low, medium, high, xhigh272000codex
grok-4.6grok (pinned)Grok 4.6low, medium, high, xhigh500000grok
grok-4.5Grok 4.5low, medium, high500000grok
or-ox-alphaor (pinned)Ox Alpha (free)low, high, max1048576openrouter
or-freeOpenRouter Free Models Router200000openrouter
or-glm-5.2Z.ai GLM 5.2 (free)high, xhigh256000openrouter
or-nemotron-3-ultraNVIDIA Nemotron 3 Ultra (free)medium, high1000000openrouter
or-nemotron-3.5-lightningNVIDIA Nemotron 3.5 Lightning (free)1000000openrouter
or-dots-3-noteDots3-Note Preview (free)512000openrouter
or-laguna-s-2.1Poolside Laguna S 2.1 (free)262144openrouter
or-north-mini-codeCohere North Mini Code (free)256000openrouter
or-gemma-4-31bGoogle Gemma 4 31B (free)262144openrouter
or-gpt-oss-20bOpenAI gpt-oss-20b (free)low, medium, high131072openrouter

"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 /effort levels (low, medium, high, xhigh, max), applied per the user contract; llmux does not itself shape claude requests. The claude rows now live as the CLAUDE_MODELS const in src/catalog.rs, which is also the source for alias→id resolution in src/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 / -terra support low→ultra; gpt-5.6-luna low→max; gpt-5.5 low→xhigh (context 272000). The legacy gpt-5.5-codex / gpt-5-codex ids 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-sol accepted 910,229 input tokens and was rejected at ~936k (Your input exceeds the context window of this model); gpt-5.6-terra accepted 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/models probe on 2026-08-21: 420 models, 21 of them with pricing.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 the OPENROUTER_MODELS const in src/catalog.rs, which is also the source for or-… → slug resolution in src/provider/openrouter.rs. The design record, including the probe evidence that OpenRouter serves a NATIVE Anthropic Messages endpoint, is openrouter/spec.md.
  • Grok context window / name — the live cli-chat-proxy /v1/models probe 2026-07-14 (grok-4.5 ctx 500000). The grok-4.6 row was verified the same way against the live cli-chat-proxy /v1/models on 2026-08-13 (ctx 500000, efforts low, medium, high, xhigh) and re-probed unchanged on 2026-08-26 with a real subscription token: grok-4.6 reasoning_efforts xhigh, high, medium, low (upstream default high, ctx 500000), grok-4.5 high, medium, low — no xhigh — ctx 500000. That asymmetry is why an above-high request keeps xhigh on grok-4.6 and clamps to high on grok-4.5. Grok effort menus come from the provider's per-model thinking-level table. The curated grok set is grok-4.6 (the default pin) and grok-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.