Skip to content

About

Claude Code mod: after each turn, says whether the time went to Claude, your tools or you.

Topics

Resources

Contributing

Security policy

Stars

6 stars

Watchers

0 watching

Forks

Repository files navigation

time-blame

A Claude Code mod that answers one question after every turn: was Claude slow, or was it your npm test?

It splits each turn's time by cause and shows it under the answer: in the terminal as a coloured line in place of Claude Code's "Worked for" line, elsewhere as a dim log line. /blame opens a panel with the whole session's split as a coloured bar. Claude never reads any of it, and nothing leaves your machine.

time-blame in a real Claude Code session: after the answer, the line shows Claude 15s and npm test 27s, then /blame opens the panel

A real run on Claude Code 2.1.302, in a small demo project whose test suite takes about 13 seconds. The waits are shown at 6× speed, as the clip says. Of the 47 seconds, Claude took 15 and npm test took 27. Watch it as a video.

The same two outputs in plain text, from an earlier live session. This is what you get outside the terminal, or where nothing can draw a panel:

⏺ time-blame: 26s · Claude 8.0s (7.2s before output) · sleep 4.7s · you 12s · other 0.3s
⏺ time-blame: this session, this machine · 1 turn · 26s of turn time
⏺ time-blame: Claude     8.0s   31%  before output 7.2s, writing 0.8s
⏺ time-blame: tools      4.7s   19%  sleep 4.7s
⏺ time-blame: you         12s   49%  approvals 12s
⏺ time-blame: other      0.3s    1%  not attributed: hooks, local work, gaps
⏺ time-blame: longest turn 26s. Times are summed waits measured in this session, not server speed.

Both blocks are copied as text from that session, where a permission dialog was left open for 12 seconds before it was approved.

Install

claude plugin marketplace add karanb192/time-blame
claude plugin install time-blame@time-blame

Then restart Claude Code or run /reload-plugins. Mods are on by default from Claude Code 2.1.287; time-blame needs 2.1.302 or later. To try it for one session without installing, clone the repo and run claude --plugin-dir ./time-blame.

Landing page: https://timeblame.aidojo.si/

What each bucket means

Every millisecond of a turn lands in exactly one bucket, so the parts always add up to the total.

Bucket Measured as When two overlap
you A permission dialog, from the moment it opens to the moment the tool starts. Also the whole of an AskUserQuestion or ExitPlanMode call. Wins over everything
tools The tool's own execution time, which Claude Code reports with each result. Named by tool, and by command for Bash. Wins over Claude
Claude, before output From the moment a model request is sent to its first text, thinking or tool-call chunk. Includes queueing, retries and network.
Claude, writing From that first chunk to the end of the request.
other Whatever is left: hooks, local work, the gaps between steps. Always shown, never hidden.

Two or more tools running at once count as parallel tools, rather than blaming whichever one was slowest to return.

A subagent's time sits inside the Agent call that started it, labelled subagent. Its own steps are not counted again.

The line appears for turns of 3 seconds or more. /blame counts every turn.

Things to know

  • The total is longer than Claude Code's "Worked for". Claude Code's counter leaves out the time a dialog waits for you. In the run above it said 13s, and time-blame said 26s: the 12 seconds of the open dialog, plus rounding.
  • Bash commands are named only from a fixed list. Common programs (npm, pytest, cargo, git, make and others) and their common subcommands (npm test, cargo build) are shown. A script name, a path or anything else shows as Bash, because a command line can carry private names. In a chained command such as git stash && npm test, the test or build step names the call, since that is where the time usually goes.
  • On a managed Claude Code install, approvals count as tool time. Approvals are timed with the PermissionRequest and PostToolUse settings-hook events. Where an organization manages Claude Code, those events skip plugins a person installs. The dialog wait then falls into the tool's time.
  • Retries are not a separate bucket. Claude Code logs a retried request only after it gives up, so a retry that succeeds leaves no record a mod can read. Retry time shows up as "before output".
  • Colour needs the terminal for the turn line. Only the terminal lets a mod redraw the line that closes a turn. In the Desktop app and VS Code the turn line is a dim log line, and an interrupted turn always is. The /blame panel draws in all three.
  • Totals live in memory. They reset on /clear, /resume and when the plugin reloads.
  • It measures this session on this machine. It says nothing about Anthropic's servers, and it keeps nothing after the session ends.

What it can reach

Validated on Claude Code 2.1.302:

❯ ./register.ts hooks: session.start, command.run{command=blame}, ui.render{component=Pane}, ui.render{component=TurnDuration}, session.end, turn.start, turn.step, classic.PermissionRequest, classic.PostToolUse, classic.PostToolUseFailure, tool.call, turn.complete
❯ ./register.ts calls: $.command.register, $.session.surfaces, $.ui.invalidate, $.ui.log, $.ui.open, $.ui.resolve

Reach L0, draws and remembers. It sees every tool call and every model request, as timing only. It draws in two places: the line that closes a turn in the terminal, and its own /blame panel.

Threat model for time-blame (reach L0, draws and remembers)
1. Reads:    which apps are drawing the session (terminal, Desktop, VS Code); timestamps of turns, model requests and tool calls; the kind of each streamed chunk (never its text); the tool name; for Bash, the command line, matched against a fixed list of program names and dropped; the execution time Claude Code reports with each result
2. Runs:     nothing
3. Sends:    nothing leaves the machine
4. Persists: nothing; the session's totals live in memory and reset on /clear and /resume
5. Hostile input: a crafted command line can only change which allowlisted label is shown or turn it into "Bash"; no input reaches a process, a file, a prompt or the network, and what it shows goes to the screen only, as drawn lines, a panel or dim log lines, none of which Claude reads

If a hook throws, Claude Code skips it and the tool call or request runs as it would without the mod.

Develop

claude plugin validate .claude-plugin/plugin.json
claude plugin test .

hooks/ledger.ts holds the accounting and the labels as pure functions; hooks/register.ts only collects timestamps. For type checking, run /plugin-types in a session in this folder, then npx tsc -p .. The generated types are git-ignored.

License

MIT. The landing page uses icons from Lucide (ISC) and the GitHub mark from Simple Icons (CC0).

About

Claude Code mod: after each turn, says whether the time went to Claude, your tools or you.

Topics

Resources

Contributing

Security policy

Stars

6 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages