You already have to answer "what did this client's AI usage cost me" every month. Today you answer it by dividing one opaque provider invoice by guesswork, then absorbing the difference. Kevin writes one row per inference request, tagged with the work item that caused it, to a database on your own disk. Cost stops being an allocation argument and becomes a query.
A spend dashboard tells you the total. It cannot tell you which engagement produced it, because the provider never knew. Attribution has to be carried on the request, by the party that knows which client it is for: you. Kevin reads that tag off the request header and writes it to the same row as the cost.
Claude Code, an agent, a batch job. Anything that speaks the Anthropic Messages API, which is the inbound surface the proxy serves. Stamps the engagement on the request.
X-Kevin-Ticket: ACME-4471
One base URL. Reads the attribution headers, calls the backend, measures tokens and latency for that exact call.
fabric_proxy/server.py
Written synchronously on your disk, with the ticket and holon columns indexed so a per-client rollup is one GROUP BY.
KEVIN_HOME/db/walt.db
The insert is synchronous and lock-guarded, and a ledger failure logs and drops rather than failing your client's request. That is the correct tradeoff for a billing artifact sitting in a production path, and you should know it is the tradeoff we made.
daemon/fabric_proxy/telemetry.py, table fabric_calls
| Column | What it settles |
|---|---|
| ticket holon | The work item that caused the spend. Both are indexed. This is the column an invoice dispute turns on. |
| session_id tool_origin task_type | Which tool and which session. Separates a developer's exploratory session from delivered work on the same engagement. |
| input_tokens output_tokens | The billable units, read from the provider response rather than estimated. |
| cost_routed_usd | What this one call cost, computed from measured tokens against the price table for the model that served it. Our arithmetic against published rates, not a copy of a provider invoice line. Reconcile it against the invoice; that is the point of having both. |
| model_routed provider | Which backend served it, so a provider price change is traceable to the calls it hit. |
| latency_ms | What the call cost in time, alongside what it cost in money. |
| pub_ver | Provenance. The build that wrote the row, so you can tell which code produced which numbers. |
Attribution tags are set by the caller, which means they are as accurate as your own dispatch discipline. Kevin records what you stamp. It cannot infer a client from a prompt, and it does not try.
SQLite. No export step, no vendor API, no rate limit.
-- per-engagement rollup for a billing period SELECT ticket, COUNT(*) AS calls, SUM(cost_routed_usd) AS usd, SUM(input_tokens) AS tok_in, SUM(output_tokens) AS tok_out FROM fabric_calls WHERE ts >= '2026-08-01' GROUP BY ticket ORDER BY usd DESC; -- shape only. A fresh install returns no rows. -- ticket calls usd tok_in tok_out -- ------ ----- ---- ------ -------
The same join runs in production inside the platform: run history attributes real cost per work item by querying this table on holon and ticket. The agency case is the same query with your engagement id in the column instead of ours.
daemon/src/ralph_control.py
Every request now records its routed-versus-baseline comparison as ledger columns, so a per-client savings rollup is a query like any other. The caveat is what it does with rows it cannot vouch for: a request logged before your upgrade has no baseline, and an unknown baseline is stored as unknown rather than as zero. Those rows are excluded from the money columns and counted separately, so the rollup reports its own coverage alongside the figure.
Which means a savings number over a window that straddles your upgrade is computed from part of that window. Check the coverage before you put it in front of a client. We would rather hand you a number with its denominator attached than a confident one you cannot defend.
Two dated events, both published by the vendors themselves, both landing inside one billing quarter. Check them against the vendor pages before you take our word for it.
Groq removes Llama 3.1 8B and Llama 3.3 70B from its free and developer tiers. If either is behind a client-facing feature you quoted in June, you are migrating a model under a live SLA, on someone else's schedule.
Promotional pricing on Claude Sonnet via AWS Bedrock reverts. Microsoft Foundry raises non-US Data Zone and Regional pricing from 2026-09-01. Margins modelled in July get a worse September.
A routing layer absorbs this. A direct integration eats it.
Each points at one base URL you control. None of them names a provider, a region, or a rate card.
ANTHROPIC_BASE_URL
One place decides which backend serves a model and what it costs. A deprecation is an edit here, not fifteen client migrations.
fabric_proxy/router.py, config.py
Adapters ship for Anthropic, Groq, OpenAI, Gemini and a local Ollama on your own GPU. Competitors are inventory here, not enemies.
fabric_proxy/providers/
The router carries a hard per-request cost cap and rejects an over-cap request with HTTP 402 before it reaches a provider. Read the limitation with it: the check only evaluates when the caller supplies a size hint on the request, so it is a backstop against a known-large call, not yet a blanket guarantee against every runaway loop. Treat it as one control, not the control.
HARD_COST_CAP_USD in fabric_proxy/config.py, raised as CostCapExceeded
Kevin does not silently substitute a cheaper model behind your client's back. The default path serves the model the tool requested, maps it to the right provider, enforces the ceiling and records the result. Tier-based model selection exists and is opt-in per deployment. We would rather you know that than discover it.
Paid, because a free trial buys attention rather than a decision. Thirty days, because that is one billing cycle, which is the only interval at which this is worth judging.
The daemon and fabric proxy on hardware you already own. The routing decision is a local function call: no vendor control plane sits between your request and your model, and nothing phones home to make it. Prompt content goes to the backend you point it at, and nowhere else.
One base URL on one client workload, plus an attribution header on dispatch. No code changes in the tools themselves. Start with one engagement, not fifteen.
One month of per-request rows for that engagement, on your disk, in a SQLite file you can query, export or hand to a client. Plus an honest read on whether the attribution survives contact with your own billing process.
The test we would apply: take the day-30 rollup into a client QBR. If it does not answer the cost question better than the invoice you take in today, do not renew. That is the whole evaluation, and it does not require a benchmark from us.
These are the cases where you should keep renting, and we would rather you learn them on this page than three weeks into a pilot.
One more that is easy to miss: owned hardware is not automatically cheaper any more. Memory and accelerator prices moved against self-hosting through 2026. The honest framing is that this makes hardware you already own worth more, and routes overflow to rented capacity rather than pretending you never need it.