Docs / Configuration
Configuration
Firstpass reads a single firstpass.toml plus a handful of environment variables. This is the full reference — ladder, gates, bandit, speculation, budgets, providers, routes and modes — and the multi-tenant options.
[ladder] and one [[gate]]. Every other section has a default and ships off — an optional feature absent from your config file is byte-invisible to callers. Add sections only when you reach for that behaviour.Config shape#
[ladder] and [[gate]]), seven optional ones. Point Firstpass at the file with FIRSTPASS_CONFIG (default: ./firstpass.toml).A minimal config is a ladder and one gate. Everything else has a default. Point Firstpass at a file with FIRSTPASS_CONFIG (default ./firstpass.toml).
# firstpass.toml — a minimal, working config
[ladder]
rungs = ["anthropic/claude-haiku-4-5", "anthropic/claude-sonnet-5"]
[[gate]]
kind = "json-valid"[ladder]#
rungs[0] and escalates up only on a gate failure. max_rungs caps how far a single request may climb.| Key | Type | Default | Meaning |
|---|---|---|---|
rungs | list of provider/model | — | Ordered cheapest→most capable. |
max_rungs | int | len(rungs) | Cap on how far a request may climb. |
rungs[0], so that entry must be your cheapest, fastest model. If rungs[0] is anthropic/claude-opus-4-8, every request starts at the top rung and pays the premium rate — there is nothing to escalate to, and the cost benefit disappears entirely.rungs[0] every time and only escalates on a gate failure.[[gate]]#
Repeatable. Each block adds a gate; all gates on a rung must pass. See Gates for the semantics of each kind.
Gate kinds
| Key | Applies to | Meaning |
|---|---|---|
kind | all | non-empty | json-valid | schema | subprocess | judge | consistency |
on_abstain | all | fail_open (default) | fail_closed |
schema | schema | JSON-Schema subset: type, required, per-property type. |
cmd, timeout_ms | subprocess | Executable + argv, and a timeout (→ abstain). |
model, rubric, threshold | judge | Judge model (must differ from candidate), rubric, score bar. |
k, threshold | consistency | Resample count and agreement bar. |
on_abstain = fail_open (the default) treats an inconclusive gate as a pass; fail_closed treats it as a failure and triggers escalation. fail_open is the safe default for gates that may time out or be unavailable.fail_open is the safe default for gates that may not always resolve.[bandit]#
rungs[0]. Gate evaluation and escalation are unchanged.The learned start-rung (detail). Default-off; default algorithm UCB1.
[bandit]
enabled = false
algo = "ucb1" # ucb1 (deterministic) | thompson (Beta, discounted)rungs[0]. Leave it off until you have enough traffic for meaningful signal.[speculation] & budgets#
[speculation]
When enabled and the current rung's gate score falls in speculation_band, Firstpass fires the next rung speculatively. If the current rung passes, the speculative call is discarded. If it fails, the next rung's answer is already in flight — saving one full rung latency at the cost of running (and paying for) a speculative call.
[speculation]
enabled = false
lookahead = 1
speculation_band = [0.35, 0.65] # only prefetch in the marginal zone
[budget]
per_request_usd = 0.05
per_session_usd = 1.00
per_day_usd = 250.00[budget]
Budget limits are hard ceilings enforced before any upstream call. A request that would exceed any ceiling is not forwarded.
| Key | Default | Ceiling scope |
|---|---|---|
per_request_usd | 0.05 | All rungs attempted for a single request |
per_session_usd | 1.00 | Cumulative spend for a session |
per_day_usd | 250.00 | Daily ceiling |
speculation_band end up passing the cheap rung anyway, you are paying for two model calls on each one — the latency saving is real, but so is the token cost. Profile your gate's actual flip rate in the band before enabling.escalation.elastic) is a separate opt-in feature — config-gated and off by default. It adjusts verification intensity proportional to doubt on the serving path and requires a calibrated λ. Do not enable it without reading Elastic verification first.[[provider]]#
name/model-id.Repeatable. Adds an OpenAI-compatible endpoint as a provider (detail).
[[provider]]
name = "myllm"
base_url = "https://api.internal.example.com/v1"
dialect = "openai" # openai | anthropic | gemini
auth = "api_key" # api_key | aws_sigv4 | gcp_oauth| Key | Meaning |
|---|---|
name | Identifier used as prefix in ladder rungs: name/model-id |
base_url | Base URL of the OpenAI-compatible endpoint |
dialect | Wire format: openai | anthropic | gemini |
auth | Auth method: api_key | aws_sigv4 | gcp_oauth |
name/model-id. See Providers for API key wiring.[[route]] & modes#
routing_mode. The per-request x-firstpass-mode header overrides the route default. Six modes from full passthrough (observe) to always-top (max).Routes let different traffic use different ladders and a per-route default routing_mode (overridden by the x-firstpass-mode header — see mode precedence).
[[route]]
match = "/v1/chat/completions"
routing_mode = "cost" # observe|cost|balanced|quality|latency|maxRouting modes
| Mode | Behaviour |
|---|---|
observe | Byte-passthrough; no routing decisions, receipts recorded only |
cost | Cheapest rung that clears the gate |
balanced | Balance cost against quality |
quality | Prefer quality; climb earlier |
latency | Prefer lowest latency |
max | Pin to the top rung (rungs[len-1]) |
Environment variables#
FIRSTPASS_MODE=observe — it records receipts and passes every request through unchanged.| Variable | Values | Meaning |
|---|---|---|
FIRSTPASS_MODE | observe | enforce | Shadow vs live. Start with observe. |
FIRSTPASS_CONFIG | path | Config file (default ./firstpass.toml). |
FIRSTPASS_DB | path | Receipt / state store location. |
FIRSTPASS_BIND | host:port | Listen address (default :8080). |
FIRSTPASS_RECEIPTS | best_effort | durable | Never-drop receipts (detail). |
FIRSTPASS_MODE_PROFILE | mode name | Env-level default mode. |
FIRSTPASS_MAX_CONCURRENCY | int | Max in-flight upstream requests. |
FIRSTPASS_MODE=observe is a byte-passthrough: every request is forwarded verbatim to the upstream, receipts are written, but no routing or gate decisions are made. The model and the caller see no difference from a direct connection — it is the zero-risk way to instrument an existing agent. Switch to enforce once you have validated your ladder and gate config against observe-mode receipts.FIRSTPASS_MODE=observe is shadow mode — zero behaviour change, full receipts. Switch to enforce to activate routing.Multi-tenant#
Multi-tenancy is opt-in and default-off. When enabled it provides Argon2id keyed auth, AES-256-GCM key custody, and per-tenant rate limits.