Docs / How it works
How it works
Firstpass is a proxy that sits in front of your provider calls. A request enters, moves through route → prove → escalate → serve, and its outcome feeds back to the router. Here is the full journey.
The request flow#
The client keeps its existing endpoint — POST /v1/messages or POST /v1/chat/completions. Firstpass intercepts, runs the cascade, and returns a normal response. The identical served bytes go back to the client; everything else is bookkeeping.
1 · Route#
rungs. There is no per-prompt classifier deciding which model should answer before any output exists. The cheap model takes every first pass. An optional learned start-rung bandit can shift where the cascade begins for traffic classes it has seen escalate repeatedly, but it never changes what gets served — only the gate decides that.The request opens on the start rung — by default the cheapest model in the ladder. Rungs are ordered cheap-to-capable and named provider/model:
The ladder
[ladder]
rungs = [
"anthropic/claude-haiku-4-5", # rung 0 — start here
"openai/gpt-mini", # rung 1
"anthropic/claude-sonnet-5", # rung 2
]No classifier — proof instead
There is no per-prompt classifier deciding which model. The cheap model simply takes the first pass. An optional learned start-rung bandit can move the entry point for classes of traffic it has seen escalate — but that only sets where the cascade begins, never what it serves.
model field. For routing decisions it reads: model name, tool count, image blocks, and request headers. It does not inspect, summarize, or rewrite the message history — and tool_use/tool_result blocks are forwarded byte-for-byte, not re-verified.2 · Prove#
What a gate sees that a classifier can't
The candidate output is handed to the gate — the heart of the system. A gate reads the actual response and returns a verdict: pass, fail, or abstain. Firstpass ships five kinds (full detail): inline checks, JSON-Schema, a bring-your-own subprocess, a native LLM judge, and self-consistency.
If the gate passes, the output is served immediately and the cascade stops. On 974 MBPP tasks, that first-rung pass happened for 82% of requests.
json-schema gate can catch a hallucinated field. An inline check catches a missing key in microseconds. A subprocess gate can run cargo test or pytest on the actual output. These are things a prompt-time classifier decides blind — the gate has the answer in hand before it rules.llm-judge gate incurs a second model call, and its cost is reported separately in the receipt's gate_cost_usd field so you can see it clearly.3 · Escalate#
max_rungs, per-request/session/day budgets, and a hard termination guarantee: on exhaustion, Firstpass serves the best attempt — a real model answer, never a router error in place of a completion.On gate failure, Firstpass climbs exactly one rung and re-runs the candidate + gate. Escalation is bounded:
The four rules
- One rung at a time — never a jump straight to the top (unless
maxmode asks for it). - Budget-capped — per-request, per-session, and per-day caps stop runaway spend;
max_rungscaps the climb. - Cross-provider failover — a transport error or 5xx from a provider fails over to the next rung, which can be a different provider entirely.
- Speculative (optional) — in the marginal gate-pass zone, prefetch the next rung in parallel so a likely escalation doesn't pay serial latency. Served bytes are byte-identical to the serial path.
Failover vs escalation
See Routing & escalation for the ladder, the bandit, speculation, and budgets in full. Failover (triggered by a 5xx or transport error) and escalation (triggered by gate failure) both advance one rung, but they are logged separately in the receipt so you can distinguish "provider down" from "output failed the gate."
max_rungs caps the climb, budget caps stop runaway spend, and on exhaustion the served-failure guarantee kicks in: a real model answer goes back to the client, never an error message in place of a completion.4 · Learn#
POST /v1/feedback. These drive adaptive conformal calibration (Gibbs–Candès), which nudges the serve threshold as your traffic distribution drifts over time. Two Prometheus gauges expose the live state of the loop.Deferred outcomes
Serving is not the end. When the true outcome of a request becomes known later — a test passed in CI, a user accepted the answer, a reviewer flagged it — you report it to POST /v1/feedback. Those deferred outcomes drive adaptive conformal calibration (Gibbs–Candès), which nudges the serve threshold as your traffic drifts. Two Prometheus gauges expose the loop live: firstpass_serve_threshold and firstpass_realized_served_failure. See The guarantee.
The calibration loop
/v1/feedback; conformal calibration keeps the serve threshold honest as traffic drifts.Observe vs enforce#
FIRSTPASS_MODE=observe to shadow the cascade without changing what's served. Every receipt records the full decision — rungs tried, gate verdicts, what would have been served — so you can validate before going live. Flip to enforce once the numbers convince you.Firstpass runs in one of two modes, set by FIRSTPASS_MODE:
Recommended rollout
The recommended rollout is observe first — collect a few days of receipts, run firstpass savings and firstpass evals to see what the cascade would have done — then flip to enforce once the numbers convince you.
firstpass savings and firstpass evals, then flip to enforce with data behind you.Anatomy of a decision#
What's in a receipt
Every request produces one receipt capturing the whole decision — the rungs tried, each gate verdict, the mode in force, the cost, and the chain link. A trimmed example:
{
"seq": 4021,
"request_id": "req_9f2c…",
"mode": "balanced",
"attempts": [
{ "rung": 0, "model": "anthropic/claude-haiku-4-5",
"gate": [{"name": "json-valid", "verdict": "pass"},
{"name": "schema", "verdict": "fail", "reason": "missing 'total'"}],
"cost_usd": 0.0003, "escalated": true },
{ "rung": 1, "model": "openai/gpt-mini",
"gate": [{"name": "json-valid", "verdict": "pass"},
{"name": "schema", "verdict": "pass", "score": 0.83}],
"cost_usd": 0.0018, "served": true }
],
"gate_cost_usd": 0.0000,
"total_cost_usd": 0.0021,
"prev_hash": "sha256:a91f…",
"hash": "sha256:5c02…"
}Inspecting after the fact
Inspect any decision after the fact with firstpass trace <request_id> or firstpass explain. The receipt is the ground truth — see Receipts & audit.
prev_hash field chains each receipt to the previous one using SHA-256. This makes the log tamper-evident: any deletion or modification of a past receipt breaks the chain. The receipt store is append-only by design, and firstpass audit walks the chain and reports the first broken link.firstpass trace <request_id> retrieves any decision by ID.