// model gateway LIVE

OpenRouter

One key, every model, priced per token

OpenRouter is what keeps Fulltrace multi-provider and cheap to run. One API key unlocks a whole catalogue of models, paid per token with no subscriptions. If a model fails mid-run, the job moves to the next one on its route, and every run is priced before it starts.

01 api key 00 subscriptions 04 role profiles 6h catalogue cache
why_openrouter [01]

Multi-provider by design

The routing philosophy across Fulltrace is not "use the strongest model everywhere". It is: use the cheapest capable model for each stage, keep repeatable work in code, and spend intelligence where it matters. That only works if switching models is trivial, and that is what OpenRouter provides: one endpoint, one key, one bill, and the whole catalogue behind it.

Model choice is a route, not a fixed value: a failed provider call moves the job to the next model in line, and the attempt is recorded in telemetry. The fix-proposal stage narrows this to transport-only failover, pinned to Claude Sonnet 4.5, so a network blip can never quietly hand a code fix to a weaker model. The full failover story lives with the runtime, on how it works; the Codex role profiles that ride this gateway live on the codex page.

Key handling follows the secrets guardrail (G10). The OPENROUTER_API_KEY lives in a user-scope environment variable, read at runtime, never stored in the repo, in config, in queue payloads, or in reports.

Multi-provider is a stance, not a bullet point: no single vendor decides what Fulltrace can run, and no subscription decides what it costs.
Where it plugs in
01Codex role profiles: four jobs, four models
02Runtime model routes with failover
03The shared model picker in Studio
04Per-model cost tracking and pricing
Status

Live and in daily use: failover routes are active, the catalogue picker is live in Studio, and four Codex role profiles run through the managed config block.

model_picker [02]

The catalogue, one keystroke away

One shared picker replaced every scattered model input in the dashboard: a searchable, grouped list over OpenRouter's live catalogue, wired to the fix-proposal model and every per-stage and per-run override. The parsing, grouping and free/paid logic behind it is a pure module covered by 23 tests, and marking is conservative: only a model priced at exactly zero counts as free.

model_picker_internalsgroups, fallback layers, endpoint
Curated groups
Claude, Codex/GPT, Other

A code-owned mapping folds OpenRouter's provider IDs into three tool groups, and the current selection is pinned at the top under its own heading, so the pick is one glance and a search away.

Never empty
Four layers of fallback

Live fetch first, a six-hour cache behind it, a stale cache behind that, and a curated built-in list as the floor. Offline or mid-outage, the picker still renders a full list.

No new surface
Metadata, not authority

The catalogue is fetched direct from the extension over a public GET: no API key needed for metadata, no new gateway endpoint, no new authority. The picker writes only config that was already writable.

cost_and_policy [03]

Priced, then accounted for

Every run gets a cost estimate before I confirm the spend, priced by a shared module that covers Anthropic, OpenAI and OpenRouter alike and attributes every token to the model that actually did the work (the dashboard shows it in action). One rule applies throughout, guardrail G1: the tightly rate-limited free models never run the jobs that check or change code. Nothing runs blind, and nothing hides in the totals.

Attribution
Every token accounted for

Usage and cost for every model shows up on the dashboard: per-model session and all-time totals, including OpenRouter model IDs alongside Claude usage. Building it surfaced a real bug: cached and reasoning tokens were being double-counted as additions when they are subsets. Fixed, and the totals are honest.

Balance
What is left, live

The dashboard also shows, live, how much OpenRouter credit is actually left, kept separate from what the subscription plans cover, so a run is never launched into an empty account.