Sessions that finish while the Code tab is unfocused are silently marked read

Status Open
Reported on v2.1.246
Maintainer reply None cached
Activity 0 comments · opened Aug 26, 2026

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?

A chat or background task that produces output while the Code tab is not focused has its unread indicator cleared within seconds, without the user ever opening it. Returning to the Code tab clears the indicator on additional sessions in the same sweep.

The practical effect is that completed background work is invisible by default. You start a task, switch to another tab, the task finishes, and there is no dot when you come back. There is no way to tell which tasks finished and which are still running. This workspace runs 20-40 background sessions concurrently, so work gets missed.

How the indicator is derived

The unread dot is not a stored flag. It is computed per session from two fields in the session record:

unread  <=>  lastActivityAt > lastFocusedAt

Both live at %APPDATA%\Claude\claude-code-sessions\<install>\<workspace>\local_<id>.json as epoch-millisecond integers. A key census across all 1,325 non-archived records found no unread, lastReadAt, or unreadCount field anywhere, so that comparison is the whole mechanism.

The bug is that lastFocusedAt is written on sessions the user never focused.

Observed instance, 2026-08-26

The user left the Code tab at approximately 05:26 and returned at 05:35:30 (confirmed). Times are America/New_York. Session names genericised.

| Session | Last activity | lastFocusedAt written | Delta | Result |
|---|---|---|---|---|
| Task A | 05:33:59 | 05:34:24 | +25s | indicator cleared, never opened |
| Task B | 04:39:06 | 05:35:30 | +56m | indicator cleared |
| Task C | 05:32:47 | 05:35:31 | +2m43s | indicator cleared |

Two distinct behaviours are visible:

  1. On completion while unfocused. Task A finished at 05:33:59 and was stamped 25 seconds later. The user was on a different tab for the entire interval and never opened that session.
  2. On tab return. Task B and Task C were stamped at 05:35:30 and 05:35:31, one second apart, coinciding with the user returning to the Code tab. Task B had been idle for 56 minutes. A single user action cannot focus two sessions in the same second.

Sessions in the same window that happened to have a turn after their stamp landed kept their indicator correctly, which is why the bug presents as intermittent rather than total.

What Should Happen?

A session that produces output while unfocused should keep its unread indicator until the user actually opens it.

Specifically:

  • lastFocusedAt should be written only in response to a real user focus event on that specific session.
  • A session should never be stamped because it produced output.
  • Sessions should never be stamped in bulk when the Code tab regains focus. Only the session actually being viewed should be marked read.

Error Messages/Logs

No error output. This is silent data loss, not a crash.

Values read from %APPDATA%\Claude\claude-code-sessions\<install>\<workspace>\local_<id>.json
(stored as epoch milliseconds; rendered here in America/New_York)

Task A   lastActivityAt 2026-08-26 05:33:59   lastFocusedAt 2026-08-26 05:34:24   -> reads as read
Task B   lastActivityAt 2026-08-26 04:39:06   lastFocusedAt 2026-08-26 05:35:30   -> reads as read
Task C   lastActivityAt 2026-08-26 05:32:47   lastFocusedAt 2026-08-26 05:35:31   -> reads as read

None of these three sessions was opened by the user.

Steps to Reproduce

  1. Open the desktop app and start a long-running background task in the Code tab.
  2. Switch to another tab (or another application) and stay there.
  3. Let the task finish. Do not touch the Code tab.
  4. Return to the Code tab and look at the session list.

Expected: the finished task shows an unread indicator.

Actual: no indicator. The session was marked read while the user was elsewhere.

To verify directly rather than by eye, read the session's record at %APPDATA%\Claude\claude-code-sessions\<install>\<workspace>\local_<id>.json before and after, and compare lastFocusedAt against lastActivityAt. Note that both are epoch-millisecond integers, not ISO strings.

Reproduces reliably here across many sessions and several days. It is easiest to see with background tasks, since those are the ones most likely to finish while the user is on another tab.

Claude Model

None

Is this a regression?

I don't know

Last Working Version

_No response_

Claude Code Version

2.1.246 (Claude Code)

Platform

Anthropic API

Operating System

Windows

Terminal/Shell

PowerShell

Additional Information

Third-party Stop hooks are ruled out

This workspace runs a Stop hook that launches powershell.exe for text-to-speech, which was the obvious suspect since the symptom appeared around the time it was installed.

It is not the cause. The hook was removed from all 37 files that declare it (the root .claude/settings.json plus 36 per-worktree copies under .claude/worktrees/*/), the app was restarted, and the hook's own log recorded zero invocations for 18 hours.

Indicators kept clearing during that silence:

| Session | Marked read | Idle at the time |
|---|---|---|
| Task D | 2026-08-25 14:19:23 | 45 min |
| Task B | 2026-08-26 04:55:09 | 16 min |
| Task A | 2026-08-26 05:23:45 | 1 min |
| Task E | 2026-08-26 05:24:53 | 27 min |

This was an end-state scan, so it undercounts: any session wrongly stamped and then given a later turn reads as unread again and never appears in the list. Four confirmed cases is a floor, not a total.

There is no user-side workaround

Writing lastFocusedAt directly into the record does not work. The app holds these records in memory and saves on its own schedule; an external write was overwritten 45 seconds later, not merged.

The only workaround found was an external script that maintains its own seen-state and ignores the app's focus stamps entirely.

Environment note

This is the desktop app (Code tab), not the terminal CLI. The Terminal/Shell field below is answered only because it is required; the integrated terminal for this workspace is PowerShell.

View original on GitHub ↗