You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
This issue was auto-closed. Issues from new contributors are auto-closed by default.
Maintainers review auto-closed issues and reopen worthwhile ones. Issues that do not meet the quality bar in CONTRIBUTING.md may not be reopened or receive a reply.
Keep the issue short, concrete, and written in your own voice.
If a maintainer replies lgtmi, your future issues will stay open. If a maintainer replies lgtm, your future issues and PRs will stay open.
I read the docs, I might have missed something important in there.
The question I am asking is if may implement a type of cashing. Basically having ccusage write the values it gets into a cache, and have the option to recall these values from cache.
I fully understand if this is not the kind of feature we want in ccusage.
Hit the same thing — lost usage due to the rotation back on June 9, so I built a small on-disk cache and have been running it as my daily driver since. To actually verify it holds, I deleted some of my logs by hand and re-ran both side by side.
Stock ccusage — only what's left on disk after the delete ($108.56):
My cached build — same machine, kept the deleted days ($465.17):
Same live data on both sides; the cache just adds back the Claude days whose logs were gone. Logic: once the logs are deleted that history is normally unrecoverable, but the cache still has it.
Speed bonus: stock run (57.5s here), while a warm cache serves precomputed rows straight from cache (0.88s) — ~65× faster on wall-clock. The first/cold run that populates the cache is ~stock speed since it computes and writes; the win is on every run after.
It's a SQLite cache that stores each log's result once, keyed by file (no double-counting), live logs always win, and there's a --live-only flag to ignore it. One honest catch: once a log is gone its cached cost can't be re-verified, so the cache only ever adds — it never overrides live data.
Happy to put up a draft PR or a quick design note if you're open to it.
I keep hitting this on ccusage monthly over time: older months keep shrinking on every run. I dug into why and I think this issue is worth doing — here's the evidence and a concrete design.
Root cause (confirmed)
Claude Code deletes session transcripts under ~/.claude/projects/**/*.jsonl once they're older than cleanupPeriodDays (default 30) on startup. That's not ccusage — it's upstream behavior, and it's well documented now:
ccusage fully rescans and recomputes from the surviving JSONL files on every run and persists nothing between runs, so once Claude prunes a file, the cost/tokens it contributed silently disappear from daily/weekly/monthly. As @Buster210 showed above, that can be the difference between ~$108 and ~$465.
Proposed design
An on-disk cache for the date-bucketed reports (daily/weekly/monthly) that only ever adds back history — it never overrides live data:
After the live scan produces per-day summaries (before --since/--until filtering), merge them with a cached copy keyed by (project, date).
For each day, keep the higher-cost of {live, cached} so a day whose logs were partially or fully pruned can't shrink. Live wins on ties (fresh data).
Persist the merged per-day summaries back. Days that still have logs get refreshed; days whose logs are gone are served from cache.
Scope the cache by timezone + cost mode so -z/--mode variants don't mix.
Cache file lives outside the paths Claude prunes (e.g. <claude-dir>/ccusage/), so it survives cleanup.
Add --no-cache to bypass read+write for a pure-live run.
Scope note: session/blocks need per-entry data, so they'd stay live-only; the cache covers the date-bucketed reports where the shrinking is visible.
I've already prototyped this against the Rust CLI and have it working. Happy to open a PR if a maintainer is open to it (I know the gate requires lgtm first).
@Spenhouet good write-up. Same root cause for me, the 28-day jsonl cleanup is what ate my June 9 history.
The main difference is where we cache. You're caching the date-bucketed summaries keyed by (project, date) and keeping the higher of {live, cached}. I went lower and cache each source log's result keyed by file, deduped on the billable-call id so nothing double counts. It's more storage, but because it's at the log level it also covers session and blocks, not just daily/weekly/monthly.
The part I spent the most time on was making sure it doesn't lie. For days whose logs still exist, it reprices on read so a warm run is identical to stock. I actually deleted a few of my own logs by hand and ran both builds side by side to confirm the live numbers still lined up. They did.
For days that are already gone, the cost falls back to a small spend ledger that keeps the value from the last run before the file disappeared. I froze that on purpose so a later price-table change can't rewrite spend I already paid. There's a test pinning it (ledger_entry_cost_immutable_after_pricing_change) so it won't silently drift.
Cache db sits in ~/.cache/ccusage, outside what Claude prunes, so cleanup leaves it alone. Warm runs are about a second here vs ~57s cold. --live-only skips it, clear-cache wipes it.
Either way the rule is the same: it only adds history back, never shrinks a day. Been running it as my daily driver for a week. Fine to align on whichever level a maintainer prefers.
A maintainer explicitly requested an implementation attempt. Clear, repository-scoped enhancement request with concrete motivation and constructive follow-up designs. It is not spam, invalid, a duplicate, explicitly wontfix, or out of scope.
Decision: kept open; Pullfrog will attempt a focused implementation PR.
Closing as not planned for now. A response cache needs an explicit retention, invalidation, privacy, and stale-data contract before it can be added safely; the issue does not define those boundaries. The current statusline process-leak work is tracked separately in #1596.
@ryoppippi I'm not really getting what the problem is on implementing caching. Without this ccusage is unusable over time. I'm using my own version of it with caching for a while now. Was just hoping you would finally add it. You closed this ticket due to some additional details not being defined but why not just raise these here so we can define them? Why closing this issue? And why not just implement it with what ever addition requirement you have in mind?
Historical audit: this discussion was auto-closed by the legacy contributor gate. That closure did not assess technical importance.
Audit result: excluded from the current maintenance scope. This request depends on an unsupported external source, unavailable schema or fixture, platform or release infrastructure the project cannot reliably maintain, an operational service, or an unsafe or underspecified design. It is not a candidate for automatic reopening or implementation.
Activity
pullfrog commentedon Jun 10, 2026
github-actions commentedon Jun 10, 2026
This issue was auto-closed. Issues from new contributors are auto-closed by default.
Maintainers review auto-closed issues and reopen worthwhile ones. Issues that do not meet the quality bar in CONTRIBUTING.md may not be reopened or receive a reply.
Keep the issue short, concrete, and written in your own voice.
If a maintainer replies
lgtmi, your future issues will stay open. If a maintainer replieslgtm, your future issues and PRs will stay open.See CONTRIBUTING.md.
ryoppippi commentedon Jun 10, 2026
@caillou
claude code deletes logs in 28 days by default. check out cc's docs and ccusage.com
caillou commentedon Jun 10, 2026
@ryoppippi thanks for your reply.
I read the docs, I might have missed something important in there.
The question I am asking is if may implement a type of cashing. Basically having
ccusagewrite the values it gets into a cache, and have the option to recall these values from cache.I fully understand if this is not the kind of feature we want in
ccusage.ryoppippi commentedon Jun 11, 2026
does ccusge takes time to you? now it's really fast right?
caillou commentedon Jun 11, 2026
@ryoppippi I don’t think I expressed my requirement well enough.
The purpose of the cash is not to speed things up, but to keep historic data, which is not provided by the Anthropic API.
Buster210 commentedon Jun 12, 2026
@ryoppippi
Hit the same thing — lost usage due to the rotation back on June 9, so I built a small on-disk cache and have been running it as my daily driver since. To actually verify it holds, I deleted some of my logs by hand and re-ran both side by side.
Stock ccusage — only what's left on disk after the delete ($108.56):
My cached build — same machine, kept the deleted days ($465.17):
Same live data on both sides; the cache just adds back the Claude days whose logs were gone. Logic: once the logs are deleted that history is normally unrecoverable, but the cache still has it.
Speed bonus: stock run (57.5s here), while a warm cache serves precomputed rows straight from cache (0.88s) — ~65× faster on wall-clock. The first/cold run that populates the cache is ~stock speed since it computes and writes; the win is on every run after.
It's a SQLite cache that stores each log's result once, keyed by file (no double-counting), live logs always win, and there's a
--live-onlyflag to ignore it. One honest catch: once a log is gone its cached cost can't be re-verified, so the cache only ever adds — it never overrides live data.Happy to put up a draft PR or a quick design note if you're open to it.
Spenhouet commentedon Jun 17, 2026
I keep hitting this on
ccusage monthlyover time: older months keep shrinking on every run. I dug into why and I think this issue is worth doing — here's the evidence and a concrete design.Root cause (confirmed)
Claude Code deletes session transcripts under
~/.claude/projects/**/*.jsonlonce they're older thancleanupPeriodDays(default 30) on startup. That's not ccusage — it's upstream behavior, and it's well documented now:.jsonl, wiping token usage historycleanupPeriodDaysset high (triggered by updates/restarts)ccusage fully rescans and recomputes from the surviving JSONL files on every run and persists nothing between runs, so once Claude prunes a file, the cost/tokens it contributed silently disappear from
daily/weekly/monthly. As @Buster210 showed above, that can be the difference between ~$108 and ~$465.Proposed design
An on-disk cache for the date-bucketed reports (
daily/weekly/monthly) that only ever adds back history — it never overrides live data:--since/--untilfiltering), merge them with a cached copy keyed by(project, date).-z/--modevariants don't mix.<claude-dir>/ccusage/), so it survives cleanup.--no-cacheto bypass read+write for a pure-live run.Scope note:
session/blocksneed per-entry data, so they'd stay live-only; the cache covers the date-bucketed reports where the shrinking is visible.I've already prototyped this against the Rust CLI and have it working. Happy to open a PR if a maintainer is open to it (I know the gate requires
lgtmfirst).Buster210 commentedon Jun 18, 2026
@Spenhouet good write-up. Same root cause for me, the 28-day jsonl cleanup is what ate my June 9 history.
The main difference is where we cache. You're caching the date-bucketed summaries keyed by
(project, date)and keeping the higher of {live, cached}. I went lower and cache each source log's result keyed by file, deduped on the billable-call id so nothing double counts. It's more storage, but because it's at the log level it also covers session and blocks, not just daily/weekly/monthly.The part I spent the most time on was making sure it doesn't lie. For days whose logs still exist, it reprices on read so a warm run is identical to stock. I actually deleted a few of my own logs by hand and ran both builds side by side to confirm the live numbers still lined up. They did.
For days that are already gone, the cost falls back to a small spend ledger that keeps the value from the last run before the file disappeared. I froze that on purpose so a later price-table change can't rewrite spend I already paid. There's a test pinning it (
ledger_entry_cost_immutable_after_pricing_change) so it won't silently drift.Cache db sits in
~/.cache/ccusage, outside what Claude prunes, so cleanup leaves it alone. Warm runs are about a second here vs ~57s cold.--live-onlyskips it,clear-cachewipes it.Either way the rule is the same: it only adds history back, never shrinks a day. Been running it as my daily driver for a week. Fine to align on whichever level a maintainer prefers.
github-actions commentedon Aug 28, 2026
Pullfrog triage: priority:medium
A maintainer explicitly requested an implementation attempt. Clear, repository-scoped enhancement request with concrete motivation and constructive follow-up designs. It is not spam, invalid, a duplicate, explicitly wontfix, or out of scope.
Decision: kept open; Pullfrog will attempt a focused implementation PR.
ryoppippi commentedon Aug 30, 2026
Closing as not planned for now. A response cache needs an explicit retention, invalidation, privacy, and stale-data contract before it can be added safely; the issue does not define those boundaries. The current statusline process-leak work is tracked separately in #1596.
Spenhouet commentedon Aug 31, 2026
@ryoppippi I'm not really getting what the problem is on implementing caching. Without this ccusage is unusable over time. I'm using my own version of it with caching for a while now. Was just hoping you would finally add it. You closed this ticket due to some additional details not being defined but why not just raise these here so we can define them? Why closing this issue? And why not just implement it with what ever addition requirement you have in mind?
ryoppippi commentedon Aug 31, 2026
Historical audit: this discussion was auto-closed by the legacy contributor gate. That closure did not assess technical importance.
Audit result: excluded from the current maintenance scope. This request depends on an unsupported external source, unavailable schema or fixture, platform or release infrastructure the project cannot reliably maintain, an operational service, or an unsafe or underspecified design. It is not a candidate for automatic reopening or implementation.