Lobstack: A receipt for every model call
An OpenAI-compatible gateway whose real output is not the routing. It is the line underneath: which model served the call, what it cost, and what any saving was measured against.
Solo — gateway contract, SDK, CLI, MCP server · 2026
The problem
Putting a router in front of five model providers is a weekend. The claim that sells one — "we cut your inference bill 60%" — is the part nobody downstream can check. A saving is a subtraction, and a subtraction without its baseline is not a measurement, it is a mood.
The second problem is mechanical, and it defeats honest cost data before it reaches anyone. On a streamed response the price cannot exist until the provider has counted tokens, which happens after the chunk carrying `finish_reason`. The obvious reader — break out of the loop when the finish reason arrives — throws the receipt away and never knows it did.
So the product surface is the receipt, not the router. The serving stack is where the interesting engineering is; the receipt is where the trust is, and it is the only half a caller can verify.
Architecture
One call, three front doors, and the one place a price can be attached: after the provider has counted.
- Typed SDK, CLI or MCP server — one key reaches all three
- Key and scope check
- Route: the model you named, or auto
- Model providers
- Metering ledger — tokens are countable only now, after finish_reason
- x_lobstack receipt: served model, tokens, cost_usd, savings_usd with its baseline_reason
- Back to the caller: the last data frame when streaming, response headers when buffered
- Validated against the published contract in CI — OpenAPI 3.1 and JSON Schema 2020-12
Key decisions
The receipt is a published contract, not a log line
The SDK repository ships the spec next to the client: OpenAPI 3.1 for the endpoints, JSON Schema 2020-12 for the receipt itself, referenced rather than copied so there is exactly one definition. Every member of the schema carries an extension naming the response header that carries the same fact on the buffered path, and a test checks that mapping against the OpenAPI document — the streamed and buffered descriptions cannot drift apart quietly.
null means unpriced. It has never meant free
Every money field is `number | null` and nothing defaults it. There is no `?? 0` in the codebase, `formatCostUsd(null)` prints "unpriced", and the buffered path transports the same fact as an empty header value — where `Number("")` is 0, so the parser tests for the empty string before it converts. This rule is written down because a real charge rendered as $0.00 for three months before it was.
A saving is only ever shown with what it was measured against
Two very different claims share one field. `named` means you asked for a model and something cheaper served it — like-for-like, against your own request. `plan_ceiling` means you sent `auto` and the comparison is the priciest model your plan allows: a real subtraction, and the most flattering one available. The SDK returns a caveat that is non-null only in the second case, and the rule for anyone rendering it is: show the reason next to the figure, or do not show the figure.
www, never the apex
The apex answers with a 307 to the www host, and RFC 9110 requires a client to drop `Authorization` when a redirect changes host. The gateway then sees a request with no credential, and answers a perfectly good key with "401 missing credentials" — an error pointing at the wrong thing entirely. The SDK sends `redirect: "manual"`, throws instead of following, and when it rewrites the host it says so through a warning rather than silently, because a silent fix teaches you nothing about why your own code will fail the same way tomorrow.
Nothing sits between a user key and us
The SDK and the CLI both have zero runtime dependencies — `fetch`, `ReadableStream` and `TextDecoder` are in the runtime, and the SSE reader is about forty lines. A package whose entire job is to hold a live credential and read a number back does not get to pull a dependency tree to do it.
Numbers
- 0 — runtime dependencies (in the SDK and in the CLI)
- 12 — receipt fixtures in CI (six must validate, six must fail)
- 3 mo — a real charge showed as $0.00 (before null-vs-zero was a written rule)
- 4 — MCP tools (one needs no key: preview the route and the cost first)
- 0 — published savings percentages (the metering has not priced production traffic yet)
There are no latency figures, uptime numbers or savings percentages anywhere in that repository, and none on this page. The metering is new and has not priced production traffic yet, so any number of that kind would be invented. The repo says so in writing, which is the part I would want to read if I were evaluating it.
lobstack.ai · SDK + published contract · CLI · MCP server