[BUG] Desktop activity dashboard streak/heatmap credits the session-start date, not each active calendar day - multi-day sessions wrongly break the streak
Preflight Checklist
- [x] I have searched existing issues and this hasn't been reported yet
- [x] This is a single bug report (please file separate reports for different bugs)
- [x] I am using the latest version of Claude Code
What's Wrong?
The activity dashboard in the Claude Code Desktop app (the "What's up next" welcome screen with Sessions / Messages / Active days / Current streak / Longest streak / heatmap) appears to attribute a session's activity to a single date rather than to every calendar day on which messages were actually sent.
Hypothesis: the streak and heatmap credit the day a session STARTS, not each day the session is active. A single long-lived session that spans multiple calendar days therefore lands entirely on its start date, leaving the intervening days blank and breaking the streak - even though messages were genuinely sent on those days.
This disproportionately affects users who run long continuous sessions, which the worktree-isolated desktop workflow actively encourages.
Evidence
- I inadvertently ran one continuous session from Jun 9 into the early hours of Jun 11.
- That session contains a message timestamped Jun 10, 2026, 9:57 PM (local) - clear activity on the 10th.
- Despite that, the 10th is not credited as an active day, and my Current streak shows 0d. My Longest streak (30d) was effectively ended by a day I was demonstrably active.
Expected Behavior
Each calendar day on which at least one message is sent should count as an active day for the heatmap and streak, regardless of which day the containing session was started.
Actual Behavior
Days on which activity occurred within an already-running session are not counted. The streak breaks despite genuine daily activity.
Possible Secondary Factor
Worth checking whether day-bucketing uses UTC vs the user's local timezone. I'm in New Zealand (UTC+12), so late-evening local activity falls near or across a UTC date boundary, which could compound the mis-bucketing.
Environment
- Product: Claude Code Desktop app (macOS)
- Hardware: Apple Silicon (M2 Max)
- App version: Claude Desktop 1.11847.5
- Timezone: Pacific/Auckland (UTC+12)
What Should Happen?
Each calendar day on which at least one message is sent should count as an active day for the heatmap and streak, regardless of which day the containing session was started.
Error Messages/Logs
N/A - no error output. This is a silent miscount in the activity dashboard display, not a crash.
Steps to Reproduce
- Start a session shortly before midnight (local time).
- Keep working in that same session past midnight, into the next calendar day (and ideally a third day).
- Open the activity dashboard.
- Observe that only the session's start date is credited in the heatmap; the later day(s) show as inactive and the current streak resets.
Claude Model
Not sure / Multiple models
Is this a regression?
No, this never worked
Last Working Version
N/A
Claude Code Version
Claude Code 2.1.114
Platform
Other
Operating System
macOS
Terminal/Shell
Other
Additional Information
Auth/platform: Claude Pro subscription via the Claude Code Desktop app (not an Anthropic API key, Bedrock, or Vertex).
Reproduced in the Claude Code Desktop app (Code tab) GUI, not a terminal session.
Worth noting the user-impact angle: a streak counter punishing you for a technicality would likely do the opposite of what gamification is for.
<img width="627" height="463" alt="Image" src="https://github.com/user-attachments/assets/56e9d4a7-594e-4bff-bc91-3a0bbed2387e" />
<img width="879" height="346" alt="Image" src="https://github.com/user-attachments/assets/9d76b1f9-9ad6-4b3d-85af-fe50ee88f5b1" />
<img width="575" height="252" alt="Image" src="https://github.com/user-attachments/assets/727e833e-90e6-40ca-a262-e29d7a0234e9" />
<img width="538" height="272" alt="Image" src="https://github.com/user-attachments/assets/d7af32c5-241c-4a7e-a45f-bdf77f2ecac3" />
<img width="570" height="250" alt="Image" src="https://github.com/user-attachments/assets/62ce0816-337f-445c-a96c-46c7661635a2" />
<img width="467" height="222" alt="Image" src="https://github.com/user-attachments/assets/e32dbc45-6db5-4bfa-8946-26b81e62fc9c" />
Showing cached comments. Read the full discussion on GitHub ↗
9 Comments
Confirmed on Windows 11, v2.1.177 — adding a workaround that works today.
Root cause (verified): The stats panel reads the first user-event timestamp per JSONL file for heatmap/active-days/streak attribution — not individual message timestamps within a continuing session. A session started on Jun 13 and continuing through Jun 14–18 lives in a single JSONL file, so all activity registers as one Jun 13 session.
Evidence from my files:
| File start date | Lines |
|---|---|
| Jun 13 | 986 (session continued for 5 days) |
| Jun 14 | 1,400 |
| Jun 15 | 3,228 |
| Jun 17 | 1,479 |
| Jun 18 | 41 |
Before fix: Sessions: 2, Active days: 1, Streak: 1d. After creating one stub JSONL per missing day: Sessions: 6, Active days: 5, Streak: 2d. Root cause confirmed.
Workaround — create one minimal stub JSONL per missing day, then restart Claude Code:
Restart the app after running — stats update on startup.
---
Reported by: @sohan1611
Confirming this on the CLI (/usage → Stats), v2.1.170, WSL2 / Ubuntu 24.04.
The bug is demonstrable from /usage's own numbers without any external tooling. It reports two things that can't both be true:
A 5-day session alongside a 1-day current streak only makes sense if a day is credited to the session's start date instead of to each calendar day its messages land on - exactly as described here.
Ground truth from the in-content timestamps over the same window: 34 consecutive active days (2026-05-19 → 2026-06-21), zero gaps. /usage shows 16 active and a 1-day streak.
Anyone can reproduce the true count:
(Likely compounded by UTC vs local-tz day-bucketing, as https://github.com/anthropics/claude-code/issues/67085 notes.) +1 - the fix is to bucket active-days/streak/heatmap by per-message timestamp, not session start date.
Confirming this on Windows desktop (new-session stats card) — same root cause, with concrete numbers in case a fresh repro helps prioritize.
Symptom: the heatmap showed a recent calendar day as empty (0), breaking what the card reported as a 55-day "longest" / 2-day "current" streak.
Reality, measured directly from
~/.claude/projects/**/*.jsonl:Mechanism (two compounding bugs):
Suggested fix: compute
active days,current/longest streak, heatmap intensity, andpeak hourby bucketing each message's timestamp in the user's local timezone, not by session-creation date.Why it matters (user impact): for people who use Claude Code every day, this card is a meaningful motivation signal — a visible record of an unbroken daily habit. Silently zeroing out real working days and resetting a months-long streak is discouraging and, more importantly, wrong — the underlying data is intact; only the aggregation is off. Would love to see this fixed. Happy to provide an anonymized per-day event count if useful.
Confirming on Windows 11, Claude Code desktop app — managed core 2.1.197 (Jun 30 build), MSIX shell 1.18286.0 (Jul 4, 2026).
I reproduced the dashboard's numbers exactly from the local transcripts (
~/.claude/projects/**/*.jsonl): counting non-sidechain sessions and their user+assistant events matched the dashboard to the message (91 sessions / 40,002 messages at first check; 92 / 40,036 after one more session was created). Grouping each session's lifetime messages under its session-start date reproduces every heatmap cell value, confirming the attribution this issue describes.Concrete failure: July 3 had 101 real messages on disk, but all of them were in two sessions opened July 2, so the July 3 bucket is 0, the heatmap shows a gap, and the streak reset to 1d despite 12+ consecutive active days of actual usage.
The one-day label offset tracked in #65665 / #67625 is also still present in this version and compounds the confusion: the bucket keyed 2026-07-02 (733 msgs) shows the tooltip "Jul 1 — 733", and the empty 2026-07-03 bucket shows "Jul 2 — 0" (system TZ UTC-4). So the visible gap appears under a label one day earlier than the actual empty bucket.
Expected: bin individual message timestamps by local calendar day, and match tooltip/label dates to bucket dates.
Edit: corrected the version line — I originally wrote "desktop 2.1.160", but that was a stale npm CLI on my PATH. The dashboard actually runs the app-managed core 2.1.197, so both behaviors reproduce on a near-current build.
Possibly a second, distinct root cause for the same symptom — worth checking alongside the session-start-date hypothesis.
On the same desktop dashboard, my blank-days /
Current streak 0dturned out to be a UTC-vs-local timezone bucketing issue, not session-start attribution. I ruled out the session-start theory for my data by bucketing on per-message timestamps directly and still seeing the shift.Environment
Claude 1.18286.0 (259c3f) 2026-07-02T07:11:03.000ZAmerica/New_York(UTC−4 during DST)Evidence
The session JSONL
"timestamp"fields are stored in UTC. When I bucket them by UTC date vs my local (EDT) date, evening sessions jump a day:00:00Zthe next day, so they land on the following UTC cell — and the real local day reads as0.America/New_Yorkmoved those events back onto the prior day and made the counts match what I actually did.So on a negative-UTC-offset timezone this manifests as the classic "recent dates off by one day" — the tooltip/heatmap credits the UTC day, not the local day.
Likely same underlying cause as #65665 (part 1: recent dates off by one day). That report is filed against the TUI
/stats; this is the desktop app dashboard, so the bucketing logic may be shared.Possible secondary effect:
Active daysalso seemed to apply a minimum-activity threshold — very light days (a few dozen messages) didn't count as active, further lowering the total. Lower confidence; noticed while reconciling the numbers.Suggested fix: bucket the heatmap and streak/active-day calculations by the user's local timezone (or make the timezone explicit/configurable), using per-message timestamps.
Follow-up with a concrete, reproducible data point on macOS that narrows this down — the desktop app's own store contains the sessions for a day the heatmap shows as empty.
On this machine there are two stores:
~/.claude/projects/<project>/<session-uuid>.jsonl~/Library/Application Support/Claude/claude-code-sessions/<workspace-id>/<id>/local_<uuid>.json— small per-session metadata records (cliSessionId,createdAt,lastActivityAt,cwd,completedTurns,model…) that reference the CLI session.For one heavily-used afternoon (local
America/New_York, UTC−4):local_*.jsonwritten 14:59 and 20:08 local, withcreatedAt/lastActivityAton that date).So the desktop app has that day's sessions in its own directory, yet the activity dashboard renders the day as empty / doesn't credit the streak. That rules out a data-capture problem and points squarely at the aggregation layer — whatever reads these records into the heatmap is either bucketing by the UTC timestamp (see above) or keying off the wrong date field, rather than crediting each local calendar day the records actually cover.
Repro sketch (no session content needed): compare
createdAt/lastActivityAt/per-message timestamps in the stores above against the day each session is credited to in the dashboard; on a negative-UTC-offset timezone, afternoon/evening-local sessions land on the wrong day or drop out.Another data point confirming the session-start-date attribution bug.
My dashboard currently shows Current streak: 0d, while Active days: 30 and Longest streak: 30d are equal — which by itself proves the streak was never actually broken in the account's history.
Local session logs (
~/.claude/projects/**/*.jsonl) show activity on every single calendar day. The day the dashboard treats as empty is 2026-07-07: ~976 messages were sent that day (from 09:00 local to 00:44 the next night, UTC+6), but all of them inside a session that was started on 2026-07-06. No new session was created on 07-07, so the dashboard credited two full days of work to 07-06, rendered 07-07 as inactive on the heatmap, and reset the current streak to 0.Message timestamps inside the spanning session file, grouped by UTC hour, show solid activity blocks on 2026-07-07 at 03–04, 09–11, and 17–18 UTC (several hundred messages) — yet the day counts as empty.
Attributing activity by per-message timestamps instead of session creation date would fix Active days, the heatmap, streaks, and peak hour all at once.
Same issue here, and I can add a verified reproduction with data.
Environment: Windows desktop app 1.22209.0.0 (bundled CLI 2.1.209), Windows 10, UTC+8.
On Jul 16 I used Claude Code for hours (~251 messages timestamped Jul 16 in my local
~/.claude/projectstranscripts — all within Jul 16 in UTC too, so not the UTC-bucketing issue). But all of it was in two resumed sessions (started Jun 30 and Jul 14), and no new session was created that day. The dashboard shows "Jul 16 — 0" and my streak reset to 0d.I replayed the stats algorithm against my local transcripts, and every dashboard number matches session-start-date bucketing:
Note the CLI
/statsscan in recent builds already buckets messages by their own timestamp (dailyActivity[date].messageCount++per message), so the desktop dashboard is inconsistent with the CLI. Users who keep one long-running session per project and resume it daily end up with empty heatmaps and permanent 0-day streaks.Confirming this on Claude Code 2.1.216 (macOS, arm64), and it is especially punishing for always-on / daemon setups.
I run a long-lived background agent (Claude Agent SDK daemon) that keeps sessions open for days. My "Longest session" reads 16d 23h. Because activity is credited to the session-start calendar day, whole days worked entirely inside a resumed / long-running session show 0 in
dailyActivity, and a single such gap resets the streak.Concrete repro from my own
~/.claude/stats-cache.json(I diagnosed it by reconstructing per-day event counts from the session JSONL timestamps):dailyActivity, even though I worked that entire local calendar day.There are two compounding root causes here:
getUTCDate/toISOStringare what the bundle uses) instead of the user's local timezone, so evening work for UTC-negative users leaks into the next day.Suggested fix: bucket each event by its own timestamp, in the user's local/system timezone, rather than by session start and rather than in UTC. That single change fixes both the multi-day-session breakage and the timezone-boundary breakage.