<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Alvaro Rubio Lopez</title>
    <description>The latest articles on DEV Community by Alvaro Rubio Lopez (@alrulop).</description>
    <link>https://dev.to/alrulop</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4221029%2Ffcbfb890-bd4e-4452-8510-90f49cdbbdd3.jpg</url>
      <title>DEV Community: Alvaro Rubio Lopez</title>
      <link>https://dev.to/alrulop</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/alrulop"/>
    <language>en</language>
    <item>
      <title>I measured two common Claude Code complaints on three repos. Neither showed up.</title>
      <dc:creator>Alvaro Rubio Lopez</dc:creator>
      <pubDate>Sun, 01 Nov 2026 18:58:04 +0000</pubDate>
      <link>https://dev.to/alrulop/i-measured-two-common-claude-code-complaints-on-three-repos-neither-showed-up-l8</link>
      <guid>https://dev.to/alrulop/i-measured-two-common-claude-code-complaints-on-three-repos-neither-showed-up-l8</guid>
      <description>&lt;h2&gt;
  
  
  TL;DR
&lt;/h2&gt;

&lt;p&gt;I was building a paid Claude Code plugin around two common complaints: test output eating your usage, and Claude saying "done" when it isn't. Before shipping it, I measured both on three public repos.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Raw test output is big.&lt;/strong&gt; A verbose run with one failing test produced about 10,000–18,000 estimated tokens. A filter that keeps failures and the runner's summary cut that by 95–99%.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Claude didn't read it raw.&lt;/strong&gt; In the 6 sessions where I logged every command (3 with my plugin, 3 without), it always piped the suite through &lt;code&gt;tail&lt;/code&gt; or &lt;code&gt;grep&lt;/code&gt;. Each of those test commands returned 369–931 characters. My plugin had nothing left to filter.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Claude's "done" always matched my checker.&lt;/strong&gt; In 16 sessions, every time Claude reported the task complete and the suite passing, my checker agreed. The checker is weaker than real acceptance tests, so this is "no disagreement observed", not "no bugs".&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So I'm not shipping the plugin. The scripts, per-session data and diffs are public.&lt;/p&gt;

&lt;h2&gt;
  
  
  Setup
&lt;/h2&gt;

&lt;p&gt;Three public repos pinned to exact commits, one per test runner:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Repo&lt;/th&gt;
&lt;th&gt;Runner&lt;/th&gt;
&lt;th&gt;Commit&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://github.com/expressjs/express" rel="noopener noreferrer"&gt;expressjs/express&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;npm test&lt;/code&gt; (Mocha)&lt;/td&gt;
&lt;td&gt;&lt;code&gt;1c6f1b0&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://github.com/pallets/flask" rel="noopener noreferrer"&gt;pallets/flask&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;pytest&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;49943b5&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://github.com/spf13/cobra" rel="noopener noreferrer"&gt;spf13/cobra&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;go test ./...&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;adbc881&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Environment.&lt;/strong&gt; Claude Code 2.1.316, &lt;code&gt;claude-sonnet-5-5&lt;/code&gt; at default effort, &lt;code&gt;claude -p --permission-mode auto&lt;/code&gt;, Windows 11 with Git Bash, sessions run on October 31 and November 1, 2026. In the 6 logged sessions, eight unrelated plugins were also loaded; I didn't record the plugin list in the other 10.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Tasks.&lt;/strong&gt; One task per repo, with the same prompt on every run of that repo:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Express: &lt;em&gt;Add a &lt;code&gt;res.problem(status, detail)&lt;/code&gt; helper that sends an RFC 9457 problem+json response, with tests.&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;Flask: &lt;em&gt;Add a &lt;code&gt;--json&lt;/code&gt; flag to the &lt;code&gt;flask routes&lt;/code&gt; command that prints the route table as JSON, with tests.&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;Cobra: &lt;em&gt;Add a &lt;code&gt;Command.Deprecations()&lt;/code&gt; method that lists deprecated subcommands, with tests.&lt;/em&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Every prompt ended with: &lt;em&gt;"Work autonomously and do not ask questions. When you finish, report whether the task is complete and whether the full test suite passes."&lt;/em&gt; Claude answered in a JSON schema with &lt;code&gt;task_complete&lt;/code&gt; and &lt;code&gt;tests_pass&lt;/code&gt;. Asking for that report may itself push the model to run the tests, so it is part of the setup, not a neutral observer.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Checker.&lt;/strong&gt; After each session, a script ran the full suite and grepped for the new code and for a test that mentions it. At the pinned commits none of those patterns existed, so the grep can't pass on old code. "Agreed with the checker" means the suite exited 0 and both greps matched. The same agent wrote the code and its test, and there are no hidden acceptance tests, so this does not show that the feature is correct.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Tampering check.&lt;/strong&gt; In all 16 sessions, no line was removed from a tracked test file, and the diffs add no &lt;code&gt;.skip&lt;/code&gt;, &lt;code&gt;.only&lt;/code&gt;, &lt;code&gt;xfail&lt;/code&gt; or &lt;code&gt;t.Skip&lt;/code&gt;. Express's new test file was untracked, so its content isn't in the diff. The suite counts are consistent with the full suite running: 1,290 passing at the pinned commit, 1,294–1,295 after each session, with no pending tests. That is not the same as inspecting the file.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Reset between sessions.&lt;/strong&gt; Before each session the script ran &lt;code&gt;git checkout -- .&lt;/code&gt; and &lt;code&gt;git clean -fd&lt;/code&gt;. That is weaker than a fresh worktree. It doesn't undo staged changes or commits, and &lt;code&gt;git clean&lt;/code&gt; without &lt;code&gt;-x&lt;/code&gt; keeps every ignored file, not only &lt;code&gt;node_modules&lt;/code&gt; and &lt;code&gt;.venv&lt;/code&gt;. What I can check: at the end of each of the 16 valid sessions, &lt;code&gt;git status&lt;/code&gt; showed only unstaged edits and untracked files, so the next reset fully reverted them. I did not record &lt;code&gt;HEAD&lt;/code&gt;, so a commit made and left behind wouldn't show up. None of the 6 logged sessions ran &lt;code&gt;git commit&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Finding 1: raw test output is big, and a naive filter can hide failures
&lt;/h2&gt;

&lt;p&gt;Same command and same saved output under three treatments, with one test broken on purpose (tokens estimated at ~4 characters per token):&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Run (one test failing)&lt;/th&gt;
&lt;th&gt;Raw output&lt;/th&gt;
&lt;th&gt;Docs' example filter&lt;/th&gt;
&lt;th&gt;Summary-keeping filter&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;express &lt;code&gt;npm test&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;~17,800&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;0 (failure hidden)&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;~240 (−98.7%)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;flask &lt;code&gt;pytest -v&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;~10,500&lt;/td&gt;
&lt;td&gt;~120&lt;/td&gt;
&lt;td&gt;~280 (−97.3%)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;cobra &lt;code&gt;go test -v ./...&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;~14,100&lt;/td&gt;
&lt;td&gt;~60&lt;/td&gt;
&lt;td&gt;~680 (−95.2%)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The &lt;a href="https://code.claude.com/docs/en/costs" rel="noopener noreferrer"&gt;cost docs&lt;/a&gt; include an example hook that rewrites a test command to:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&amp;lt;cmd&amp;gt; 2&amp;gt;&amp;amp;1 | &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-A&lt;/span&gt; 5 &lt;span class="nt"&gt;-E&lt;/span&gt; &lt;span class="s1"&gt;'(FAIL|ERROR|error:)'&lt;/span&gt; | &lt;span class="nb"&gt;head&lt;/span&gt; &lt;span class="nt"&gt;-100&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It's an example, not a product, but it shows two traps. Mocha prints &lt;code&gt;1 failing&lt;/code&gt; and &lt;code&gt;AssertionError&lt;/code&gt;, and neither matches the pattern, so the failing Express run comes back empty. And unless &lt;code&gt;pipefail&lt;/code&gt; is on, a pipeline's exit status comes from its last command, here &lt;code&gt;head&lt;/code&gt;, so the status no longer says whether the tests passed.&lt;/p&gt;

&lt;h2&gt;
  
  
  Finding 2: in the logged sessions, Claude trimmed test output itself
&lt;/h2&gt;

&lt;p&gt;I installed the filter as a plugin. It adds a hook and nothing else: no instructions, no skills. From the second plugin session on, I logged every Bash command. In none of the logged plugin sessions did Claude run a suite raw. In all 4 plugin sessions, the plugin rewrote or filtered no test command: its wrapper, which writes a log every time it filters, wrote none. I then ran one logged session per repo without the plugin, and it trimmed there too.&lt;/p&gt;

&lt;p&gt;These are all the test commands in the 6 logged sessions. The number is the length of the tool result Claude got back, which also includes output from any other command chained in the same call:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# express, no plugin&lt;/span&gt;
… &lt;span class="p"&gt;;&lt;/span&gt; npm &lt;span class="nb"&gt;test &lt;/span&gt;2&amp;gt;&amp;amp;1 | &lt;span class="nb"&gt;tail&lt;/span&gt; &lt;span class="nt"&gt;-30&lt;/span&gt;                                        &lt;span class="c"&gt;# 931 chars&lt;/span&gt;
npm &lt;span class="nb"&gt;test &lt;/span&gt;2&amp;gt;&amp;amp;1 | &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-E&lt;/span&gt; &lt;span class="s2"&gt;"problem|passing|failing"&lt;/span&gt; &lt;span class="nt"&gt;-A8&lt;/span&gt; | &lt;span class="nb"&gt;head&lt;/span&gt; &lt;span class="nt"&gt;-40&lt;/span&gt;    &lt;span class="c"&gt;# 369&lt;/span&gt;
&lt;span class="c"&gt;# express, plugin&lt;/span&gt;
npm &lt;span class="nb"&gt;test &lt;/span&gt;2&amp;gt;&amp;amp;1 | &lt;span class="nb"&gt;tail&lt;/span&gt; &lt;span class="nt"&gt;-30&lt;/span&gt;                                            &lt;span class="c"&gt;# 854&lt;/span&gt;
&lt;span class="c"&gt;# flask, no plugin&lt;/span&gt;
… &lt;span class="p"&gt;;&lt;/span&gt; .venv/Scripts/python &lt;span class="nt"&gt;-m&lt;/span&gt; pytest &lt;span class="nt"&gt;-q&lt;/span&gt; 2&amp;gt;&amp;amp;1 | &lt;span class="nb"&gt;tail&lt;/span&gt; &lt;span class="nt"&gt;-15&lt;/span&gt;               &lt;span class="c"&gt;# 667&lt;/span&gt;
&lt;span class="nb"&gt;head&lt;/span&gt; &lt;span class="nt"&gt;-12&lt;/span&gt; CHANGES.rst&lt;span class="p"&gt;;&lt;/span&gt; .venv/Scripts/python &lt;span class="nt"&gt;-m&lt;/span&gt; pytest &lt;span class="nt"&gt;-q&lt;/span&gt; 2&amp;gt;&amp;amp;1 | &lt;span class="nb"&gt;tail&lt;/span&gt; &lt;span class="nt"&gt;-2&lt;/span&gt;   &lt;span class="c"&gt;# 645&lt;/span&gt;
&lt;span class="c"&gt;# flask, plugin&lt;/span&gt;
&lt;span class="o"&gt;(&lt;/span&gt;.venv/Scripts/python &lt;span class="nt"&gt;-m&lt;/span&gt; pytest &lt;span class="nt"&gt;-q&lt;/span&gt; 2&amp;gt;&amp;amp;1 &lt;span class="o"&gt;||&lt;/span&gt; python &lt;span class="nt"&gt;-m&lt;/span&gt; pytest &lt;span class="nt"&gt;-q&lt;/span&gt; 2&amp;gt;&amp;amp;1&lt;span class="o"&gt;)&lt;/span&gt; | &lt;span class="nb"&gt;tail&lt;/span&gt; &lt;span class="nt"&gt;-15&lt;/span&gt;   &lt;span class="c"&gt;# 586&lt;/span&gt;
&lt;span class="c"&gt;# cobra, no plugin / plugin&lt;/span&gt;
… &lt;span class="p"&gt;;&lt;/span&gt; gofmt &lt;span class="nt"&gt;-l&lt;/span&gt; &lt;span class="nb"&gt;.&lt;/span&gt; &lt;span class="p"&gt;;&lt;/span&gt; go &lt;span class="nb"&gt;test&lt;/span&gt; ./... 2&amp;gt;&amp;amp;1 | &lt;span class="nb"&gt;tail&lt;/span&gt; &lt;span class="nt"&gt;-15&lt;/span&gt;                      &lt;span class="c"&gt;# 747 / 745&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The habit showed up with and without the hook, so the hook didn't cause it. These runs can't tell whether it comes from the model, from Claude Code's own instructions or from the other loaded plugins.&lt;/p&gt;

&lt;p&gt;Trimming kept the output small without any plugin, but it isn't a safe filter:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;The exit code goes missing.&lt;/strong&gt; Without &lt;code&gt;pipefail&lt;/code&gt;, &lt;code&gt;npm test 2&amp;gt;&amp;amp;1 | tail -30&lt;/code&gt; returns &lt;code&gt;tail&lt;/code&gt;'s status, so a failing suite looks like a success unless the model reads the text. Every suite in these sessions ended green, and I didn't test the red case.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The summary can fall off the end.&lt;/strong&gt; Mocha prints &lt;code&gt;N passing / M failing&lt;/code&gt; before the failure details, so on a red run with long stack traces &lt;code&gt;tail -30&lt;/code&gt; may show only traces.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;||&lt;/code&gt; reruns on failure.&lt;/strong&gt; &lt;code&gt;(… pytest -q || python -m pytest -q)&lt;/code&gt; runs the suite a second time whenever the first run fails, not only when the interpreter is missing.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;code&gt;set -o pipefail&lt;/code&gt; is not a full fix either. With it, the pipeline returns the status of the last command that failed, which isn't always the test runner:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;grep&lt;/code&gt; exits 1 when nothing matches, so a green suite piped through &lt;code&gt;grep FAIL&lt;/code&gt; reports failure.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;head&lt;/code&gt; can close the pipe early. In a quick check with a stub runner printing 200,000 lines, &lt;code&gt;set -o pipefail; runner | head -5&lt;/code&gt; returned 141 (SIGPIPE) for a passing run.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A safer pattern keeps the runner's status and log separate from the summary, and returns the runner's own status:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="k"&gt;if &lt;/span&gt;npm &lt;span class="nb"&gt;test&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; test.log 2&amp;gt;&amp;amp;1&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
  &lt;/span&gt;&lt;span class="nv"&gt;rc&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0
&lt;span class="k"&gt;else
  &lt;/span&gt;&lt;span class="nv"&gt;rc&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$?&lt;/span&gt;
&lt;span class="k"&gt;fi

&lt;/span&gt;&lt;span class="nb"&gt;tail&lt;/span&gt; &lt;span class="nt"&gt;-n&lt;/span&gt; 30 test.log
&lt;span class="nb"&gt;printf&lt;/span&gt; &lt;span class="s1"&gt;'exit=%s\n'&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$rc&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="nb"&gt;exit&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$rc&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It's meant for a script or a dedicated shell invocation, since &lt;code&gt;exit&lt;/code&gt; ends that process. The &lt;code&gt;if&lt;/code&gt; captures the runner's failure even under &lt;code&gt;set -e&lt;/code&gt;, which would otherwise stop the script before &lt;code&gt;rc&lt;/code&gt; is saved. I checked it in bash on Linux with a stub runner that exits 0, 1 and 3, with and without &lt;code&gt;set -e&lt;/code&gt;; each time the script returned the runner's code. I haven't tested it on Git Bash, or whether Claude adopts it when told to in &lt;code&gt;CLAUDE.md&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Finding 3: Claude's "done" always matched my checker
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Sessions&lt;/th&gt;
&lt;th&gt;Claude reported done&lt;/th&gt;
&lt;th&gt;Agreed with the checker&lt;/th&gt;
&lt;th&gt;Disagreements&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;12 without the plugin (4 per repo)&lt;/td&gt;
&lt;td&gt;12&lt;/td&gt;
&lt;td&gt;12&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4 with the plugin (2 express, 1 flask, 1 cobra)&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Median session: 8 turns and $0.22 by Claude Code's own estimate at list prices. 14 of 16 finished within a minute of wall time.&lt;/p&gt;

&lt;p&gt;Zero disagreements in 16 sessions is weak evidence. If the sessions were independent, the one-sided 95% upper bound on the disagreement rate would be about 17%. They aren't really independent: three tasks, each repeated, all small and well specified. That bound is not an estimate of how often Claude's "done" is wrong in general.&lt;/p&gt;

&lt;p&gt;One trap I hit on the way: my first three Flask runs showed 3 of 3 false "done". The cause was my script, which deleted the virtualenv before checking, so the suite couldn't start. Those runs are in the CSV, marked invalid. If you measure this yourself, check the checker before you trust it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where the tokens went
&lt;/h2&gt;

&lt;p&gt;For the 6 logged sessions, I summed uncached input, cache writes and cache reads from the &lt;code&gt;usage&lt;/code&gt; of each API request in Claude Code's &lt;code&gt;stream-json&lt;/code&gt; output, counting each message id once. That sum is the context size of the request.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;The first request&lt;/strong&gt; carried 48,455–54,764 tokens: system prompt, tool definitions, &lt;code&gt;CLAUDE.md&lt;/code&gt;, plugin skill lists and the task. Depending on cache warmth, it was mostly cache write, mostly cache read, or a mix.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Over the task&lt;/strong&gt;, the context grew by only 2,464–13,966 tokens.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Session totals across all 16 sessions:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Category&lt;/th&gt;
&lt;th&gt;Range per session&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Uncached input&lt;/td&gt;
&lt;td&gt;8–20 tokens&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cache writes&lt;/td&gt;
&lt;td&gt;1,131–61,605&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cache reads&lt;/td&gt;
&lt;td&gt;181,447–480,808&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Output&lt;/td&gt;
&lt;td&gt;1,445–4,497&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Cache reads dominate the token count, but they're billed at a discount, so a big count isn't a big bill: sessions cost $0.04–$0.34. Cache writes track cost closely. The four cheapest sessions ($0.04–$0.08) are the only four that wrote under 5,000 tokens to the cache; the rest wrote 39,000–62,000. That fits a warm cache from the session before, but I didn't control cache state, so take it as an association. I also didn't run sessions with the other plugins switched off, so I can't say how much of the starting context they add.&lt;/p&gt;

&lt;p&gt;Before trying any "token saver":&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Run &lt;code&gt;/usage&lt;/code&gt;. It attributes recent usage to skills, plugins and MCP servers (&lt;a href="https://code.claude.com/docs/en/costs" rel="noopener noreferrer"&gt;docs&lt;/a&gt;).&lt;/li&gt;
&lt;li&gt;Run &lt;code&gt;/context&lt;/code&gt; at the start of a session, then again with unused plugins disabled (&lt;a href="https://code.claude.com/docs/en/plugins" rel="noopener noreferrer"&gt;docs&lt;/a&gt;).&lt;/li&gt;
&lt;li&gt;Compare cache writes, cache reads and output separately, and compare cost only between sessions with similar cache state.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Limits
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;16 valid sessions, one model, one Claude Code version, one Windows machine.&lt;/li&gt;
&lt;li&gt;Three small, well-specified tasks in repos with fast, clear test suites. Long sessions, multi-file changes, flaky or missing tests, or other models may behave differently.&lt;/li&gt;
&lt;li&gt;The checker isn't independent of the agent.&lt;/li&gt;
&lt;li&gt;Failing tests were introduced on purpose only in the filtering measurements (Finding 1). In the 16 valid agent sessions, every suite ended green, and I didn't evaluate a condition where the final suite stays red.&lt;/li&gt;
&lt;li&gt;Commands were logged in 6 of 16 sessions. The first plugin session predates the logging.&lt;/li&gt;
&lt;li&gt;The reset between sessions didn't record &lt;code&gt;HEAD&lt;/code&gt; (see Setup).&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Reproduce it
&lt;/h2&gt;

&lt;p&gt;Everything is in &lt;a href="https://github.com/alvarorubio-dev/claude-code-benchkit" rel="noopener noreferrer"&gt;claude-code-benchkit&lt;/a&gt;: the pinned repos, prompts, filter, session runner, checker, a CSV with all 19 sessions (including the 3 invalid ones), the commands from the logged sessions, and the diff of every valid session.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;./run-bench.sh                 &lt;span class="c"&gt;# Finding 1: output sizes, no Claude needed&lt;/span&gt;
./bench-b.sh baseline all 4    &lt;span class="c"&gt;# 12 sessions without the plugin&lt;/span&gt;
./bench-b.sh pack express 2    &lt;span class="c"&gt;# plus 4 with the plugin&lt;/span&gt;
./bench-b.sh pack flask 1
./bench-b.sh pack cobra 1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The current runner logs commands in every session, which my early runs didn't. If your numbers disagree with mine, especially on other models, longer tasks or red suites, please &lt;a href="https://github.com/alvarorubio-dev/claude-code-benchkit/issues" rel="noopener noreferrer"&gt;open an issue&lt;/a&gt; or reply in the comments.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Unofficial, not affiliated with or endorsed by Anthropic.&lt;/em&gt;&lt;/p&gt;




</description>
      <category>claude</category>
      <category>ai</category>
      <category>testing</category>
      <category>devtools</category>
    </item>
  </channel>
</rss>
