<?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: Magicrails</title>
    <description>The latest articles on DEV Community by Magicrails (@magicrails).</description>
    <link>https://dev.to/magicrails</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%2F3905010%2Ff4051d2a-a0a7-4c6e-a3eb-48d0b5899912.png</url>
      <title>DEV Community: Magicrails</title>
      <link>https://dev.to/magicrails</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/magicrails"/>
    <language>en</language>
    <item>
      <title>I Let My AI Agent Run Overnight. It Cost $437.</title>
      <dc:creator>Magicrails</dc:creator>
      <pubDate>Wed, 29 Apr 2026 20:22:39 +0000</pubDate>
      <link>https://dev.to/magicrails/i-let-my-ai-agent-run-overnight-it-cost-437-dd7</link>
      <guid>https://dev.to/magicrails/i-let-my-ai-agent-run-overnight-it-cost-437-dd7</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;This is the launch-day essay. It's the most important piece of writing for the launch — more important than the README. The README sells &lt;em&gt;the tool&lt;/em&gt;; this sells &lt;em&gt;the problem&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Tone: first-person, narrative, specific. No marketing voice. Land softly on the library.&lt;/p&gt;

&lt;p&gt;Length target: ~1,000 words. Flat, factual, slightly self-deprecating.&lt;/p&gt;

&lt;p&gt;Where to host: dev.to + your personal blog + (optionally) cross-posted to Substack. Avoid Medium — they paywall and de-rank organic posts.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  I Let My AI Agent Run Overnight. It Cost $437.
&lt;/h2&gt;

&lt;p&gt;Last month I built a small agent. It was supposed to read through a directory of legal documents, summarize them, and file the summaries into a database. The whole thing was maybe 80 lines of LangChain plus a custom tool that looked at filesystem state.&lt;/p&gt;

&lt;p&gt;I tested it on five files. It worked. I queued up the full job — 1,200 documents — and went to bed.&lt;/p&gt;

&lt;p&gt;I woke up to a Slack DM from my CFO that I'd rather not paste in full. The short version: the agent had been calling the same tool — &lt;code&gt;list_files("/data")&lt;/code&gt; — over and over, getting the same 1,200 filenames back, and reasoning that maybe if it called it again it would notice something it had missed. It did not notice anything it had missed. It called it 14,000 times. Each call burned a few hundred tokens of context, plus the model's reasoning step around the tool call.&lt;/p&gt;

&lt;p&gt;By the time the rate limiter slowed it down and a token quota stopped it cold, it had spent $437.&lt;/p&gt;

&lt;p&gt;I was lucky. The Anthropic dashboard showed the spike. The quota saved me from another zero. A friend at a different company had the same kind of bug and didn't notice for three days. His final bill was $5,200.&lt;/p&gt;

&lt;p&gt;This post is about why this happens, why nothing in the existing tooling catches it before it happens, and the very small library I ended up writing because I couldn't keep working without it.&lt;/p&gt;

&lt;h3&gt;
  
  
  The failure mode
&lt;/h3&gt;

&lt;p&gt;The agent didn't crash. It didn't error. From its own perspective, it was doing exactly what it was told: "use the tools available to make progress on the task." It had a tool. It used the tool. The tool returned data. The data didn't unblock the task, so it tried again.&lt;/p&gt;

&lt;p&gt;There is no exception to catch when this happens. There is no log line that says "this is bad." The traces look normal — every individual call looks like every other normal call. The only signal is &lt;strong&gt;cost&lt;/strong&gt;, and cost is post-hoc.&lt;/p&gt;

&lt;p&gt;This is the central problem with autonomous agents in 2026: they don't fail loudly. They fail expensively.&lt;/p&gt;

&lt;h3&gt;
  
  
  Three patterns I've seen in the wild
&lt;/h3&gt;

&lt;p&gt;After my own incident, I started asking around. Almost every agent developer I talked to had a story. The patterns clustered into three:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Tool-call loops.&lt;/strong&gt; The agent calls the same tool with the same arguments, gets the same answer, doesn't realize it's not making progress, tries again. Mine was this. The CrewAI examples I've seen in the wild often hit it on &lt;code&gt;web_search&lt;/code&gt; queries that return the same top-10 results.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Budget runaway.&lt;/strong&gt; The agent isn't stuck per se — it's just doing work that costs more than the work was worth. A "summarize this PDF" call expands into thirty subagent calls because the planner LLM decided each section deserved its own dedicated agent with a 200k-token context window.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Reasoning loops.&lt;/strong&gt; The trickiest one. The agent's state — its memory, its plan, its scratchpad — stops changing across iterations. From the outside it's still calling tools, still emitting tokens. But internally, it's stuck on the same thought. I once watched an agent rewrite the same paragraph thirty times, each rewrite identical to the last, because its self-critique step kept producing the same critique.&lt;/p&gt;

&lt;h3&gt;
  
  
  What existing tools catch
&lt;/h3&gt;

&lt;p&gt;Almost nothing, in real time.&lt;/p&gt;

&lt;p&gt;The observability platforms — Langfuse, Arize Phoenix, AgentOps, LangSmith — are excellent at showing you what happened, after it happened. You open the trace, you see the loop, you say "ah." The dashboards are beautiful. They will tell you, in retrospect, exactly how you spent $437.&lt;/p&gt;

&lt;p&gt;Validation libraries — Guardrails AI, Pydantic-AI — check that the agent's output matches a schema. They don't watch the agent's behavior over time. A perfectly-formatted JSON output that arrives 14,000 times is still 14,000 wasted calls.&lt;/p&gt;

&lt;p&gt;Routing libraries — LiteLLM, OpenRouter — switch between models for cost reasons. Useful, but they don't stop a runaway. A loop on a cheap model is still a loop.&lt;/p&gt;

&lt;p&gt;Provider-side caps — the spending limits in the OpenAI dashboard, the Anthropic budget alerts — are account-wide and lagging. They cut you off after the limit is hit, sometimes hours later, and they don't distinguish a runaway from legitimate work.&lt;/p&gt;

&lt;p&gt;What's missing, I realized, is a brake. Something in-process that watches what the agent is doing and stops it before the bill arrives.&lt;/p&gt;

&lt;h3&gt;
  
  
  Magicrails
&lt;/h3&gt;

&lt;p&gt;So I wrote one. It is genuinely small — a few hundred lines of pure Python, no dependencies — and it does three things:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;magicrails&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;guard&lt;/span&gt;

&lt;span class="nd"&gt;@guard&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;budget_usd&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mf"&gt;10.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;max_repeats&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;stasis_steps&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;my_agent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;task&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="bp"&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;budget_usd=10.0&lt;/code&gt; — track tokens against a built-in pricing table, halt at $10.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;max_repeats=3&lt;/code&gt; — if the same tool gets called with identical arguments three times in a window, halt.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;stasis_steps=5&lt;/code&gt; — if the hash of the agent's state hasn't changed in five iterations, halt.&lt;/p&gt;

&lt;p&gt;When any of those trip, the default behavior is to raise a &lt;code&gt;TripError&lt;/code&gt; and exit cleanly. You can override that with a Slack webhook, a human-in-the-loop prompt, or any function you want.&lt;/p&gt;

&lt;p&gt;It's framework-agnostic. There are adapters for the Anthropic and OpenAI Python SDKs that auto-instrument token counting; LangChain and CrewAI adapters are the next thing. Or you can use it without a framework at all — call &lt;code&gt;session.record_tokens(...)&lt;/code&gt; from wherever your inference happens.&lt;/p&gt;

&lt;p&gt;It's not an observability platform. It's not a tracing tool. It's not a guardrails framework in the validation sense. It does one thing: stop an agent that is about to cost you money or time you cannot get back.&lt;/p&gt;

&lt;p&gt;The library is at &lt;a href="https://github.com/magicrails/magicrails" rel="noopener noreferrer"&gt;github.com/magicrails/magicrails&lt;/a&gt; and &lt;code&gt;pip install magicrails&lt;/code&gt;. It's MIT-licensed.&lt;/p&gt;

&lt;h3&gt;
  
  
  What I'd do differently
&lt;/h3&gt;

&lt;p&gt;If I'd had this two months ago, the bill would have been $9.87 instead of $437. I would not have written this essay. The colleague-of-a-colleague with the $5,200 bill would have found out at $20.&lt;/p&gt;

&lt;p&gt;Build agents. Run them overnight. But install a brake first. The agent isn't going to install one for you.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Source: &lt;a href="https://github.com/magicrails/magicrails" rel="noopener noreferrer"&gt;github.com/magicrails/magicrails&lt;/a&gt;. Discussion: [HN thread link]&lt;/em&gt;&lt;/p&gt;

</description>
      <category>agents</category>
      <category>ai</category>
      <category>devjournal</category>
      <category>llm</category>
    </item>
  </channel>
</rss>
