Prompt Cache Control
Prompt-cache meter above the Claude Code prompt: how many tokens each request read from, wrote to and sent past the cache, a live countdown to the cache's expiry, and what to do about it (keep going, compact or clear). The TTL follows Claude Code's own rules for your account (1 hour on a Claude subscription, 5 minutes on an API key, cloud provider or usage credits, plus the TTL variables and setting) and corrects itself from request timing. When Claude Code will compact an idle conversation by itself, it counts down to that too. cache opens a per-turn table.
npx claude-code-templates@latest --skill β’β’β’β’β’β’β’β’β’β’β’β’β’β’β’β’β’β’β’β’Interactive Terminal Locked
Unlock this skill to run and inspect the interactive installation sequence.
prompt-cache-control (Claude Cache Control)
A prompt-cache meter above the Claude Code prompt. Every request Claude makes
reports how much of its prompt the cache served, how much it wrote and how much
went uncached; this mod keeps those numbers per request and per turn, counts
down to the moment the cache lapses and tells you what to do about it: keep
going, /compact or /clear.
cache ββββββββββ 98% read 80k Β· wrote 1k Β· new 300 β± 3:41 5m Β· warm: keep going cache ββββββββββ 0% read 0 Β· wrote 52k Β· new 300 β± 4:58 5m Β· cache missed: model changed (β¦) cache ββββββββββ 98% read 150k Β· wrote 1k Β· new 300 β± 0:00 5m Β· expired: the next message rewrites 151k tokens. /compact first, or /clear if the task is done
/cache opens a pane: the time left with a solid bar that shrinks as the cache runs out (green, yellow below 40% of the lifetime, red from the warning threshold), a stacked read / wrote / new bar for the last request, and a colour-coded table with one row per turn. Bars are filled cells and columns have fixed widths with no-break spaces, so the terminal and the Desktop (HTML) pane render the same.
How the countdown works
From Anthropic's prompt caching documentation:
input_tokens (uncached remainder) + cache_read_input_tokens + cache_creation_input_tokens./compact./clear starts a new conversation in the same process, so the meter and the /cache table start over with it. A change in the prefix (model, effort or thinking settings, tool set, system prompt, CLAUDE.md) makes the next request write instead of read. The mod names the cause when it sees a miss: model changed, the cache had lapsed, or the prefix changed.Which lifetime your account gets
The mod follows Claude Code's own rules (prompt caching: cache lifetime, Claude Code 2.1.242 or later). For the main conversation the TTL is the first match of:
| # | Source | Result |
|---|---|---|
| 1 | the mod's ttl option (5m / 1h) | what you set |
| 2 | FORCE_PROMPT_CACHING_5M=1 | 5 minutes |
| 3 | CLAUDE_CODE_PROMPT_CACHE_TTL | 5m or 1h |
| 4 | the promptCacheTtl setting (local, project or user settings file) | 5m or 1h |
| 5 | ENABLE_PROMPT_CACHING_1H=1 | 1 hour |
| 6 | the account | 1 hour on a Claude subscription within its plan usage; 5 minutes on usage credits, an API key or a cloud provider |
The account comes from the rate-limit windows the last response reported: a five_hour or seven_day window means a subscription, and one at 100% means requests now draw on usage credits. An API key or a cloud provider reports no such window, and before the first response nothing is known, so the mod starts from 5 minutes there. Managed settings are not readable from a mod.
On top of that the mod watches the traffic, which beats rows 2 to 6: a request that hits the cache more than 5 minutes after the previous one proves the 1-hour lifetime (a later miss does not undo it, since a changed prefix looks the same), and a miss 5 to 60 minutes after the previous request, with the same model and a prompt that did not shrink, says the entry lapsed, so 5 minutes (a later hit overrules it). That covers what the mod cannot see: managed settings, a gateway that rewrites the TTL, or a subscription that ran out of plan usage mid-session. The pane header names the source in use.
Why the mod infers instead of reading it: the API names the TTL of each write (cache_creation.ephemeral_5m_input_tokens / ephemeral_1h_input_tokens) and Claude Code's status line exposes it as prompt_cache.ttl, but the mod API passes on only the four token counts. To check by hand, claude -p "hello" --output-format json and read usage.cache_creation.
Other switches read from the environment at session start:
| Variable | Effect on the meter |
|---|---|
DISABLE_PROMPT_CACHING=1 (and _HAIKU, _SONNET, _OPUS) | the band says caching is off for that model |
Idle compaction (Claude Code 2.1.290+)
Claude Code can compact a large terminal conversation by itself while you are away, shortly before its one-hour cache lapses, so your next message reads a summary instead of rewriting the whole prompt. When that will happen, the band adds a magenta β£ 41:12 next to the cache countdown: the time until Claude Code compacts if nobody types. After it happens, a toast and the band say compacted while idle (240k β 30k), and the old countdown stops.
It fires at 90% of the cache lifetime (about 54 minutes) only when all of these hold (read from the 2.1.299 build, not from documentation):
| Condition | Where the mod reads it |
|---|---|
| The feature is rolled out to your account | the tengu_sunny_locket flag Claude Code caches in ~/.claude.json; mode: "off" means it never runs, and "idleCompaction": true does not turn it on |
| Auto-compact is on | DISABLE_COMPACT, DISABLE_AUTO_COMPACT, autoCompactEnabled |
| Idle compaction is not turned off | "idleCompaction": false in settings.json |
| The cache lives one hour and is still warm | the same lifetime as the main countdown |
| The prompt is at least the threshold | CLAUDE_CODE_IDLE_COMPACT_MIN_TOKENS, never below 100K, 200K when unset |
The mod reads only those two keys from ~/.claude.json (or $CLAUDE_CONFIG_DIR/.claude.json); without the cached flag it shows no idle countdown. /cache shows a line saying whether it is armed and, if not, why (for example not rolled out to this account (mode off) or waits for 200k tokens; the prompt is 80k). Two settings in the catalog set it up: environment/idle-compaction-early (from 100K) and environment/idle-compaction-off.
What it hooks
turn.step: reads each main-loop request's usage (subagents have their own prefixes and are left out)$.clock.every(1000): redraws the countdown, and only while its text changes, so an idle expired session costs nothingui.render on AbovePrompt (the band) and on Pane (/cache)session.compact: notes a compaction of the main conversation, and announces one with trigger idle$.ui.toast: once per cache entry at the warning threshold (60 s by default) and again at 10, 3, 2 and 1 seconds left, for prompts of 20k tokens or moreOptions
ttl: string "auto" | "5m" | "1h" (default auto) warnSeconds: number countdown threshold for the yellow state and the toast (default 60) compactAtTokens: number prompt size that makes an expired cache suggest /compact (default 100000) band: boolean row above the prompt (default true) status: boolean entry under the prompt, "cache 98% Β· 3:41" (default false) toast: boolean toasts at the threshold, 10, 3, 2 and 1 s (default true) idleCompact: boolean idle compaction countdown and notice (default true)
The 100k compactAtTokens is a judgement, not a figure from the documentation: lower it if your model's cache writes are expensive for you.
Install
npx claude-code-templates@latest --mod observability/prompt-cache-control claude
It is written to .claude/skills/prompt-cache-control/, which Claude Code auto-loads as prompt-cache-control@skills-dir once the workspace trust prompt is accepted. For one session with hot reload: claude --plugin-dir .claude/skills/prompt-cache-control. claude plugin validate .claude/skills/prompt-cache-control prints every event it hooks and every $ call it makes; claude plugin test .claude/skills/prompt-cache-control runs its tests.
Options are read from user settings (~/.claude/settings.json, never project settings), --settings <file> or managed settings, under the plugin's full id:
{ "pluginConfigs": { "prompt-cache-control@skills-dir": { "options": { } } } }Requirements. Mods are on by default in Claude Code 2.1.287+. Typed against Anthropic's declarations: https://github.com/anthropics/claude-code/tree/main/mods
How to Use & Getting Started
# Step 1: Initialize skill agent setup
npx skills add Prompt Cache Control --install-production
python -m pip install -r requirements.txt
codex plugin install Prompt Cache Control@latest
export API_KEY=secret_token_key_here
Installation Runbook & Walkthrough Locked
Unlock this skill to reveal complete step-by-step setup guides, terminal commands, configuration recipes, repository links, and interactive installation video walkthroughs.
Unlock full access to Prompt Cache Control
Get instant access to complete setup guides, repository source code, and integration assets.
More in mod
View all mod skills βJev Model Router
Picks the model and the reasoning effort for each task with TypeSafe's Jev, a System One decision model reached either through TypeSafe's own API or the Vercel AI Gateway. Routes subagent models at agent.spawn and the main loop's effort and model at turn.step, in both directions, falling back to the engine's built-in classifier when no key is set.
Jev Skill Suggestion
Keeps the skill listing out of the context window and lets TypeSafe's Jev, a System One decision model, pick at most one skill per prompt from the skills' descriptions, the way TypeSafe's skill-suggestion cookbook does: one request ranks every skill and asks whether the prompt needs a skill at all, a second re-reads the top three with their SKILL.md and can reject them all. The winner's SKILL.md is attached to the prompt, so the skills can be hidden from the model altogether ( jev-skill-suggestion:setup makes them user-invocable-only and context counts them at 0). Falls back to the engine's built-in classifier when no key is set.
Stack Viewer
A side pane that maps every component your session runs and where it is installed from: skills, subagents, commands, hooks, MCP servers, plugins and mods, settings, memory and output styles. Pick a type in the sidebar to see its scopes as a tree in precedence order (Enterprise, CLI flag, Local, Project, User, Plugin, Built-in) with what each one holds, and which components are active, shadowed by a higher scope, or off.