Artificial Intelligence

The Real Cost of an AI Coding Agent: We Tracked 30 Days of Token Bills

We instrumented a single coding agent against a real backlog for thirty days, logged every request, and found the bill had almost nothing to do with the code it wrote.

Source code on a laptop screen washed in blue and violet light
Source code on a laptop screen washed in blue and violet light

We put one coding agent on a real backlog for thirty days and logged every request it made. The repository was a mid-sized service codebase, roughly 180,000 lines across TypeScript and Go, with a working test suite and a queue of 41 genuine tickets: bug fixes, a dependency migration, two small features, and a long tail of refactors nobody had got round to. One agent, one model class, one team. The month cost about 1,840 US dollars in inference.

Every figure in this piece is illustrative and comes from that single run. It is not a benchmark, it is not an average across teams, and it should not be quoted as one. Rates, tokenizers and agent harnesses all move fast enough that anyone reproducing this next quarter should expect different totals. What we think travels is the shape of the spend, because the shape follows from how agent loops work rather than from which vendor you picked.

The shape, in one line: the agent's own output was a small fraction of the tokens and a large fraction of the cost, and the volume was dominated by the agent reading the same material over and over. Almost everything we did to halve the bill was an attack on repetition, not on the model.

The single biggest line item was not the code the agent wrote. It was the code it read again.

How we instrumented it

We put a logging proxy in front of the model endpoint and recorded the usage object returned on every response: input tokens, output tokens, cache-read tokens and cache-write tokens, kept as four separate counters rather than collapsed into one number. Collapsing them is the mistake that hides everything interesting, because those four are priced very differently.

Each request was tagged with three things: the session identifier, the backlog ticket it belonged to, and the tool call that triggered it. That third tag is the one that pays for itself. Without it you can see that a session cost eleven dollars; with it you can see that four of those dollars arrived immediately after a file read that returned 2,400 lines. We emitted the same counters as OpenTelemetry GenAI metrics so they landed in the dashboards the team already watches, which meant nobody had to remember to go and look at a bespoke tool.

We reconciled our totals against the provider's own billing export once a week. Ours ran about two per cent under theirs, consistently. Some drift is expected: token-counting endpoints return estimates, harnesses inject their own scaffolding, and rounding accumulates over tens of thousands of requests. We treated anything inside a few per cent as agreement and anything outside it as a bug in our tagging.

Where the tokens actually went

Here is the split of billed input tokens across the thirty days. Again: one team, one agent, one codebase, illustrative only.

  • Conversation history replayed on each request: about 58%. This is the transcript so far - prior instructions, prior tool calls, prior tool results - re-sent because the model is stateless.
  • Tool results: about 24%. File reads, search output, test runner output, type checker output, git diffs.
  • System prompt and tool schemas: about 11%. Fixed per request, and it grows every time someone connects another tool server.
  • Human instructions: about 2%. The part everyone thinks about is the part that costs least.
  • Everything else, including retried and malformed requests: about 5%.

Why the pricing-page estimate was wrong

Before the run, someone on the team had sketched a monthly estimate from the published per-million rates and a guess at how much code the agent would write. That estimate was out by roughly a factor of six, and the error was structural rather than careless.

A pricing page prices a request. An agent bills a task, and a task is a loop. A twenty-turn session sends the accumulated transcript twenty times, so the cost of a session grows with roughly the square of its length rather than linearly. Anyone estimating from lines of code produced is measuring the output of the loop and ignoring the loop.

Three smaller effects compounded it. Tool schemas are re-sent on every request for the life of the session, so connecting five tool servers because they might be useful is a fixed tax on every turn whether or not the agent calls them. Tokenizers differ between model generations - recent frontier models from the vendor class we used count noticeably more tokens for identical text than their predecessors - so estimates carried over from last year's model understate the bill. And caching is not free: on the vendor documentation we worked from, a cache write is priced above plain input, at 1.25x for a short time-to-live and 2x for a longer one, while a cache read is a fraction of it. Cache the wrong thing and you pay a premium for a prefix that never gets read back.

The failure modes that cost the most

Four patterns accounted for most of the waste we could actually name.

The retry loop. The agent makes a tool call, it fails, it tries a variation, that fails, and each attempt drags the whole transcript with it. One migration ticket in our log burned about 140 dollars over nineteen turns and produced no merged diff; the underlying problem was a missing environment variable the agent had no way to see. Failed tool calls and their follow-on turns were roughly 9% of spend for the month.

Unbounded reads. The default behaviour of most harnesses is to read a whole file into context. Changing three lines in a 2,400-line module costs the full file, and then costs it again on every subsequent turn because it is now in the transcript. This was the single largest contributor to the tool-results slice.

Output floods. A test suite that prints per-assertion progress, a linter run across the whole tree, a search that matches a vendored directory. Each one dumps thousands of tokens of low-information text into the permanent record of the session.

Cache expiry across human pauses. Short-lived caches typically expire in minutes. A developer who kicks off a task, goes to a meeting and comes back to review has usually paid full price to rebuild the prefix. This one is invisible unless you log cache reads and writes separately.

A tool call that fails the same way twice is not persistence, it is a billing loop.

Four changes that roughly halved it

We changed four things and ran a second stretch under the same backlog conditions. Spend per completed ticket fell by a little over half. The savings below are our attribution from the logs, not a controlled experiment - we changed all four at once because we wanted the bill down, not a paper.

  • Stable cache prefixes. We froze the system prompt, the tool schemas and a compact repository map into one block that does not change within a session, and placed the cache breakpoint at its end. Volatile content - the current diff, the ticket text - goes after it. This moved a large share of input to cache-read pricing. Biggest single win, roughly 30% off the total.
  • Bounded tool output. File reads default to a line range rather than the whole file. Search returns matching lines with three lines of context, not file contents. Test output is filtered to failures. Anything over a threshold is truncated with an explicit marker so the agent knows it can ask for more. Cut the tool-results slice by about 40%.
  • A hard retry ceiling. Two failures of the same tool against the same target and the agent stops and reports rather than improvising. Pair it with a cheap pre-flight - typecheck and lint before the agent starts reasoning about a fix - so it fails on a clear error rather than a guess. Recovered most of that 9%.
  • Task-class routing. Mechanical work (dependency bumps, mechanical renames, test scaffolding) goes to a smaller, cheaper model with a tighter tool set. Design work and anything touching more than three files goes to the larger one. The routing rule is a short checklist a human applies when filing the ticket, not a clever classifier, and it has not needed to be clever.

What this log does not tell you

It does not measure quality. We tracked spend per completed ticket, not spend per ticket that stayed completed. An agent configuration that is 40% cheaper and produces changes that get reverted the following sprint is not cheaper, and thirty days is too short a window to see that clearly.

It does not include human time, which on several tickets exceeded the inference cost by a wide margin once review is counted. It also does not generalise across languages: a repository with very large generated files, or one where the useful unit of context is a whole schema rather than a function, will have a different split.

And it is one agent on one codebase. We are reporting it at Techtrendery.com because the instrumentation method is reusable and the shape was consistent week to week, not because the numbers are authoritative for anyone else.

What to do on Monday

If you are running an agent on real work and cannot currently answer the question "what did last week cost, by ticket", start here. None of this takes longer than an afternoon.

  • Log the four token counters separately - input, output, cache read, cache write - per request, tagged with session, ticket and triggering tool call. Until you have the tool tag you are guessing.
  • Reconcile against your provider's billing export weekly and investigate anything more than a few per cent apart, because the gap is usually your tagging rather than their meter.
  • Find your top five sessions by cost and read them end to end. In our log, four of the five had an obvious pathology visible within a minute of reading.
  • Set a hard retry ceiling and a tool-output size cap today, before you touch caching. They are configuration changes with no architectural cost.
  • Then place one cache breakpoint at the end of your genuinely static prefix, and verify from the logs that cache reads actually appear. If you see writes without corresponding reads, you are paying the write premium for nothing.
  • Put a budget alert on spend per ticket, not spend per month. The monthly number tells you that something went wrong after you can no longer find out what.

Sources and further reading

How this article was produced

Written by Daniel Osei and edited to the Techtrendery.com editorial policy. Figures described as illustrative are exactly that and are labelled in the text. If you find an error, tell us through the contact page — corrections are published in place with a dated note.