Repository navigation
fix(cache-timer): use Claude Code's reported cache expiry when present - #576
Merged
Merged
Conversation
The widget inferred the countdown from the newest assistant row's timestamp
plus a configured TTL, because - as its comment said - the expiry was never
exposed. Claude Code now ships a prompt_cache object in status JSON carrying
warm, caching_observed, ttl and the real expires_at, so the guess is no longer
necessary.
Two things the inference gets wrong, both fixed by reading the reported value:
- A resumed session shows HOT while a user row sits at the tail, even when
the cache lapsed hours ago. That is exactly backwards from what the widget
is for: the moment you most need to know the cache is cold is when you come
back to an idle session.
- A turn that read an entry written much earlier restarts the countdown from
the wrong anchor.
Verified against real payloads with the same settings:
warm before: Cache: HOT after: Cache: 34:46
cold before: Cache: HOT after: Cache: COLD
legacy before: Cache: HOT after: Cache: HOT
The third case has no prompt_cache field and falls through to the existing
transcript logic unchanged, so older Claude Code versions keep working.
StatusJSON gains a permissive prompt_cache schema; every field is optional and
nullable, and caching_observed === false is treated as no signal rather than as
cold.
Assisted-by: claude:claude-opus-5
Contributor
|
Thanks for this, reading
Happy to help with any of these if useful. |
Contributor
This was referenced Oct 31, 2026
Closed
Closed
pcvelz
added a commit
to pcvelz/ccstatusline-usage
that referenced
this pull request
Nov 2, 2026
Upstream: weekly limit timers (sirmalloc#768), prompt cache miss widgets (sirmalloc#770), context window size env override (sirmalloc#352, sirmalloc#407), windowed speed fixes (sirmalloc#769, sirmalloc#771), separator/renderer fixes (sirmalloc#773), custom-command styling (sirmalloc#775), clickable cwd links (sirmalloc#744), account email from live credentials (sirmalloc#724), cache timer reported expiry + short toggle (sirmalloc#576, sirmalloc#592), claude-status lock (sirmalloc#635, sirmalloc#772), dedup token metrics (sirmalloc#622, sirmalloc#725, sirmalloc#735). Not adopted: sirmalloc#765 terminal width from COLUMNS with fixed reserve - the fork keeps flexMode/compactThreshold and tmux pane priority. Hand edits outside conflicts: - README.md: kept fork Configure flex separator behavior bullet and older-updates details wrapper; dropped upstream Related Projects additions (claude-eta) - AGENTS.md: kept fork terminal width wording (sirmalloc#765 not adopted) - src/types/FlexMode.ts, src/tui/components/TerminalWidthMenu.tsx, src/tui/components/__tests__/TerminalWidthMenu.test.ts, src/tui/components/TerminalOptionsMenu.tsx, src/tui/components/__tests__/TerminalOptionsMenu.test.ts: restored, fork keeps terminal width settings - src/tui/App.tsx, src/tui/components/index.ts, src/types/index.ts: re-wired terminal width menu and FlexMode export - src/types/StatusJSON.ts: dropped fork duplicate prompt_cache key, upstream schema is a superset - src/utils/terminal.ts: COLUMNS source gated on non-tmux so tmux pane width keeps priority - src/widgets/WeeklyLimitTimer.ts, src/utils/usage-prefetch.ts, src/widgets/__tests__/WeeklyLimitTimer.test.ts: compat fix - fableUsage/fableResetAt -> weeklyFableUsage/weeklyFableResetAt - src/widgets/ApiUsage.tsx: compat fix - Context Bar honors effective context window (override, clamp, 1.0M format); Weekly renders a valid value despite a session error - src/widgets/__tests__/ApiUsage.localModelFallback.test.ts: output tokens no longer counted in context (upstream sirmalloc#730) - src/utils/__tests__/renderer-flex-width.test.ts, src/utils/__tests__/renderer-ansi.test.ts, src/utils/__tests__/gradient.test.ts, src/utils/__tests__/renderer-separator-collapse.test.ts, src/utils/__tests__/config.test.ts, src/tui/__tests__/App.test.ts: fork deviation - fork width model (flexMode, 6-column full reserve, kept settings, Terminal Width menu entry) - src/utils/__tests__/default-colors.test.ts: fork deviation - accept ansi256:/hex: defaults - src/utils/__tests__/usage-prefetch.test.ts: fork deviation - weekly usage comes from the API, fork widget imports from ApiUsage - src/widgets/__tests__/CurrentWorkingDir.test.ts, src/widgets/__tests__/CustomCommand.test.ts: Settings literal gains flexMode/compactThreshold - src/utils/__tests__/context-window.test.ts, src/utils/__tests__/jsonl-metrics.test.ts: restored fork tests upstream dropped - docs/test-retirements.md: ledger for the dev-reload snapshot-path and RemoteControlStatus glyph (sirmalloc#605) tests upstream replaced
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
CacheTimerinfers its countdown from the newest assistant row's timestamp plus a configured TTL. Its own comment explains why:That is no longer true. Claude Code now includes a
prompt_cacheobject in the status JSON:Why the inference is wrong in the case that matters most
The widget exists to tell you the cache went cold. The inference is least reliable in exactly that situation:
getTranscriptStatereturns{ isWorking: true }whenever a user-role row sits at the tail, and a user row is what a resumed session starts with. So you come back to a session that has been idle for three hours and the widget says🔥 HOT— the opposite of the truth, at the one moment you would act on it.Change
getReportedRemainingSeconds()readsprompt_cache.expires_atand returns null when the field is absent, so older Claude Code versions fall through to the existing transcript logic untouched.caching_observed === falseis treated as "no signal", not as cold. Everything downstream — the glyph slots, the raw/labeled formatting, the TTL keybind — is unchanged.Verified against real payloads, same settings,
--configheld constant:Cache: 🔥 HOTCache: 🟢 34:46warm: falseCache: 🔥 HOTCache: ❄️ COLDprompt_cache(older Claude Code)Cache: 🔥 HOTCache: 🔥 HOTThe middle row is the bug; the third row is the compatibility check.
Notes
StatusJSONgains a permissiveprompt_cacheschema — every field optional and nullable, coerced numbers like the neighbouringrate_limits.bun run lint(tsc + eslint) clean.hit_ratio, andrecache_tokens_if_cold, which is how many tokens the next turn must reprocess once the entry lapses. That second number is the actionable one — a lapsed 1-hour entry on a 200k context is a rebuild billed at 2× the input rate. Happy to add a widget for it separately if you'd want one.https://claude.ai/code/session_01Jy7HKv8er6ZiodbjFeped2