<?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: Serhii Antonuik</title>
    <description>The latest articles on DEV Community by Serhii Antonuik (@uagents8).</description>
    <link>https://dev.to/uagents8</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%2F4235170%2F3aea2576-a4b2-43d5-8895-e120ed73c925.jpg</url>
      <title>DEV Community: Serhii Antonuik</title>
      <link>https://dev.to/uagents8</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/uagents8"/>
    <language>en</language>
    <item>
      <title>How we built an AI that fixes failed builds (and why we verify the patch before building)</title>
      <dc:creator>Serhii Antonuik</dc:creator>
      <pubDate>Mon, 09 Nov 2026 14:09:11 +0000</pubDate>
      <link>https://dev.to/uagents8/how-we-built-an-ai-that-fixes-failed-builds-and-why-we-verify-the-patch-before-building-47ap</link>
      <guid>https://dev.to/uagents8/how-we-built-an-ai-that-fixes-failed-builds-and-why-we-verify-the-patch-before-building-47ap</guid>
      <description>&lt;p&gt;It's Tuesday, 11 p.m. The demo is at nine. You push one last change to your&lt;br&gt;
agent, and the deploy fails: a dependency you installed locally and never&lt;br&gt;
wrote down, a variable you renamed in one file and not the other, a port your&lt;br&gt;
framework picked by itself. The error is somewhere in three hundred lines of&lt;br&gt;
build log.&lt;/p&gt;

&lt;p&gt;We run a hosting platform for AI agents, and that moment is the one we wanted&lt;br&gt;
to remove. Not with a chatbot that explains the log, but with a button: &lt;strong&gt;Fix&lt;br&gt;
with AI&lt;/strong&gt;. One click, and a fixed copy of your agent is live a few minutes&lt;br&gt;
later, or you are told clearly why not.&lt;/p&gt;

&lt;p&gt;The hard part turned out not to be "ask a model for a patch". It was&lt;br&gt;
everything around the model. This is how it works, and what each part taught us.&lt;/p&gt;

&lt;h3&gt;
  
  
  Triage first: is this even a code problem?
&lt;/h3&gt;

&lt;p&gt;Our first version sent every failure straight to code generation. It went&lt;br&gt;
wrong in a very specific way: an agent missing a required environment variable&lt;br&gt;
was "fixed" again and again. The model can't set a variable, so it wrote code&lt;br&gt;
around the missing value, the deploy failed the same way, and the user clicked&lt;br&gt;
again.&lt;/p&gt;

&lt;p&gt;Now every attempt starts with a diagnosis that sorts the failure. Three&lt;br&gt;
outcomes are possible before any code is touched:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;A value only the owner can know.&lt;/strong&gt; A missing API key, connection string or
host. The fix stops and says which variable to set. We learned this one in a
stress test: a model "fixed" a missing database URL by writing its own
placeholder in as the real value, and the agent started, connected to
nothing, and reported success. Now a credential-looking name or a
placeholder-looking value is never filled in by AI.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A configuration change the evidence supports.&lt;/strong&gt; If the platform's own
health-check events show "connection refused" on the expected port, the
port is aligned in configuration and the agent is redeployed. If the agent
was stopped by a genuine out-of-memory kill, it is moved up one size
(within the plan; at the largest size it stops and says so). The diagnosis
alone is not enough; the evidence has to agree - and "exit code 137" alone
is not evidence of a memory kill, because a process stopped for failing
its health check exits the same way. We learned that one live too: an
agent bound to the wrong interface was given more memory twice before the
one-line code fix ran.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A real code problem.&lt;/strong&gt; Everything else goes on to the patching pipeline.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A failure caused by us, such as a temporary capacity limit while building, is&lt;br&gt;
never sent to a model at all. No patch can fix our capacity, and trying would&lt;br&gt;
spend the user's allowance on nothing.&lt;/p&gt;

&lt;h3&gt;
  
  
  Choosing a model per failure class
&lt;/h3&gt;

&lt;p&gt;Not every failure deserves the same model. A missing import is mechanical; a&lt;br&gt;
race condition across three files is not. So before generating anything, a&lt;br&gt;
fast, cheap model labels the failure &lt;strong&gt;LOW&lt;/strong&gt;, &lt;strong&gt;MEDIUM&lt;/strong&gt; or &lt;strong&gt;HIGH&lt;/strong&gt;, with a&lt;br&gt;
one-sentence reason. If that call fails, deterministic rules decide instead:&lt;br&gt;
known patterns like &lt;code&gt;ModuleNotFoundError&lt;/code&gt; or &lt;code&gt;SyntaxError&lt;/code&gt; mean LOW,&lt;br&gt;
deadlocks, segmentation faults and out-of-memory signals mean HIGH, and a&lt;br&gt;
generic "never became ready" with no application error also goes to HIGH,&lt;br&gt;
because there is nothing safe to guess from.&lt;/p&gt;

&lt;p&gt;Each label has its own ordered chain of models. LOW and MEDIUM failures start&lt;br&gt;
with a fast model that has a very large context window; HIGH ones, and every&lt;br&gt;
second attempt, start with the strongest coding models we use. If one provider in the&lt;br&gt;
chain errors, times out or is rate-limited, the next one answers.&lt;/p&gt;

&lt;p&gt;Two lessons from running this in production:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Routing everything to the strongest model made the fix the most
expensive thing we sell.&lt;/strong&gt; Starting easy cases on a cheaper model, and
saving the expensive ones for hard failures and retries, kept quality where
it matters and costs bounded by each plan's monthly AI budget.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A fallback you never exercise is not a fallback.&lt;/strong&gt; We found two models
in our chains failing almost every call for weeks: for one, our account's
rate limit was smaller than a single fix prompt; for the other, the context
window was. Both were fixed, and every chain was re-tested with a real-size
prompt.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  What the model sees
&lt;/h3&gt;

&lt;p&gt;The model gets the error output (the tail, where the failure is), your&lt;br&gt;
Dockerfile if there is one, and up to 60 source files. The files the error&lt;br&gt;
names come first and whole, even when they are larger than the usual&lt;br&gt;
per-file limit, because a fix for a syntax error needs the file's header too.&lt;br&gt;
It also gets the &lt;strong&gt;names&lt;/strong&gt;, never the values, of the environment variables&lt;br&gt;
you have set, so it doesn't invent a "missing variable" that exists.&lt;/p&gt;

&lt;p&gt;Before anything leaves the platform, files that exist to hold credentials&lt;br&gt;
(&lt;code&gt;.env&lt;/code&gt;, private keys) are left out, and values that look like secrets are&lt;br&gt;
replaced with placeholders. The real values go back into the patched files&lt;br&gt;
afterwards. This is pattern-based and can't catch every secret, which is why&lt;br&gt;
we tell users to keep secrets in variables, not in code.&lt;/p&gt;

&lt;h3&gt;
  
  
  Two gates before any build: parse, then a security review
&lt;/h3&gt;

&lt;p&gt;A build takes real time and real money. An early patch for a Go service&lt;br&gt;
dropped the file's &lt;code&gt;package&lt;/code&gt; line; it went to a full build only for the&lt;br&gt;
compiler to reject it in the first second. Now every patch must &lt;strong&gt;parse&lt;/strong&gt;&lt;br&gt;
before anything is built: real parsers for Python, Go, Java, JavaScript,&lt;br&gt;
TypeScript, Rust and JSON, plus Go-specific checks for the mistakes models&lt;br&gt;
actually make (a dropped or renamed package clause, &lt;code&gt;=&lt;/code&gt; instead of &lt;code&gt;==&lt;/code&gt; in a&lt;br&gt;
condition). A patch that fails goes back to the model with the parser's&lt;br&gt;
message. For a typical file this takes well under a millisecond.&lt;/p&gt;

&lt;p&gt;We also check the whole snapshot, not only the patched files. In a stress test&lt;br&gt;
a repository with several broken files cost one redeploy per broken file,&lt;br&gt;
because each fix only looked at the file the latest error named. Now every&lt;br&gt;
file that doesn't parse is listed in the prompt and ranked first.&lt;/p&gt;

&lt;p&gt;Then the patch goes through an &lt;strong&gt;automated security review&lt;/strong&gt;, the same one&lt;br&gt;
every deploy from source goes through. If it finds a critical problem, nothing&lt;br&gt;
is built. If the review itself can't complete, nothing is built either: there&lt;br&gt;
is no human between the click and the deploy to weigh a skipped check, so the&lt;br&gt;
pipeline fails closed.&lt;/p&gt;

&lt;h3&gt;
  
  
  Deploy a copy, then ask the health check
&lt;/h3&gt;

&lt;p&gt;The patched code is never pushed to your repository. No commits, branches or&lt;br&gt;
pull requests. It is written to a snapshot, built by the normal build&lt;br&gt;
pipeline and deployed as a &lt;strong&gt;new version&lt;/strong&gt; of the agent, marked as AI-fixed,&lt;br&gt;
next to the versions you already have. If you don't like it, you restore the&lt;br&gt;
previous version in one click, and your next push builds from your own code&lt;br&gt;
again.&lt;/p&gt;

&lt;p&gt;The new version goes through the same health check as any deploy: the agent&lt;br&gt;
must start, listen on its port and answer. In our own tests, fixed copies went&lt;br&gt;
live in 2 to 4.5 minutes, depending on the error and the size of the code.&lt;/p&gt;

&lt;p&gt;If the health check fails, one more attempt runs automatically, and it is told&lt;br&gt;
what the first attempt changed and what happened. That second attempt is&lt;br&gt;
routed to the strongest models. After two attempts it stops and says so. A&lt;br&gt;
human clicking again later starts a new streak, but the history of what&lt;br&gt;
already failed is kept, so the same wrong fix isn't proposed with fresh&lt;br&gt;
confidence.&lt;/p&gt;

&lt;h3&gt;
  
  
  What counts
&lt;/h3&gt;

&lt;p&gt;A plan includes a number of AI Fixes a month. &lt;strong&gt;Only a code fix that ends with&lt;br&gt;
your agent passing its health check uses one.&lt;/strong&gt; A patch that failed to parse,&lt;br&gt;
failed the security review, failed to build or failed to come up costs no fix.&lt;br&gt;
Every model call does draw on the plan's monthly AI budget, which is how the&lt;br&gt;
cost stays bounded either way.&lt;/p&gt;

&lt;h3&gt;
  
  
  What failures taught us: memory
&lt;/h3&gt;

&lt;p&gt;Models are confident, and a model will propose the same failed fix twice.&lt;br&gt;
So the platform remembers outcomes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;When a fix is confirmed healthy, it is stored for your own account. The
same error on the same files can get that fix back without a model call.
Confirmed fixes are never reused across accounts.&lt;/li&gt;
&lt;li&gt;When a patch fails, its fingerprint is recorded. A patch that has already
failed twice for a similar error is rejected outright. When another
customer hits a similar error, the model is warned with the error
signature, the error output and the names of the files that failed patch
changed. &lt;strong&gt;Never the code itself.&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  What it doesn't do
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;It fixes failed builds and deploys, not an agent that crashes days after
it went live.&lt;/strong&gt; Today that gets a restart, a crash email and a plain-language
diagnosis. Repairing a live agent is on our public roadmap.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;It can't make an agent smaller than its workload.&lt;/strong&gt; If an agent is killed
for using more memory than its size allows, the repair is a larger size,
not a patch: AI Fix moves it up one size when the kill is genuine, and
stops and tells you when the next size is not in your plan.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;It needs source code.&lt;/strong&gt; An agent deployed from a ready-made image has no
code to patch; diagnosis still explains the failure.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;It isn't always right&lt;/strong&gt;, which is why it stops after two attempts and why
every result is a version you can roll back. We'll publish real success
rates once we have enough launch traffic to make them honest.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Try it
&lt;/h3&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fnm9ue1uf7gfloz52nmgn.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fnm9ue1uf7gfloz52nmgn.png" alt="How AI Fix decides and checks a fix: a flowchart from a failed build, through triage, the patch gates and the health check, to a live version" width="800" height="749"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Every plan includes AI Fix. If you have an agent that works on your laptop,&lt;br&gt;
deploy it, break it on purpose, and press the button:&lt;br&gt;
&lt;a href="https://uagents8.com/?utm_source=devto&amp;amp;utm_medium=referral&amp;amp;utm_campaign=launch-2026-11&amp;amp;utm_content=devto-ai-fix-article" rel="noopener noreferrer"&gt;uagents8.com&lt;/a&gt;.&lt;br&gt;
Launch code &lt;strong&gt;LAUNCH30&lt;/strong&gt; takes 30% off the first three months on Builder or&lt;br&gt;
Growth until 30 November.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>cicd</category>
      <category>debugging</category>
      <category>llm</category>
    </item>
  </channel>
</rss>
