The engineering companion to "What It Actually Costs to Run an AI Workforce." Everything below is the shipped system, not a design doc.
The subsystem is the meter, not an agent
The earlier appendices each dismantled one teammate. This one, like the safety appendix before it, has no teammate to dismantle, because cost accounting in this system is not a feature of Pulse or Scout or Memo. It is a property of the runtime they share. Every model call any agent makes passes through the same three steps: the tokens it used are captured, priced against a fixed table, and written to a row that never gets overwritten. If you want to know what an agent costs, you do not read that agent's code. You read the meter, and the meter is the same for all of them.
Nothing here is estimated at the model layer. The estimation only enters when we forecast — "a typical research brief costs about eight cents" — and every forecast in the blog is built from the exact prices below times a stated token count, so it can be reproduced rather than trusted.
A microdollar, and why we count in them
The unit is the microdollar: one millionth of a US dollar. It is not a flourish. A routing decision costs on the order of a thousand microdollars — a tenth of a cent — and if we stored costs in cents as floating-point numbers, that value would round to zero or drift as we summed thousands of runs. Integer microdollars keep the arithmetic exact all the way from a single tool call up to a monthly total, with no accumulated rounding error. Everything downstream (agent_runs.cost_microdollars, the daily report, the query tool) carries the integer and divides by 1,000,000 only at the moment of display.
Price × tokens = cost
The pricing lives in one small table, in microdollars per token, sourced from the published Anthropic rate card:
const PRICING = {
'claude-sonnet-4-6': { input: 3, output: 15 }, // $3 / $15 per million tokens
'claude-haiku-4-5-20251001': { input: 1, output: 5 }, // $1 / $5 per million tokens
};estimateCost(model, inputTokens, outputTokens) looks up the model, multiplies, and rounds to an integer microdollar. Two design choices matter. First, the return is { costMicrodollars, costUnknown } — a model missing from the table does not silently record $0 and vanish; it returns costUnknown: true, logs a console.warn naming the model, and the caller stamps metadata.costUnknown on the run so the gap is visible in the data rather than hidden in it. Second, the token counts are not our guess — they come straight from the model provider on every call.
Every run leaves a receipt
The agent_runs table is the ledger. Each row records input_tokens, output_tokens, total_tokens, cost_microdollars (a bigint, commented // 1 = $0.000001), the model, the agent_name, the trigger_type (cron / slack_command / slack_mention / slack_dm / webhook), steps, tools_used, tool_errors, duration_ms, and success. One model invocation, one row.
Writes go through insertAgentRun, which is a plain insert with onConflictDoNothing — logging is idempotent, so a retry of the same run cannot double-count the spend. The token figures are read off the Vercel AI SDK result in the executor: result.usage.inputTokens and result.usage.outputTokens, defaulted to zero if the provider omits them. That is the entire capture path: usage in, price applied, row written.
Two rows per question: the router/worker split
The single biggest cost lever is not a discount, it is model selection, and it is visible in the ledger as two rows per interaction.
Free-text messages (mentions and DMs) are first classified by the cheap model. MODEL_IDS.ROUTER is Haiku, and that routing call is logged as its own agent_runs row with agent_name: 'router'. Only then does the chosen agent run on MODEL_IDS.TASK, Sonnet, logged as a second row. Both rows carry their own token counts and cost_microdollars from the same estimateCost call.
The economics are stark per message: a routing pass is roughly 800 input + 30 output Haiku tokens ≈ 950 microdollars, about a tenth of a cent. Sending every message straight to Sonnet would skip that tenth of a cent but pay Sonnet's rate to answer questions Haiku could triage for a third of the input price. Slash commands carry an explicit agentHint and skip routing entirely (no router row at all), because the user already named the agent — you do not pay to classify what was not ambiguous.
The daily report that never calls a model
Once a day, runDailyCostReport aggregates the previous 24 hours and posts a per-agent-plus-total breakdown to OPS_SLACK_CHANNEL. The aggregation is one grouped query, getDailyCostSummary: SUM(cost_microdollars) and COUNT(*) grouped by agent_name over started_at ∈ [from, to). The report formats each agent as $X.XXXX (N runs), a divider, then the total.
The point worth making is what the report does not do: it never calls an LLM. The cron dispatcher handles it before any agent normalization, on the COST_REPORT_CRON = '15 14 * * *' schedule. So the subsystem whose job is accounting for spend adds nothing to the spend — it is arithmetic and string formatting over rows we already wrote. The same cron piggybacks two cleanup passes (expired OAuth states, old conversation messages), also LLM-free.
Cron agent work is metered like everything else: the pulse daily and weekly summaries each log their cost, stamping metadata.costUnknown when a model is unpriced. The report reads those rows; it does not generate new ones.
Pulling the real numbers
The daily post is the summary; the ground truth is queryable. docs/marketing/tools/cost-queries.mjs connects to the same Postgres and runs the analyst's version of the report: all-time span and totals, last-30-days per agent (with average cost per run), spend by trigger type, and per-agent slices — pulse cron summaries, Scout interactive research, Memo runs, the Haiku router line. Because every run is a row with a model, a trigger, a timestamp, and an exact cost, "what did Scout's research actually cost us last month, on average, per brief" is a GROUP BY, not a spreadsheet exercise. The figures in the blog are worked from the price table for reproducibility; this is the tool that reads what was truly spent.
The honest limits
Where the accounting stops, stated plainly:
- Inference is not total cost of ownership. Everything metered here is the model's charge. It excludes infrastructure (Cloudflare Workers, Neon Postgres, Hyperdrive, Workers AI embeddings), the one-time build, and ongoing human oversight. A single "the AI costs $X" number that folds those together is doing something the meter deliberately does not.
- The per-task figures are forecasts. The receipts in
agent_runsare exact; the "about four cents" style claims are price × typical tokens. A task over an unusually large document costs proportionally more, and a heavy-context Scout run can run several times a light one. - Unpriced models read as zero until added.
estimateCostrecords$0+costUnknownfor a model not inPRICING. Swap the provider (the SDK makes this a one-line change) and until its rates are added, its runs undercount — flagged inmetadata, but a real gap. - Embeddings are not in this table. Semantic-search embedding calls run on Cloudflare Workers AI and are not priced into
agent_runs; the microdollar ledger is the LLM meter specifically.
The cost split, with the arithmetic
The arithmetic that underpins the blog, in one place, from the prices above:
Action | Model | Input tok | Output tok | Microdollars | ≈ USD |
|---|---|---|---|---|---|
Route one message | Haiku | 800 | 30 | 800×1 + 30×5 = 950 | ~$0.001 |
| Sonnet | 5,000 | 400 | 5,000×3 + 400×15 = 21,000 | ~$0.02 |
Pulse daily summary | Sonnet | 10,000 | 800 | 10,000×3 + 800×15 = 42,000 | ~$0.04 |
Memo transcript digest | Sonnet | 10,000 | 1,000 | 10,000×3 + 1,000×15 = 45,000 | ~$0.05 |
Scout research brief | Sonnet | 20,000 | 1,200 | 20,000×3 + 1,200×15 = 78,000 | ~$0.08 |
Every figure is input × input_price + output × output_price, the exact expression estimateCost evaluates. The reason we can publish this at all is that the system was built to answer it from its own records — not to reconstruct it later from an invoice, but to write the receipt at the moment of the spend. Metering was a design decision, and this table is what it buys: a cost you can check, one call at a time.
Building something like this, or trying to work out what your own agents really cost to run?
Back to the non-technical story.
