Skip to main content

Claude Timestamp

Every message stamped with the time it happened, and how long it took.

What it does

Claude Timestamp is a Claude Code plugin, not an MCP server: hooks that run at fixed points in a session, plus a /timestamps command to change them. Every assistant message gets a marker like [13:22:13] in your own timezone, followed by how long the turn took, such as +2m14s, counted from the moment you pressed enter to the moment the reply appeared. A turn that crosses a threshold you set gets its duration coloured, so you notice it instead of reading past it. A gap between two messages gets its own label, so a session you return to the next morning still reads in order.

The model is also told the local time of each prompt, so it can reason about when things happened; you can switch that off and keep only the visible marker. On exit, a summary follows: how long the session ran, how many turns, how much of that was waiting, and how long you were away.

Display is display only. The marker is drawn as messages render, never enters the transcript, and never reaches the model.

Quick start

Requires jq and bash, nothing else. If jq is missing, the plugin says so once and then does nothing, rather than failing quietly.

bash
claude plugin marketplace add AraneaDev/claude-timestamp
claude plugin install claude-timestamp@aranea-claude-tools

Hooks are bound when a session starts, so start a new session before markers appear. An already-running session will not pick the plugin up.

Examples

The timestamps on real assistant messages, generated by the project's own screenshot tooling against a real Claude Code session.

Timestamps on assistant messages, with a slow turn highlighted

Two fast turns render dim. The third crossed the slow threshold, so its duration is coloured.

Capabilities

/timestamps changes the current user's settings without you having to find the settings file. The command takes the request directly, so /timestamps tokyo, /timestamps no colour and /timestamps 12 hour clock all work in one step; run it with no argument and it asks. Changes take effect on your next message, because every hook reads the settings file again on each call.

Seven hooks, all of them harness-only, so none of them cost model context.

HookJob
SessionStartCheck jq, prune old state, point a new user at /timestamps
UserPromptSubmitRecord the turn start, tell the model the local time
MessageDisplayDraw the marker on the first batch of each message
SessionEndReport the summary, record the session, clear its state
PreToolUse / PostToolUse / PostToolUseFailureTime tool calls and count failures, only when TOOL_TIMING=on

MessageDisplay fires repeatedly as a message streams. Only the first batch gets a marker; the rest return nothing at all, which Claude Code reads as 'show the original text'. Returning the text unchanged would have meant a wasted round trip on every batch of every message.

Configuration

Settings live in ~/.claude/claude-timestamp.conf as KEY=value, checked against a list of known keys and never executed, so a stray line in it cannot run anything. A project can layer its own settings on top in .claude/claude-timestamp.conf; only the keys it names are overridden.

SettingDefaultWhat it does
TZmachine localIANA name such as Europe/Amsterdam, or empty for local time
DISPLAY_FORMAT24h24h, short, 12h, iso, or any strftime string
COLORdimnone, dim, gray, red, green, yellow, blue, magenta, cyan
ELAPSEDonShows how long the turn took
SLOW_AFTER60Colours the duration past this many seconds, 0 disables
IDLE_AFTER3600Marks a gap this long between messages, 0 disables
SUMMARYonReports session totals on exit
TOOL_TIMINGoffTimes individual tool calls; the only setting that costs anything per tool call rather than per message

A value the plugin cannot use is replaced by its default, and is named at the start of the next session.

Platform notes

Tested on Linux, macOS and Windows on every push. Git Bash on Windows ships without a timezone database: date there silently falls back to UTC for any IANA name it cannot resolve. The plugin detects this, uses local time instead, mentions it once at session start, and refuses to write a pinned zone it knows cannot be honoured. UTC and GMT still work, since those need no database.

Tool timings use sub-second precision where the shell provides it, which needs bash 5 or newer. macOS still ships /bin/bash as bash 3.2, and BSD's date has no %N, so there is no portable fallback: on those platforms durations round to whole seconds and the call counts carry the signal.