Skip to content

Build1 publisher2 min readPublished

A Stop hook clocked Claude Code's code-reviewer subagent at 37 seconds per call

Claude Code hands a Stop hook the full session transcript when a session ends. Joining each tool_use to its tool_result on tool_use_id yields per-agent seconds and error flags, and one operator says the numbers cut his weekly bill 15 to 20 percent.

The Engineer · Build desk

Illustration accompanying A Stop hook clocked Claude Code's code-reviewer subagent at 37 seconds per call

What happened

  • Timing every subagent invocation put the general-purpose agent at 18 seconds on average, Explore at 22 and code-reviewer at 37, the reverse of what the operator expected to find.
  • The Stop hook is a shell script Claude Code runs when a session ends, handed JSON on stdin that carries the session id and the path to the session's transcript.
  • Subagent launches show up in that transcript as tool_use blocks named "Agent", even though the interface labels the same tool "Task".
  • A two-pass Python script builds dictionaries of calls and results, then matches them on tool_use_id to compute how long each invocation took.

Compiled by The EngineerSomething wrong?How this is made

Why it matters

  • decision Operators running mixed subagents can settle which one to stop invoking by reflex from a file of durations instead of an impression formed while waiting.
  • exposure Any ledger built this way depends on an internal transcript field name, so a rename in a future Claude Code release stops the counting without failing loudly.
  • capability The same tool_use to tool_result join times any tool the transcript records, so per-tool latency is available without vendor telemetry or an SDK.
  • cost The saving is quoted as a share of an undisclosed weekly bill, so a team cannot budget against it or say what the same habit change would return.

The parse is a join. A subagent launch lands in the transcript as a tool_use block, and its outcome lands later, on its own line, as a tool_result carrying the same tool_use_id [10]. Pass one of the script builds two dictionaries, uses and results; pass two matches them on that id and computes the duration [11]. The success bit is is_error on the result line: present and true means the call ended in error, absent means it worked [10].

Grep the transcript for the tool name you see in the interface and you get nothing back. Claude Code's UI displays "Task"; the log records "name": "Agent" [7]. The script's comment spells it out: `In Claude Code transcripts, the 'Task' tool is recorded as name="Agent"` [8]. Which agent ran is one level down, in input.subagent_type [9].

The author expected the general-purpose agent to be the slow one [2]. Code-reviewer's 37-second average is about 2.1 times general-purpose's 18 [17], and 15 seconds past Explore [18]. Acting on the hunch would have meant tuning the fastest of the three agents he measured [19]. The author wrote that a sense of an agent being heavy is not data [15].

What accumulates in the ledger at ~/.claude/logs/agent-invocations.jsonl is durations and error flags, one line per invocation [12]. Token counts are not among the fields the post describes reading [5]. The reported outcome is a weekly Claude Code spend cut of roughly 15 to 20 percent after one habit changed [3], and the yen figure the post does put on the table is the setup's monthly revenue, about 1.2M yen [16]. For that percentage to carry into another setup, duration would have to track token spend across the agents you run, and code-reviewer would have to be invoked about as often in your workflow as in his.

The hook fires on session end [4]. A session that mixes Explore, code-reviewer and general-purpose calls can run for tens of minutes [14], and none of it reaches the ledger until it stops [20]. Aggregation is a weekly jq pass over the file [13].

Adoption is one line in ~/.claude/settings.json, and the hook changes none of Claude Code's behaviour because it reads an artifact the session already writes [6][5].

What to watch

  • Per-call token counts appearing in the transcript would let the same tool_use_id join price agents in tokens instead of seconds.
  • A rename of the Agent tool name, or a change to the transcript's JSONL layout, would break every hook built on this parse.
  • A published baseline weekly bill would make the 15 to 20 percent figure checkable by anyone else.
Loading claim ledger
Loading source directory links
Loading share composer
Loading topic controls
Loading related stories