<?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: Chris Kilner</title>
    <description>The latest articles on DEV Community by Chris Kilner (@chris-rhiza-fr).</description>
    <link>https://dev.to/chris-rhiza-fr</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.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3852885%2Fec56afcf-065f-4a30-8ec1-edf05b712d1d.png</url>
      <title>DEV Community: Chris Kilner</title>
      <link>https://dev.to/chris-rhiza-fr</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/chris-rhiza-fr"/>
    <language>en</language>
    <item>
      <title>83k tokens to fix a few tests!? No thanks</title>
      <dc:creator>Chris Kilner</dc:creator>
      <pubDate>Tue, 31 Mar 2026 08:31:47 +0000</pubDate>
      <link>https://dev.to/chris-rhiza-fr/83k-tokens-to-fix-a-few-tests-no-thanks-2kgd</link>
      <guid>https://dev.to/chris-rhiza-fr/83k-tokens-to-fix-a-few-tests-no-thanks-2kgd</guid>
      <description>&lt;p&gt;Claude burned 83,000 tokens fixing test failures after a refactor — raw pytest output, coverage noise, ruff warnings, all re-fed every loop.&lt;/p&gt;

&lt;p&gt;It worked. But it was absurdly expensive.&lt;/p&gt;

&lt;p&gt;The problem isn’t the model — it’s the context.&lt;/p&gt;

&lt;p&gt;So I made &lt;a href="https://github.com/rhiza-fr/py-cq" rel="noopener noreferrer"&gt;&lt;code&gt;cq&lt;/code&gt;&lt;/a&gt; (&lt;a href="https://pypi.org/project/python-code-quality/" rel="noopener noreferrer"&gt;&lt;code&gt;python-code-quality&lt;/code&gt;&lt;/a&gt; on PyPI) It runs 10+ quality tools and surfaces exactly one thing at a time.&lt;/p&gt;

&lt;h2&gt;
  
  
  Minimal context
&lt;/h2&gt;

&lt;p&gt;Instead of dumping everything into the prompt, &lt;code&gt;cq&lt;/code&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;runs tools in priority order&lt;/li&gt;
&lt;li&gt;stops at the first failure&lt;/li&gt;
&lt;li&gt;emits a single, focused fix request
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; cq check &lt;span class="nb"&gt;.&lt;/span&gt; &lt;span class="nt"&gt;-o&lt;/span&gt; llm
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="sb"&gt;`&lt;/span&gt;src/myproject/utils.py:21&lt;span class="sb"&gt;`&lt;/span&gt; — &lt;span class="k"&gt;**&lt;/span&gt;F841&lt;span class="k"&gt;**&lt;/span&gt;: Local variable &lt;span class="sb"&gt;`&lt;/span&gt;unused_variable&lt;span class="sb"&gt;`&lt;/span&gt; is assigned to but never used

18:     min_dist &lt;span class="o"&gt;=&lt;/span&gt; float&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"inf"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
19:     nearest_city &lt;span class="o"&gt;=&lt;/span&gt; None
20:     &lt;span class="k"&gt;for &lt;/span&gt;city &lt;span class="k"&gt;in &lt;/span&gt;cities:
21:         unused_variable &lt;span class="o"&gt;=&lt;/span&gt; 67
22:         dist &lt;span class="o"&gt;=&lt;/span&gt; calc_dist&lt;span class="o"&gt;(&lt;/span&gt;current_city, city&lt;span class="o"&gt;)&lt;/span&gt;

Please fix only this issue. After fixing, run &lt;span class="sb"&gt;`&lt;/span&gt;cq check &lt;span class="nb"&gt;.&lt;/span&gt; &lt;span class="nt"&gt;-o&lt;/span&gt; llm&lt;span class="sb"&gt;`&lt;/span&gt; to verify.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That’s it. No test logs, no coverage spam, no unrelated warnings.&lt;/p&gt;

&lt;p&gt;If the error looks like a caller / callee mismatch, we fetch the callee signature to potentially avoid an extra tool-call.&lt;/p&gt;

&lt;h2&gt;
  
  
  The minimal loop
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;smallest complete context → smallest capable model → fewest tool calls → successful edit&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Small, focused context means you can use a small, cheap model and get the fix in 1 second. No tool-calling needed (if you edit yourself):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;cq check &lt;span class="nb"&gt;.&lt;/span&gt; &lt;span class="nt"&gt;-o&lt;/span&gt; llm | ollama run qwen3:4b &lt;span class="nt"&gt;--think&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;false&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="s1"&gt;'show a unified diff to correct this code. Add a one line explanation'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;&lt;span class="gd"&gt;--- a/src/myapp/calculator.py
&lt;/span&gt;&lt;span class="gi"&gt;+++ b/src/myapp/calculator.py
&lt;/span&gt;&lt;span class="p"&gt;@@ -1,5 +1,5 @@&lt;/span&gt;
 def evaluate(expression):
&lt;span class="gd"&gt;-    return eval(expression)
&lt;/span&gt;&lt;span class="gi"&gt;+    import ast
+    return ast.literal_eval(expression)
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Explanation:&lt;/strong&gt; Replaced &lt;code&gt;eval()&lt;/code&gt; with &lt;code&gt;ast.literal_eval()&lt;/code&gt; to safely evaluate strings as Python literals.&lt;/p&gt;

&lt;p&gt;Apply the fix. Run &lt;code&gt;cq&lt;/code&gt; again. Repeat.&lt;/p&gt;

&lt;p&gt;Or with Claude Code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;cq check &lt;span class="nb"&gt;.&lt;/span&gt; &lt;span class="nt"&gt;-o&lt;/span&gt; llm | claude &lt;span class="nt"&gt;-p&lt;/span&gt; &lt;span class="s2"&gt;"fix this"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Tool ordering
&lt;/h2&gt;

&lt;p&gt;In &lt;code&gt;-o llm&lt;/code&gt; mode, the tools are run sequentially, and we stop at the first error.&lt;/p&gt;

&lt;p&gt;In other modes, we run in parralel and cache results for fast re-runs.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;cq check &lt;span class="nb"&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;┏━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━┳━━━━━━━━━━┓
┃ Tool             ┃     Time ┃                    Metric ┃ Score   ┃ Status   ┃
┡━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━╇━━━━━━━━━━┩
│ compile          │    0.47s │                   compile │ 1.000   │ OK       │
│ ruff             │    0.22s │                      lint │ 1.000   │ OK       │
│ ty               │    0.80s │                type_check │ 1.000   │ OK       │
│ bandit           │    0.53s │                  security │ 1.000   │ OK       │
│ pytest           │    2.11s │                     tests │ 1.000   │ OK       │
│ radon-cc         │    0.34s │                simplicity │ 0.982   │ OK       │
│ radon-mi         │    0.41s │           maintainability │ 0.848   │ OK       │
│ radon-hal        │    0.36s │             file_bug_free │ 0.810   │ OK       │
│ radon-hal        │          │            file_smallness │ 0.655   │ OK       │
│ radon-hal        │          │        functions_bug_free │ 0.808   │ OK       │
│ radon-hal        │          │       functions_smallness │ 0.808   │ OK       │
│ vulture          │    0.37s │                 dead_code │ 1.000   │ OK       │
│ interrogate      │    0.38s │              doc_coverage │ 0.853   │ OK       │
│                  │          │                     Score │ 0.945   │          │
└──────────────────┴──────────┴───────────────────────────┴─────────┴──────────┘
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Claude Code stop hook
&lt;/h2&gt;

&lt;p&gt;If you want to auto-run, add a hook to your project's &lt;code&gt;.claude/settings.json&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"hooks"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"Stop"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"matcher"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;""&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"hooks"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"command"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"command"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"cq check . -o score &amp;amp;&amp;amp; echo 'CQ: all clear' || cq check . -o llm; true"&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}]&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}]&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;pass → tiny output&lt;/li&gt;
&lt;li&gt;fail → targeted fix prompt&lt;/li&gt;
&lt;li&gt;loop continues with minimal context&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For manual use, create &lt;code&gt;.claude/commands/cq-fix.md&lt;/code&gt;:&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="si"&gt;$(&lt;/span&gt;cq check &lt;span class="nb"&gt;.&lt;/span&gt; &lt;span class="nt"&gt;-o&lt;/span&gt; llm&lt;span class="si"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;/cq-fix&lt;/code&gt; embeds the live output directly into the prompt.&lt;/p&gt;

&lt;h2&gt;
  
  
  Install
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;uv tool &lt;span class="nb"&gt;install &lt;/span&gt;python-code-quality
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Help
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;cq check &lt;span class="nt"&gt;--help&lt;/span&gt;

 Usage: cq check &lt;span class="o"&gt;[&lt;/span&gt;OPTIONS] &lt;span class="o"&gt;[&lt;/span&gt;PATH]                                                                                                                                                                                                                                                                                                                                            

 Feed the results from 11+ code quality tools to an LLM. Try: cq check &lt;span class="nb"&gt;.&lt;/span&gt; &lt;span class="nt"&gt;-o&lt;/span&gt; llm

╭─ Arguments ─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
│   path      &lt;span class="o"&gt;[&lt;/span&gt;PATH]  Path to Python file or project directory &lt;span class="o"&gt;[&lt;/span&gt;default: .]                                                           │
╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
╭─ Options ───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
│ &lt;span class="nt"&gt;--output&lt;/span&gt;       &lt;span class="nt"&gt;-o&lt;/span&gt;      &lt;span class="o"&gt;[&lt;/span&gt;table|score|json|llm|raw]  Output mode: table &lt;span class="o"&gt;(&lt;/span&gt;default&lt;span class="o"&gt;)&lt;/span&gt;, score, json, llm                                   │
│ &lt;span class="nt"&gt;--log-level&lt;/span&gt;            TEXT                        Logging level &lt;span class="o"&gt;(&lt;/span&gt;DEBUG, INFO, WARNING, ERROR, CRITICAL&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;default: CRITICAL]        │
│ &lt;span class="nt"&gt;--clear-cache&lt;/span&gt;                                      Clear cached tool results before running                                         │
│ &lt;span class="nt"&gt;--workers&lt;/span&gt;              INTEGER                     Max parallel workers &lt;span class="o"&gt;(&lt;/span&gt;default: one per tool, use 1 &lt;span class="k"&gt;for &lt;/span&gt;sequential&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;default: 0]  │
│ &lt;span class="nt"&gt;--language&lt;/span&gt;     &lt;span class="nt"&gt;-l&lt;/span&gt;      TEXT                        Override language detection &lt;span class="o"&gt;(&lt;/span&gt;e.g. python, typescript, rust&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="c"&gt;# FUTURE             │&lt;/span&gt;
│ &lt;span class="nt"&gt;--only&lt;/span&gt;                 TEXT                        Comma-separated tool IDs to run &lt;span class="o"&gt;(&lt;/span&gt;e.g. ruff,ty,pytest&lt;span class="o"&gt;)&lt;/span&gt;                            │
│ &lt;span class="nt"&gt;--skip&lt;/span&gt;                 TEXT                        Comma-separated tool IDs to skip &lt;span class="o"&gt;(&lt;/span&gt;e.g. bandit,vulture&lt;span class="o"&gt;)&lt;/span&gt;                           │
│ &lt;span class="nt"&gt;--exclude&lt;/span&gt;              TEXT                        Comma-separated paths to exclude &lt;span class="o"&gt;(&lt;/span&gt;e.g. demo,docs&lt;span class="o"&gt;)&lt;/span&gt;                                │
│ &lt;span class="nt"&gt;--help&lt;/span&gt;                                             Show this message and exit.                                                      │
╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Notes&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Python only (for now), but the approach generalizes&lt;/li&gt;
&lt;li&gt;No agent/tool orchestration required — just a shell pipeline&lt;/li&gt;
&lt;li&gt;Works with local models or hosted ones&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Repo: &lt;a href="https://github.com/rhiza-fr/py-cq" rel="noopener noreferrer"&gt;github.com/rhiza-fr/py-cq&lt;/a&gt; — MIT, actively maintained.&lt;/p&gt;

&lt;p&gt;Enjoy!&lt;/p&gt;

</description>
      <category>ai</category>
      <category>python</category>
      <category>cli</category>
    </item>
  </channel>
</rss>
