<?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: Oscar Lansh</title>
    <description>The latest articles on DEV Community by Oscar Lansh (@oscar_lansh_net).</description>
    <link>https://dev.to/oscar_lansh_net</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%2F4218013%2F62c823e9-0030-401f-bd46-05261f81d0c9.png</url>
      <title>DEV Community: Oscar Lansh</title>
      <link>https://dev.to/oscar_lansh_net</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/oscar_lansh_net"/>
    <language>en</language>
    <item>
      <title>How Claude Spend Guard tracks reported costs — and where it can still fail</title>
      <dc:creator>Oscar Lansh</dc:creator>
      <pubDate>Sun, 01 Nov 2026 18:20:17 +0000</pubDate>
      <link>https://dev.to/oscar_lansh_net/how-claude-spend-guard-stops-runaway-claude-code-sessions-and-where-it-can-still-fail-53od</link>
      <guid>https://dev.to/oscar_lansh_net/how-claude-spend-guard-stops-runaway-claude-code-sessions-and-where-it-can-still-fail-53od</guid>
      <description>&lt;p&gt;Claude Code's &lt;code&gt;--output-format stream-json&lt;/code&gt; output includes &lt;code&gt;total_cost_usd&lt;/code&gt; in the final &lt;code&gt;result&lt;/code&gt; event. Claude Spend Guard parses that field and compares it with the cap you set when that event arrives.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx claude-spend-guard &lt;span class="nt"&gt;--cap&lt;/span&gt; 5 &lt;span class="nt"&gt;--&lt;/span&gt; claude &lt;span class="nt"&gt;-p&lt;/span&gt; &lt;span class="s2"&gt;"refactor the auth module"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Important limitation:&lt;/strong&gt; in a single &lt;code&gt;claude -p&lt;/code&gt; run, the first dollar-cost value may arrive only after the work is finished. Spend Guard cannot use that final value to stop the same run early, so it is not a per-request or in-flight hard cap. The command below shows setup, not a guarantee that an over-budget run will be interrupted before it completes.&lt;/p&gt;

&lt;p&gt;When Spend Guard receives a supported cost report at or above the cap, it sends &lt;code&gt;SIGTERM&lt;/code&gt; to the process group, waits for a grace period, then sends &lt;code&gt;SIGKILL&lt;/code&gt; to anything still running. There is no dashboard, account, or server: it is a local process wrapper.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why a wrapper instead of a dashboard or an SDK hook
&lt;/h3&gt;

&lt;p&gt;Usage dashboards such as &lt;code&gt;claude-spend&lt;/code&gt; and &lt;code&gt;claude-usage&lt;/code&gt; help you review spending after the fact. SDK middleware such as &lt;code&gt;llm-spend-guard&lt;/code&gt; and &lt;code&gt;budget-guard&lt;/code&gt; applies when your own code calls a provider API. I wanted a guard for the &lt;code&gt;claude&lt;/code&gt; CLI process itself, including unattended terminal runs.&lt;/p&gt;

&lt;p&gt;Claude Code is the only CLI for which this package currently parses a confirmed dollar-cost field. Other CLIs do not expose the same confirmed cost signal in their output, so their support uses weaker fallback modes instead of implying the same behavior.&lt;/p&gt;

&lt;h3&gt;
  
  
  What happens when parsing breaks
&lt;/h3&gt;

&lt;p&gt;The tool has three visible states:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;ENFORCING&lt;/strong&gt; — a supported cost value has been parsed and is being compared with the cap. This does not mean a cost is available during an in-flight request; for a single &lt;code&gt;claude -p&lt;/code&gt; run, the final cost can arrive after the run ends.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;DEGRADED&lt;/strong&gt; — the output format no longer matches what the parser expects; the tool warns instead of quietly implying the cap still works.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;UNVERIFIED&lt;/strong&gt; — an unconfirmed CLI or version is being used; the tool asks for confirmation before running without verified enforcement.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The failure mode I wanted to avoid was a tool that stops parsing cost but still claims the cap is being enforced. The final-event timing is a separate limitation: correct parsing cannot make a cost value available before Claude emits it.&lt;/p&gt;

&lt;h3&gt;
  
  
  Zero telemetry, enforced by CI
&lt;/h3&gt;

&lt;p&gt;The package has no runtime dependencies. Its test suite stubs Node networking primitives and checks that the wrapper does not make network calls; a dependency blocklist also guards against adding common telemetry packages later.&lt;/p&gt;

&lt;h3&gt;
  
  
  What it cannot do
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;For a single &lt;code&gt;claude -p&lt;/code&gt; run, it cannot stop the run based on a dollar value that only appears in the final &lt;code&gt;result&lt;/code&gt; event. The run may already be over by then.&lt;/li&gt;
&lt;li&gt;It cannot undo cost already incurred before a supported report reaches the cap.&lt;/li&gt;
&lt;li&gt;A child process that deliberately detaches from the process group may escape the kill.&lt;/li&gt;
&lt;li&gt;Windows does not provide a direct equivalent of Unix &lt;code&gt;SIGTERM&lt;/code&gt;, so graceful shutdown is weaker there.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Those limitations are documented in the README.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx claude-spend-guard &lt;span class="nt"&gt;--cap&lt;/span&gt; 5 &lt;span class="nt"&gt;--&lt;/span&gt; claude &lt;span class="nt"&gt;-p&lt;/span&gt; &lt;span class="s2"&gt;"your prompt"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The tool is MIT licensed and runs locally. If you run Claude Code unattended, I’d like to hear which edge cases you would test first.&lt;/p&gt;

&lt;p&gt;npm: &lt;a href="https://www.npmjs.com/package/claude-spend-guard" rel="noopener noreferrer"&gt;https://www.npmjs.com/package/claude-spend-guard&lt;/a&gt;&lt;br&gt;
GitHub: &lt;a href="https://github.com/toxot-net/claude-spend-guard" rel="noopener noreferrer"&gt;https://github.com/toxot-net/claude-spend-guard&lt;/a&gt;&lt;/p&gt;

</description>
      <category>claude</category>
      <category>ai</category>
      <category>opensource</category>
    </item>
  </channel>
</rss>
