AI operating cost and harness design / Field essay 42

The five-minute cache cliff that made waiting subagents expensive.

A short cache lifetime mismatched to subagents waiting behind long commands caused large prompt-prefix rewrites. Configure lifetime by worker role and verify positive and negative paths; meter savings remain unmeasured.

Published

AI OPERATIONS AND CACHE LIFECYCLE DESIGN
FIELD ESSAY 42 / AI OPERATING COST AND HARNESS DESIGN

The five-minute cache cliff that made waiting subagents expensive

I found the largest subagent token write bucket in the five-minute gaps after commands finished. The agents had not changed; their prompt cache had expired while they waited.

I was looking at our subscription meter because the usual advice to shorten prompts had not explained the spend. I separated cache reads, cache writes, and output, then compared those meter events with the transcript timelines. That second view changed the diagnosis. The subagents were writing far more than they were growing their context.

Across the measured window, subagents used 85% of their cache-write tokens on rewrites. The report attributed 131.7 million tokens to rewrites, with 127.6 million following gaps longer than five minutes. The largest bucket was the five-to-fifteen-minute interval: 98.8 million rewritten tokens across 259 events. A typical subagent carried about 380,000 tokens of context. If a shell command held it for six minutes, the next turn could miss the five-minute cache and write that prefix again.

That is a timing problem disguised as a prompt-size problem. The task itself did not need another 380,000 tokens. The agent had already paid to establish that prefix; waiting past the cache lifetime made it pay again.

Why the queue changed the economics

A subagent often waits while a build, test, or another tool call runs. The wall clock can be mostly idle even though the agent's next request is expensive. A short cache lifetime assumes the same session will return quickly. That assumption breaks when the agent is a worker in a larger workflow, where its next step depends on a long-running command or another lane.

I initially treated cache policy as a provider-level detail. The evidence made it look more like a workload setting. Interactive sessions, headless jobs, and subagents have different wait patterns. Applying one default to all of them hides where the expiry cost lands.

I also had to be careful about what the report did and did not prove. The measured tokens are rewrites under the report's model of prefix growth and cache reuse. The cost estimate depended on a coarse subscription meter. It did not establish a realized quota saving after a change, and it did not mean every rewrite was preventable. Account switches, compaction, and genuinely new context can also force writes.

Change one boundary, then test the control

I set the subagent prompt-cache lifetime to one hour in the settings installer. Then I checked the setting at the boundary: a subagent launched with the option wrote to the one-hour cache; the control without it wrote to the five-minute cache. I checked the settings-file form as well, and verified that a plain headless parent session now created subagents with the longer lifetime.

The control mattered. Seeing a one-hour cache event alone could have meant the test harness or account was already using that setting. The negative case showed that removing the option restored the five-minute behavior. The setting was therefore affecting the observed cache class, rather than merely appearing in a config file.

This was a narrow fix: assign a longer cache to the worker role whose measured wait pattern crossed the shorter threshold. It did not shorten the prompts, remove useful context, or change how often the workers ran. I chose that boundary because the evidence showed large rewrites clustered immediately after five minutes, while growth from genuinely new tool output was a separate category.

Measure realized outcomes after configuration changes

The report estimated that moving the rewrites after five-to-sixty-minute gaps into reads could reduce quota use, but it explicitly left the result to be checked against later meter data. I am not treating that estimate as a result. The next useful read is a before-and-after comparison with the same transcript classification, same account population, and enough elapsed time to observe the worker waits. I would also track whether the longer lifetime creates a different constraint, such as more cache retention without useful reuse.

The broader lesson is to measure the shape of waiting, not just the size of prompts. Agent fleets have roles with different idle intervals. A five-minute default can work well for a fast interactive loop and fail badly for a worker parked behind a test suite. Cache lifetime belongs in the workload configuration, and the control case belongs in the verification.

Schedule around the cache lifetime

A subagent waiting on a shell command is still holding its context. If the provider’s cache lifetime passes before the next call, the next turn may have to write that context again. The workflow can look idle while the expensive part is simply waiting. I now treat a long tool wait as an orchestration event: either do the blocking work outside the model turn and resume promptly, or persist a concise checkpoint and start a fresh bounded turn when the result is ready.

This does not mean every task should be split into tiny prompts. Smaller turns can lose relevant state and create more coordination overhead. The useful measure is the ratio between stable context, active work and idle time. A long-running compile belongs in a tool process that returns a result; it should not require the model to remain open and then replay a huge prefix after cache expiry.

Treat waits as part of the model call

A waiting agent is not free simply because it is not generating tokens. The next turn may need the entire stable prefix again if the cache expired while the tool was running. That connects orchestration design to model cost: a six-minute wait can be a cache event, not just a slow test. I now ask whether the model needs to remain in a live turn while the command runs, or whether the job can continue independently and return a compact result.

There are two viable patterns. For short waits, keep the worker alive and make the cache lifetime exceed the expected gap. For longer work, persist the task state, release the model session, and resume from a bounded summary once the tool has completed. The second pattern saves context but adds handoff risk: a summary can omit a constraint, and a new worker may not share the old process state. The choice should be measured against accepted outcome and recovery cost, not token reduction alone.

I would instrument invocation time, last active turn, next turn, cache reads and cache writes by worker role. Then compare ordinary and long-wait cohorts while holding the task class constant. A harmless short wait is the control; a deliberate wait beyond the cache boundary tests the cliff. Only after that should I change the role-specific TTL or orchestration behavior. The observed rewrite total is a cost signal, while post-change savings remain unproven until the same meter is measured again.

Choose a resume boundary deliberately

The checkpoint should be a compact record of the decision, current task state, completed tool calls and unresolved question—not an unbounded transcript summary. I compare the resumed worker against the original acceptance criteria and run a small context-recall check for constraints that must survive the handoff. If a result depends on hidden process state, the process needs to persist outside the model session or the task must stop for an owner. A longer TTL is useful for expected waits, but it should not become an excuse to keep every idle agent alive indefinitely. Expiry and a safe resume path are complementary controls.

For an evaluation, record invocation timestamps and separate cache reads from writes. Compare turns after short waits with turns after the cache window, holding the prompt and model fixed. Then test a workflow change: short polling, asynchronous completion, or a structured checkpoint. Keep correctness and accepted output constant while measuring cost. The objective is not fewer tokens in isolation; it is fewer repeated context writes for the same accepted result. Which orchestration wait in your system routinely crosses its cache lifetime?

How this was verified

I compared the pinned cache-write report against the subagent TTL setting experiment and control. The report identifies rewrites and idle-gap buckets; it does not prove a post-change quota reduction. The 14–35% savings range was an estimate and is omitted here as an outcome.

CONNECTED READINGForward and back
Keep reading

The answer deserves
another experiment.

Back to the journal