feat(desktop): sidebar plans read in regular weight, bold only when unread
Merged
DA
8d ago+363+363+012345678901234567890123456789-62-62-01234567890123456789
Dean: "Let's not use bold text for plans in the sidebar, it makes them look like they are unread. Maybe let's use it for unread plans."
What
- Plan names in the sidebar use regular weight. This includes the selected row, since its fill already marks it. The inline rename field matches.
- An unread plan's name is semibold, the old weight. Screen readers hear "(unread)" after the name. This applies the same way to pinned rows, rows under a repository, and archived rows.
- What unread means: the plan was saved after its "last looked" mark on this Mac. That covers saves by Luke, an agent, or you on another Mac. It clears once you've had the plan open long enough to count as looked: #2025's 3-second rule. After that, saves that land while the plan is open never make it unread, so the open plan doesn't flicker bold when the list refreshes ahead of the document.
- No second store. The sidebar reads #2025's per-plan marks (
luke.planLooks, the service's save timestamps by plan id). Those marks now live in one shared atom (planning/use-plan-looks.ts), backed by the same storage, so a look on the open plan clears its row right away. Each write starts from what storage holds, so a second panel window's marks aren't overwritten. The comparison is the summary'supdatedAtagainst the mark. The mark now also takes the plan'supdatedAtinto account, because the service stamps that apart from the revision's own time. - Seeding on first run. The first time this build reads the plan list successfully (
listRead, which is new onPlansControl), it marks every listed plan that has no mark yet, archived ones included, at its currentupdatedAt. It then setsluke.planLooksSeeded. A read list in which no plan has a mark, meaning another account this Mac hasn't listed before, is seeded the same way. Nothing reads as unread until that has happened. So the plans that already exist don't all turn bold, and a plan you looked at under #2025 keeps its real mark. Once seeded, a plan with no mark (for example, one started on another Mac) is unread once anything has been saved in it after it was started. A fixture (staged) run shows nothing as unread and seeds nothing. - The collapsed group header gets no unread hint. That part was optional and would add clutter next to #2043's count.
Tests (desktop/desktop-sidebar.test.ts, through DesktopSidebar)
- On first run, the listed plans are read, the open one included, and nothing is unread before the list read lands. This covers seeding.
- A plan saved after its mark is unread, and so is a new plan from another Mac with saves in it. A plan with no saves isn't. An archived plan follows the same rule, and the row says "(unread)".
- Opening an unread plan: it stays bold until
PLAN_LOOKpasses on theTestClock(the realusePlanLooksruns beside it), then it's read, and it stays read after you leave it. - A save that lands on the plan you're looking at never makes it unread.
- Another account's plans, listed on this Mac for the first time, are read.
- Checked: the 2nd and 3rd fail with the change reverted. Disabling seeding fails the 1st and 2nd. Removing the "watched" exclusion fails the 4th. Dropping the account-switch seed fails the 5th. #2025's
plan-looks.test.tsstill passes unchanged.
Screenshots
Headless Chrome, real DesktopSidebar and real stylesheet, Linux fonts. "Usage-based invoices" is open. "Billing retries" and "Search ranking" are unread.
| Light | Dark |
|---|---|
![]() | ![]() |
CI could not verify the Mac UI, and ./scripts/verify.sh was not run. This was built on a Linux VM. LUKE-159 is the manual Mac pass. ./scripts/check.sh exits 0.
š¤ Generated with Claude Code

