<?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: Mirza Iqbal</title>
    <description>The latest articles on DEV Community by Mirza Iqbal (@mjmirza).</description>
    <link>https://dev.to/mjmirza</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%2F1235534%2F747e1cbd-2637-4cd5-9bb8-a536f31a8980.jpg</url>
      <title>DEV Community: Mirza Iqbal</title>
      <link>https://dev.to/mjmirza</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/mjmirza"/>
    <language>en</language>
    <item>
      <title>My nightly Claude Code cron was about to start costing real money</title>
      <dc:creator>Mirza Iqbal</dc:creator>
      <pubDate>Sun, 14 Jun 2026 15:01:36 +0000</pubDate>
      <link>https://dev.to/mjmirza/my-nightly-claude-code-cron-was-about-to-start-costing-real-money-2ndm</link>
      <guid>https://dev.to/mjmirza/my-nightly-claude-code-cron-was-about-to-start-costing-real-money-2ndm</guid>
      <description>&lt;p&gt;A billing change lands tomorrow, and last week I went looking for what it would break in my own setup.&lt;/p&gt;

&lt;p&gt;Its headline is narrow. interactive subscription work stays exactly as it was, but anything running headless, in the background, on a schedule, starts drawing from a separate metered pool with its own limit.&lt;/p&gt;

&lt;p&gt;My subscription was safe. my habits were not.&lt;/p&gt;

&lt;p&gt;Somewhere along the way I had built the thing everyone builds. a nightly job that wakes up, calls the model to do some work, and goes back to sleep. Quiet, useful, and as of tomorrow, billed against a pool I never wanted it touching.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Two ways my work talked to Claude.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;When I actually looked, every call I made fell into one of two buckets.&lt;/p&gt;

&lt;p&gt;First, there was me, sitting there, working live. asking, building, iterating. That is what the subscription covers, and it stayed put.&lt;/p&gt;

&lt;p&gt;Second, there was automation. scheduled jobs, background runs, anything that called the model with nobody in the loop. I had treated both as "using Claude", one undifferentiated thing. That billing change drew a hard line between them that I had never bothered to draw myself.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;One of them was about to get metered.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Interactive work was fine. Automated work was the exposure.&lt;/p&gt;

&lt;p&gt;That nightly cron had felt free, because it rode the same subscription I was already paying for. Tomorrow it stops being free and starts metering against a separate quota. Same job, same output, suddenly a line item.&lt;/p&gt;

&lt;p&gt;Multiply one quiet background call by every night of a month, and the free automation I had forgotten I was running becomes a bill I never planned for.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why the nightly cron was the casualty.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;That broken pattern was specific. a headless call to the model, fired by a schedule, with nobody watching.&lt;/p&gt;

&lt;p&gt;It was also the shape I had reached for without thinking, because backgrounding a task feels like the smart, hands-off move. That change turned my cleverest-feeling automation into my most expensive one.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How I actually split it.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I did not kill the automation. I cut it in two.&lt;/p&gt;

&lt;p&gt;Work that needs no model, the gathering, the checking, the prep, stays in a plain scheduled script that costs nothing. Work that genuinely needs Claude moved back to where I am present and the subscription covers it. That schedule still runs. it stops calling the model behind my back.&lt;/p&gt;

&lt;p&gt;Unglamorous, and the whole fix. background does the cheap deterministic work, model work happens in the lane that was always covered.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;My honest opinion.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Here it is. tomorrow's split raised no costs for me. it surfaced which of my automations were never on the subscription to begin with.&lt;/p&gt;

&lt;p&gt;I had blurred two different things into one word and let a metered pattern hide inside a flat-rate habit. That change created nothing new. it switched on a light that showed what was already there. Anyone running scheduled model calls on a subscription plan has the same light about to come on.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What the split actually exposed.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Nothing about my work got worse. one pattern got a price tag, and that price tag was honest.&lt;/p&gt;

&lt;p&gt;What I gained is knowing, for every automation I run, which side of the line it sits on. metered or covered, background or present, deterministic or model. I should have known that before a billing change forced me to look. now I cannot unsee it, and every new automation gets sorted on day one.&lt;/p&gt;

&lt;p&gt;If you run anything that calls a model on a schedule, go find it before tomorrow does. Whatever feels free is the thing most likely to surprise you.&lt;/p&gt;

&lt;h2&gt;
  
  
  Your turn
&lt;/h2&gt;

&lt;p&gt;What background job are you running that you have never checked the bill for.&lt;/p&gt;

&lt;h2&gt;
  
  
  If this was useful
&lt;/h2&gt;

&lt;p&gt;I work through this in public, the wins and the freezes both, mostly on LinkedIn and YouTube. If the real version of building in the open is useful to you, that is where it lives. &lt;a href="https://www.linkedin.com/in/mirzajhanzaib/" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt;, YouTube and X under Mirza Iqbal, and the work at &lt;a href="https://next8n.com" rel="noopener noreferrer"&gt;next8n.com&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>claudecode</category>
      <category>llmops</category>
      <category>automation</category>
      <category>devops</category>
    </item>
    <item>
      <title>My 8-hour job died at hour 3 and I had checkpointed almost nothing</title>
      <dc:creator>Mirza Iqbal</dc:creator>
      <pubDate>Sun, 14 Jun 2026 08:31:52 +0000</pubDate>
      <link>https://dev.to/mjmirza/my-8-hour-job-died-at-hour-3-and-i-had-checkpointed-almost-nothing-545h</link>
      <guid>https://dev.to/mjmirza/my-8-hour-job-died-at-hour-3-and-i-had-checkpointed-almost-nothing-545h</guid>
      <description>&lt;p&gt;For hours the job had been running clean.&lt;/p&gt;

&lt;p&gt;It was a long grind, the kind you start and walk away from, trusting it to chew through the pile while you do something else. Hundreds of items, one after another, all fine.&lt;/p&gt;

&lt;p&gt;Three hours in, the quota ran dry and everything stopped.&lt;/p&gt;

&lt;p&gt;I came back to a dead run and a sinking feeling. Work had been going for hours, yet my last save sat way back near the start, because I had told myself I would commit when it was all done. So resuming meant starting again near the beginning, with three hours of finished work stranded and no way to reach it.&lt;/p&gt;

&lt;p&gt;That is the moment I learned the interruption was never the real problem.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The cap does not care about your progress.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;A quota, a timeout, a crash, a killed process. None of them check whether you are at a clean stopping point. They land whenever they land, mid-item, mid-thought, mid-everything.&lt;/p&gt;

&lt;p&gt;Blaming the interruption is comfortable, because it sits outside you. It is also the one part you cannot control. Your cap will always arrive at the worst moment, and planning around "it will not happen this run" is planning to lose work.&lt;/p&gt;

&lt;p&gt;So I stopped trying to dodge the interruption and started designing for it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Resume cost is a number you choose.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Here is the idea that changed how I build long jobs. how much work an interruption can destroy is a setting, decided before the run starts.&lt;/p&gt;

&lt;p&gt;Save progress every N items and your worst case loss is N items. Pick N of 500 and a crash can cost you 500 items of redone work. Pick N of 10 and the same crash costs you 10. Same interruption, wildly different pain, and the only difference is a decision you made up front.&lt;/p&gt;

&lt;p&gt;That grind had effectively chosen N of everything. one commit, at the very end. So the worst case was the entire run, and the entire run is what I paid.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why committing at the end is the bug.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;A single end-commit feels efficient. fewer writes, cleaner history, less fuss while the job runs.&lt;/p&gt;

&lt;p&gt;It is a trap. every interruption before that final commit erases all of it. You have built a system whose resume cost equals its full runtime, then handed it to an environment that interrupts at random.&lt;/p&gt;

&lt;p&gt;My fix was unglamorous. save often, in small bounded steps, and never save a broken half-item. A failed item gets skipped, never checkpointed, so you never resume into a corrupt state. Boring, mechanical, and it turns a lost afternoon into a lost minute.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The opinion I will defend.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Here it is. blaming the cap, the timeout, or the crash for lost work is misdiagnosing your own design.&lt;/p&gt;

&lt;p&gt;An interruption is a certainty, not an accident waiting to maybe happen. If losing the run hurts, the real fault is the unbounded resume cost you allowed, while the interruption was always going to come. Bound that cost and the same crash becomes a shrug.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What checkpoint discipline actually buys.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Nothing about my jobs runs faster now. checkpointing adds a little overhead, and I pay it gladly.&lt;/p&gt;

&lt;p&gt;What I bought is the right to walk away. A long job can die at any moment, at hour one or hour seven, and the cost is always the same small number of items rather than the whole run. The crash still happens. I stopped letting it set fire to hours of finished work.&lt;/p&gt;

&lt;p&gt;If you run anything long, a batch, a grind, an overnight pipeline, decide your resume cost on purpose before you start it. Your cap is coming. the only open question is how much it gets to take.&lt;/p&gt;

&lt;h2&gt;
  
  
  Your turn
&lt;/h2&gt;

&lt;p&gt;What is the longest run you have lost, and what would a checkpoint have saved.&lt;/p&gt;

&lt;h2&gt;
  
  
  If this was useful
&lt;/h2&gt;

&lt;p&gt;I work through this in public, the wins and the freezes both, mostly on LinkedIn and YouTube. If the real version of building in the open is useful to you, that is where it lives. &lt;a href="https://www.linkedin.com/in/mirzajhanzaib/" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt;, YouTube and X under Mirza Iqbal, and the work at &lt;a href="https://next8n.com" rel="noopener noreferrer"&gt;next8n.com&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>claudecode</category>
      <category>automation</category>
      <category>productivity</category>
      <category>devops</category>
    </item>
    <item>
      <title>I stopped letting the invoice be the first place I learn my LLM costs spiked</title>
      <dc:creator>Mirza Iqbal</dc:creator>
      <pubDate>Sat, 13 Jun 2026 09:02:20 +0000</pubDate>
      <link>https://dev.to/mjmirza/i-stopped-letting-the-invoice-be-the-first-place-i-learn-my-llm-costs-spiked-8p2</link>
      <guid>https://dev.to/mjmirza/i-stopped-letting-the-invoice-be-the-first-place-i-learn-my-llm-costs-spiked-8p2</guid>
      <description>&lt;p&gt;For a while, the invoice was my cost monitor.&lt;/p&gt;

&lt;p&gt;I would build, ship, run agents all month, and find out how it went when the bill arrived. If something had gone wrong, the bill told me. Calmly. Weeks late.&lt;/p&gt;

&lt;p&gt;Terrible way to learn you have a problem.&lt;/p&gt;

&lt;p&gt;One month a small mistake quietly burned money for days, and my running total still looked normal until the very end, because a month is a big bucket and a few bad days hide inside it. By the time the number was obviously wrong, the money was already spent and I could do nothing but pay it.&lt;/p&gt;

&lt;p&gt;So I stopped trusting the invoice to warn me. It cannot. Wrong shape for the job.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why a bill is a lagging alarm.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;A bill is cumulative. It only ever goes up, and it reports at the end. Both of those make it useless as a warning.&lt;/p&gt;

&lt;p&gt;Cumulative means a spike gets averaged into a month of normal usage, so it barely moves the total until it has run for a while. End-of-period means you find out after you can act. An alarm that rings only once the house has burned down has a better name. a receipt.&lt;/p&gt;

&lt;p&gt;To catch a cost spike you have to watch something that moves the moment the spike starts, and that is never your total.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Signal one. the burn rate.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;First thing I watch now is spend per unit of time rather than spend in total.&lt;/p&gt;

&lt;p&gt;Burn rate reacts at once. A retry storm, a jump to a heavier model, an agent stuck in a loop, all of them show up as the rate climbing within the hour, long before the monthly total looks unusual. Your total stays calm while the rate is already screaming.&lt;/p&gt;

&lt;p&gt;Rate leads because it measures change, and a spike is nothing but change.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Signal two. the cost-to-work fit.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Rate alone is not enough, because sometimes you genuinely are doing more work and spending more is correct.&lt;/p&gt;

&lt;p&gt;So the second signal is cost measured against the work it produced. Call it cost-fit. Spend climbing while output stays flat is the real alarm. Spend climbing because you shipped twice as much is fine.&lt;/p&gt;

&lt;p&gt;Cost-fit tells you whether a spike is a problem or a busy day. Without it you either miss real spikes or flinch at every normal one.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why the total fools you.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;A running total feels like the honest number because it is the one you pay. Yet it lags, it averages, and it is the hardest view to act on.&lt;/p&gt;

&lt;p&gt;Watching the total is watching the scoreboard after the game has ended. Watching the rate and the fit is following the game while you can still change the score.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The opinion I will defend.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Here it is. Of every place to discover a cost problem, an invoice is the worst, and most people have no other place.&lt;/p&gt;

&lt;p&gt;They open a dashboard, see a running total, feel informed, and miss every spike that matters, because a total cannot show a spike until it is too big to undo. A prettier dashboard does not change that. Watching the two leading signals does.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What watching the right two changed.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Nothing about my spending got cheaper because I started watching it. that was never the point.&lt;/p&gt;

&lt;p&gt;A problem now reaches me the same hour it starts, while it is small and reversible, instead of at month-end when it is large and already paid. A runaway loop that once cost me a quiet week now costs me twenty minutes. The spike still happens. I no longer learn about it from the invoice.&lt;/p&gt;

&lt;p&gt;Got only the bill as your cost signal? Then you are reconciling spend after the fact rather than watching it. Watch the rate, watch the fit, and let the invoice go back to being a receipt instead of a warning that always arrives too late.&lt;/p&gt;

&lt;h2&gt;
  
  
  Your turn
&lt;/h2&gt;

&lt;p&gt;What is the last bill that surprised you, and what would have warned you sooner.&lt;/p&gt;

&lt;h2&gt;
  
  
  If this was useful
&lt;/h2&gt;

&lt;p&gt;I work through this in public, the wins and the freezes both, mostly on LinkedIn and YouTube. If the real version of building in the open is useful to you, that is where it lives. &lt;a href="https://www.linkedin.com/in/mirzajhanzaib/" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt;, YouTube and X under Mirza Iqbal, and the work at &lt;a href="https://next8n.com" rel="noopener noreferrer"&gt;next8n.com&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>claudecode</category>
      <category>llmops</category>
      <category>devtools</category>
      <category>productivity</category>
    </item>
    <item>
      <title>I automated my content pipeline and it kept writing the wrong articles</title>
      <dc:creator>Mirza Iqbal</dc:creator>
      <pubDate>Fri, 12 Jun 2026 20:51:37 +0000</pubDate>
      <link>https://dev.to/mjmirza/i-automated-my-content-pipeline-and-it-kept-writing-the-wrong-articles-2mh7</link>
      <guid>https://dev.to/mjmirza/i-automated-my-content-pipeline-and-it-kept-writing-the-wrong-articles-2mh7</guid>
      <description>&lt;p&gt;For weeks my content pipeline did exactly what I built it to do.&lt;/p&gt;

&lt;p&gt;It pulled from a pile of sources, drafted clean articles, rendered the covers, handled the publish. The machinery worked.&lt;/p&gt;

&lt;p&gt;And the output was wrong.&lt;/p&gt;

&lt;p&gt;Not broken-wrong. Polished, on-topic, technically fine, and still the wrong thing to have written that day. I kept shipping articles nobody needed, on the day nobody was asking, while the thing actually worth saying sat unwritten in a folder.&lt;/p&gt;

&lt;p&gt;It took me an embarrassing while to see it. I had automated the easy half and left the hard half to luck.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Generation was never my bottleneck.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Writing is the part everyone races to automate. Feed in a topic, get out a draft. That problem is, for practical purposes, solved. A pipeline can produce a competent article on almost anything you point it at.&lt;/p&gt;

&lt;p&gt;So the volume went up and the value did not. More posts, same flat result. I had mistaken throughput for progress, which is the oldest trap in automation.&lt;/p&gt;

&lt;p&gt;The draft was never the scarce resource. The decision in front of the draft was.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Selection is the job nobody automates.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Selection is choosing what deserves to exist before a single word is written. Of all the things you could say today, which one is worth your name on it.&lt;/p&gt;

&lt;p&gt;That choice carries everything the draft cannot. Is this relevant to the people I want to reach. Is the timing right, or is the moment already gone. Does it sound like me, or like anyone. Is it the thing I am uniquely placed to say, or a thing a thousand others could say better.&lt;/p&gt;

&lt;p&gt;A generator answers none of that. It will write whatever you hand it with equal confidence, including the wrong thing, beautifully.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why a machine cannot pick for you.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Selection runs on context the machine does not have. What you learned last week from a client. The argument that changed your mind. The thing your audience is quietly struggling with that nobody has named yet.&lt;/p&gt;

&lt;p&gt;That is taste, and taste is lived. It is the accumulated judgment of a specific person who has paid attention to a specific world. You can feed a model your past, but you cannot feed it your nose for what matters next.&lt;/p&gt;

&lt;p&gt;So when I let the pipeline both choose and write, I was handing away the one part that was actually mine. The part that was the whole point.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The opinion I will defend.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Here it is. Generation is a commodity now, and selection is the entire game.&lt;/p&gt;

&lt;p&gt;The people whose content lands are not better writers than the people whose content disappears. They are better choosers. They have a sharper sense of what is worth saying, to whom, right now. The draft is downstream of that, and the draft was never where the edge lived.&lt;/p&gt;

&lt;p&gt;If your content is not connecting, do not reach for a better generator. Look at what you are choosing to make, and who decided it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What changed when I treated selection as the work.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I did not throw the pipeline away. I moved myself to the front of it.&lt;/p&gt;

&lt;p&gt;The machine still does the heavy lifting it is good at. But the choice of what to write now sits with me, on purpose, before anything runs. I look at what I actually learned this week, what my readers are actually stuck on, what only I can say with a straight face. Then the pipeline works on a target I chose, instead of a target it guessed.&lt;/p&gt;

&lt;p&gt;The volume dropped. The hit rate climbed. Fewer articles, more of them worth reading. That trade was the whole fix, and it cost me nothing but the honesty to admit that the easy half had never been the problem.&lt;/p&gt;

&lt;p&gt;If you are automating your content and the results feel hollow, check which half you handed to the machine. If you gave it the choosing, take that back. Let it write. You decide what is worth writing.&lt;/p&gt;

&lt;h2&gt;
  
  
  Your turn
&lt;/h2&gt;

&lt;p&gt;What do you let a tool choose for you that you should be choosing yourself.&lt;/p&gt;

&lt;h2&gt;
  
  
  If this was useful
&lt;/h2&gt;

&lt;p&gt;I work through this in public, the wins and the freezes both, mostly on LinkedIn and YouTube. If the real version of building in the open is useful to you, that is where it lives. &lt;a href="https://www.linkedin.com/in/mirzajhanzaib/" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt;, YouTube and X under Mirza Iqbal, and the work at &lt;a href="https://next8n.com" rel="noopener noreferrer"&gt;next8n.com&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>automation</category>
      <category>agents</category>
      <category>productivity</category>
      <category>ai</category>
    </item>
    <item>
      <title>My first production agent was spaghetti because one layer did three jobs</title>
      <dc:creator>Mirza Iqbal</dc:creator>
      <pubDate>Fri, 12 Jun 2026 07:17:31 +0000</pubDate>
      <link>https://dev.to/mjmirza/my-first-production-agent-was-spaghetti-because-one-layer-did-three-jobs-1l0i</link>
      <guid>https://dev.to/mjmirza/my-first-production-agent-was-spaghetti-because-one-layer-did-three-jobs-1l0i</guid>
      <description>&lt;p&gt;It demoed perfectly.&lt;/p&gt;

&lt;p&gt;Clean output, every case green, the kind of run that makes you screenshot the terminal.&lt;/p&gt;

&lt;p&gt;Then it reached production and fell apart inside a day.&lt;/p&gt;

&lt;p&gt;What followed was the worst kind of debugging. The agent would return something wrong, and I could not tell why. Was it the prompt. Was it a timeout on a tool call. Was it stale data. Was it a retry firing twice and confusing the next step. I spent far longer staring at that agent than I ever spent building it.&lt;/p&gt;

&lt;p&gt;That pain was on the dev.to front page this week. someone wrote about spending ten times longer debugging AI code than writing it. I felt that one in my spine.&lt;/p&gt;

&lt;p&gt;Here is what I eventually found. one layer of my agent was quietly doing three jobs at once.&lt;/p&gt;

&lt;p&gt;Most agent failures that people blame on the model are not reasoning failures at all. They are IO failures wearing a reasoning costume. The model looked broken because the layer around it was broken, and the two were tangled into the same lump of code.&lt;/p&gt;

&lt;p&gt;As a Mastra Agent Ambassador I now build every agent around one promise. each layer does exactly one job. Three layers, three responsibilities, nothing crossing a line it should not.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Reasoning. the layer that decides.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This is the model. Its only job is to think and choose. Given clean inputs, what is the next step.&lt;/p&gt;

&lt;p&gt;It should never fetch data. It should never retry a failed call. It should never format a payload for a downstream system. The moment reasoning starts doing IO, you can no longer tell a bad decision apart from a bad fetch, and your debugging time doubles overnight.&lt;/p&gt;

&lt;p&gt;Keep this layer boring. Inputs in, a decision out.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;IO. the layer that talks to the world.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Every call to an API, a database, a tool, a file. All of it lives here, and all of it is deterministic.&lt;/p&gt;

&lt;p&gt;This is where retries belong. Where timeouts belong. Where validation belongs. Where the guardrails belong, the checks that clean what comes in before the model ever sees it, and what goes out before a user ever does. Mastra gives you input and output processors for exactly this, a home for that discipline so it is not smeared across your prompts.&lt;/p&gt;

&lt;p&gt;When IO is its own layer, a failed call reads as a failed call. It surfaces as an IO error, not as a confusing model answer. That one separation is what gave me my nights back.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Orchestration. the layer that sequences.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This is the loop. It holds state, decides when to call reasoning and when to call IO, manages approvals, and knows when the task is finished.&lt;/p&gt;

&lt;p&gt;It does not think, that belongs to reasoning. It does not fetch, that belongs to IO. It conducts.&lt;/p&gt;

&lt;p&gt;When orchestration is thin and explicit, you can read your agent like a short story. step, check, step, check. When it is tangled with the other two, you get the spaghetti I shipped the first time.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why the framework alone will not save you.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Here is the opinion I will defend. the framework is not the thing that keeps you clean. the layer discipline is.&lt;/p&gt;

&lt;p&gt;You can write the same spaghetti inside Mastra that you would write with nothing at all. The tools make the right structure easy, but they do not force it on you. If you let reasoning fetch, and IO decide, and orchestration think, no framework on earth will make that agent debuggable.&lt;/p&gt;

&lt;p&gt;The discipline stays yours to keep. The framework only makes keeping it cheaper.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What changed after I split them.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The next agent I built with the three layers held apart was not smarter. The model was the same model. But when something broke, I knew within a minute which box to open. A wrong answer was a reasoning issue. A missing value was an IO issue. A step out of order was orchestration. The fog was gone.&lt;/p&gt;

&lt;p&gt;That is the whole payoff. not a cleverer agent, a debuggable one. And a debuggable agent is the only kind you can run in production without dreading the pager.&lt;/p&gt;

&lt;p&gt;If you are building your first real agent, do not start with the prompt. start by drawing three boxes and promising yourself that nothing leaks across a line it should not own. It is the least glamorous decision you will make, and the one that saves you the most sleep.&lt;/p&gt;

&lt;h2&gt;
  
  
  Your turn
&lt;/h2&gt;

&lt;p&gt;Which layer do you overload by accident most, reasoning, IO, or orchestration.&lt;/p&gt;

&lt;h2&gt;
  
  
  If this was useful
&lt;/h2&gt;

&lt;p&gt;I work through this in public, the wins and the freezes both, mostly on LinkedIn and YouTube. If the real version of building agents in the open is useful to you, that is where it lives. &lt;a href="https://www.linkedin.com/in/mirzajhanzaib/" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt;, YouTube and X under Mirza Iqbal, and the work at &lt;a href="https://next8n.com" rel="noopener noreferrer"&gt;next8n.com&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>mastra</category>
      <category>agents</category>
      <category>ai</category>
      <category>vercel</category>
    </item>
    <item>
      <title>My first production agent was spaghetti because one layer did three jobs</title>
      <dc:creator>Mirza Iqbal</dc:creator>
      <pubDate>Fri, 12 Jun 2026 07:09:53 +0000</pubDate>
      <link>https://dev.to/mjmirza/my-first-production-agent-was-spaghetti-because-one-layer-did-three-jobs-5a2l</link>
      <guid>https://dev.to/mjmirza/my-first-production-agent-was-spaghetti-because-one-layer-did-three-jobs-5a2l</guid>
      <description>&lt;p&gt;It demoed perfectly.&lt;/p&gt;

&lt;p&gt;Clean output, every case green, the kind of run that makes you screenshot the terminal.&lt;/p&gt;

&lt;p&gt;Then it reached production and fell apart inside a day.&lt;/p&gt;

&lt;p&gt;What followed was the worst kind of debugging. The agent would return something wrong, and I could not tell why. Was it the prompt. Was it a timeout on a tool call. Was it stale data. Was it a retry firing twice and confusing the next step. I spent far longer staring at that agent than I ever spent building it.&lt;/p&gt;

&lt;p&gt;That pain was on the dev.to front page this week. someone wrote about spending ten times longer debugging AI code than writing it. I felt that one in my spine.&lt;/p&gt;

&lt;p&gt;Here is what I eventually found. one layer of my agent was quietly doing three jobs at once.&lt;/p&gt;

&lt;p&gt;Most agent failures that people blame on the model are not reasoning failures at all. They are IO failures wearing a reasoning costume. The model looked broken because the layer around it was broken, and the two were tangled into the same lump of code.&lt;/p&gt;

&lt;p&gt;As a Mastra Agent Ambassador I now build every agent around one promise. each layer does exactly one job. Three layers, three responsibilities, nothing crossing a line it should not.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Reasoning. the layer that decides.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This is the model. Its only job is to think and choose. Given clean inputs, what is the next step.&lt;/p&gt;

&lt;p&gt;It should never fetch data. It should never retry a failed call. It should never format a payload for a downstream system. The moment reasoning starts doing IO, you can no longer tell a bad decision apart from a bad fetch, and your debugging time doubles overnight.&lt;/p&gt;

&lt;p&gt;Keep this layer boring. Inputs in, a decision out.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;IO. the layer that talks to the world.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Every call to an API, a database, a tool, a file. All of it lives here, and all of it is deterministic.&lt;/p&gt;

&lt;p&gt;This is where retries belong. Where timeouts belong. Where validation belongs. Where the guardrails belong, the checks that clean what comes in before the model ever sees it, and what goes out before a user ever does. Mastra gives you input and output processors for exactly this, a home for that discipline so it is not smeared across your prompts.&lt;/p&gt;

&lt;p&gt;When IO is its own layer, a failed call reads as a failed call. It surfaces as an IO error, not as a confusing model answer. That one separation is what gave me my nights back.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Orchestration. the layer that sequences.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This is the loop. It holds state, decides when to call reasoning and when to call IO, manages approvals, and knows when the task is finished.&lt;/p&gt;

&lt;p&gt;It does not think, that belongs to reasoning. It does not fetch, that belongs to IO. It conducts.&lt;/p&gt;

&lt;p&gt;When orchestration is thin and explicit, you can read your agent like a short story. step, check, step, check. When it is tangled with the other two, you get the spaghetti I shipped the first time.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why the framework alone will not save you.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Here is the opinion I will defend. the framework is not the thing that keeps you clean. the layer discipline is.&lt;/p&gt;

&lt;p&gt;You can write the same spaghetti inside Mastra that you would write with nothing at all. The tools make the right structure easy, but they do not force it on you. If you let reasoning fetch, and IO decide, and orchestration think, no framework on earth will make that agent debuggable.&lt;/p&gt;

&lt;p&gt;The discipline stays yours to keep. The framework only makes keeping it cheaper.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What changed after I split them.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The next agent I built with the three layers held apart was not smarter. The model was the same model. But when something broke, I knew within a minute which box to open. A wrong answer was a reasoning issue. A missing value was an IO issue. A step out of order was orchestration. The fog was gone.&lt;/p&gt;

&lt;p&gt;That is the whole payoff. not a cleverer agent, a debuggable one. And a debuggable agent is the only kind you can run in production without dreading the pager.&lt;/p&gt;

&lt;p&gt;If you are building your first real agent, do not start with the prompt. start by drawing three boxes and promising yourself that nothing leaks across a line it should not own. It is the least glamorous decision you will make, and the one that saves you the most sleep.&lt;/p&gt;

&lt;h2&gt;
  
  
  Your turn
&lt;/h2&gt;

&lt;p&gt;Which layer do you overload by accident most, reasoning, IO, or orchestration.&lt;/p&gt;

&lt;h2&gt;
  
  
  If this was useful
&lt;/h2&gt;

&lt;p&gt;I work through this in public, the wins and the freezes both, mostly on LinkedIn and YouTube. If the real version of building agents in the open is useful to you, that is where it lives. &lt;a href="https://www.linkedin.com/in/mirzajhanzaib/" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt;, YouTube and X under Mirza Iqbal, and the work at &lt;a href="https://next8n.com" rel="noopener noreferrer"&gt;next8n.com&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>mastra</category>
      <category>agents</category>
      <category>ai</category>
      <category>vercel</category>
    </item>
    <item>
      <title>Green tests, broken docs. Dogfooding caught what 15 tests missed</title>
      <dc:creator>Mirza Iqbal</dc:creator>
      <pubDate>Thu, 11 Jun 2026 14:41:19 +0000</pubDate>
      <link>https://dev.to/mjmirza/green-tests-broken-docs-dogfooding-caught-what-15-tests-missed-16bk</link>
      <guid>https://dev.to/mjmirza/green-tests-broken-docs-dogfooding-caught-what-15-tests-missed-16bk</guid>
      <description>&lt;p&gt;A broken doc still renders.&lt;/p&gt;

&lt;p&gt;That is the whole reason documentation rot is so dangerous.&lt;/p&gt;

&lt;p&gt;The page looks fine right up to the moment someone clicks the link that went nowhere.&lt;/p&gt;

&lt;p&gt;This week I shipped a small tool to catch that, and the tool taught me a lesson I keep relearning.&lt;/p&gt;

&lt;h2&gt;
  
  
  What the tool does
&lt;/h2&gt;

&lt;p&gt;It scans a folder of markdown and flags three kinds of rot.&lt;/p&gt;

&lt;p&gt;A link to a file that moved and now returns a 404.&lt;/p&gt;

&lt;p&gt;A table of contents anchor that drifted away from its heading.&lt;/p&gt;

&lt;p&gt;And the one most link checkers skip, a doc that nothing else references.&lt;/p&gt;

&lt;p&gt;That last one deserves a name. It is dead code wearing a different hat.&lt;/p&gt;

&lt;p&gt;Nobody deletes it because nobody is sure it is unused. Nobody reads it because nothing points to it. It sits there and goes stale, quietly lying to the next person who finds it by accident.&lt;/p&gt;

&lt;p&gt;If you have ever run a dead code check on a codebase, you already understand the orphan doc. Same idea, applied to markdown.&lt;/p&gt;

&lt;h2&gt;
  
  
  The part where I got humbled
&lt;/h2&gt;

&lt;p&gt;I wrote 15 tests. They ran on Ubuntu and macOS. All green.&lt;/p&gt;

&lt;p&gt;Then I pointed the checker at my own setup, hundreds of real files, and it lit up a long table of contents as completely broken.&lt;/p&gt;

&lt;p&gt;Every anchor reported wrong.&lt;/p&gt;

&lt;p&gt;Except the anchors were fine. I checked by hand. The links matched the headings.&lt;/p&gt;

&lt;p&gt;The bug was mine, and it was a good one.&lt;/p&gt;

&lt;h2&gt;
  
  
  The bash trap
&lt;/h2&gt;

&lt;p&gt;Here is the heading lookup, simplified.&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="nb"&gt;set&lt;/span&gt; &lt;span class="nt"&gt;-uo&lt;/span&gt; pipefail

&lt;span class="c"&gt;# does the anchor match any heading slug in the file?&lt;/span&gt;
heading_slugs &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$file&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; | &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-Fxq&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$anchor&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; report_broken &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$anchor&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It reads as correct at a glance. Generate the heading slugs, search them for the anchor, and report only when the search fails.&lt;/p&gt;

&lt;p&gt;The trap is the interaction between two things you turned on for safety.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;grep -q&lt;/code&gt; exits the moment it finds a match. It does not read the rest of the input. When it exits, it closes the pipe.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;heading_slugs&lt;/code&gt;, still writing, gets a broken pipe and dies with a non-zero status.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;set -o pipefail&lt;/code&gt; then declares the whole pipeline failed, because one stage in it failed, even though the stage that mattered succeeded.&lt;/p&gt;

&lt;p&gt;So a real match was reported as a miss. On a one heading doc the producer finishes before grep closes the pipe, so the bug hides. On a forty heading doc it fires every time.&lt;/p&gt;

&lt;p&gt;The fix is to keep the producer out of grep's pipeline.&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;# process substitution. grep's exit status is its own, the producer's death&lt;/span&gt;
&lt;span class="c"&gt;# is not part of the pipeline, so pipefail stays out of it.&lt;/span&gt;
&lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-Fxq&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$anchor&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &amp;lt;&lt;span class="o"&gt;(&lt;/span&gt;heading_slugs &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$file&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; report_broken &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$anchor&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Two smaller bugs were hiding behind the loud one. The slug list was printed without newlines, so every slug ran together into a single line. And the slug collapsed repeated dashes while the platform that renders the anchors does not, so a heading with a separator mismatched its own valid anchor. The fix for the second one is to normalize both sides through the same function, so any difference cancels.&lt;/p&gt;

&lt;h2&gt;
  
  
  The two lessons
&lt;/h2&gt;

&lt;p&gt;A passing test suite proves the cases you imagined. It says nothing about the cases you did not.&lt;/p&gt;

&lt;p&gt;My tests had one heading because one heading was easy to write. Real docs have forty, and forty is where the bug lived.&lt;/p&gt;

&lt;p&gt;The fastest way to find what your tool misses is to turn it on yourself first. The real corpus is the test the synthetic fixtures cannot be.&lt;/p&gt;

&lt;p&gt;I shipped a checker for rot, and the checker found rot in the work of the checker's own author. That is the job working as intended.&lt;/p&gt;

&lt;h2&gt;
  
  
  One question for you
&lt;/h2&gt;

&lt;p&gt;If you write bash, this trap is somewhere in your scripts right now.&lt;/p&gt;

&lt;p&gt;A strict mode plus a command that exits early is a quiet false signal, and it only shows up under the inputs you did not test.&lt;/p&gt;

&lt;p&gt;I write about the unglamorous parts of building tools that survive real use, the bugs that pass every test and fail on contact with reality.&lt;/p&gt;

&lt;p&gt;So tell me. What is the bug your own tests were too polite to catch?&lt;/p&gt;

</description>
      <category>bash</category>
      <category>testing</category>
      <category>documentation</category>
      <category>cli</category>
    </item>
    <item>
      <title>I keep shipping my best work to an audience of one</title>
      <dc:creator>Mirza Iqbal</dc:creator>
      <pubDate>Thu, 11 Jun 2026 05:50:52 +0000</pubDate>
      <link>https://dev.to/mjmirza/i-keep-shipping-my-best-work-to-an-audience-of-one-4fbm</link>
      <guid>https://dev.to/mjmirza/i-keep-shipping-my-best-work-to-an-audience-of-one-4fbm</guid>
      <description>&lt;p&gt;There is a folder on my machine I am quietly proud of.&lt;/p&gt;

&lt;p&gt;Almost nobody has seen what is inside it.&lt;/p&gt;

&lt;p&gt;Years of work live there. A knowledge system I built and rebuilt until it actually held. Pipelines that run on their own. An archive I shaped book by book, late at night, to a standard I would defend to anyone.&lt;/p&gt;

&lt;p&gt;The audience for all of it is one person.&lt;/p&gt;

&lt;p&gt;Me.&lt;/p&gt;

&lt;h2&gt;
  
  
  I am good at the part nobody watches
&lt;/h2&gt;

&lt;p&gt;Give me a hard private problem and I will go deep, finish it, polish it past the point that makes sense, and feel calm the whole way.&lt;/p&gt;

&lt;p&gt;Ask me to put a fraction of that in front of strangers and something locks.&lt;/p&gt;

&lt;p&gt;The post stays a draft.&lt;br&gt;
The repo stays private.&lt;br&gt;
The talk I could give stays an idea.&lt;/p&gt;

&lt;h2&gt;
  
  
  The part I have stopped pretending about
&lt;/h2&gt;

&lt;p&gt;Private mastery is a comfortable place to hide.&lt;/p&gt;

&lt;p&gt;It feels like work because it is work. Real, hard, skilled work. But it asks nothing of the part of me that is afraid of being judged. No comments. No silence after posting. No one telling me I got it wrong.&lt;/p&gt;

&lt;p&gt;A private win cannot be rejected.&lt;/p&gt;

&lt;p&gt;That is exactly why it is safe. And safe is the problem.&lt;/p&gt;

&lt;h2&gt;
  
  
  The bill comes quietly
&lt;/h2&gt;

&lt;p&gt;Nobody can hire what they cannot see.&lt;br&gt;
Nobody can learn from a system that lives on one laptop.&lt;br&gt;
Nobody can follow a person who never shows up.&lt;/p&gt;

&lt;p&gt;I have met people who know less than I do and earn more, and for a long time that felt unfair. It is not unfair. They ship in public. They let the work be seen, judged, and remembered. The knowledge was never the thing that paid. Being known for it was.&lt;/p&gt;

&lt;h2&gt;
  
  
  The fear has already been tested
&lt;/h2&gt;

&lt;p&gt;Four separate organizations made me an ambassador for their tools. I have spoken on a real stage. People I respect chose to work with me.&lt;/p&gt;

&lt;p&gt;None of that happened in private.&lt;/p&gt;

&lt;p&gt;Every one of those doors opened because, for a moment, I let the work be seen. So the fear has already had its turn. And it lost.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I am actually doing about it
&lt;/h2&gt;

&lt;p&gt;I am not going to pretend I fixed this.&lt;/p&gt;

&lt;p&gt;What I am doing is smaller. One thing leaves the folder each day now. A post. A note. A piece of the work, shown badly rather than hidden perfectly.&lt;/p&gt;

&lt;p&gt;This post is one of them.&lt;/p&gt;

&lt;p&gt;It is not my best work. My best work is still in the folder. But this one has something the folder never will.&lt;/p&gt;

&lt;p&gt;It can be seen.&lt;/p&gt;

&lt;h2&gt;
  
  
  Your turn
&lt;/h2&gt;

&lt;p&gt;What is the best thing you have built that almost nobody has seen?&lt;/p&gt;

&lt;h2&gt;
  
  
  If this was useful
&lt;/h2&gt;

&lt;p&gt;I work through this in public now, the wins and the freezes both, mostly on LinkedIn and YouTube. If the real version of building in the open is useful to you, that is where it lives.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.linkedin.com/in/mirzajhanzaib/" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt;, YouTube and X under Mirza Iqbal, and the work at &lt;a href="https://next8n.com" rel="noopener noreferrer"&gt;next8n.com&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>career</category>
      <category>productivity</category>
      <category>discuss</category>
      <category>devto</category>
    </item>
    <item>
      <title>Four ambassador titles and I still could not press publish</title>
      <dc:creator>Mirza Iqbal</dc:creator>
      <pubDate>Wed, 10 Jun 2026 16:47:09 +0000</pubDate>
      <link>https://dev.to/mjmirza/four-ambassador-titles-and-i-still-could-not-press-publish-3lg1</link>
      <guid>https://dev.to/mjmirza/four-ambassador-titles-and-i-still-could-not-press-publish-3lg1</guid>
      <description>&lt;p&gt;I knew exactly what to build. The stack, the pattern, the deploy, the post, all of it clear in my head. Almost none of it shipped for years.&lt;/p&gt;

&lt;p&gt;That gap has a name most of us avoid saying out loud. Knowing and doing are two very different skills.&lt;/p&gt;

&lt;p&gt;This is not a story from someone who never struggled with it. I hold four ambassador titles. Sixteen years in tech. Documented savings in the millions for real enterprise clients.&lt;/p&gt;

&lt;p&gt;And I would still sit with a finished thing and refuse to press publish.&lt;/p&gt;

&lt;p&gt;For a long stretch I was sure the problem was knowledge. So I learned more. Another framework, another course, another deep read. More input felt like motion.&lt;/p&gt;

&lt;p&gt;Learning was the most comfortable way to avoid the actual work. The actual work was exposure.&lt;/p&gt;

&lt;p&gt;Private work felt safe. A repo nobody opens. A draft nobody reads. A side project that quietly stays a side project. My best thinking happened where no one could judge it.&lt;/p&gt;

&lt;p&gt;Public work felt like walking into a lit room full of people. So I went and found one more thing to learn first.&lt;/p&gt;

&lt;p&gt;Here is the part I had backwards.&lt;/p&gt;

&lt;p&gt;We keep treating knowledge as the bottleneck. The real one is distribution.&lt;/p&gt;

&lt;p&gt;I know developers with a fraction of my knowledge earning far more, because they ship in the open while I polished in private.&lt;/p&gt;

&lt;p&gt;What finally broke it had nothing to do with motivation. Motivation is a feeling, and feelings do not arrive on schedule.&lt;/p&gt;

&lt;p&gt;The rule that worked was almost too small to be scary. Ship one honest thing today, then do it again tomorrow before the fear catches up.&lt;/p&gt;

&lt;p&gt;So I started treating done as the goal and perfect as the enemy. One public post. One small repo. One real reply to a real person who was waiting.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3qvuukrt3hox2dhjx2fp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3qvuukrt3hox2dhjx2fp.png" alt="From knowing to shipping, the freeze logged" width="800" height="350"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;My early ones were not my best work. That was the whole point. Reps were the work. Polish was procrastination wearing a respectable outfit.&lt;/p&gt;

&lt;p&gt;If you are sitting on things you know you should ship, look closely at the real blocker.&lt;/p&gt;

&lt;p&gt;You probably do not have a knowledge problem. You have an exposure problem wearing a knowledge costume. One more course leaves it exactly where it is. One small shipped thing moves it.&lt;/p&gt;

&lt;p&gt;Honesty check, because this is not a victory lap. The freeze still shows up before I publish, including right before this post went out.&lt;/p&gt;

&lt;p&gt;What changed is simple. Now I ship anyway, small and often, and let the reps do what reassurance never could.&lt;/p&gt;

&lt;p&gt;In the last few weeks that meant public repos, posts here most days, and the messages I had avoided for months. None of them were perfect. Every one of them got shipped.&lt;/p&gt;

&lt;h2&gt;
  
  
  Your turn
&lt;/h2&gt;

&lt;p&gt;One question, and the easy version of it.&lt;/p&gt;

&lt;p&gt;What is the one thing you know you should ship but have not yet?&lt;/p&gt;

&lt;p&gt;Name the thing in the comments. Skip the reasons. The thing is enough.&lt;/p&gt;

&lt;h2&gt;
  
  
  If this was useful
&lt;/h2&gt;

&lt;p&gt;I work through this in public, the wins and the freezes both, mostly on LinkedIn and YouTube. If the real version of building in the open is useful to you, that is where it lives. Connect on &lt;a href="https://www.linkedin.com/in/mirzajhanzaib/" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt;, I am on YouTube and X as Mirza Iqbal, and the work is at &lt;a href="https://next8n.com" rel="noopener noreferrer"&gt;next8n.com&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>career</category>
      <category>productivity</category>
      <category>discuss</category>
      <category>beginners</category>
    </item>
    <item>
      <title>3 patterns broke when I ran Claude Code unattended for 7 days</title>
      <dc:creator>Mirza Iqbal</dc:creator>
      <pubDate>Wed, 10 Jun 2026 06:34:50 +0000</pubDate>
      <link>https://dev.to/mjmirza/3-patterns-broke-when-i-ran-claude-code-unattended-for-7-days-5apl</link>
      <guid>https://dev.to/mjmirza/3-patterns-broke-when-i-ran-claude-code-unattended-for-7-days-5apl</guid>
      <description>&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;API Error: 400 messages.N.content.M: `thinking` blocks in the latest
assistant message cannot be modified. These blocks must remain as they
were in the original response.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That error ended a session I was not watching.&lt;/p&gt;

&lt;p&gt;168 hours. 47 sessions. Claude Code running real grinds while I slept, traveled, and worked on other things.&lt;/p&gt;

&lt;p&gt;Three patterns broke over the week. None of them were the failure I expected going in.&lt;/p&gt;

&lt;p&gt;Here is the strongest thing I took away.&lt;/p&gt;

&lt;p&gt;Loud crashes were the failures I worried about. They were rarely the ones that hurt.&lt;/p&gt;

&lt;p&gt;What actually hurt looked like forward motion while it quietly destroyed work or stalled the queue.&lt;/p&gt;

&lt;p&gt;I run automation like this for a living, across DACH enterprise deployments, and the same three shapes keep showing up. Naming them is most of the fix.&lt;/p&gt;

&lt;h2&gt;
  
  
  Pattern one. The turn that poisons itself
&lt;/h2&gt;

&lt;p&gt;This was the unexpected one.&lt;/p&gt;

&lt;p&gt;With extended thinking on, every assistant turn carries a thinking block that must round-trip back to the model byte for byte on the next request.&lt;/p&gt;

&lt;p&gt;Interrupt that turn at the wrong moment, or let an automatic compaction rebuild the history, and the block comes back changed.&lt;/p&gt;

&lt;p&gt;Then the server rejects the whole request. Your turn dies. Your run stops.&lt;/p&gt;

&lt;p&gt;What surprised me is that nothing in my own tooling could catch it.&lt;/p&gt;

&lt;p&gt;That error returns at the transport layer, after the turn has already failed.&lt;/p&gt;

&lt;p&gt;My hooks fire around tools and sessions. They never fire around a failed API request.&lt;/p&gt;

&lt;p&gt;So the instinct to write a guard that catches it and retries is a dead end. There is no event to hang the guard on.&lt;/p&gt;

&lt;p&gt;Here is the real fix. You cannot script your way out of this one. It is a discipline.&lt;/p&gt;

&lt;p&gt;Do not resume a turn you interrupted mid-thought. Rebuild the history cleanly, or start fresh, before you continue.&lt;/p&gt;

&lt;p&gt;Sit with the cheaper lesson underneath. Some of the most expensive failures cannot be automated around. You can only avoid them.&lt;/p&gt;

&lt;h2&gt;
  
  
  Pattern two. The cliff at 83 percent
&lt;/h2&gt;

&lt;p&gt;This second pattern cost me the most actual work.&lt;/p&gt;

&lt;p&gt;My longest grind committed its progress rarely. One checkpoint every few hours of running.&lt;/p&gt;

&lt;p&gt;That feels fine while it runs. It is a trap.&lt;/p&gt;

&lt;p&gt;When the rate-limit cap exhausted partway through, the resume point sat hours behind the real progress.&lt;/p&gt;

&lt;p&gt;One grind of more than 800 items stalled at 83 percent. Roughly 17 percent of the work was momentum I had to win back by hand.&lt;/p&gt;

&lt;p&gt;Run the math and it is plain. Commit once every few hours, and any interruption at hour three erases hours.&lt;/p&gt;

&lt;p&gt;This fix is mechanical. How often you commit becomes a property of the loop, something the loop handles on its own so you never have to remember.&lt;/p&gt;

&lt;p&gt;Bind the resume cost to a small fixed number of items. A cap exhaustion or a crash then costs you that small number of items. Your afternoon stays safe.&lt;/p&gt;

&lt;p&gt;This is the pattern I now refuse to start a long loop without.&lt;/p&gt;

&lt;h2&gt;
  
  
  Pattern three. The ghost lock
&lt;/h2&gt;

&lt;p&gt;Quietest of the three, and the one that looked most like everything was fine.&lt;/p&gt;

&lt;p&gt;Each worker reserved its slot with a lock file. Standard practice for stopping two runs from colliding.&lt;/p&gt;

&lt;p&gt;One run got killed hard. The lock file stayed behind, with a dead process id inside it.&lt;/p&gt;

&lt;p&gt;My queue then did exactly what it was told. It saw a reservation and waited.&lt;/p&gt;

&lt;p&gt;Nothing was running. Nothing was progressing. The dashboard looked busy.&lt;/p&gt;

&lt;p&gt;It sat blocked for around 70 minutes before the stale lock aged out on a timer.&lt;/p&gt;

&lt;p&gt;Make the lock aware of the thing it protects, and the problem disappears.&lt;/p&gt;

&lt;p&gt;Any lock that names a process should release the moment that process is gone. Waiting for a clock to run down is the slow, expensive path.&lt;/p&gt;

&lt;p&gt;Reap on death. Keep the timeout only as a backstop.&lt;/p&gt;

&lt;h2&gt;
  
  
  One thread connects all three
&lt;/h2&gt;

&lt;p&gt;Look at the three together and the shared shape is obvious.&lt;/p&gt;

&lt;p&gt;A loud failure is a gift. You see it, you fix it, you move on.&lt;/p&gt;

&lt;p&gt;Dangerous failures in an unattended run wear the costume of progress.&lt;/p&gt;

&lt;p&gt;A poisoned turn that stops a session you were not watching.&lt;/p&gt;

&lt;p&gt;A grind that commits so rarely it gives back hours on the first interruption.&lt;/p&gt;

&lt;p&gt;A queue that waits politely on a worker that already died.&lt;/p&gt;

&lt;p&gt;Every one of them looked, from the outside, like a healthy system.&lt;/p&gt;

&lt;p&gt;Here is the real lesson of running a thing for a week with nobody watching.&lt;/p&gt;

&lt;p&gt;Your monitoring is tuned for the errors that shout. The ones that cost you are the errors that smile.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I am not pasting here
&lt;/h2&gt;

&lt;p&gt;I run a version of each fix in production. The exact instrumentation, the commit-interval numbers, and the runbook that maps each failure shape to a first response are the work I bring to client engagements.&lt;/p&gt;

&lt;p&gt;Leaving them out is on purpose.&lt;/p&gt;

&lt;p&gt;Paste the implementation, and the next person to hit this copies it and never has the conversation that surfaces the deeper problem underneath.&lt;/p&gt;

&lt;p&gt;That conversation is where the real damage gets caught.&lt;/p&gt;

&lt;p&gt;Pattern is the gift. Recipe is the work.&lt;/p&gt;

&lt;h2&gt;
  
  
  Your turn
&lt;/h2&gt;

&lt;p&gt;You have left an agent or a long job running unsupervised at some point.&lt;/p&gt;

&lt;p&gt;Something broke while you were not looking.&lt;/p&gt;

&lt;p&gt;Which of these three did you hit, and what would you name the one I missed?&lt;/p&gt;

&lt;p&gt;Drop the shape you saw in the comments.&lt;/p&gt;

&lt;p&gt;Our shared library of failure modes only gets sharper when more of us name the thing out loud.&lt;/p&gt;

</description>
      <category>claudecode</category>
      <category>ai</category>
      <category>productivity</category>
      <category>automation</category>
    </item>
    <item>
      <title>Your MCP server's write tools are silently dropping their body</title>
      <dc:creator>Mirza Iqbal</dc:creator>
      <pubDate>Mon, 08 Jun 2026 14:09:19 +0000</pubDate>
      <link>https://dev.to/mjmirza/your-mcp-servers-write-tools-are-silently-dropping-their-body-475j</link>
      <guid>https://dev.to/mjmirza/your-mcp-servers-write-tools-are-silently-dropping-their-body-475j</guid>
      <description>&lt;p&gt;If you have built a Model Context Protocol server with a passthrough tool, the kind that&lt;br&gt;
lets the model call any endpoint, there is a real chance its write operations are quietly&lt;br&gt;
broken in some clients. You may not have noticed, because reads work.&lt;/p&gt;

&lt;p&gt;I hit this building an open source MCP server for Hetzner. Listing worked perfectly. Every&lt;br&gt;
create, update, and delete came back from the API with the same complaint.&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="err"&gt;A&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;valid&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;JSON&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;document&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;is&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;required.&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The body was arriving empty. Here is why, and the single line that fixed it.&lt;/p&gt;

&lt;p&gt;First, here it is working. This server stands up a load-balanced stack and tears it back&lt;br&gt;
down in plain language, with a cost guard in front of every billed action.&lt;/p&gt;

&lt;p&gt;  &lt;iframe src="https://www.youtube.com/embed/OhaUP-Fhq_0"&gt;
  &lt;/iframe&gt;
&lt;/p&gt;

&lt;h2&gt;
  
  
  The symptom
&lt;/h2&gt;

&lt;p&gt;A passthrough tool needs a free-form body so the model can send any payload. The obvious&lt;br&gt;
way to type that in Zod looks harmless.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;unknown&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;optional&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Reads need no body, so every GET sailed through. The moment the model tried a POST, the&lt;br&gt;
body never reached the API.&lt;/p&gt;
&lt;h2&gt;
  
  
  The root cause
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;z.unknown()&lt;/code&gt; compiles to an empty JSON schema. Not an object, not a string, an empty shape.&lt;/p&gt;

&lt;p&gt;Several MCP clients drop a property whose schema is empty. There is nothing to validate and&lt;br&gt;
nothing to send, so the field is stripped before the request leaves the client. Your server&lt;br&gt;
receives the call with the body undefined, forwards an empty payload, and the API rejects it.&lt;/p&gt;

&lt;p&gt;The cruel part is that the error comes from the upstream service, not from your server, so&lt;br&gt;
you go hunting in the wrong place for an hour.&lt;/p&gt;
&lt;h2&gt;
  
  
  The fix
&lt;/h2&gt;

&lt;p&gt;Give the body a real schema. An object is enough, and accepting a JSON string as well makes&lt;br&gt;
it work no matter how a client serializes the payload.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;union&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;record&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;string&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;unknown&lt;/span&gt;&lt;span class="p"&gt;()),&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;string&lt;/span&gt;&lt;span class="p"&gt;()]).&lt;/span&gt;&lt;span class="nf"&gt;optional&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then parse a string body into an object before you use it. The schema is now non-empty, so&lt;br&gt;
clients forward the field, and the string branch covers the clients that send serialized&lt;br&gt;
JSON. That is the whole fix.&lt;/p&gt;
&lt;h2&gt;
  
  
  How I knew the fix actually held
&lt;/h2&gt;

&lt;p&gt;A schema change you cannot see is a schema change you cannot trust. So I wrote a suite that&lt;br&gt;
drives the compiled server over stdio, the exact artifact a client loads, against the live&lt;br&gt;
API. Reads, the cost and delete guards, and a create then delete for every resource type.&lt;br&gt;
Every billed resource is removed in a finally block, so a failure never leaks a charge.&lt;/p&gt;

&lt;p&gt;It caught the bug, proved the fix, and runs on every change now. The number that matters is&lt;br&gt;
not that it compiles, it is that every tool answered the real API and the account was left&lt;br&gt;
clean.&lt;/p&gt;
&lt;h2&gt;
  
  
  If you build MCP servers
&lt;/h2&gt;

&lt;p&gt;Two things to carry away.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Audit any tool that types an input as unknown or leaves it untyped. Give it a real schema.&lt;/li&gt;
&lt;li&gt;Test write tools through the built server against the real service, not only your unit
tests. This failure only appeared at the client boundary.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The server I found this in is open source under MIT. It gives an AI assistant the full&lt;br&gt;
Hetzner platform, Cloud, Storage Box, and Robot dedicated servers.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx &lt;span class="nt"&gt;-y&lt;/span&gt; hetzner-mcp
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;What is the most painful silent failure you have hit building MCP tools?&lt;/p&gt;

</description>
      <category>mcp</category>
      <category>typescript</category>
      <category>ai</category>
      <category>opensource</category>
    </item>
    <item>
      <title>Your private GitHub repo CI is one quota away from going red</title>
      <dc:creator>Mirza Iqbal</dc:creator>
      <pubDate>Mon, 08 Jun 2026 10:40:03 +0000</pubDate>
      <link>https://dev.to/mjmirza/your-private-github-repo-ci-is-one-quota-away-from-going-red-3673</link>
      <guid>https://dev.to/mjmirza/your-private-github-repo-ci-is-one-quota-away-from-going-red-3673</guid>
      <description>&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;status      conclusion   elapsed
completed   failure      2s
completed   failure      1s
completed   failure      3s
completed   failure      2s
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Four CI runs.&lt;/p&gt;

&lt;p&gt;Every one red.&lt;/p&gt;

&lt;p&gt;Every one dead in under three seconds.&lt;/p&gt;

&lt;p&gt;No build. No tests. No lint.&lt;/p&gt;

&lt;p&gt;I spent twenty minutes reading my own diff for the bug.&lt;/p&gt;

&lt;p&gt;There was no bug.&lt;/p&gt;

&lt;p&gt;The repo was private, and it had run out of free Actions minutes.&lt;/p&gt;

&lt;p&gt;I had green checks for two days.&lt;/p&gt;

&lt;p&gt;Then red checks for the better part of a week.&lt;/p&gt;

&lt;p&gt;The last green run was the 23rd. By the 25th every check was failing. It stayed red until the monthly minutes reset on the 1st.&lt;/p&gt;

&lt;p&gt;Nothing in the code changed across that line.&lt;/p&gt;

&lt;h2&gt;
  
  
  A quota death wears a code failure's face
&lt;/h2&gt;

&lt;p&gt;This is the part that wastes your afternoon.&lt;/p&gt;

&lt;p&gt;A real failure and a quota failure paint the same red X on your pull request.&lt;/p&gt;

&lt;p&gt;Same icon. Same color. Same sinking feeling.&lt;/p&gt;

&lt;p&gt;So you do the rational thing.&lt;/p&gt;

&lt;p&gt;You open the diff. You re-read the test. You blame the last commit.&lt;/p&gt;

&lt;p&gt;You push a fix that fixes nothing, watch it go red in two seconds, and push another.&lt;/p&gt;

&lt;p&gt;The faster the run dies, the more it feels like your code, because a fast failure reads like a fast, obvious mistake.&lt;/p&gt;

&lt;p&gt;It is the opposite.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F876g8cr9dyubnihm9bwo.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F876g8cr9dyubnihm9bwo.png" alt="Real red has a log. Quota red has none." width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The tell is in the clock, not the logs
&lt;/h2&gt;

&lt;p&gt;Open the run.&lt;/p&gt;

&lt;p&gt;A real failure has a body. Steps that started. A step that executed and then failed. A log you can read.&lt;/p&gt;

&lt;p&gt;A quota failure has no body at all.&lt;/p&gt;

&lt;p&gt;The run is marked failed, the steps list is empty, and the whole thing is over in one to three seconds.&lt;/p&gt;

&lt;p&gt;That is the signature.&lt;/p&gt;

&lt;p&gt;Failed conclusion, zero steps executed, near-instant finish.&lt;/p&gt;

&lt;p&gt;When you see that shape three runs in a row, stop reading your code.&lt;/p&gt;

&lt;p&gt;The dispatcher rejected the job before a runner ever picked it up.&lt;/p&gt;

&lt;p&gt;You are not looking at a broken build. You are looking at a closed gate.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why private repos are the ones that bite
&lt;/h2&gt;

&lt;p&gt;Public repositories get unlimited Actions minutes.&lt;/p&gt;

&lt;p&gt;Private ones get a free monthly allowance, and the meter is invisible until it hits zero.&lt;/p&gt;

&lt;p&gt;There is no warning step. No yellow. No banner telling you that five percent is left while you still have a window to act.&lt;/p&gt;

&lt;p&gt;The minutes drain quietly across every push, every scheduled job, every auto-sync hook you wired up to feel productive.&lt;/p&gt;

&lt;p&gt;The more automation you bolt onto a private repo, the faster you walk into the wall.&lt;/p&gt;

&lt;p&gt;And the wall does not announce itself. It starts answering every push with a two-second red.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5k283ksrrzz8avcuv1f0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5k283ksrrzz8avcuv1f0.png" alt="Free private minutes drain silently, then the gate closes." width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The one question that ends the loop
&lt;/h2&gt;

&lt;p&gt;Before you touch the diff, ask one thing.&lt;/p&gt;

&lt;p&gt;Did the run actually run.&lt;/p&gt;

&lt;p&gt;Open the latest red run and look at whether any step executed.&lt;/p&gt;

&lt;p&gt;If steps ran and one failed, it is your code. Read the log.&lt;/p&gt;

&lt;p&gt;If no steps ran and it died in seconds, it is the gate. Close the editor.&lt;/p&gt;

&lt;p&gt;That single check turns a half-day of phantom debugging into a ten-second diagnosis.&lt;/p&gt;

&lt;p&gt;I now run it before I read a single line of my own changes, because my reflex to blame my code is wrong often enough to be dangerous.&lt;/p&gt;

&lt;h2&gt;
  
  
  What you actually do about it
&lt;/h2&gt;

&lt;p&gt;You have three honest moves, and none of them is push again.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Flip the repo public if the code can be public. Unlimited minutes, problem gone.&lt;/li&gt;
&lt;li&gt;Wait for the monthly reset if the work can wait. The meter refills on its own.&lt;/li&gt;
&lt;li&gt;Pay for more minutes if it is real production and neither of those fits.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;What you do not do is keep firing commits at a closed gate.&lt;/p&gt;

&lt;p&gt;Every fix you push while out of minutes is another two-second red that teaches you nothing and convinces you a little harder that your code is haunted.&lt;/p&gt;

&lt;h2&gt;
  
  
  The green log lies more than the red one
&lt;/h2&gt;

&lt;p&gt;Here is the uncomfortable part.&lt;/p&gt;

&lt;p&gt;For two days my checks were green, and I trusted them.&lt;/p&gt;

&lt;p&gt;But the green was running on borrowed minutes that were about to run out.&lt;/p&gt;

&lt;p&gt;A passing check told me my pipeline was healthy.&lt;/p&gt;

&lt;p&gt;What it actually told me was that the meter still had room.&lt;/p&gt;

&lt;p&gt;The status icon measures whether the job was allowed to run, not whether your project is sound.&lt;/p&gt;

&lt;p&gt;Most of us read a green check as proof of correctness.&lt;/p&gt;

&lt;p&gt;It is closer to proof of permission.&lt;/p&gt;

&lt;p&gt;The day those two diverge is the day you lose an afternoon to a failure that was never in your code.&lt;/p&gt;

&lt;h2&gt;
  
  
  Your turn
&lt;/h2&gt;

&lt;p&gt;Go look at your last failed CI run on a private repo.&lt;/p&gt;

&lt;p&gt;Did the steps execute, or did it die in two seconds with an empty body.&lt;/p&gt;

&lt;p&gt;If you have ever pushed a fix at a run that was never going to run, tell me how long it took you to notice.&lt;/p&gt;

&lt;p&gt;For me it was twenty minutes and three commits, and I build CI guardrails for a living.&lt;/p&gt;

</description>
      <category>github</category>
      <category>cicd</category>
      <category>devops</category>
      <category>claudecode</category>
    </item>
  </channel>
</rss>
