On a Tuesday in March, a procurement analyst pointed a browser agent at a supplier portal and asked it to "pull every line item and flag anything unusual."
There were 4,200 line items. The agent opened each one. Each page it opened became context for the next model call, the one deciding where to click next. Every item it flagged as unusual spawned a follow-up task, and each follow-up queried the data warehouse to compare that line against historical spend. Some of those follow-ups flagged anomalies of their own. Which spawned their own follow-ups.
Nobody set a depth limit, because nobody knew there was a depth to limit.
It ran for nineteen hours. The analyst found out on Wednesday morning, when a Slack alert fired about warehouse credits.
Here's what that Tuesday cost. Only one of these lines arrives on a bill with the word "AI" anywhere on it:

Tokens were 28% of it.
When the CFO asks what happened, "our AI usage went up" won't survive the follow-up question. It tells the room you can't see your own environment. And there's a second question waiting behind it, the one your CEO has probably already asked: who's actually getting value out of this, and who's just burning money?
Both are answerable from data you can start collecting this week.
Term Definition
If you already run AI infrastructure, skip this. If you're the one being asked the questions rather than the one running the tools, these five terms carry the whole argument.
Token. The unit AI vendors meter and bill. Roughly three-quarters of a word. You buy them by the million.
Context. Everything the model gets shown on a single request: your instructions, the list of tools it's allowed to use, any files it has opened, and the conversation so far. This is the important part. The model remembers nothing between requests, so the entire context is re-sent every single time.
Turn. One request and response. A person using a chatbot takes a handful of turns. An agent working on its own can take hundreds, and every one of them re-sends that whole context. This is why an agent's cost grows faster than the amount of work it's doing.
Cache. A way to avoid paying to re-process the unchanged part of the context on every turn. Cheap when it works, and more expensive than not using it at all when it breaks. There's a worked example below.
MCP server. A connector that plugs an agent into an outside system: your ticketing tool, a database, Slack. Adding one changes the list of tools the agent can see, which turns out to matter a great deal for your bill.
The four questions you'll get asked
Every conversation a CIO has about AI spend collapses into four questions. They need four different answers from four different places, and the vendor invoice can't give you any of them.
- Why did it go up?
- Who spent it?
- Is anyone getting value?
- What is this really costing us?
Take them in order.
Question 1: Why did it go up?
The invoice tells you the total changed. It won't tell you which of several very different things happened, and the fix for each one is completely different.
You need three numbers tracked over time: sessions per day, median cost per session, and p99 cost per session. Read them together and the spike sorts itself into a category.
|
What you see |
What happened |
Where to look next |
|---|---|---|
|
Sessions up, median flat |
Adoption. More people using the tool. |
Nowhere. Report it as adoption, because it's the thing you bought. |
|
Sessions flat, median up |
Behavior changed. Agents doing more per task. |
Model mix, turns per session |
|
Sessions flat, median flat, total up |
Outliers ate the budget |
Question 2 below |
|
Median flat, p99 climbing |
Runaway loops |
Guardrails, not pricing |
Ten minutes with those three numbers turns a panicked board question into a category with a next step.
When the model gets upgraded
"Our bill jumped right after the vendor shipped a new model" is a question you will get. It usually has one of four causes, and your own data can tell them apart.
The dullest explanation is that the price per token changed. Group cost by model, by week. If the mix shifted toward something pricier, you're done in one chart.
The second is that the default changed underneath you. Tools upgrade their default model, and if you never pinned one, your fleet migrated without anybody filing a ticket. Same chart catches it. A clean cutover date is the tell.
The third surprises people. A better model finishes longer autonomous chains before it gives up or asks for help. That means more turns per session, and every turn re-sends the accumulated context. Capability and consumption move together. Check median turns per session on either side of the upgrade date.
The fourth is that your cache broke, and it's worth its own section.
Cache economics, or the 12.5x math
Prompt caching is the biggest single lever on agent cost, and almost nobody outside the platform team knows how it's priced.
Remember that every turn re-sends the whole context. Most of that context doesn't change between turns: the same instructions, the same tool list, the same files. Caching lets the vendor store the processed version of that unchanging part so it doesn't have to be paid for again on every turn.
The same tokens carry three different prices depending on how the cache treats them:
|
|
Price |
When you pay it |
|---|---|---|
|
Normal input |
1x |
No caching in play |
|
Cache write |
1.25x (5-minute) or 2x (1-hour) |
The first time, when the vendor processes and stores it |
|
Cache read |
0.1x |
Every later turn that hits the cache |
The 12.5x is just the write price divided by the read price. Identical tokens, twelve and a half times the cost, depending entirely on whether the cache hit.
Here's what that looks like on a real session. Take a 100,000-token context, an agent that runs for 50 turns, and a model priced at $3 per million input tokens:

Working, the session costs $1.85. Broken, it costs $18.75. And note the trap in that third row: thrashing costs more than never having enabled caching, because you pay the storage premium on every single turn and never once collect the discount.
Now notice what didn't change down that table. The five million token count. The agent didn't do more work, the sessions weren't longer, and a usage dashboard would show three identical numbers. Only the price moved. That's precisely why this goes unnoticed until the invoice arrives.
So what breaks it? The cache matches on an exact prefix, meaning the opening stretch of the context has to be byte-for-byte identical to last time. It's checked in a fixed order, tools → system → messages, and a change at any level invalidates that level and everything below it. Since tool definitions sit at the very top, changing them invalidates the entire thing.
There's a self-inflicted version of this too, and it's common. Someone puts something that changes on every call near the top of the prompt: a timestamp, a session ID, today's date, often added for debugging and never removed. The opening bytes are now different every time, so the cache never matches, and your hit rate is zero permanently.
The fixes are unglamorous. Keep the opening of your prompts identical between turns. Put anything that changes at the end, never the beginning. Treat tool-definition changes as change-managed events with an owner. And put "did anyone touch the tool definitions?" on your cost-spike runbook, because it will not occur to anyone in the room otherwise.

Question 2: Who spent it?
Your vendor invoice aggregates to the org, maybe to an API key. That's no use for chargeback and actively unhelpful when you're hunting a runaway.
The fix takes about ten minutes, and it has to happen before you need it. If you do one thing from this article, do this one.
Stamp cost identity at the source
Claude Code, and anything else exporting OpenTelemetry (the industry-standard format tools use to emit this kind of operational data), supports OTEL_RESOURCE_ATTRIBUTES. Set it at rollout in your deployment config, and every metric leaving every machine carries your cost taxonomy:
OTEL_RESOURCE_ATTRIBUTES=department=engineering,team=platform,cost_center=CC-1024,environment=production
Read that as one variable being set to a comma-separated list. The first = assigns the variable. Every = after it sits inside the value, pairing a label with what you want that label to say:
|
Pair |
What it buys you |
|---|---|
|
|
Roll-up by department, for the exec-level view |
|
|
The level most cost conversations actually happen at |
|
|
The field finance needs to charge it back |
|
|
Separates real production spend from experimentation |
Use your own values, obviously. The last pair earns its place faster than people expect: without it, a team piloting an agent in a sandbox looks identical to production workload, and you can lose a week arguing about a number that was never real spend.
That's the whole trick. Every event now allocates itself. Skip it and no amount of downstream cleverness will tell you which team spent what, because the information was never captured in the first place.
A few attributes come free without any configuration: session.id, organization.id, user.account_uuid, and terminal.type. One caveat before you design dashboards around them. user.email, user.id, and model are not standard across every metric, so plan to join user.account_uuid against your identity provider, the system that already knows who works here, to get a human name.
The metrics that matter
The native metric surface is small, and for cost work it's well chosen:
|
Metric |
Unit |
What it's for |
|---|---|---|
|
|
USD |
Session cost, the spine of everything |
|
|
tokens |
Carries type: input / output / cacheRead / cacheCreation |
|
|
count |
Your adoption denominator |
|
|
count |
Commits produced |
|
|
count |
PRs produced |
|
|
count |
Code changed |
|
|
count |
Accept/reject, a quality signal |
Cost and output, in the same stream, keyed to the same session. Your entire ROI calculation is sitting right there, and most organizations aren't collecting any of it.
Finding the person who burned a team's worth in a day
Three queries, in this order.
Cost by user by day, sorted descending. The outlier usually doesn't need a chart.
Then cost by session for that user. A thousand small sessions means you have a workflow problem. One enormous session means you have a runaway.
Then token type mix and turn count on the big session. Heavy cacheCreation alongside a high turn count is the signature of an agent grinding through context that keeps growing.
Then make it permanent. Alert when a session exceeds some multiple of your trailing median session cost, and when a user exceeds a multiple of their own trailing daily median. Absolute thresholds go stale within a quarter. Relative ones don't. This is the difference between finding out at turn 200 and finding out on Wednesday.
Question 3: Is anyone getting value?
This is what your CEO actually asked, usually phrased as "who isn't using this properly." Better question than it sounds, because the answer splits into three groups that need completely different responses.
Dormant seats. Licensed, zero sessions in the last 30 days. Cross your seat roster against distinct active users and reclaim or reassign. This is the fastest money in the exercise, and it's worth running the query before you assume the number is small.
Active and productive. Sessions that turn into commits, PRs, merged work. Measure these with cost per merged PR, or cost per closed ticket if your teams aren't shipping code. That's your unit economics.
Active, expensive, and not producing much. Your rabbit holes.
That third group is where the instinct goes wrong. It's rarely a discipline problem, and treating it as one will poison your rollout faster than the cost will hurt you. Usually it's a task scoped too broadly for an agent, a guardrail that was never set, or somebody who hasn't yet worked out where the tool is strong. Coaching and better defaults, not a leaderboard.
One signal that gets ignored: claude_code.code_edit_tool.decision records accept versus reject. A high reject rate means you're paying full price for output your engineers throw away. It shows up as a cost problem, but it's a quality problem, and it's often the earliest sign a team has the agent pointed at the wrong kind of work.
The number to give the board
Stop reporting AI spend. Report cost per outcome, with a trend.
"We spent $80,000 on AI last quarter" invites exactly one response: "make it less" and you cannot win that conversation. Whereas "we're at $41 per merged pull request, down from $63 last quarter, on 38% more volume" is a different meeting entirely. Same money just arrives as an efficiency story that has a direction.
Question 4: What's it really costing?
An AI agent is a workload generator. The tokens are the receipt for the thinking, and everything the agent then goes and does lands on somebody else's budget line. There are four bills, and most organizations only watch the first.
The AI invoice is tokens, and it's frequently the minority of true cost.
Then there's the infrastructure your agents move. An agent that opens 60 draft PRs triggers 60 pipeline runs, and a wide test matrix turns that into thousands of runner minutes. Add sandbox and container compute, egress, and artifact and log storage.
The third bill is metered services the agent calls, and this is where the real money hides. Warehouse credits, because an agent exploring a dataset will cheerfully scan tables a human analyst learned to avoid in week two. Per-call SaaS and enrichment APIs. Search APIs. Anything you pay for by the request, being called by something that never gets tired.
The fourth is observability. You switched on telemetry to understand the first three, and your SIEM charges by the gigabyte. Turning on content capture can multiply AI-tool log volume considerably. Worth doing, but budget for it deliberately, and filter and route before you ingest rather than storing everything and sorting it out later.
An agent has no cost intuition. A junior analyst learns within a fortnight not to SELECT * against a 40-terabyte table. An agent will do it two hundred times if the loop tells it to, at three in the morning, without hesitating once.
None of that is an argument against agents. It describes the guardrails they need, and guardrails are something engineering organizations already know how to build. It also shifts the conversation off "AI is expensive" and onto something you can actually staff.
Putting the traces together
This is a join problem, and the order matters more than the tooling.
- Stamp identity at the source.
OTEL_RESOURCE_ATTRIBUTESwith cost center, team, department, environment, set before rollout. Everything downstream depends on it. - Give agents their own identities. Distinct service accounts, API keys, and warehouse roles per agent workload. If your agents borrow a human's credentials, cross-system attribution is impossible and you'll never connect a warehouse spike back to a session. A five-minute decision at rollout that determines whether step 6 works at all.
- Land AI metrics next to your cost exports. Normalize agent telemetry into the same store as cloud billing, CI/CD usage, and warehouse query history, on the same time base and shared keys. This is the step people skip, and the one that decides whether a question takes a single query or four exports and a spreadsheet.
- Build a session spine. One row per session.id carrying cost, tokens by type, turn count, duration, user, team, cost center, and the commits and PRs that came out of it. That table alone answers Questions 1 through 3.
- Resolve identity by joining
user.account_uuidto yourIdPfor names and org structure. - Attach the downstream spend, using the session's time window and the agent identity from step 2: CI runs it triggered, warehouse queries it issued, metered API calls it made, egress from its host. Now Question 4 is answerable too.
The same Tuesday, traced
With that spine in place, Wednesday morning takes about fifteen minutes.
Cost by day shows Tuesday at 6x the trailing median. Cost by user puts 94% of the excess on a single account_uuid, which rules out a fleet-wide pricing change. Cost by session finds three sessions, one of them running nineteen hours.
Then the diagnosis. Token mix on that session is 71% cacheCreation, meaning context churned on every turn and nothing was ever reused. Turn count is north of 12,000. Joining to CI by the agent's identity turns up 61 PRs opened inside the window, each firing the full matrix. Joining to the warehouse by service account turns up 900 queries, several of them unbounded scans.
The root cause isn't that the agent misbehaved. Three controls were missing: a depth limit, a per-session budget cap, and any constraint on recursively spawning subtasks. All three are configuration. All three are an afternoon's work, once you can see them.
The uncomfortable summary
A lot of organizations deployed AI agents with the cost controls appropriate to a text editor and the spending power of a small data center.
The instrumentation to fix that isn't exotic. Cost, tokens by type, sessions, commits, and PRs are emitted natively today. Cost centers can be stamped onto every event with a single environment variable. The join to the rest of your infrastructure spend is a time window and an identity.
The data usually exists. What's missing is that nobody collected it, nobody allocated it, and it never landed anywhere it could be joined against the rest of the IT bill. So a fifteen-minute question turns into a three-week project that still ends in a guess.
The invoice arrives before the explanation. Collect the data now, while the question is still hypothetical.