Skip to content

feat(ui): optional last-update timestamp badge on session rows#1165

Draft
rodrimendoza wants to merge 1 commit into
asheshgoplani:mainfrom
rodrimendoza:feat/session-timestamps
Draft

feat(ui): optional last-update timestamp badge on session rows#1165
rodrimendoza wants to merge 1 commit into
asheshgoplani:mainfrom
rodrimendoza:feat/session-timestamps

Conversation

@rodrimendoza
Copy link
Copy Markdown

@rodrimendoza rodrimendoza commented May 23, 2026

Summary

Adds an opt-in dim Nm ago / Nh ago / Nd ago badge after each session row, showing the most recent of:

  1. Instance.CreatedAt (SQLite, persisted floor)
  2. Instance.LastStartedAt (SQLite, lifecycle restart)
  3. Latest hook event UpdatedAt (StatusFileWatcher, present when agent-deck hooks are installed in Claude/Codex settings)
  4. Confirmed tmux activity time (StateTracker.lastChangeTime, gated on a new realActivityConfirmed flag so freshly-built trackers don't falsely report "just now" for every session after restart)

The formula lives in pickBadgeTime (pure function) so it's unit-testable in isolation. LastAccessedAt is deliberately excluded — attaching to a quiet session to peek at it isn't an "update", and including it made the badge lie.

No pre-existing issue — happy to file one and discuss the design first if preferred.

Screenshots

Settings menu — toggle on (off by default)

image

Sessions list with the badge enabled

image

Why a new realActivityConfirmed flag in tmux.StateTracker?

Naively reading lastChangeTime is the obvious first attempt and was where I started. It doesn't work because tmux.go initializes lastChangeTime = time.Now() at tracker construction — so right after agent-deck starts, every session reports "just now" regardless of how long it's actually been idle.

The flag flips true only at the explicit-busy confirmation paths inside Session.GetStatus and Session.getStatusFallback (git grep 'realActivityConfirmed = true'), never at construction. Callers consult the bool before consuming the time value, so the "never observed" case falls back to the lifecycle floor.

How to enable

Settings → DISPLAY → Show session timestamps (default off). Persisted as [display] show_session_timestamps = true. Toggle takes effect immediately, no restart.

Risk

Render-path cost per row per tick: two in-memory accessor calls (hook watcher map + tmux confirmed activity) plus a handful of time.Time comparisons. No new I/O, no new goroutines. The StatusFileWatcher already runs for hook status display.

Test plan

  • go build ./... clean
  • New unit tests pin: the realActivityConfirmed flag (false at init, true after confirmation, zero-time sentinel when unobserved), the full pickBadgeTime formula across all 4 layers with nil/zero/unobserved edges, LastAccessedAt exclusion, nil tmuxSession safety, merge round-trip, settings-panel scroll mapping reaches the new row
  • Manual verification: badge ticks live during an active Claude answer, freezes at last-active timestamp when Claude finishes, no false "just now" mass reset after agent-deck restart
  • Maintainer manual verification

🤖 Generated with Claude Code

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 23, 2026

Important

Review skipped

Draft detected.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 01131376-b938-4ced-89e9-4ca0dc370fb3

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Comment @coderabbitai help to get the list of available commands and usage tips.

@rodrimendoza rodrimendoza force-pushed the feat/session-timestamps branch 5 times, most recently from 1d3e79e to a906e85 Compare May 23, 2026 14:18
Adds an opt-in dim "Nm ago" / "Nh ago" / "Nd ago" badge after each
session row, controlled by [display] show_session_timestamps in
config.toml (default off, toggle in Settings → DISPLAY).

The badge picks the newest of, in order:

  1. Instance.CreatedAt            (SQLite, persisted floor)
  2. Instance.LastStartedAt        (SQLite, lifecycle restart)
  3. Latest hook event UpdatedAt   (StatusFileWatcher, present when
                                    agent-deck hooks are installed
                                    in Claude/Codex settings)
  4. Confirmed tmux activity time  (tmux.StateTracker.lastChangeTime,
                                    gated on a new realActivityConfirmed
                                    flag so freshly-built trackers
                                    don't falsely report "just now"
                                    for every session post-restart)

LastAccessedAt is deliberately excluded: attaching to a quiet session
to peek at it isn't an "update", and including it made the badge lie.

Why a new flag in tmux.StateTracker?
  Naively reading lastChangeTime doesn't work — tmux.go initializes it
  to time.Now() at tracker construction, so right after agent-deck
  starts every session reports "just now" regardless of how long it's
  actually been idle. The flag flips true only at the explicit-busy
  confirmation paths in Session.GetStatus and getStatusFallback (grep
  realActivityConfirmed = true), never at construction. Callers
  consult the bool before consuming the time.

Performance: render-path cost per row per tick is two in-memory
accessor calls (hook watcher map + tmux confirmed activity) plus a
handful of time.Time comparisons. No new I/O, no new goroutines.
The StatusFileWatcher already runs for hook status display.

Persistence: the toggle is added to MergePanelConfigOntoDisk's
allowlist (issue asheshgoplani#1067) so it actually round-trips; the cached value
on Home is refreshed immediately after the panel saves, so the
toggle takes effect without a restart.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@rodrimendoza rodrimendoza force-pushed the feat/session-timestamps branch from a906e85 to baa7dd8 Compare May 23, 2026 20:55
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant