I tried to count whether Claude's thinking is being cut, and July had no column to count

On Saturday mornings a scheduled task digs through Reddit, Hacker News and GitHub for “OSS ideas one person could build” and appends them to a note. It is the machine’s way of answering the question from the previous post: what to build next. Each seed comes as a card with fixed fields: the pain, the evidence, what already exists, the smallest version, the risk. The first Saturday produced one seed, a tool to look at how Claude Code spends thinking tokens.

The evidence field pointed at an r/ClaudeAI post. It cites a 65-day analysis of 43,000+ Claude Code invocations: 39% of Fable 5 calls get zero thinking tokens, the median is 123, and August’s thinking budget dropped 18 to 50% compared with July. The title begins “It’s time to cancel your subscriptions”. I have no idea whether it is true. But I use Claude Code every day, and every one of those calls is recorded on my disk. If I count, I know my share.

Not in the hook, already on disk

The seed’s “smallest version” field proposed a PostToolUse hook that receives the thinking-token count, appends it to a file, and a weekly summary on top. The risk field said “unverified whether the Claude Code hook callback payload includes the thinking token count”. So I checked that first.

It does not. I dropped in a temporary hook that dumps stdin to a file. What arrives is the session ID, the tool name, the tool’s input and output, a transcript_path, and so on. No token counts anywhere. That matches the official reference. The OpenTelemetry metrics have only four kinds, input, output, cache read, cache write, and no thinking breakdown either.

Instead it was inside the JSONL that transcript_path points to. Claude Code writes the conversation under ~/.claude/projects/, one event per line, and each assistant response line carries a usage block. Inside it, output_tokens_details.thinking_tokens is the thinking-token count. The thinking text itself is empty, only a signature remains, so you cannot read what it thought, but the count is there.

So no hook is needed. Nothing to write; just read what is already written, after the fact. The tool got smaller than the seed proposed.

The counting tool

It became a Go CLI called claude-thinking-stats. Like the previous two, standard library only, no dependencies, and it modifies nothing. brew install nobu666/tap/claude-thinking-stats gets it. Run with no arguments and it prints the last seven days, one row per day. Days without Claude Code use get no row, so this week is six rows. The 418 on September 21 is the day I was building this tool.

$ claude-thinking-stats
day         requests   output  thinking  think%  zero%  p50    p95  missing  models
2026-09-15         4    4,212       484    11.5   75.0    0    411        0  claude-opus-5
2026-09-18        75   62,020    21,009    33.9   34.7  101  1,185        0  claude-fable-5-1,claude-opus-4-8,claude-opus-5,claude-sonnet-4-6
2026-09-19       128  142,638    64,250    45.0   21.9  146  1,517        0  claude-fable-5-1,claude-sonnet-4-6
2026-09-20        60   82,744    51,813    62.6   25.0  127  3,298        0  claude-fable-5-1,claude-opus-5,claude-sonnet-4-6
2026-09-21       418  445,982   135,882    30.5   30.6  104  1,211        0  claude-fable-5-1,claude-sonnet-4-6
2026-09-22        42   42,821    13,991    32.7   33.3  138  1,282        0  claude-fable-5-1

requests is the number of responses. The same response is written as several lines, one per content block, with an identical usage, so rows are folded by message.id. output and thinking are token totals, and think% is thinking as a share of output tokens. zero% is the share of responses with zero thinking tokens; p50 and p95 are the median and 95th percentile of thinking tokens per response. models lists the models in that row. -by switches the grouping to session, model, project or effort (the thinking-intensity setting), and -top 10 lists the ten responses that thought the most.

missing is the number of responses whose usage had no thinking_tokens field at all. When I wrote the spec, this was insurance: “older versions and non-thinking models probably lack the field, so treat missing as zero and just show the count”. This column ends up being the main character.

July had no column

I ran the whole history grouped by model.

$ claude-thinking-stats -by model -since all
model              requests     output  thinking  think%  zero%  p50    p95  missing
claude-fable-5          513    515,442         0     0.0  100.0    0      0  513
claude-fable-5-1        942  1,018,321   282,952    27.8   32.1  140  1,201  0
claude-opus-4-8          49    272,302       191     0.1   98.0    0      0  45
claude-opus-5           227    222,721    37,356    16.8   76.7    0  1,162  144
claude-sonnet-4-6     1,688  1,904,717   592,570    31.1   56.8    0  1,061  827
claude-sonnet-5         510    262,013         0     0.0  100.0    0      0  510
note: 2039 responses had no thinking_tokens field (counted as 0; see the missing column)

Fable 5: all 513 responses are missing. Not zero thinking; no field to count. Sonnet 5’s 510 are all missing too, Sonnet 4.6 is missing 827 of 1,688, Opus 5 is missing 144 of 227. Across the six models, 2,039 of 3,929 responses, a bit over half, had no field.

Responses per month split into those with and without a thinking-token field. July: all 1,434 lack the field. August: 572 of 1,177 have it, 605 do not. September: all 1,318 have it. The field first appears on August 16

Cut by month: all 1,434 July responses lack the field, August lacks it in 605 of 1,177, and all 1,318 September responses have it. The first day the field appears is August 16, and the last day with a missing field is August 23. The transcript also records the Claude Code version that wrote each line, and cutting by version the boundary is 2.1.229. Not one line written by an earlier version has thinking_tokens.

Why some models have so many missing rows in the model table has nothing to do with how new the model is; it is when I used it. Fable 5 and Sonnet 5 were July. Opus 5’s 144 missing rows run until August 14 and its 83 counted rows start on August 16. Opus 4.8’s only counted rows are four in September. Fable 5.1 does not show up in the transcripts until September, so all 942 of its rows are September.

The post says August dropped compared with July. In my transcripts, no July response can have its thinking counted, whatever the model. Neither can August until the second half. The post does not say how its author got July’s numbers, so I cannot tell. What I can say is that from the records Claude Code keeps on its own, comparing July’s thinking with August’s was not possible on my machine.

Where the field exists, the numbers are not far from the post’s

The post counted Fable 5. The only model on my disk with the field is its successor, Fable 5.1. Different generations, so strictly they do not line up. With that caveat, Fable 5.1’s 942 responses have 32.1% zero thinking and a median of 140 tokens. Not far from the post’s 39% and 123.

From here on the numbers are not the tool’s output; I split the same Fable 5.1 responses by hand. Responses with zero thinking have a median of 377 output tokens; responses that did think have 906. That reads as the short responses in the middle of a tool-call chain, call a tool, get the result, call the next, coming back without thinking.

Whether to call that “being cut” is not something these numbers can answer. There is nothing to compare against. How much July’s Fable 5 thought on the same kind of response is unknowable, because the field is not there. What is knowable is when counting became possible, and the distribution since. Whatever decides a cancellation, my records did not supply it.

So the tool claims only that much. If thinking feels thinner, look at zero% across weeks with -by day. When choosing an effort level or a model, -by effort and -by model show whether the setting you pay for changes how much thinking you get. When you hit a usage limit, -top 10 shows what thought that hard. In my case the top of -top 10 is reviews and rewrites of blog posts, 17,000 thinking tokens in a single response.

Before comparing, find out what can be counted

When I read the post I assumed counting would settle it. What counting produced was not a verdict but a date: the point in my own records from which counting is possible at all. The seed’s risk field, “unverified whether it is included”, was right, it was not. In exchange the records were already on disk, and those records carried no thinking field before August 16.

When checking someone else’s number against your own records, look at the missing column before lining up the numbers. The column I added as insurance held the biggest number on the first day I ran it.

comments powered by Disqus