Skip to content
← All guides

Cutting Your Token Bill Without Cutting Quality

6 min read

Most token waste is context hygiene, not model choice. Where the spend actually goes, and the session habits that cut it without hurting output.

Your agent bill went up by a third last month and the volume of shipped work did not. Before you go shopping for a cheaper model, look at what you are actually paying for, because in a typical agent session the dominant line item is neither the model tier nor the code the agent writes.

Output is a rounding error

Every turn, the whole conversation goes back over the wire. System prompt, your context file, every file the agent has read, every tool result, every diff it produced, every apology it made for the diff it produced. On turn 60 of a session, the same thirty files it opened on turn 4 are still riding along, still being charged for, still nudging attention away from the two files that matter now.

Some arithmetic, with the assumptions stated. Say the context stabilises around 40,000 tokens by turn 30 and stays roughly flat, you take 60 turns in a working day, and you work twenty days a month. Assume an input rate of three dollars per million tokens and an output rate of fifteen. Those are plausible mid-tier figures rather than any vendor's current card, and rates move, so treat the ratios as the point.

Uncached input: 40,000 × 3 / 1,000,000 = $0.12 a turn. Sixty turns is $7.20 a day, and twenty days is $144 a month.

Now output. Say the agent writes 800 tokens a turn on average, which is a decent-sized patch plus explanation. That is 48,000 output tokens a day. 48,000 × 15 / 1,000,000 = $0.72 a day, or $14.40 a month.

So the thing you asked for costs a tenth of the thing you left lying around. Every optimisation aimed at making the agent write less is aimed at the wrong ten percent.

Caching rewards boring session structure

Prompt caching works on a stable prefix. If the first N tokens of your request are byte-identical to last time, they can be read from cache at a fraction of the fresh input rate. Assume a cached read costs a tenth of fresh input, and that 90% of your 40k context is a stable prefix.

Per turn: 36,000 × 0.30 / 1,000,000 = $0.0108, plus 4,000 × 3 / 1,000,000 = $0.012. That is $0.0228 a turn, $1.368 a day, $27.36 a month. Same context, same work, roughly a fifth of the cost.

The catch is that caching is exquisitely sensitive to prefix churn. Anything that mutates early in the conversation invalidates everything after it. Injecting a timestamp or a git SHA into the system prompt. Re-ordering the files you attach. Editing your CLAUDE.md mid-session. Tooling that shuffles a file listing on every turn. Each of these silently drops you back to full input rates while the dashboard shows nothing unusual, because you are still sending the same number of tokens, just paying ten times more per token.

So the practical rule is: put the stable things first and the volatile things last. Project instructions, then architecture notes, then the task, then the churn.

"Read the whole file" is a quality problem first

The reflex to open apps/web/src/lib/billing/stripe.ts in full, all 900 lines of it, feels thorough. It is usually worse on both axes. You pay for 900 lines, and then the model has to locate the one function that matters inside a haystack it now has to hold in attention alongside everything else.

Targeted search is cheaper and sharper:

rg -n "createCheckoutSession" apps/web/src --type ts -A 20
rg -n "export (async )?function|export const" apps/web/src/lib/billing/stripe.ts

The first gives you the definition and its immediate body. The second gives you the file's shape in about forty lines, from which you can decide what you actually need. This is the same discipline you would apply reading unfamiliar code yourself, and it produces better patches for exactly the same reason: the relevant context has a higher share of the attention budget.

Read whole files when the file is genuinely small, when you are about to rewrite it, or when the behaviour depends on ordering across the file. Otherwise, search.

Your context file is not a manifesto

AGENTS.md and CLAUDE.md-style files have a habit of growing into 400-line documents full of aspiration. "Write clean, maintainable code." "Follow best practices." "Consider edge cases." That prose is re-sent every single turn of every single session, and it changes nothing, because the model already intends to write clean code.

What earns its place is anything the model cannot infer from the repository in the first thirty seconds. The package manager is pnpm and npm install breaks the lockfile. Migrations live in packages/db/migrations and are generated, never hand-edited. Tests run with pnpm test --filter web and the root-level test script is a leftover that fails. The legacy/ directory is dead and should not be modified.

Forty lines of that is worth more than four hundred lines of encouragement, and it costs a tenth as much on every turn for the rest of the project's life.

Start a new session at task boundaries

One 200-turn mega-session is the most expensive shape available. Context accumulates monotonically, cache hit rates degrade as the prefix drifts, and by turn 150 the model is reasoning over a transcript in which half the facts have since been contradicted by later edits.

Finish the auth refactor, commit, start fresh for the billing work. The new session re-reads three files it needs, which costs a few thousand tokens once, and then runs at 18k of context instead of 55k. Using the cached figures from earlier, 18k with a 90% stable prefix comes to 16,200 × 0.30 / 1,000,000 = $0.00486 plus 1,800 × 3 / 1,000,000 = $0.0054, so $0.01026 a turn, about $12.31 a month at the same volume. That is the compound effect of caching and hygiene together, against $144 for the naive version.

The false economies

Two habits look like savings and are not.

The first is aggressive truncation: cutting context so far that the agent has to guess. It guesses plausibly, which is the problem. You get a patch that calls a helper with the wrong signature, or reimplements something that already exists two directories over. The rework costs more turns than the context would have.

The second is asking for a patch without letting the agent read the surrounding code. "Just add a null check on line 84." It adds one, in a style that does not match, duplicating a guard that the caller already performs. Cheap turn, expensive review.

Both fail the same way: you save input tokens now and spend them on correction later, at a worse cache hit rate, with your own attention as the additional cost.

Batch, and push exploration sideways

Related edits belong in one instruction. "Rename UserSession to AuthSession across the codebase, update the imports, update the Prisma schema, and update the two tests that reference it" is one pass over one context. Four separate requests re-send the same context four times, and the agent has to re-derive the intent each round.

Exploration is different. When you need to answer "where does rate limiting actually get applied", that investigation might touch fifteen files, and none of them belong in the main session afterwards. Spawn a subagent or a side session, let it burn context freely, and bring back the three-line answer. The main thread stays lean and its cache prefix stays intact.

None of this requires a cheaper model. It requires treating context as something you curate rather than something that happens to you, which is a habit most of us built for our own working memory years ago and then forgot to extend to the agent sitting next to us.

tokenscost-controlcontext-managementprompt-caching