Claude Action Timeline
Timestamps for every Claude Code action. A live timeline of what Claude
Code is doing in your workspace — every prompt, tool call, reply and how long
each took — read from the session transcripts Claude Code already writes
locally.

Unofficial. This is an independent, community-built extension. It is not
made by, endorsed by, or affiliated with Anthropic. "Claude" is Anthropic's
trademark and is used here only to describe what the extension reads.
What you get
- Timeline view (activity bar → clock icon): one row per action with the
wall-clock time beside it. Tool calls show a one-line summary (the command's
description, the file's name, the search pattern…) and gain a duration the
moment their result lands. Failed tool calls are marked, and a call the
permission layer refused reads
denied with its reason — a permission
rule, a call you declined, or an auto-mode classifier outcome — in a muted
icon rather than the error red, because a rule doing its job is not a
failing tool. A call still waiting for its result reads no result 4m
with an ellipsis icon — the age stays current — and API errors and
conversation compactions get rows of their own instead of masquerading as
replies or vanishing.
- Click to open: rows for file tools (
Read, Edit, Write,
NotebookEdit) open the file they acted on; the hover shows the full path.
Rows for everything else stay inert.
- Reveal in Transcript: right-click any row to open the session's
.jsonl
at the line that row came from — the raw record behind the summary.
- Status bar: the time and name of Claude's latest action, always in
view. Hovering it shows the session being followed, its state (working,
awaiting your input, or quiet), when it started and how long it spans,
the last action with its duration, what the view holds, the busiest
tool, the transcript file being read, and a Send feedback link (also in
the palette as Claude Timeline: Send Feedback): rate the extension on
the store your editor installs from — the VS Marketplace in official VS
Code, Open VSX in VSCodium, Cursor or Windsurf — or report a problem or
idea on GitHub issues. Click the status bar item to open the timeline.
- Frozen-session triage: the session's state is assessed from the
transcript — the one signal that keeps answering when the chat UI hangs.
When a turn is open but nothing has been written for a while (3 minutes;
10 for shells, agents and workflows, which legitimately run long), the
status bar turns warning-coloured with the measured span (
quiet 4m) and
the hover names the unanswered call and the recovery path. Facts, not
verdicts: an idle session reads as awaiting your input, never as a
flag, because the transcript cannot tell a hung tool from a slow one —
and this extension does not pretend it can. Large single-turn writes
(16k+ characters) note the known VS Code extension hang they can trigger
in the row's tooltip, with the workaround.
- Copy Freeze Report: one command puts a paste-ready diagnostic on the
clipboard — state, unanswered calls with ages, recent API errors,
compactions, transcript stat, recovery steps. Prompt and reply text is
counted, never quoted, so the report is safe for a public issue after a
read-through.
- Live: the view follows the newest session for the workspace and updates
as the transcript grows (directory watch + a 2-second polling backstop).
- Session picker: pin an older session or go back to following the latest.
- Copy as text: the whole visible timeline as timestamped plain text.
- Log (Claude Timeline: Show Log): which directory was searched, which
session is being followed and why it changed, and a lines-in/events-out
tally. An empty timeline has several causes and this is how you tell them
apart. Raise the detail with Developer: Set Log Level.
Rows read like this — a text illustration, not a screenshot; the right-hand
part is VS Code's dimmed item description, aligned here only for legibility:
Both sessions were writing, so it stayed put 14:04:12
Publish the package 14:03:59 · Bash · 0.3s · denied (permission rule)
Run the unit tests 14:03:58 · Bash · 6.4s · failed
FOLLOW_HYSTERESIS_MS 14:03:57 · Grep · 0.2s
follow.ts 14:03:56 · Read · 0.1s
why does the timeline keep flipping? 14:02:41
On the left, whatever the action carried: a Bash call's description, a file
tool's file name, a search pattern, or — for a prompt, reply or thinking
block — its opening 80 characters, all whitespace collapsed to single spaces
and an ellipsis at the cut. A multi-line prompt therefore reads as one
flattened line, not as its first line. On the right, the timestamp, the tool,
the duration once its result lands, and the outcome when there is one to
report — failed when the result came back an error, or denied with its
reason when the call was refused before it ran. Newest is at the top by
default.
How it works
Claude Code appends one JSON line per event to
~/.claude/projects/<workspace-slug>/<session-id>.jsonl. This extension only
reads those files — no network, no processes, nothing written to disk. The
transcript format is internal to Claude Code and changes between versions, so
the parser is deliberately defensive: lines it does not recognize are skipped
silently rather than breaking the view.
Durations come from pairing each tool_use id with its tool_result line, so
they measure the real gap between the call and its result.
Settings
| Setting |
Default |
Meaning |
claudeActionTimeline.claudeDir |
"" |
Directory holding projects/; empty means ~/.claude |
claudeActionTimeline.showThinking |
false |
Show thinking blocks as entries |
claudeActionTimeline.showSubagents |
false |
Show subagent (sidechain) activity |
claudeActionTimeline.showDurations |
true |
Per-tool durations — in the row, its tooltip and Copy as Text |
claudeActionTimeline.newestFirst |
true |
Newest action at the top |
claudeActionTimeline.maxEvents |
500 |
Entries kept in the view (50–5000) |
claudeActionTimeline.timeFormat |
time |
time = HH:MM:SS, timeWithDate = MMM D HH:MM:SS |
timeFormat governs the row's description, the status bar and Copy as Text. A
row's tooltip is the detail view and always shows the full local date and
time, whichever format is set.
Limitations
- Multi-root workspaces: the first folder is used (re-resolved when folders
change). A window with no folder open has no workspace path to resolve, so
the view stays empty.
- Transcripts are found by the absolute path Claude Code ran in, which is what
names the directory under
projects/. A drive letter in the other case is
handled; reaching the same project by a different path (a symlink, a
subfolder, a UNC share) is not — that path has its own directory, or none.
- Remote development: the extension prefers the workspace side
(
extensionKind: ["workspace", "ui"]), so in SSH/WSL/container windows it
reads the remote ~/.claude — the machine where Claude Code actually runs.
- When two sessions write concurrently (an interactive one plus a background
agent), follow-latest sticks with the current session until the other has
been ahead for 30 seconds, instead of flip-flopping between them.
- Long sessions are trimmed, not paged: the view shows the last
maxEvents
entries and at most 5000 are held in memory, so the earliest actions of a
very long session eventually drop out of the view.
- The transcript format is Claude Code's internal format. When a Claude Code
update changes it, unrecognized lines simply do not appear until this
extension catches up. The log warns when a batch of lines yields no events,
which is what that looks like from in here.
CLAUDE_CONFIG_DIR is honoured when claudeActionTimeline.claudeDir is
empty, so a relocated ~/.claude is usually found with no configuration.
Treat it as best-effort: it is undocumented upstream, so the setting remains
the supported way to point this extension somewhere else. The log records
which of the two won.
Development
npm install
npm run lint # ESLint
npm test # tsc + node:test over src/test
npm run package # the installable .vsix, via @vscode/vsce
Press F5 in VS Code to launch an Extension Development Host.
TypeScript is pinned to ~6.0.3: typescript-eslint throws on TS 7.0 rather
than warning, so the compiler and the lint step have to move together (see
typescript-eslint#10940). Raise both once TS >= 7.1 is supported.
engines.node (>=20.19.0) is the floor for linting and testing, inherited
from ESLint 10 — deliberately higher than the oldest runtime the extension
itself supports, which is VS Code 1.90's Node 20.9 host (see below).
npm run package needs Node 22 or newer — @vscode/vsce pulls in @azure/*
packages and @typespec/ts-http-runtime that require it — so npm ci on
Node 20 logs EBADENGINE warnings for a tool that only the packaging step
uses.
CI (GitHub Actions) runs lint and tests on a matrix of ubuntu-latest and
windows-latest against Node 20, 22 and 24; a second job then runs the
packaging step on Linux and uploads the resulting .vsix as a build artifact.
Node 20 is in the matrix deliberately: engines.vscode admits VS Code 1.90,
whose extension host runs Node 20.9, so the 20.x line is where the oldest
supported host lives. The @types/node pin to ^20.19 keeps the compiler on
that line — it rejects APIs from Node 21 and later, though not the handful
added between 20.9 and 20.19 — and the matrix's Node 20 leg proves the code
runs there.
The requirements (each paired with the test or CI step that holds it), the
design rationale, and the security posture — including the ledger of accepted
warnings — live in docs/.
Releasing
Pushing a v* tag builds the .vsix and attaches it to a draft GitHub
Release. The workflow refuses tags whose commit is not on main, and tags
that disagree with package.json about the version — so a release can only
come from reviewed history, and its artifact can never contradict its own
label.
git tag -a vX.Y.Z -m "X.Y.Z"
git push origin vX.Y.Z
Then review the draft and publish it. Storefront publishing stays manual:
publish tokens are long-lived credentials with write access to the publisher
account, which is not something to keep in CI for a project this size. From a
Node 22+ shell, with the .vsix downloaded from the release, the same tested
artifact goes to both storefronts:
npx @vscode/vsce publish --packagePath claude-action-timeline-X.Y.Z.vsix
npx ovsx publish claude-action-timeline-X.Y.Z.vsix -p <open-vsx-token>
(vsce reads its Azure DevOps token from VSCE_PAT or an earlier
vsce login; Open VSX serves VSCodium, Cursor and Windsurf users.)
License
MIT