One router · many models · decisions you can read
Route each request by the concept it belongs to.
Not by a guess at how hard the prompt looks. Concepts are written down, reviewed in a pull request, and readable by a person — and hard constraints gate before any preference ranks, so no score can outvote a requirement.
$ curl -s api.fiferouter.com/v1/explain -d '{"text":"can this retry double-charge the customer?"}' concept moneypath.verify confidence 1.0 (embedding) objective quality eliminated vendor-frontier — residency chain infra-large chosen infra-large
The request was classified into a concept, the concept pinned residency to in-infra, the pin eliminated the strongest model in the pool, and what was left is what ran. No provider was called — so a routing change can be reviewed against real phrasing before it ships.
The order is the whole safety story
Filter, then rank, then stick.
Ranking and stickiness are handed the survivor set, never the pool — so a preference has nothing to reach past. It is a property of the call graph, not a rule someone has to remember.
Four artifacts, kept apart on purpose
Adding a model is a config edit.
It never touches a concept and never requires a retrain. That separation is the entire maintenance story.
Concept catalogue
What kinds of request exist. A description, at least three exemplars, required capabilities, hard constraints. Adding a route is an example sentence.
Pool
What can be reached, and on what terms — residency, tier, context window, capabilities, price. Adding a model is a row.
Policy table
Concept → ranked candidates plus one objective. The ranked list is also the fallback chain.
Decision log
One record per model attempt — fallbacks, refusals and errors included. Routing metadata only, never prompt or response content.
Explainable, or it doesn't ship
Every choice leaves a record.
It names what served you
The response's model field is the model that actually ran, not the one you asked for. A router that reports the request rather than the result is unauditable.
Refusals are typed
402 for a spend cap — never a quiet downgrade to something cheaper. 422 when hard filters leave nothing compliant. 502 when the chain is exhausted.
Your prompt stays out of it
The decision record is a closed set of typed fields with no free-form extra. Leaking content would take a deliberate schema change, in a diff a reviewer would see.
See it decide.
Type a request. Watch it get classified, watch the filters eliminate models, and see what it would route to — without spending a token.
Open the playground