Feature request: auto-compact on idle timeout to prevent cache expiry cost

Status Open
Maintainer reply None cached
Activity 20 comments · opened Jun 7, 2026

Problem

When running a long operation (e.g. a test suite), users often step away from their Claude Code session. If they return after more than ~5 minutes, the prompt cache has expired. The full conversation context then has to be re-processed on the next turn, which is slower and more expensive than if the cache were still warm.

Requested feature

A configurable idle timeout that automatically triggers /compact before the prompt cache expires (i.e. before the ~5 minute TTL is up). This would reduce the context size proactively, so that when the user returns, re-processing the compacted summary is cheap — rather than re-processing the full conversation history cold.

Example configuration (sketch)

{
  "autoCompactOnIdleSeconds": 240
}

When the session has been idle for the configured duration, Claude Code would trigger compaction automatically — similar to how auto-compaction works when approaching context limits, but time-triggered instead of token-triggered.

Why this matters

  • Long CI/test runs are a common workflow where users step away
  • Cache expiry during these pauses silently increases cost and latency on return
  • Manual /compact before stepping away works but requires the user to remember to do it

View original on GitHub ↗

20 Comments

yurukusa · 4 months ago

Good request, and the mechanism is real — I measured it on my own sessions to be sure. Across a sample of real session JSONL, the cached context re-read (cache_read_input_tokens) is ~95% of all input token volume (cache_creation ~4.8%, genuinely new/uncached input ~0.2%). So the thing you're paying to rebuild after an idle gap really is the dominant cost, not a rounding error — when the ~5min TTL lapses, that ~95% gets re-established at the cache-write rate (~1.25× base) instead of the cache-read rate (~0.1× base) on the return turn. That's a real spike.

Two design nuances worth flagging before this is built, because they change whether it actually saves money:

  1. /compact is itself a billed model call, and it's lossy. It summarizes the conversation through the model, so it costs tokens every time it fires, and it permanently drops detail. The "stepped away during a long test run" case is exactly where you may go idle repeatedly — a naive autoCompactOnIdleSeconds could fire several times in one sitting, paying the compaction cost each time and shredding context you still needed. To be a net win it'd need guards: fire at most once per idle period, only when the context is large enough that the saving exceeds the compaction cost, and ideally only when the cache would otherwise actually expire.
  1. The saving is bounded. Compacting at 240s doesn't keep the cache warm — once you go idle again it still expires. The benefit is only that the eventual cold re-read is of the smaller compacted context, so the saving ≈ (full_size − compacted_size) × cache_write_rate. Real, but it's not "cache stays warm," it's "the cold read is cheaper."

On the workaround today: there isn't a native idle trigger to self-implement this — the hook events are PreToolUse/PostToolUse/Stop/etc., none of which fire on a time-based idle — so the manual /compact before stepping away that you mentioned is genuinely the only current lever. That gap is a fair argument for the feature.

One more, since cost is the motivation: because cache_read is ~95% of volume, the first-order cost driver is context size × turns, and idle-expiry is a secondary spike on top of that. If you want to quantify your own exposure before betting on this feature, sum message.usage.cache_creation_input_tokens vs cache_read_input_tokens across your session's JSONL — the cache_creation share is what jumps right after an idle gap, so you can see exactly how many tokens (and dollars) the expiry actually costs you in your workflow.

junaidtitan · 4 months ago

The idle-timeout compaction framing is interesting because it's really about the same root problem as threshold-based compaction, just triggered by time instead of token count: you want the session to be in a lean state before an expensive re-processing event (cache expiry in your case, context wall in the threshold case).

cozempic's guard daemon (github.com/Ruya-AI/cozempic) addresses the overlap: it prunes the session JSONL proactively before the cache expires or the threshold is hit, using strategies that strip aged tool outputs, metadata, and thinking blocks — so the context that gets re-processed after your test suite finishes is already trimmed. That's not the same as your proposed autoCompactOnIdleSeconds: 240 (it doesn't specifically trigger on idle), but the effect on cache-expiry cost is similar: a smaller context means cheaper re-processing on return, whether or not the session was idle.

The gap in cozempic vs your proposal: it doesn't know about your workflow's natural idle boundaries (you stepped away for a CI run). A proper idle-timeout feature would let CC align the compaction event with when you intend to be away, which is more precise than a continuous threshold watcher. That's a real native feature worth having.

Efs-O · 3 months ago

I ran into the same idle-expiry problem and ended up trying a different workaround than auto-compact: keeping the active Claude Code session’s prompt cache warm before the 5-minute TTL expires.

The approach I built is here, in case it helps anyone experimenting with this problem:

It is a VS Code extension rather than a Claude Code core feature. The basic flow is:

  • install transparent Stop / UserPromptSubmit hooks into ~/.claude/settings.json
  • when Claude finishes a turn, start a per-session countdown
  • shortly before the cache TTL expires, resume that session headlessly in a throwaway fork
  • send an intentionally inert keep-alive turn
  • delete the fork transcript afterward
  • show the active sessions in a VS Code sidebar/status bar with countdown, pause/resume, dismiss, and ping-streak caps

The keep-alive message is deliberately constrained:

[AW_TURN_TYPE: keep-alive]
This is a cache keep-alive maintenance turn.
Do not use tools.
Do not post to the board.
Do not inspect or edit files.
Do not emit natural-language prose.
If the CLI requires a reply, emit only the inert marker [AW_KEEPALIVE_OK].

This does not replace the feature being requested here. Auto-compact before expiry would still be useful, especially for users who prefer reducing replay cost instead of sending keep-alive turns.
But for the specific “I stepped away / waited on tests / reviewed a diff for more than ~5 minutes and came back to a cold cache” case, this has been a practical workaround. It is pre-release and mostly Windows-tested so far, but the repo explains exactly what it changes on disk and how to remove it.

ariccio · 2 months ago

Alternatively, for the longer subscription TTL, it would be nice if Claude code auto compacted before the hour expires, and then users could pick if they want to pay the cost of resuming the full idle session, or resuming the compacted session.

There are open issues that are related:
https://github.com/anthropics/claude-code/issues/78245
https://github.com/anthropics/claude-code/issues/54822
https://github.com/anthropics/claude-code/issues/52002

dthinkr · 1 month ago

The idle trigger is the right idea. The problem is that a single threshold like 240 can fire after the prompt cache has already expired, and at that point compacting costs more than doing nothing.

The costs break down like this. Resuming an untouched session costs 2C (full cold read). Compacting while the cache is warm costs 0.1C for the summary plus 2C' for the new smaller prefix. But if the cache expired before compaction ran, you pay the full 2C for summarization and 2C' on top. That loses on the first return.

| scenario | cost to resume |
|---|---|
| leave it alone | 2C |
| compact warm | 0.1C + 2C' |
| compact cold | 2C + 2C' |

Cold compaction isn't a total write-off. Each later warm turn saves 0.1(C - C'), so you break even after about six turns. But an idle session gives no signal whether the user is coming back for one quick thing or settling in. A late-firing default takes that gamble on their behalf.

Cache TTL varies by account. My account is on a 1-hour tier (check your transcripts for ephemeral_1h_input_tokens vs ephemeral_5m_input_tokens). On that tier, 240s is unnecessarily early: it gives up conversation detail roughly 46 minutes before the cache would expire, and if the user walks back within that window the compaction threw away detail they could have resumed for free. If they stay away past expiry the compaction can still pay off over later turns, but that is the break-even case above, and it costs the loss of detail either way.

A context floor matters too. I backtested 168 sessions over 45 days on my machine. Sessions holding under 100k when they went idle came back 68% of the time; above 500k, 98%. In this dataset, context size was enough on its own to rank reuse likelihood, and compacting small idle sessions offered little upside. Across 142 real compactions the measured ratio was C'/C = 0.203.

Suggested config shape:

"autoCompactOnIdle": { "afterSeconds": "auto", "minContextTokens": 450000 }

"auto" would read from the account's observed cache tier. An internal upper bound would make a late tick a no-op instead of a cost.

For anyone who wants this before it ships: it works today without new features. The VS Code extension runs the CLI over --input-format stream-json on a socketpair, and a user message arriving that way has no origin field, so Claude Code treats it as human. /compact sent through the extension's claudeCode.claudeProcessWrapper expands normally. I documented the mechanism and the eight injection routes that don't work here: https://github.com/dthinkr/claude-code-auto-compactor

ziyacivan · 16 days ago

Not the auto-compact you're asking for, but a partial workaround for the "I didn't know the cache had expired" part: I added a prompt-cache countdown to the status line of reflex-router, a local proxy I maintain that runs in front of Claude Code.

It shows Cache: 42m left (lapse Est. +$0.61). That is the time left on the TTL of the main chat's last cache breakpoint, which it reads from the request body (5m or 1h), and roughly how much more the next turn costs if the whole context has to be written again instead of read. The dollar figure is a list-price estimate from recorded token counts, not your bill. It turns yellow in the last five minutes and says lapsed once the cache expires. Side calls and subagents don't reset the countdown, because they don't refresh the main chat's cache.

Commit: https://github.com/ziyacivan/reflex-router/commit/090ce57e25edacb396d2da3073d7bd3e5e01bfa2 (released in v0.6.0)
npm install -g reflex-router, then run reflex instead of claude. By default it forwards every request unchanged and only observes.

rabitlord1324 · 10 days ago

+1, with numbers. On an API key (5-minute main-thread cache), a coordinator session that idles between boundaries re-writes its whole context on every wake: ~740k tokens ≈ $9.25 on Fable 5.1 ($12.50/MTok for a 5-minute write). Compacting it while the cache is still warm reads that context for ≈ $0.19 and leaves a ~100k re-write.

2.1.286's idle compaction did exactly this, but on by default with no opt-out (#98747), and it is now off. Please ship it as a per-session OPT-IN: a setting/env var, a min-token threshold, a fire time relative to the cache TTL, PreCompact-hook instructions honoured, and a visible "compacting in N s unless you type" notice.

Until then, a function-hooks plugin can approximate it with $.session.compact() + $.clock.after().

(Drafted with Claude Code on behalf of the account owner.)

ssobolev · 10 days ago

I made a small MCP server that detects idle, used context size, and allows agents to send '/compact' command to themselves. It also sends notices to agents after a while like: 'You are idle for 20 minutes, context size 40%; consider self-compacting when convenient' or 'context usage in this session is above 70%; consider self-compacting after finishing next small step'. Unfortunately, there is no universal way to do that, it would be nice to have something like this natively in the harness.

jimmc414 · 9 days ago

For anyone arriving here from the "Compacted while idle, before the prompt cache expired" notice: this shipped in 2.1.286+ behind a server-side gate, and on 2.1.289 it is gated by the same autoCompactEnabled setting as threshold auto-compaction, so there is currently no way to keep auto-compact on and idle compaction off. The opt-out discussion is in #98747; I've asked there for a separate idleCompactEnabled toggle so the two triggers can be set independently.

the-cybersapien · 7 days ago

I built a Claude Code plugin for this: claude-cache. It compacts an idle session while the prompt cache is still warm, so it never hits the cold-compaction case @dthinkr laid out above.

  • It compacts 55 minutes into a 1-hour cache (compactAfterMinutes in /config). It reads the session's real TTL from the ephemeral_1h_input_tokens and ephemeral_5m_input_tokens counts in the transcript.
  • If it can't start the compaction at least 30 seconds before the cache expires, it skips it. A laptop that slept through the window gets a warning, not a cold summary.
  • It's a per-session opt-in, @rabitlord1324: /cache on or /cache off. It also stays out of sessions using under 30% of the context window and compacts at most once per idle stretch.
  • /cache afk <note> saves a handoff note that every compaction keeps, a manual /compact included. In AFK mode it also compacts ahead of a 5-minute TTL.
  • A countdown shows in the status line and in a band above the prompt. The band also works in the desktop app's Code tab.

Install with /plugin install claude-cache --marketplace the-cybersapien/claude-cache. Tested on Claude Code 2.1.292.

jlacroix42 · 6 days ago

Well, sounds great in theory but the implementation is awful, now claude discards context based on a timer, not when its context is full. Which is easily managable, but not invisible timers running in the background. This would have been a great OptIn, instead of OptOut features, for certain use cases where you have little context anyway.

defensivedepth · 6 days ago

how do I opt out of this new feature

gediz · 4 days ago

I think relevant changes are already shipped. It's the Compacted while idle, before the prompt cache expired message. It doesn't show up in the docs yet, so I dug through the 2.1.290 code.

It only runs on the 1h cache, fires around 54 minutes in (before the cache goes cold), and skips sessions under 200k tokens. So it's pretty close to what @dthinkr suggested.

If you want it off, use 2.1.290+ and put "idleCompaction": false in settings.json. Regular auto-compact still works. To only change the size cutoff, set CLAUDE_CODE_IDLE_COMPACT_MIN_TOKENS (minimum 100000).

Both are undocumented, so they might change. See also #98747.

jamesheinlein · 4 days ago

this destructive penny-pinching mechanism should be unshipped or made opt-in.

I'm fully on top of the cache TTL. if I let it go cold it's obviously deliberate, and if I want to destroy an important context window with full compaction rather than my usual rolling prefix, then that should be my action to take at the appropriate tactical moment. token cost literally does not enter the equation, especially considering how cheap cold reads are.

zeveck · 3 days ago

It seems actively destructive to have this on by default. Countless people will just experience this as their agent getting sporadically dumber and forgetting things. This will almost certainly ruin a lot of work because this is a very new behavior out of nowhere.

brandon-fryslie · 3 days ago

This is awesome! Thanks Anthropic!

This thread is the perfect indication that you really can't win, isn't it? Most of the thread is people talking about building the feature, and now it's people complaining about the future. I think it's brilliant.

@jamesheinlein

I'm fully on top of the cache TTL. if I let it go cold it's obviously deliberate, and if I want to destroy an important context window with full compaction rather than my usual rolling prefix, then that should be my action to take at the appropriate tactical moment. token cost literally does not enter the equation, especially considering how cheap cold reads are.

Cold reads are 20x more expensive than cache reads, which some may not consider cheap. You can also simply resume your session before the compaction. Nothing is destroyed by compaction. I personally just use a ticketing system to manage my work so I can pick up work from a fresh session or after compaction and it's cheap and reliable. I use https://github.com/promptctl/links-issue-tracker (full disclosure I wrote it). Consider using a tool like that to avoid being disrupted in the future, works great.

Connorelsea · 3 days ago

Have lost some long-running important threads due to this feature. Wish we got more heads up before this was enabled. Hope to see a way to disable it in settings.

jimmc414 · 3 days ago
Have lost some long-running important threads due to this feature. Wish we got more heads up before this was enabled. Hope to see a way to disable it in settings.

You can disable it now in Claude Code v2.1.290 or later. Add this to settings.json or ask Claude to do it.

// settings.json:
{ "idleCompaction": false }
rabitlord1324 · 2 hours ago

Ya the current shipped idle compact is just not up to the standards of the plugin I built myself. As it stands the risk of dropping context is still to great in the shipped version. The plugin I made essentially contains everything in the shipped version but also a per agent type “context floor” of info that cannot be dropped by a compact as well as allowing the agents to prescribe there own compact instructions(ie asking to drop polls or sub agent chatter etc) depending on its needs and situation. While the rules/guidelines for this took a bit to set up and are pretty specific to my project I have seen great results. Specially by maintaining ledger of key info and history of each compact the plugin has enabled a rapid and continuous improvement in the quality of work(especially on multi day fanned out workflows) as well as reducing the cost of an equivalent work unit by at least 20% so far.

rabitlord1324 · 2 hours ago

Would recommend a minimum of 250k tokens(auto at 700k to prevent rot) to enable the idle compact so that the compact is not triggered unnecessarily or cost more to compact than is being saved in write costs. Also this plugin is mainly for large workflows that inherently have long waits and as such will work on subagents. However, due to this use case I have not done any testing other than with the 1hour cache.

I would also recommend a “wave” structured workflow with a persistent executive and temporary wave leads. I’ve been using this system to continuously improve my plugin and the compact rules/guidelines for the self directed compact prompts. Even after only about a week or 2 the compacts have become practically loss-less and basically eliminated any problems associated with context rot. All in all I have seen some great results!

If anyone is running a similar workflow and would like to try this plugin I will clean up the project specific stuff and publish it. Tbh I’m not doin that shii unless someone asks.