Feature: render per-message timestamps in the chat TUI

Resolved 💬 3 comments Opened May 9, 2026 by tomicles Closed May 13, 2026

Summary

Surface the per-message timestamps already stored in the on-disk JSONL transcript inside the TUI scrollback, so users can see when each user message and assistant response happened without leaving the chat surface.

Background

Each entry in ~/.claude/projects/<project-id>/<session-id>.jsonl already carries a precise timestamp. The TUI displays showTurnDuration (relative duration of the most recent turn) but offers no rendering of absolute per-message timestamps.

UserPromptSubmit hooks can inject timestamp content into the prompt context, but the output appears as <system-reminder> metadata — not inline with the user's message bubble — so it doesn't address the use cases below.

Use cases (operational, not prediction-related)

  1. Forensic review of past sessions. When auditing what happened — "when did the deploy land", "when did the security finding surface", "when did the subagent complete" — the user has to grep the JSONL or the bash log. Inline timestamps make scrollback review sufficient.
  1. Long-running session triage across compactions. Sessions that span multiple days and survive context compactions lose temporal anchor — the summary collapses turns into a paragraph with no time markers. Per-message timestamps preserved in scrollback maintain the original event chronology even after summarization.
  1. Idle-time vs active-time identification. Gaps in scrollback where Claude was waiting on the user vs actively working are invisible without timestamps. Useful for understanding "I stepped away for an hour and Claude finished this in 2 minutes" vs "Claude took 8 minutes on that turn."
  1. Multi-session orchestration. Users running multiple Claude Code sessions in parallel tmux panes (e.g. one per project) need to correlate cross-session events. "Did I dispatch the inbox message in session A before or after the failure surfaced in session B?" Without timestamps, the user has to mentally interpolate from clock-glances.
  1. Background agent / subagent completion mapping. When async subagents (Agent tool with run_in_background: true) complete and notify back, knowing the wall-clock time of the notification helps the user understand whether the work actually ran overnight or whether the session was paused.
  1. Subscription rate-limit reconstruction. Pro/Max subscription windows are 5-hour rolling. Users hitting rate limits would benefit from seeing which turns burned the most capacity by mapping high-activity turns to clock time. Today this requires opening the JSONL.
  1. Verifying model claims about "when" — and catching when the model gets it wrong. Without inline timestamps, the model has no visible ground truth for time-of-day. It can (and does) write "shipped this morning", "good push tonight", "the audit landed earlier today" with no anchor — and these phrases stick even when the conversation has spanned midnight or run for days across resumed sessions. The user has no efficient way to catch it; they'd have to mentally cross-check against actual wall-clock or open the JSONL.

Concrete failure observed during the session that motivated this issue: the assistant wrote "good push tonight" describing work that had actually completed the previous calendar day. The user noticed because they happened to be paying attention to date-vs-claim drift; in normal flow this kind of error slips through. Inline per-message timestamps make it obvious — both for the user reading scrollback and for the model reading its own prior context.

This isn't a model-quality fix per se; it's a UI fix that makes the time-of-day axis visible enough to catch errors that today are silent.

  1. Pair-debugging forensics. When a deploy at 11:43 breaks something a user tests at 11:50, having timestamps in scrollback turns the chat into a usable forensic record alongside server logs.
  1. Preserving "when" across resumed sessions. claude --resume <project> re-loads scrollback. Today the user has no marker of whether a particular line happened 5 minutes ago or 3 days ago. Timestamps make resumed sessions navigable.

Proposed implementation

Add a settings.json key:

{
  "showMessageTimestamps": true,
  "messageTimestampFormat": "%a %Y-%m-%d %I:%M:%S %p %Z"
}

(Format string in strftime(3) syntax — defaults to ISO 8601 if not specified.)

Add a CLI flag for one-off enable: --message-timestamps.

Render shape (proposal — final design at maintainer discretion):

[Sat 2026-05-09 11:55:47 AM PDT]
> hello

[Sat 2026-05-09 11:55:48 AM PDT]
< Claude's response continues here...

Or compact, right-aligned:

> hello                                          [11:55:47 AM PDT]

< Claude's response...                           [11:55:48 AM PDT]

Notes

  • Data already exists in the JSONL — this is a render-side change only.
  • showTurnDuration and showMessageTimestamps are independently useful; suggest both can coexist.
  • Timezone display should follow system locale; absolute UTC could be a secondary option.
  • Live updates not required — timestamps are recorded at message time and don't change.

Workarounds today (all incomplete)

  • UserPromptSubmit hook injecting [timestamp] to stdout — appears as <system-reminder> metadata, not inline with message bubble.
  • Manual grep of the on-disk JSONL — works but breaks flow.
  • External tmux status bar polling a hook-written sentinel file — visible but not coupled to specific messages.

---

Versioning: Tested behavior current as of Claude Code v2.1.x. No existing key controls absolute timestamp rendering per claude-code-guide confirmation.

View original on GitHub ↗

This issue has 3 comments on GitHub. Read the full discussion on GitHub ↗