What Does a Month of Autonomous Coding Agents Cost? My Ledger: 106.8M Tokens, 1,128 Shipped Tasks, €0 Revenue
📅 August 5, 2026 · ⏱️ 6 min read
If you are evaluating autonomous coding agents, the question you actually have is “what will a month of this cost me?” — and every page you find answers a different question. Vendor pages price a token. Benchmarks price a benchmark. Neither prices what you care about: one finished, reviewed change landing in your repository.
I have run two independent agent loops on one box for four weeks. Every run appends a line of accounting to a log: tokens spent, tasks planned, tasks that passed an independent verifier, and why the run ended. This post is that ledger, recomputed from the raw log on 2026-08-05, plus the one failure mode that cost more than any other and that no pricing page will ever warn you about.
The denominator matters more than the number
Before any figure: a shipped task here means a change that a separate verifier agent re-checked against the acceptance criteria and passed. It is not a task an agent declared finished. That distinction is the whole ballgame: self-reported completion inflates the count and deflates the cost-per-task, and it is the easiest place for a benchmark to flatter itself.
The other denominator is runs. A run is one wake-up of the loop: plan, build, verify, stop. A run may ship several tasks or none.
Here is what the two logs held on 2026-08-05, counting every scored run and skipping resume markers (bookkeeping lines that record no spend):
| Runs | Tokens | Shipped tasks | Tokens per shipped task | |
|---|---|---|---|---|
| Loop A (2026-07-08 → 08-05) | 495 | 58,779,407 | 722 | ~81,400 |
| Loop B (2026-07-09 → 08-05) | 442 | 48,067,199 | 406 | ~118,400 |
| Combined | 937 | 106,846,606 | 1,128 | ~94,700 |
Roughly 95,000 tokens per shipped task, averaged over 937 runs and four weeks.
Two loops on the same engine differ by 45% on that ratio, which tells you the figure is a property of the work, not the tooling. Loop A did many small, well-specified changes to code that already had tests; Loop B did fewer, larger, more open-ended ones. A cost-per-task quoted without saying what kind of task is decoration.
The number moved when I recomputed it
I want to be blunt about this, because it is the most useful thing here. My own working notes carried “~155k tokens per shipped task” for weeks. When I sat down to write this post and recomputed it from the raw log rather than from memory, it came out at ~95k.
The remembered figure was about 60% too high. It was not a lie; it was a real measurement taken earlier over a smaller, more expensive window, which then got repeated as a standing fact while the denominator kept growing underneath it. That is how internal metrics rot: not by being wrong when written, but by being right once and never re-derived.
If you take one habit from this post, take that one. The recomputation is four lines:
const rows = require('fs').readFileSync(LOG, 'utf8').trim().split('\n')
.map(JSON.parse).filter((r) => !r.resumeMarker);
const tokens = rows.reduce((a, r) => a + (r.spentTokens || 0), 0);
const shipped = rows.reduce((a, r) => a + r.verified, 0);
console.log(rows.length, tokens, shipped, Math.round(tokens / shipped));
The expensive part is not the work, it is the deadlock
Every run records why it stopped. Across the two logs on 2026-08-05, the endings were: Loop A — 469 runs ended having shipped tasks, 23 ended reporting no work available, 3 hit an agent timeout; Loop B — 403 shipped, 39 reported no work available. That last category is the one that costs money, because a run that finds nothing to do still pays to plan, read state, and reason about the board before giving up. Loop B’s 39 empty runs consumed 2,103,996 tokens, about 4.4% of that loop’s 48,067,199 for the month, and produced zero shipped tasks.
Most were legitimate; an empty board is allowed. Four were not.
On 2026-08-01 at 22:33, 22:57 and 23:28 UTC, and again on 2026-08-05 at 10:16, four consecutive runs spent 95,400 + 90,886 + 139,273 + 111,756 = 437,315 tokens and shipped nothing, each reporting an empty queue. At the combined ~94,700 tokens per shipped task, that is roughly four and a half tasks’ worth of budget spent on nothing.
The board was not empty. Three jobs sat on it the entire time.
The cause: a safety filter rejects any job whose verification command contains dangerous shell — sudo, git push, writes into system directories. One job’s command contained the literal string /var/www, for an innocent reason. The job description said the work was “committed but not yet deployed,” and the only way to check that is to look at the web root. The description created the phrase; the phrase tripped the regex; the job was dropped before any worker saw it.
Then two things turned a dropped job into a stuck month. A one-job-per-repository rule meant no substitute could be tried. And the run, having filtered its own queue to empty, reported an empty queue — the honest thing to say and the least useful. Every subsequent run got identical inputs and made the identical decision, silently.
A quarter of a million tokens, then some, to find a typo in a job description.
A drop filter without a safety valve does not degrade — it deadlocks
Here is the generalisable part, and it is why I am writing this rather than just fixing my regex.
The same file contains a second filter. It rejects jobs whose titles don’t match a required format. That one has an explicit escape hatch: if every job was rejected on title format alone and nothing else survived, it readmits exactly one, logs loudly that the planner is misbehaving, and lets the run proceed. The comment says it plainly — so the run is not lost to formatting.
The dangerous-command filter has no such valve. Same file, same author, same afternoon, opposite failure semantics.
That asymmetry is the bug, not the regex. A filter that can empty the queue needs to know the difference between “there is nothing to do” and “I rejected everything.” Those two states look identical downstream and mean opposite things. If your agent system has any filter that can drop the last candidate, make it report why the queue is empty, not just that it is. An empty-because-filtered queue should be an alarm. An empty-because-done queue is a success.
Revenue
€0. Nothing in this estate has earned money to date. Not “early days,” not “pre-monetisation” — zero euros, against 106,846,606 tokens across 937 runs in four weeks. I am publishing the cost side because it is the side I can measure honestly, and because a cost figure without the revenue figure beside it is the omission that makes vendor pages useless.
What this does not tell you
Tokens are not euros. I am publishing token counts because that is what my log records. Converting to currency requires knowing the model mix, the cache-hit rate and the input/output split per run, and mine varied across the month. A flat euro-per-task derived from a token count is multiplying by a number someone made up.
You cannot audit this. The two logs are private. You are reading my arithmetic on data you cannot see, which is a weaker claim than I would like to be making. Take the method — count shipped tasks a verifier passed, divide the whole token spend by it including the wasted runs, re-derive monthly — and run it against your own log. That number will be trustworthy in a way this one is not.
One box, two loops, four weeks. No claim that ~95,000 tokens per shipped task generalises to your codebase. It is one operator’s ledger over one month, which is one more ledger than was available before.
The average hides the tail. Across those same 937 scored runs on 2026-08-05, an individual run ranged from 14,095 to 378,932 tokens, with a median of 96,139 and the middle 90% falling between roughly 37,700 and 243,100. A 27x spread between cheapest and dearest run means the mean is a budgeting figure, not a prediction of any single run.
Follow new posts by RSS: paste dankdev.com/feed.xml into any feed reader. It is a plain XML file — no signup, no email address, no account. Posts land there the same day they go up, and there is nothing to unsubscribe from later.