# Agent's Personality Tax: Stop Re‑Buying Your Agent's Context

> Source: <https://tanishq.xyz/engineering/agent-personality-tax>
> Published: 2026-07-25 19:39:07+00:00

# The Personality Tax: Stop Re‑Buying Your Agent’s Context

How I cut my agent’s inference bill by 85% with two cache breakpoints.

I built an agent that never sleeps. All day it runs small background tasks: checking on things (mail, calendar, the feeds I follow), tidying up what it remembers, rebuilding its sense of “now” every few minutes, nudging me when something needs attention. An agent like that is running inference all day, and it adds up fast.

What surprised me was where the money went: not into thinking, not into doing, but into remembering. A language model keeps nothing between calls, so every background task starts from zero: the agent’s instructions, its tools, everything it knows about me (my projects, my habits, how I like my coffee), re-sent and re-billed as if for the first time, every few minutes, around the clock, usually just to find out that nothing happened. I call it the **personality tax**.

The tax isn’t the price of having a personality. It’s the price of never separating that personality from what the agent is holding right now: what time it is, what it just looked up, where it is in the task. Keep those apart, and the tax mostly goes away. Most of the work is finding the line between the two.

The obvious fix is to cache the prompt: the provider keeps it on hand, and reading it back costs a tenth of the usual price. But caching your prompt and caching it *well* are different things. Do it naively and your bill goes up, past what you paid with no cache at all.

## Why the naive cache backfires

Prompt caching is prefix caching: everything before your marker is reused, as long as it’s byte-for-byte identical to the last call. Which means a cached region is only as stable as the fastest-changing thing inside it. Your tool definitions might not change for weeks. Doesn’t matter. If a live clock sits anywhere before the marker, the whole region changes every second, and the cache dies with it.

Now the failure mode writes itself. The natural place for a breakpoint is the end of the system prompt, and that’s where most people put it. But any real agent keeps something in that prompt that changes on every call: a clock (“Tue 9:41 AM”), a freshly recalled fact (“his flight lands Friday”), the state of the current task (“step 3 of 7”). So the cache goes stale every second, every call rewrites it from scratch at a premium, and nothing ever reads it back. You’re paying more than if you’d never cached, because writes cost extra and writes are all you’re doing.

## Sort the prompt by what changes, not what it means

Every part of the prompt has a **stability horizon**, how long it stays true. Sort the prompt by it, and give each part a cache that lives about as long: cache each part of the prompt for no longer than it stays true.

The awkward part: this isn’t how we naturally organize prompts. We arrange context by meaning: tools here, memory there, personality up top. A cache doesn’t care what a block means. It cares how long the block sits still.

In my agent, everything shook out into two speeds: parts that hold still for an hour or more, and parts that change within minutes. Two speeds means two breakpoints, and a prompt in three parts. The static prefix (tools, identity, rules) changes only when I edit the agent, so it sits under the hour-long cache. The volatile suffix (the clock, the fact it just recalled, the step it’s on) changes every call, so it’s kept out of that long cache on purpose. And the conversation rides a second, shorter cache that rolls forward as the agent works.

The first breakpoint is where the personality tax is easiest to see. Tools and identity are big, and they almost never change. So after the first call of the hour they come back at a tenth of the price, and they’re only rewritten when I actually edit the agent. The tax doesn’t disappear, but it drops by ten times and stays there.

The second breakpoint is the same tax in a quieter form. An agent rarely answers in one step. It calls a tool, reads the result, calls another, and every round is a fresh request that re-sends the whole conversation so far. Round ten pays for rounds one through nine all over again: the agent buying back the self it’s built up this task, round after round. Over a long task, the conversation’s cost grows with the square of the rounds.

*R*, the tool rounds in one runR = 20

The conversation alone bills **$0.46**: Δ is re-sent **190** times over the run, and the first tool result is paid for **20** times.

at Claude Sonnet’s $3.00/MTok, with u = 45 tok and Δ = 800 tok

Each round re-sends every earlier round, so doubling the tool rounds roughly quadruples the conversation’s cost.

The rolling breakpoint flattens that curve. It works because a conversation only looks dynamic: the past is frozen, byte for byte, and only the newest edge moves. So before each call, the agent slides the marker to the end of whatever exists so far. Everything behind the marker comes from cache. Round ten reads rounds one through nine at a tenth of the price, and pays full price only for the newest result. Each round, the cached region grows and the part you pay for stays one block wide.

Providers can now roll the conversation breakpoint for you, so use that. What no automation can decide is the partition: which bytes of your agent are stable enough for the long cache, and which have to stay out.

Finding the cut for your own agent comes down to three questions, asked block by block. First, how fast does it change, and do you decide when? A feature flag barely changes, but a user can flip it any time. You don’t control the timing, so it belongs with the clock, not the tools, even though it looks structural. Second, will something read it back before it changes? A stable block nobody reuses is a write you pay for and never recover. Third, what comes after it? Because caching matches on the prefix, one unstable block spoils everything downstream, so the bytes you can’t predict go last.

Then order the blocks slowest to fastest, cut wherever the change rate crosses into a shorter cache lifetime, and count the cuts. Mine came out to two; another agent lands somewhere else.

## The numbers

An argument that only holds on a whiteboard isn’t worth much. So here’s one window, straight off my agent’s usage dashboard, priced at Sonnet’s input rate.

| Token class | Tokens | Rate | Cost |
|---|---|---|---|
| cache reads | 868,800 | $0.30/MTok | $0.261 |
| cache writes | 39,655 | $3.75/MTok | $0.149 |
| fresh input | 45 | $3.00/MTok | $0.00014 |
| what I paid | 908,500 | 0.150× | $0.41 |
| same window, no cache | 908,500 | 1.000× | $2.73 |

Of the roughly 909K input tokens in that window, only 45 were bought at full price, and those were the message I typed. Everything else came out of the cache at a tenth of the price: the tools, the identity, the memory, the whole conversation so far. 95.6% of the input was served from cache, and the bill came in **85%** lower than with no cache: about 6.7× cheaper for exactly the same work.

What’s left is one unavoidable write per turn. The clock sits just ahead of the conversation, so when the minute changes, the conversation region gets rewritten once. In this window that was 4.4% of the tokens and 36% of what I paid, exactly where the cost model says it should land.

A tenth is also the floor: reads are the only thing discounted, while writes, the fresh edge, and everything the model generates still cost full price. Short exchanges save less; long runs save more. One window proves little on its own, so here’s the same cost model run across three workloads.

And outside the simulator, on the provider’s own dashboard, a full week of production traffic tells the same story.

## The obvious objections

Three objections come up every time, and each one is how somebody talks themselves out of doing this.

First: this is overthought, just cache the whole prompt and move on. That’s the naive version, and it’s the one that backfires. It is exactly the hour-long cache wrapped around a clock. Caching everything and caching well aren’t the same move.

Second: the real answer is a smaller context, not a cached one. There’s good work on exactly that: summarize, retrieve, carry less. It’s a genuinely good idea, and it isn’t a rival to this one. A smaller context is a cheaper thing to cache. Compaction shrinks the bill; caching cuts the rate on whatever remains. You want both.

Third, the honest one: some agents shouldn’t bother. If your agent answers in one shot and never loops, there’s nothing to read back, and the rolling breakpoint is pure overhead. Break-even is low, two or three reuses and a cache has paid for itself, but an agent that truly never reuses its context should keep one breakpoint on the static prefix and skip the second. Mine loops on nearly everything, so it was never close. Yours might be.

## The general idea

Strip away the pricing and the provider, and what’s left is a way of seeing context that outlasts the numbers. An agent’s context isn’t one object. It’s a stack of state changing at wildly different speeds: tools drift monthly, identity weekly, a profile daily, a recalled fact for one task, the clock on every call, the conversation on every round. We’re used to organizing that stack by what each layer means. For cost, it wants to be organized by stability horizon. Two breakpoints are just the smallest useful cut. A different agent will want a different cut, and the number of cuts is a fact about your workload, not about the technique.

Make the cut, wherever it falls for you, and the agent stops paying to become itself on every call. For me, that was the line between something I could demo and something I could afford to leave running.

Want to know where the cut falls for your agent? The model behind every number above runs in your browser, right below. Set the static prefix to your agent’s boot size, say how busy it is, pick a model, and read the monthly bill. The mismatch row stays in on purpose: a standing reminder that caching switched on wrong costs more than caching left off.

| Strategy | Effective × | $/day | $/month |
|---|---|---|---|
| No caching | 1.000 | $43.85 | $1,315 |
| Horizon mismatch | 1.378 | $60.43 | $1,813 |
| Horizon-aligned · two breakpoints | 0.261 | $11.46 | $344 |
| saved vs no caching | $972/mo |

Horizon-aligned caching serves **84.7%** of all input tokens from cache, pulling the effective rate down to **0.26×** of full price.

Input costs only. Interactive turns are spaced 15 minutes apart, past the 5-minute TTL, so the conversation cache never carries across turns (the rolling breakpoint’s worst case).

## The fine print

The exact terms, for anyone checking the arithmetic. A cache read costs a tenth of a normal token. A cache write costs a premium: a quarter more for the five-minute cache, double for the hour. Reading an entry resets its timer.

| Token | Rate | At $3.00/MTok |
|---|---|---|
| fresh (uncached) | 1.00× | $3.00 |
| cache read | 0.10× | $0.30 |
| cache write · 5-minute | 1.25× | $3.75 |
| cache write · 1-hour | 2.00× | $6.00 |

**Caching only touches input.** It never discounts what the model generates, so a chatty agent saves less. Those replies do re-enter the prompt as history on the next call, where they ride the cache like everything else, but as input, not output.**Keep the cached bytes stable.** Anything a setting can change, a toggle or a flag, will bust the prefix mid-session. Tunable state belongs outside the cached region.**Idle gaps reset the cache.** Go quiet for an hour and the static prefix cold-starts: one 2× write, earned back within a few calls. Go quiet for five minutes and the conversation cache is gone. A genuinely always-on agent rarely notices, because its heartbeats double as keep-alives.**Rewriting history busts the cache.** Summarizing or compacting the conversation changes the bytes, so treat it like a config change: rare and batched.**A cached region has a minimum size.** Below a model-specific floor (roughly 1,024 tokens on older Sonnet, 2,048 on Sonnet 4.6, 4,096 on Opus and Haiku 4.5) the provider silently skips the cache and bills the region at full price, with no error. A real agent’s boot prompt clears this easily; a toy one may not, which is why the calculator flags it.**Breakpoints only look back so far.** A breakpoint searches a bounded window of recent blocks (20, on Anthropic) for a prior entry. A single turn that appends more than that (many parallel tool calls and their results) can push the previous entry out of range, and the next call silently misses. The rolling breakpoint mostly sidesteps this by writing on every call, but a heavily parallel turn may need an extra marker mid-turn.**My measured window is a flattering one:** no cold starts, no config edits. Estimate your own with the calculator above.**Prices drift; ratios don’t.** The dollars here use Claude Sonnet 4.6’s $3 per million input tokens (July 2026). Sonnet 5’s standard rate matches, with a $2 introductory rate through 31 August 2026. Every multiple and percentage on this page is independent of the base price. Only the totals move with it.

## Further reading

- Anthropic:
[Prompt caching](https://platform.claude.com/docs/en/build-with-claude/prompt-caching)and[Pricing](https://platform.claude.com/docs/en/pricing) - Packer et al.:
[MemGPT](https://arxiv.org/abs/2310.08560). Shrinking context composes with caching; it does not compete with it. - Anthropic:
[Claude Code](https://code.claude.com/docs), which ships its own variant of the rolling breakpoint.
