Why your AI bill keeps climbing before you type a word
I check the usage meter the way other people check the weather. Last week the number climbed on a day I had barely typed anything, and that is a strange thing to look at, because there is no error to read and no incident to open. The work got done. The meter moved anyway.
If your AI bill is climbing and you cannot point at the thing you did to cause it, the spend is almost certainly structural rather than behavioral. You are not paying for what you typed. You are paying a fixed floor that your harness and your config re-send on every single request, and that floor is only visible at the API boundary, not on the dashboard that summarizes it for you. The fix is to measure the request that actually leaves your machine, once, and then multiply it by how often your agent talks.
why is my AI bill so high when I barely used it?
Because your prompt is the small part. An independent study this week put a proxy between an agent and the model and logged 150 real request and response pairs at the boundary. One popular agent harness emitted roughly 33,000 tokens of system prompt, tool schemas, and injected scaffolding before the user's first word arrived. Another emitted about 7,000 for the same job. Same model, same task, and a 4.7x difference in what the model reads before any actual work begins.
That is the floor, and you never see it. Nothing itemizes it, nothing throws, and it gets re-sent or re-read on every turn of the loop. Then your config multiplies it. A large instruction file rides every request in that repo, and a 72KB one adds something like 20,000 tokens to each call. Every tool server you connect adds its schema, roughly 1,000 to 1,400 tokens per server per request, whether or not the agent calls it. None of that is waste, exactly. It is the price of the enforcement and the tooling you chose. It is just a price nobody quoted you.
doesn't prompt caching make this free?
Not the way most vibe coders assume. Three costs survive caching, and they are the three that move the bill.
The cache write is re-paid every time the window lapses. Walk away for lunch, come back, and the stable prefix you thought you had paid for once gets written again. The cache read is discounted, but it is multiplied by request count, and an agent loop makes a lot of requests. And context-window consumption gets no cache discount at all: a cached token still occupies the window, so a fat prefix still crowds out the room your agent needs to think, and you pay for the crowding in re-reads and retries.
Then there is prefix instability. If anything near the top of the request changes between turns, and harnesses inject plenty that changes, the cached prefix stops matching and you rewrite it instead of reading it. I have shipped this exact bug in a vibe coded automation: one quality flag changed the request enough that caching silently stopped happening. Nothing errored. The only signal was a cache-read counter sitting at zero in the response metadata, and I only found it because the counter was instrumented before it was needed.
the 750MB list endpoint nobody noticed
The most expensive thing I ever shipped had nothing to do with tokens, and it taught me the whole lesson.
An internal dashboard on a client build was timing out. Not slow, timing out. The obvious read was a slow query, so that is where a normal debugging session goes: indexes, joins, the database. I went to the boundary instead and looked at what the endpoint was actually returning on the wire. The list endpoint was serializing full records, and each record carried its imagery inline as base64. Fifty rows moved roughly 750MB. The database was fine. The query was fine. Every layer of the stack reported success while the browser choked on three quarters of a gigabyte it never asked for. A lightweight response shape, ids and labels only, dropped the same call to about 500KB. That is a factor of 1,500, and it took one look at the actual payload to find.
Nothing errored there either. The dashboard was just expensive, in latency instead of dollars, and it was expensive on every single request. A 33,000 token bootstrap and a 750MB list response are the same disease at different altitudes: a payload riding every call that nobody ever looked at, because every layer above it kept reporting green.
what do I actually measure?
Measure at the boundary, not at the dashboard. Concretely, four numbers.
The floor. Capture one real request from your agent, the whole serialized thing, and count the tokens in it before your prompt. That number is what every turn costs you to say hello. If you have never seen it, you do not know your own unit economics.
The multiplier. Count your requests per session, not per day. The floor is not a cost, it is a rate. Floor times turns is the bill.
The fan-out. This one surprised me most. In the boundary study, a 121,000 token task became 513,000 tokens once it was split across two subagents, a 4.2x blowup, because each subagent pays its own bootstrap and the orchestrator then reads the whole transcript back. Parallelism is not free. It buys wall-clock time with tokens, which is often the right trade, but only if you know you are making it.
The cache truth. Read the cache-hit and cache-write counters out of the response metadata, not out of a settings page that says caching is on. On is a claim. The counter is a fact.
what tends to break with this
The failure mode I see most in metered vibe coding, and the one I lived, is tuning the wrong layer. The bill goes up, so you shorten prompts, trim your instructions, and tell yourself to be more concise. Meanwhile the actual multiplier is structural: a fat instruction file on every request, five tool servers you forgot were connected, an unstable prefix rewriting the cache mid-session, a fan-out pattern paying the bootstrap three times. You can write the tersest prompt of your life and change the bill by a rounding error, because prompts were never where the money was.
The second failure mode is thinking a dashboard is a measurement. A dashboard is a summary written by the party being measured. It is a fine place to notice a trend and a terrible place to find a cause. The counter in the response, and the bytes on the wire, are the only things that cannot politely lie to you.
questions that keep coming up
Should I just use the leaner harness? Not automatically. The harness with the bigger floor can still win a session by batching tool calls well and finishing in fewer turns. Floor times turns is the number that matters, and a heavy harness that halves your turn count is cheaper than a light one that wanders. Measure the session, not the request.
Is the instruction file worth its weight? Mine is, and I keep it. But I keep the enforcement in hooks and validators, which cost nothing per request, and I keep the prose file as lean as the job allows. Anything that has to be re-read every single turn should be earning its seat every single turn.
Why doesn't anything warn me? Because nothing is broken. Cost is not an error condition. The system is doing exactly what you configured it to do, at exactly the price of that configuration, and no exception handler in the world fires on "working, expensively." That is the whole argument for instrumenting cost as a first-class output before you need it, rather than after a bill you cannot explain.
If you are running a vibe coded automation in production and you have no instrumented view of what a single turn actually costs you, and you want a sparring partner on building that readout before the next surprise, /work-with-us. Automation work starts with the measurement, not the migration.
The meter is not the enemy. Not seeing it is.
// part of the ai automation topic
// grab the free starter kit that makes your AI stop forgetting and stop guessing: get it →
// building with AI? the field manual has the structured lessons.
// hitting this on a real build? this is what I fix →