<?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: Tech Geeks</title>
    <description>The latest articles on DEV Community by Tech Geeks (@tech_geeks_a72ac908b0102d).</description>
    <link>https://dev.to/tech_geeks_a72ac908b0102d</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%2F4230900%2Ffb313143-4c14-468b-a307-5fe16eab83f6.png</url>
      <title>DEV Community: Tech Geeks</title>
      <link>https://dev.to/tech_geeks_a72ac908b0102d</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/tech_geeks_a72ac908b0102d"/>
    <language>en</language>
    <item>
      <title>Why AI Writes Broken ESP32 Code (and How to Fix It for Arduino-ESP32 3.x)</title>
      <dc:creator>Tech Geeks</dc:creator>
      <pubDate>Fri, 06 Nov 2026 19:10:49 +0000</pubDate>
      <link>https://dev.to/tech_geeks_a72ac908b0102d/why-ai-writes-broken-esp32-code-and-how-to-fix-it-for-arduino-esp32-3x-2o0b</link>
      <guid>https://dev.to/tech_geeks_a72ac908b0102d/why-ai-writes-broken-esp32-code-and-how-to-fix-it-for-arduino-esp32-3x-2o0b</guid>
      <description>&lt;p&gt;You ask an AI assistant for a simple ESP32 sketch, it hands you clean, confident code, and the compiler replies with &lt;code&gt;'ledcSetup' was not declared in this scope&lt;/code&gt;. Or worse, it compiles, you flash it, and the board boot-loops.&lt;/p&gt;

&lt;p&gt;This isn't bad luck. It's the most predictable failure in AI-assisted firmware, and once you know its shape it's easy to prevent.&lt;/p&gt;

&lt;h2&gt;
  
  
  Firmware is not a forgiving sandbox
&lt;/h2&gt;

&lt;p&gt;A hallucinated function in a web app gives you a red squiggle. A hallucinated pin number on a microcontroller can drive current into the wrong pin and release the "magic smoke". Firmware talks to real hardware in real time: a blocking call trips a watchdog and reboots the board, and a wrong register writes garbage to real silicon. The AI can't see your wiring, feel heat or measure current. It only sees text.&lt;/p&gt;

&lt;p&gt;Two failure modes dominate:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Hallucination.&lt;/strong&gt; The model invents a function, register, pin or whole library. A USENIX Security 2025 study of 576,000 generated code samples found hallucinated packages in at least 5.2% of cases for commercial models and 21.7% for open-source ones.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Deprecated APIs.&lt;/strong&gt; The model writes real code that &lt;em&gt;used to&lt;/em&gt; work. An ICSE 2025 study measured deprecated API usage of 25% to 38% across eight Python libraries. On the ESP32 this shows up constantly.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A 2026 study that tested 27 LLMs on ESP32 hardware across eight embedded scenarios found that 19 to 23 models could produce compilable code for simple apps, but only 3 to 5 produced working solutions for complex ones. The most common failure was hallucinated libraries or incorrect API usage.&lt;/p&gt;

&lt;h2&gt;
  
  
  The version trap: Arduino-ESP32 2.x vs 3.x
&lt;/h2&gt;

&lt;p&gt;The ESP32 world had two big breaking changes recently: Arduino-ESP32 went from 2.x to 3.x, and ESP-IDF went from 4.x to 5.x. Models were trained on years of 2.x examples, so they confidently generate the old API.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;PWM (LEDC)&lt;/strong&gt; is the classic example. In core 2.x you set up a channel, attached a pin to it, and wrote to the channel:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Arduino-ESP32 2.x: does NOT compile on core 3.x&lt;/span&gt;
&lt;span class="n"&gt;ledcSetup&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;5000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;      &lt;span class="c1"&gt;// channel, frequency, resolution&lt;/span&gt;
&lt;span class="n"&gt;ledcAttachPin&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;        &lt;span class="c1"&gt;// pin, channel&lt;/span&gt;
&lt;span class="n"&gt;ledcWrite&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;128&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;          &lt;span class="c1"&gt;// channel, duty&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In 3.x, channels are assigned automatically and you work with the pin directly:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Arduino-ESP32 3.x&lt;/span&gt;
&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;ledPin&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="c1"&gt;// a safe output pin&lt;/span&gt;

&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;setup&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;ledcAttach&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ledPin&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;5000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;  &lt;span class="c1"&gt;// pin, 5 kHz, 8-bit resolution&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;loop&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;duty&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;duty&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="mi"&gt;255&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;duty&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;ledcWrite&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ledPin&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;duty&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;delay&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Hardware timers&lt;/strong&gt; changed too. The old four-argument style, &lt;code&gt;timerBegin(0, 80, true)&lt;/code&gt; with a timer number, prescaler and count direction, is gone. In 3.x, &lt;code&gt;timerBegin&lt;/code&gt; takes the timer frequency in hertz, and alarms are set with &lt;code&gt;timerAlarm&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;I2C in ESP-IDF 5.x&lt;/strong&gt; replaced the legacy driver (&lt;code&gt;i2c_config_t&lt;/code&gt;, &lt;code&gt;i2c_driver_install&lt;/code&gt;, &lt;code&gt;i2c_master_write_to_device&lt;/code&gt;) with a bus-and-device model (&lt;code&gt;i2c_new_master_bus&lt;/code&gt;, &lt;code&gt;i2c_master_bus_add_device&lt;/code&gt;, &lt;code&gt;i2c_master_transmit&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;The fix is to make the model confront the version before it writes anything:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;I'm on Arduino-ESP32 core 3.3.x (ESP-IDF 5.5). Before writing code,
list any APIs you plan to use that CHANGED between core 2.x and 3.x
(e.g., LEDC, timer, I2C). For each, show the OLD call and the NEW 3.x call.
Then write the sketch using ONLY the 3.x API.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  The pin rules your AI doesn't reliably know
&lt;/h2&gt;

&lt;p&gt;ESP32 pins are not interchangeable, and this is where AI most often bricks projects. For the classic ESP32-WROOM-32:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Pins&lt;/th&gt;
&lt;th&gt;Rule&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;GPIO 6–11&lt;/td&gt;
&lt;td&gt;Wired to the internal SPI flash. Using them crashes the chip. Never touch them.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;GPIO 34, 35, 36, 39&lt;/td&gt;
&lt;td&gt;Input only: no output drivers and no internal pull-ups. They can't drive an LED or relay.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;GPIO 0, 2, 12, 15&lt;/td&gt;
&lt;td&gt;Strapping pins, sampled at boot. The wrong level or an attached load can stop the board booting.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ADC2 pins (0, 2, 4, 12–15, 25–27)&lt;/td&gt;
&lt;td&gt;Unusable for &lt;code&gt;analogRead()&lt;/code&gt; while Wi-Fi is on. Use ADC1 (GPIO 32–39) in any networked project.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;I2C also needs pull-up resistors (4.7 kΩ is typical). That is a hardware fact no amount of code can fix.&lt;/p&gt;

&lt;p&gt;Put these rules in the prompt, and ask the model to justify every pin it picks:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Write an Arduino-ESP32 3.x sketch for an ESP32-WROOM-32 that:
- reads a potentiometer on an ADC1 pin (Wi-Fi is ON, so NOT ADC2),
- drives an LED with PWM using ledcAttach()/ledcWrite() (NOT ledcSetup),
- avoids GPIO 6–11 and never uses 34–39 for the LED.
State which pins you chose and why each is safe.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Make the rules permanent with an instruction file
&lt;/h2&gt;

&lt;p&gt;Rather than repeating yourself, put the rules in the project instruction file your agent reads: &lt;code&gt;CLAUDE.md&lt;/code&gt; for Claude Code, &lt;code&gt;AGENTS.md&lt;/code&gt; for Codex and many other tools, or &lt;code&gt;.cursor/rules&lt;/code&gt; for Cursor.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="gh"&gt;# Firmware project rules&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; Board: ESP32-S3-DevKitC-1. Framework: Arduino-ESP32 core 3.3.x (ESP-IDF 5.5).
&lt;span class="p"&gt;-&lt;/span&gt; Use ONLY the 3.x API. Never use ledcSetup/ledcAttachPin or the 4-arg timerBegin.
&lt;span class="p"&gt;-&lt;/span&gt; Never assign GPIO 6–11 (SPI flash).
&lt;span class="p"&gt;-&lt;/span&gt; Analog sensors must use ADC1 pins because Wi-Fi is enabled.
&lt;span class="p"&gt;-&lt;/span&gt; After any change, run &lt;span class="sb"&gt;`pio run`&lt;/span&gt;. Paste the full error output before editing.
&lt;span class="p"&gt;-&lt;/span&gt; Never use delay() inside a FreeRTOS task longer than 50 ms; use vTaskDelay.
&lt;span class="p"&gt;-&lt;/span&gt; Cite the doc page for any peripheral API you use.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Pin the board and framework in &lt;code&gt;platformio.ini&lt;/code&gt; too, so builds are reproducible and the agent can run &lt;code&gt;pio run&lt;/code&gt; itself. Then it can write, compile, read the errors and fix them in a loop.&lt;/p&gt;

&lt;h2&gt;
  
  
  A five-step verification ritual
&lt;/h2&gt;

&lt;p&gt;The model's confidence has nothing to do with its correctness, so check every time:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Compile.&lt;/strong&gt; If it doesn't build, feed back the full error verbatim.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Static analysis.&lt;/strong&gt; &lt;code&gt;cppcheck --enable=all --inconclusive src/&lt;/code&gt; catches null dereferences, buffer overflows and uninitialised reads that both the compiler and the AI miss.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cross-check the docs.&lt;/strong&gt; Verify every pin, register and function against the current reference. This is where deprecated APIs get caught.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Demand citations.&lt;/strong&gt; Ask the model to name the documentation page for each peripheral call. Unsourced claims are where hallucinations hide.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Simulate before you flash.&lt;/strong&gt; Wokwi simulates the ESP32 family in the browser or VS Code, so the AI can test logic without risking your board.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;AI is a strong assistant and a weak authority. Used with a tight loop and these guardrails, it will write a lot of your firmware, and your board will survive the experience.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Originally published on &lt;a href="https://www.techbrosebooks.co.in/blog/esp32-ai-code-arduino-core-3" rel="noopener noreferrer"&gt;TechBrosEbooks&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;This article is adapted from the ebook &lt;strong&gt;&lt;a href="https://www.techbrosebooks.co.in/books/vibe-coding-your-esp32-ai-assisted-firmware-without-the-magic-smoke?utm_source=devto&amp;amp;utm_medium=referral&amp;amp;utm_campaign=esp32-ai-code-arduino-core-3" rel="noopener noreferrer"&gt;Vibe-Coding Your ESP32&lt;/a&gt;&lt;/strong&gt;, which also covers ESPHome, hardware-in-the-loop debugging, memory, timing and power, safety rails for mains and motors, a complete 3D-printer enclosure monitor build, and a 12-point pre-flash checklist.&lt;/p&gt;

</description>
      <category>esp32</category>
      <category>arduino</category>
      <category>iot</category>
      <category>ai</category>
    </item>
    <item>
      <title>How to Test an AI Agent: Start With Error Analysis, Not Metrics</title>
      <dc:creator>Tech Geeks</dc:creator>
      <pubDate>Fri, 06 Nov 2026 19:08:19 +0000</pubDate>
      <link>https://dev.to/tech_geeks_a72ac908b0102d/how-to-test-an-ai-agent-start-with-error-analysis-not-metrics-1bce</link>
      <guid>https://dev.to/tech_geeks_a72ac908b0102d/how-to-test-an-ai-agent-start-with-error-analysis-not-metrics-1bce</guid>
      <description>&lt;p&gt;Your agent passed the demo. Does it still work on the 500th request?&lt;/p&gt;

&lt;p&gt;Agents fail differently from normal software. A normal bug throws an exception. An agent bug returns a confident, well-formatted, wrong answer with HTTP 200: the right tool with the wrong ID, an extra loop, a step quietly skipped. Nothing alerts you, and the only witness is an unhappy user.&lt;/p&gt;

&lt;p&gt;The good news is that you already know the fix. It's the testing discipline you practise every day, adapted to a component that is non-deterministic and takes many steps. Traces replace stack traces, eval datasets replace test fixtures, and graders replace assertions.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why agents are hard to test
&lt;/h2&gt;

&lt;p&gt;Four properties make agents different:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Non-determinism.&lt;/strong&gt; The same task can produce different tool sequences on different runs. One green run proves the agent &lt;em&gt;can&lt;/em&gt; succeed, not that it reliably &lt;em&gt;will&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Multi-step trajectories.&lt;/strong&gt; The answer can be right for the wrong reasons. You have to test the path, not only the destination.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Compounding errors.&lt;/strong&gt; An agent that is 95% reliable per step succeeds only about 60% of the time over ten steps (0.95 to the power of 10).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Silent failure.&lt;/strong&gt; Fluent text with a 200 status. Monitoring has to inspect content, not just status codes and latency.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Step 1: measure flakiness before anything else
&lt;/h2&gt;

&lt;p&gt;The cheapest first test needs no graders at all. Run each task several times and see how consistent the agent really is:&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;collections&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Counter&lt;/span&gt;

&lt;span class="n"&gt;TASKS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Refund order A123&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Change my email to a@b.com&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Where is my parcel?&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="n"&gt;N&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;

&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;task&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;TASKS&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;outcomes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;trace&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;run_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="c1"&gt;# your agent, instrumented
&lt;/span&gt;        &lt;span class="n"&gt;tools&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;tuple&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;trace&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;tool_calls&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;outcomes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;trace&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;success&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;tools&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="n"&gt;passes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ok&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;ok&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;outcomes&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;paths&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Counter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;outcomes&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;task&lt;/span&gt;&lt;span class="si"&gt;!r}&lt;/span&gt;&lt;span class="s"&gt;: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;passes&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;/&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; passed, &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;paths&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; distinct tool paths&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If one task shows 3/5 passes and four different tool paths, you have found your first reliability problem.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 2: read your traces before you write a single metric
&lt;/h2&gt;

&lt;p&gt;This is the step most teams skip, and the one that matters most. Teams that ship reliable agents start by &lt;strong&gt;reading 50 to 100 real traces&lt;/strong&gt; and writing down what went wrong. The process is borrowed from qualitative research:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Collect traces.&lt;/strong&gt; Pull 50 to 100 real runs from production or staging.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Open coding.&lt;/strong&gt; For each trace, write a free-form note on the &lt;em&gt;first&lt;/em&gt; failure you see. Later failures are often side effects of the first.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Axial coding.&lt;/strong&gt; Group your notes into a taxonomy of 5 to 8 specific failure modes.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Count.&lt;/strong&gt; Tally each mode. The top two or three are where you write evals.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;A spreadsheet is enough. A typical result for a support agent might be: wrong customer looked up (14), refund issued without a policy check (9), answered from memory instead of the knowledge base (7). Those three lines are your eval roadmap.&lt;/p&gt;

&lt;p&gt;Stop when new traces stop revealing new failure modes, which usually happens within about 100. An LLM can help cluster your notes, but it never replaces the reading.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 3: trace everything
&lt;/h2&gt;

&lt;p&gt;You can't do error analysis without traces. A trace is the agent's flight recorder: every model call, tool call and retrieval, with tokens, cost and timing. It's a tree of spans, with one &lt;code&gt;invoke_agent&lt;/code&gt; root and &lt;code&gt;chat&lt;/code&gt; and &lt;code&gt;execute_tool&lt;/code&gt; children.&lt;/p&gt;

&lt;p&gt;Instrument against the OpenTelemetry GenAI conventions for portability, but pin versions, because they are still marked as in development. Tag every run with a prompt version and an agent version, so a regression can be tied to the change that caused it. Langfuse and Arize Phoenix are open source; LangSmith and Braintrust are managed; Datadog, Honeycomb and Grafana let you keep agent traces next to the rest of your telemetry. The tool matters less than the habit of reading traces every week.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 4: build a small eval dataset from real failures
&lt;/h2&gt;

&lt;p&gt;Start with &lt;strong&gt;20 to 50 tasks drawn from the failures you found&lt;/strong&gt;, and grow the set every week. Every task needs a success criterion two engineers would agree on. Include negative cases too, such as a refund request that should be refused, or you will optimise the agent into acting when it shouldn't.&lt;/p&gt;

&lt;p&gt;If you generate synthetic inputs, generate them along explicit dimensions (intent × persona × difficulty) rather than asking for "50 questions". Let an LLM draft the inputs, but write the expected outcomes yourself.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 5: grade with code wherever you can
&lt;/h2&gt;

&lt;p&gt;Use code for anything checkable: final state, which tools were called, their arguments, output format, step and cost budgets, safety rules. &lt;strong&gt;Final-state checks are the strongest graders&lt;/strong&gt; for agents that take actions. Did the refunds table end up with exactly the right rows?&lt;/p&gt;

&lt;p&gt;Two rules keep code graders from becoming brittle. Assert what must and must not happen, but never hard-code one exact tool sequence. And give every trial a fresh, isolated environment, or your scores measure test pollution instead of the agent.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 6: use LLM judges narrowly, and calibrate them
&lt;/h2&gt;

&lt;p&gt;For things code can't check, like "did every policy claim come from the knowledge base?", an LLM judge can scale human judgement to thousands of traces. But judges have known biases: position, verbosity and self-preference. Design around them:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;one narrow judge per failure mode, with a binary pass or fail&lt;/li&gt;
&lt;li&gt;reasoning before the verdict&lt;/li&gt;
&lt;li&gt;"length is not a virtue" stated in the rubric&lt;/li&gt;
&lt;li&gt;a judge from a different provider than the agent&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Then calibrate the judge like a classifier against traces a human has labelled. Measure its true-positive and true-negative rates, not raw agreement. A judge with a 60% true-negative rate misses four in ten real failures.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 7: track the right numbers
&lt;/h2&gt;

&lt;p&gt;Report four numbers per suite: pass@1, pass^k, cost per task and latency per task. &lt;strong&gt;pass@k&lt;/strong&gt; means at least one of k attempts succeeded; &lt;strong&gt;pass^k&lt;/strong&gt; means all k did. A customer-facing agent needs pass^k, because a customer gets one attempt. Run each task 3 to 5 times, and watch median and p95 cost and latency: long tails usually reveal loops.&lt;/p&gt;

&lt;h2&gt;
  
  
  The north star
&lt;/h2&gt;

&lt;p&gt;Look at your data before you build anything. The rest — datasets, graders, judges and CI gates — only works if it targets the failures your agent actually has.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Originally published on &lt;a href="https://www.techbrosebooks.co.in/blog/how-to-test-an-ai-agent" rel="noopener noreferrer"&gt;TechBrosEbooks&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;This article is adapted from the ebook &lt;strong&gt;&lt;a href="https://www.techbrosebooks.co.in/books/is-your-ai-agent-actually-working-evals-observability-debugging-for-production-agents?utm_source=devto&amp;amp;utm_medium=referral&amp;amp;utm_campaign=how-to-test-an-ai-agent" rel="noopener noreferrer"&gt;Is Your AI Agent Actually Working?&lt;/a&gt;&lt;/strong&gt;, which goes further with OpenTelemetry instrumentation code, a reusable grader library, judge calibration, evals in CI/CD and production, and an end-to-end example of fixing a real support-triage agent.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>testing</category>
      <category>llm</category>
      <category>agents</category>
    </item>
    <item>
      <title>Why Your AI Coding Agent Bill Grows With Every Turn (and 7 Ways to Cut It)</title>
      <dc:creator>Tech Geeks</dc:creator>
      <pubDate>Fri, 06 Nov 2026 19:06:25 +0000</pubDate>
      <link>https://dev.to/tech_geeks_a72ac908b0102d/why-your-ai-coding-agent-bill-grows-with-every-turn-and-7-ways-to-cut-it-3ko5</link>
      <guid>https://dev.to/tech_geeks_a72ac908b0102d/why-your-ai-coding-agent-bill-grows-with-every-turn-and-7-ways-to-cut-it-3ko5</guid>
      <description>&lt;p&gt;If you use Claude Code, Cursor or Codex every day, you have probably had one of two surprises: an API bill much larger than you expected, or a "you've hit your usage limit" message halfway through the afternoon. Both have the same cause, and once you see it, most of the fixes become obvious.&lt;/p&gt;

&lt;h2&gt;
  
  
  An agent resends everything, every time
&lt;/h2&gt;

&lt;p&gt;A chatbot answers one message. A coding agent works in a loop: it thinks, reads a file, runs a command, reads the output, and thinks again. Every step is a separate request to the model, and every request carries the whole context:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Part of the request&lt;/th&gt;
&lt;th&gt;Typical size&lt;/th&gt;
&lt;th&gt;Sent when&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;System prompt and tool definitions&lt;/td&gt;
&lt;td&gt;Thousands of tokens&lt;/td&gt;
&lt;td&gt;Every request&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Instruction files (CLAUDE.md, AGENTS.md, rules)&lt;/td&gt;
&lt;td&gt;Hundreds to thousands&lt;/td&gt;
&lt;td&gt;Every request&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Conversation history&lt;/td&gt;
&lt;td&gt;Grows every turn&lt;/td&gt;
&lt;td&gt;Every request&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Tool results (file contents, command output)&lt;/td&gt;
&lt;td&gt;Often the largest part&lt;/td&gt;
&lt;td&gt;Every request after they appear&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;So a one-line question asked in a session that has been open all day still pays for the whole day's conversation.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why cost grows with the square of session length
&lt;/h2&gt;

&lt;p&gt;Say each turn adds about 5,000 tokens. Turn 1 sends 5k, turn 2 sends 10k, and turn 20 sends 100k. Add it up and a 20-turn session processes roughly &lt;strong&gt;1.05 million input tokens&lt;/strong&gt;, even though only 100k of them were new.&lt;/p&gt;

&lt;p&gt;Here is a quick model of that at illustrative Claude Sonnet 5 list prices ($2 per million input tokens, $0.20 per million for cache hits):&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="n"&gt;PRICE_IN&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;PRICE_CACHE_WRITE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;PRICE_CACHE_HIT&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;2.00&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;2.50&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;0.20&lt;/span&gt;  &lt;span class="c1"&gt;# $ per million tokens
&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;session_cost&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;turns&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;tokens_added_per_turn&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;cached&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;total_in&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;new_total&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;turns&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;total_in&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;tokens_added_per_turn&lt;/span&gt;  &lt;span class="c1"&gt;# whole context re-sent
&lt;/span&gt;        &lt;span class="n"&gt;new_total&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;tokens_added_per_turn&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;cached&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;total_in&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mf"&gt;1e6&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;PRICE_IN&lt;/span&gt;
    &lt;span class="n"&gt;reused&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;total_in&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;new_total&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;new_total&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mf"&gt;1e6&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;PRICE_CACHE_WRITE&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;reused&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mf"&gt;1e6&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;PRICE_CACHE_HIT&lt;/span&gt;

&lt;span class="c1"&gt;# 10 turns: $0.55 uncached, $0.17 cached
# 20 turns: $2.10 uncached, $0.44 cached
# 40 turns: $8.20 uncached, $1.28 cached
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Doubling a session from 20 to 40 turns roughly quadruples the uncached input cost. And that ignores output tokens, which cost about five times as much as input across the Claude line-up.&lt;/p&gt;

&lt;p&gt;Subscriptions are not immune. On Pro, Max or Team plans you don't see a per-request bill, but the same tokens drain your usage window.&lt;/p&gt;

&lt;h2&gt;
  
  
  Seven ways to cut the cost
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Measure for a week first
&lt;/h3&gt;

&lt;p&gt;You can't cut what you can't see. In Claude Code, &lt;code&gt;/usage&lt;/code&gt; shows session tokens by model, cache reads and writes and an estimated cost, and &lt;code&gt;/context&lt;/code&gt; shows what is filling the window right now. Track four numbers: cost per session, cost per &lt;em&gt;completed task&lt;/em&gt;, the share of input served from cache, and how much of your spend goes to the premium model. Judge every later change by cost per completed task. A cheap model that needs three attempts isn't cheap.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. One task, one session
&lt;/h3&gt;

&lt;p&gt;This single habit fixes the most common cause of runaway spend. When you switch to unrelated work, start fresh (&lt;code&gt;/clear&lt;/code&gt; in Claude Code, a new chat in Cursor or Codex). Clearing costs nothing; carrying yesterday's debugging session into today's feature makes every message pay for both. Use &lt;code&gt;/rename&lt;/code&gt; first if you might want to &lt;code&gt;/resume&lt;/code&gt; the old session.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Default to the mid-tier model
&lt;/h3&gt;

&lt;p&gt;Most daily coding work doesn't need a flagship model. Use a mid-tier model (Sonnet-class) for features, bug fixes and refactors, a small one (Haiku-class) for renames, boilerplate and log summaries, and save the premium tier for architecture and nasty concurrency bugs. A useful pattern: &lt;strong&gt;plan with the premium model, then switch with &lt;code&gt;/model&lt;/code&gt; to implement.&lt;/strong&gt; The expensive model spends a few thousand tokens thinking instead of hundreds of thousands editing files.&lt;/p&gt;

&lt;p&gt;Thinking is billed as output, the most expensive kind of token. Lower the effort level for routine tasks.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Put your instruction file on a diet
&lt;/h3&gt;

&lt;p&gt;CLAUDE.md, AGENTS.md and Cursor rules are loaded on every request, so every line is a recurring cost. Anthropic recommends keeping CLAUDE.md under 200 lines. Apply a simple test to each line: &lt;em&gt;if I delete this, will the agent make a mistake in most sessions?&lt;/em&gt; If not, move it out. Multi-step procedures like releases belong in skills or on-demand docs that load only when needed.&lt;/p&gt;

&lt;p&gt;Cutting a 400-line file (about 5,000 tokens) to 40 lines saves around 4,500 tokens per request. Over a few hundred requests a day, that's over a million tokens.&lt;/p&gt;

&lt;h3&gt;
  
  
  5. Keep noisy output out of context
&lt;/h3&gt;

&lt;p&gt;Test runners and build logs can produce thousands of lines, and every line is resent on every later turn. Ask for filtered commands ("run &lt;code&gt;pytest -q&lt;/code&gt; and show only failures"), push verbose jobs to a subagent so only a summary comes back, and block generated code, lockfiles and vendored dependencies from being read.&lt;/p&gt;

&lt;h3&gt;
  
  
  6. Stop breaking the prompt cache
&lt;/h3&gt;

&lt;p&gt;Prompt caching lets the model reuse a context prefix it has already processed at &lt;strong&gt;a tenth of the normal input price&lt;/strong&gt;, and your coding tool usually turns it on for you. But the prefix has to be byte-identical. These habits break it:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;connecting or disconnecting MCP servers mid-session (tool definitions sit near the start of the prefix)&lt;/li&gt;
&lt;li&gt;switching models mid-conversation (caches are per model)&lt;/li&gt;
&lt;li&gt;editing your instruction file during a session&lt;/li&gt;
&lt;li&gt;coming back to a huge session after a long break, once the cache has expired&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;code&gt;/usage&lt;/code&gt; reports your cache-hit share. If it drops, one of these is usually why.&lt;/p&gt;

&lt;h3&gt;
  
  
  7. Use cheap subagents for legwork, but not for everything
&lt;/h3&gt;

&lt;p&gt;A subagent runs in its own context and returns only a summary, which is ideal for searching a codebase or digesting test output. Pin it to a small model and your main context stays small too. But each subagent loads its own instructions and tools, so spawning one for a two-line lookup can cost more than doing it inline. Agent teams multiply this: Anthropic's docs put them at about 7x the tokens of a standard session when teammates run in plan mode.&lt;/p&gt;

&lt;h2&gt;
  
  
  What normal looks like
&lt;/h2&gt;

&lt;p&gt;For a sense of scale, Anthropic reports that Claude Code averages about $13 per developer per active day across enterprise deployments, with 90% of users under $30. The two usual causes of unexpectedly high spend are exactly the ones above: &lt;strong&gt;long sessions that are never cleared, and a premium model left as the default.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Prices and plan limits change often, so check your provider's pricing page before acting on any figure here. The principles don't change: measure, route, trim, cache and guard.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Originally published on &lt;a href="https://www.techbrosebooks.co.in/blog/why-ai-coding-agent-costs-grow" rel="noopener noreferrer"&gt;TechBrosEbooks&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;This article is adapted from the ebook &lt;strong&gt;&lt;a href="https://www.techbrosebooks.co.in/books/stop-burning-tokens-cost-engineering-for-ai-coding-agents?utm_source=devto&amp;amp;utm_medium=referral&amp;amp;utm_campaign=why-ai-coding-agent-costs-grow" rel="noopener noreferrer"&gt;Stop Burning Tokens&lt;/a&gt;&lt;/strong&gt;, which covers each technique in depth with configs and scripts, including a hook that filters test output, local-model fallback, spend guardrails, and a 30-day rollout plan.                                                                                                                                                                                                                                                                                                                                                                                                            &lt;/p&gt;

</description>
      <category>ai</category>
      <category>llm</category>
      <category>productivity</category>
      <category>claude</category>
    </item>
    <item>
      <title>AI Agents for Backend Engineers: What Carries Over and What's New</title>
      <dc:creator>Tech Geeks</dc:creator>
      <pubDate>Fri, 06 Nov 2026 19:02:45 +0000</pubDate>
      <link>https://dev.to/tech_geeks_a72ac908b0102d/ai-agents-for-backend-engineers-what-carries-over-and-whats-new-12jh</link>
      <guid>https://dev.to/tech_geeks_a72ac908b0102d/ai-agents-for-backend-engineers-what-carries-over-and-whats-new-12jh</guid>
      <description>&lt;p&gt;If you write backend code, you're closer to building production AI agents than you think. Queues, retries, idempotency, logs: it all carries over. What's new is a component that makes decisions, gives different answers to the same input, and can be talked into things. Here's the translation layer.&lt;/p&gt;

&lt;h2&gt;
  
  
  An agent is an LLM with three upgrades
&lt;/h2&gt;

&lt;p&gt;A plain LLM call can only talk. An agent can act, because it adds:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Tools:&lt;/strong&gt; functions it can call, such as querying a database or sending an email.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Memory:&lt;/strong&gt; a record of what has happened so far.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A loop:&lt;/strong&gt; it works step by step until the job is done. It thinks, acts, checks the result, and decides what's next. This pattern is called ReAct (reason + act).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Before you build one, ask whether a single, well-prompted LLM call would do. Summarising a paragraph is one call. Finding, fixing and testing a bug across 40 files is a job for an agent.&lt;/p&gt;

&lt;h2&gt;
  
  
  Tools: the model asks, your code decides
&lt;/h2&gt;

&lt;p&gt;Function calling is the mechanism behind tools, and the most important thing to internalise is that &lt;strong&gt;the model never runs anything itself&lt;/strong&gt;. You give it a menu of tools, each with a name, description and parameters. When it wants one, it replies with a structured request, and your code decides whether to run it. That's what keeps you in control.&lt;/p&gt;

&lt;p&gt;Two habits make tools reliable:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Write descriptions like API docs&lt;/strong&gt;, including when &lt;em&gt;not&lt;/em&gt; to use the tool. "Fetch a customer's recent orders. Use for order status or refunds. Not for product search." That last sentence prevents a surprising number of wrong picks.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Validate arguments like any user input.&lt;/strong&gt; Check the schema, check that referenced IDs exist, and rate-limit.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The &lt;strong&gt;Model Context Protocol (MCP)&lt;/strong&gt;, released by Anthropic in late 2024, lets you wrap a tool once and reuse it across any MCP-compatible agent. Think of it as USB-C for AI tools.&lt;/p&gt;

&lt;h2&gt;
  
  
  Memory is plumbing you build
&lt;/h2&gt;

&lt;p&gt;LLMs remember nothing between calls; every bit of memory is something you store and feed back in. Short-term memory is the current conversation, limited by the context window. Long-term memory lives outside the model and is loaded only when relevant.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;RAG&lt;/strong&gt; (retrieval-augmented generation) is the common way to bring in outside knowledge: store documents in a vector database, retrieve the closest chunks, and put them in the prompt. Retrieve broadly, then re-rank and keep only the best few, and tell the model to answer using &lt;em&gt;only&lt;/em&gt; that context so it doesn't guess.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Checkpointing&lt;/strong&gt; means saving the agent's state after every step, so a restart resumes instead of starting over. It's the same reason you keep sessions in a database, not an in-memory dict.&lt;/p&gt;

&lt;h2&gt;
  
  
  Infrastructure: normal backend work, with two twists
&lt;/h2&gt;

&lt;p&gt;Production agents are mostly the backend engineering you already do. The twists are that LLMs are non-deterministic and that their tool calls have real side effects. Four things keep you safe:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Durable execution.&lt;/strong&gt; Tools like Temporal save progress at every step, so a crash resumes where it left off.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Sensible timeouts and retries.&lt;/strong&gt; LLM calls can take a minute or more; back off politely on rate limits.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Idempotency keys.&lt;/strong&gt; A retried tool call must happen only once in the real world.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Sandboxes.&lt;/strong&gt; Run agent-written code in an isolated environment, never on your own server.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The idempotency key is the one engineers most often forget, and it's one line:&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="n"&gt;payments&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;refund&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;order_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;A123&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;500&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;idempotency_key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;refund:A123&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;# The payment service sees the same key twice but refunds only once.
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Cost matters too. Prompt caching lets providers reuse the repeated parts of your prompt; Anthropic reports savings of up to 90% on long prompts.&lt;/p&gt;

&lt;h2&gt;
  
  
  Observability: agents fail quietly
&lt;/h2&gt;

&lt;p&gt;An agent's failures don't throw errors. You get a confident wrong answer, or a strange route to a right one, and a health check won't catch either. &lt;strong&gt;Tracing&lt;/strong&gt; records every step as a span: what the model decided, which tool it called, what came back, the cost and the latency. Tools like Langfuse and LangSmith show this as a timeline.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Evaluation&lt;/strong&gt; is testing for agents: plain assertions for exact things (right tool, right ID), and an LLM judge scoring fuzzy things against a rubric. Run evals in CI before every release, sample live traffic afterwards, and turn every production failure into a new test case.&lt;/p&gt;

&lt;h2&gt;
  
  
  Security: assume the model can be tricked
&lt;/h2&gt;

&lt;p&gt;Agents act on text, and attackers can write text. The top risk is &lt;strong&gt;prompt injection&lt;/strong&gt;: instructions hidden in a page, email or document the agent reads. You can't fully prevent it, so contain it:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Least privilege,&lt;/strong&gt; enforced in code, not in the prompt.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Human approval&lt;/strong&gt; for anything risky or irreversible: refunds, deletions, outgoing emails.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Treat model output as untrusted.&lt;/strong&gt; Never &lt;code&gt;eval()&lt;/code&gt; it, and parameterise any SQL it touches.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Keep secrets out of prompts.&lt;/strong&gt; The model gets tools, never raw API keys.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The mantra: assume the model can be tricked, and make sure a tricked model can't do much damage. For example, an &lt;code&gt;issue_refund()&lt;/code&gt; that raises &lt;code&gt;NeedsHumanApproval&lt;/code&gt; above a set amount can't be pushed past that limit by a fooled model, because the code enforces the limit, not the prompt.&lt;/p&gt;

&lt;h2&gt;
  
  
  Go multi-agent last
&lt;/h2&gt;

&lt;p&gt;Multi-agent systems are expensive and fragile. Anthropic's multi-agent research system used about 15 times more tokens than a normal chat, and a 2025 study found failure rates of 41% to 87% across multi-agent frameworks. What works best is one lead agent holding the full picture, with small helpers that do one job and report back a summary.&lt;/p&gt;

&lt;h2&gt;
  
  
  A learning path for a few weekends
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Build a tiny agent with raw API calls and two tools, no framework.&lt;/li&gt;
&lt;li&gt;Add RAG over a folder of your own notes.&lt;/li&gt;
&lt;li&gt;Add tracing and 50 test cases, then break things on purpose.&lt;/li&gt;
&lt;li&gt;Rebuild it in a framework: LangGraph, or the OpenAI or Claude Agent SDK.&lt;/li&gt;
&lt;li&gt;Add durable execution and an approval step.&lt;/li&gt;
&lt;li&gt;Expose a tool through MCP.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;By step six you'll understand what frameworks do under the hood, which makes you much better at choosing and debugging them.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Originally published on &lt;a href="https://www.techbrosebooks.co.in/blog/ai-agents-for-backend-engineers" rel="noopener noreferrer"&gt;TechBrosEbooks&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;This article is adapted from the quick-start guide &lt;strong&gt;&lt;a href="https://www.techbrosebooks.co.in/books/ai-agent-orchestration-infrastructure-for-software-engineers?utm_source=devto&amp;amp;utm_medium=referral&amp;amp;utm_campaign=ai-agents-for-backend-engineers" rel="noopener noreferrer"&gt;AI Agent Orchestration &amp;amp; Infrastructure for Software Engineers&lt;/a&gt;&lt;/strong&gt;, which covers each idea in one short chapter, with orchestration patterns, multi-agent handoffs and A2A, an end-to-end support-ticket triage agent, and a pre-ship checklist.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>agents</category>
      <category>backend</category>
      <category>llm</category>
    </item>
    <item>
      <title>Workflows vs Agents: The 6 AI Agent Orchestration Patterns (and When to Go Multi-Agent)</title>
      <dc:creator>Tech Geeks</dc:creator>
      <pubDate>Fri, 06 Nov 2026 18:07:33 +0000</pubDate>
      <link>https://dev.to/tech_geeks_a72ac908b0102d/workflows-vs-agents-the-6-ai-agent-orchestration-patterns-and-when-to-go-multi-agent-10b9</link>
      <guid>https://dev.to/tech_geeks_a72ac908b0102d/workflows-vs-agents-the-6-ai-agent-orchestration-patterns-and-when-to-go-multi-agent-10b9</guid>
      <description>&lt;p&gt;"Agent orchestration" sounds exotic, but the question underneath it is plain: how do you arrange one or more LLM calls into a system that solves a real task, reliably? The answer most teams who have shipped agents converge on is also plain. As Anthropic put it in its December 2024 guide &lt;em&gt;Building effective agents&lt;/em&gt;: "the most successful implementations weren't using complex frameworks or specialized libraries. Instead, they were building with simple, composable patterns."&lt;/p&gt;

&lt;h2&gt;
  
  
  Workflows versus agents
&lt;/h2&gt;

&lt;p&gt;Anthropic draws a line that's worth adopting:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Workflows&lt;/strong&gt; are systems where LLMs and tools are orchestrated through &lt;em&gt;predefined code paths&lt;/em&gt;. You write the control flow.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Agents&lt;/strong&gt; are systems where the LLM &lt;em&gt;dynamically directs its own process&lt;/em&gt; and tool use. The model decides the control flow at runtime.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Workflows give predictability and consistency for well-defined tasks. Agents are the better option when the path genuinely can't be predicted in advance. For many applications, a single well-prompted LLM call with retrieval and good examples is enough.&lt;/p&gt;

&lt;h2&gt;
  
  
  The six patterns
&lt;/h2&gt;

&lt;p&gt;Each one maps onto something you already know from distributed systems.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Pattern&lt;/th&gt;
&lt;th&gt;What it does&lt;/th&gt;
&lt;th&gt;Familiar analogy&lt;/th&gt;
&lt;th&gt;Use it when&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Prompt chaining&lt;/td&gt;
&lt;td&gt;A fixed sequence; each call's output feeds the next, with optional checks between steps&lt;/td&gt;
&lt;td&gt;A Unix pipe or ETL pipeline&lt;/td&gt;
&lt;td&gt;The task splits into clean, fixed subtasks (outline → draft → revise)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Routing&lt;/td&gt;
&lt;td&gt;A classifier sends each input to a specialised handler&lt;/td&gt;
&lt;td&gt;An API gateway routing by path&lt;/td&gt;
&lt;td&gt;Different request types need different prompts, tools or models&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Parallelization&lt;/td&gt;
&lt;td&gt;Run subtasks concurrently and merge, by sectioning or by voting&lt;/td&gt;
&lt;td&gt;Scatter-gather / MapReduce&lt;/td&gt;
&lt;td&gt;Parts are independent, or you want confidence from repeated runs&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Orchestrator–workers&lt;/td&gt;
&lt;td&gt;A lead LLM decides the subtasks at runtime and delegates them&lt;/td&gt;
&lt;td&gt;A coordinator fanning jobs out to a worker pool&lt;/td&gt;
&lt;td&gt;You can't know the subtasks up front, such as code changes across an unknown number of files&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Evaluator–optimizer&lt;/td&gt;
&lt;td&gt;One LLM generates, another critiques against criteria, repeat&lt;/td&gt;
&lt;td&gt;A CI suite gating a build&lt;/td&gt;
&lt;td&gt;You have clear quality criteria and iteration measurably helps&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Autonomous agent&lt;/td&gt;
&lt;td&gt;The model runs a reason–act–observe loop freely until done&lt;/td&gt;
&lt;td&gt;—&lt;/td&gt;
&lt;td&gt;Maximum flexibility is worth maximum cost and unpredictability&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The patterns compose: a router often feeds a prompt chain, and an orchestrator's workers often run an evaluator–optimizer loop. But each added layer adds a failure mode. &lt;strong&gt;Every extra LLM call adds latency, cost and a compounding error rate&lt;/strong&gt;, so add calls deliberately, at decision points you chose.&lt;/p&gt;

&lt;h3&gt;
  
  
  Routing: the most underrated pattern
&lt;/h3&gt;

&lt;p&gt;Routing deserves a closer look because it's cheap and it pays twice. A support inbox with billing, tech and general questions sends each message through a small classifier first:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;input -&amp;gt; [ Router LLM ] classifies intent
               |
      +--------+---------+
      v        v         v
   billing  tech-support  general
  (prompt+   (prompt+     (cheap
   tools)     tools)      model)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The router does one narrow job: output a category. Keeping it tool-free and single-purpose makes it fast, cheap, and easy to test with a plain classification eval. And it lets you send easy questions to a cheap model and hard ones to a capable one.&lt;/p&gt;

&lt;h2&gt;
  
  
  The agent loop, and why it needs a budget
&lt;/h2&gt;

&lt;p&gt;Underneath every autonomous agent is the &lt;strong&gt;ReAct&lt;/strong&gt; loop (Yao et al., 2022): the model writes a thought, takes an action, observes the result, and repeats. To a backend engineer, it's a &lt;code&gt;while&lt;/code&gt; loop around a stateless handler:&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="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;step&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;MAX_STEPS&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;  &lt;span class="c1"&gt;# a budget cap prevents infinite loops
&lt;/span&gt;    &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;llm&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;chat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;tools&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;tool_schemas&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;tool_call&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;tools&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;tool_call&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;](&lt;/span&gt;&lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;tool_call&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;raw&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;role&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;tool&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;content&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;)})&lt;/span&gt;
        &lt;span class="k"&gt;continue&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;content&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c1"&gt;# no tool call -&amp;gt; final answer
&lt;/span&gt;    &lt;span class="k"&gt;break&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That step budget isn't decoration. An unbounded agent loop is the agent equivalent of runaway recursion.&lt;/p&gt;

&lt;h2&gt;
  
  
  Single agent or multi-agent?
&lt;/h2&gt;

&lt;p&gt;This was the field's biggest architecture debate of 2025, and the evidence is worth knowing before you build a team of agents.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Against:&lt;/strong&gt; in June 2025, Cognition (the makers of Devin) published &lt;em&gt;Don't Build Multi-Agents&lt;/em&gt;. Their argument: parallel subagents that don't share full context make conflicting implicit decisions, and "actions carry implicit decisions, and conflicting decisions carry bad results."&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;For, with a price:&lt;/strong&gt; a day later, Anthropic described its multi-agent research system, a Claude Opus 4 lead with Claude Sonnet 4 subagents. It beat a single Claude Opus 4 agent by 90.2% on their internal research eval. It also used about &lt;strong&gt;15 times more tokens&lt;/strong&gt; than a chat interaction, against roughly 4x for a single agent.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The failure data:&lt;/strong&gt; the MAST study (Cemri et al., NeurIPS 2025) annotated 1,642 execution traces across seven multi-agent frameworks and found &lt;strong&gt;failure rates from 41% to 86.7%&lt;/strong&gt;. About 42% of failures came from specification and system design, 37% from misalignment between agents, and 21% from weak task verification.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The consensus that emerged by 2026: multi-agent helps for genuinely parallel, breadth-first work such as research. The reliable shape is &lt;strong&gt;one stateful orchestrator that holds the full context, with narrow, stateless subagents that return summaries&lt;/strong&gt;, not a chatty peer-to-peer mesh. Even Cognition's author later acknowledged that setups following exactly this shape "actually work."&lt;/p&gt;

&lt;h2&gt;
  
  
  How agents talk to each other
&lt;/h2&gt;

&lt;p&gt;When you do need more than one agent, there are three coordination mechanisms, from tightest to loosest coupling:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Shared state:&lt;/strong&gt; every agent reads and writes one common state object. Best for agents inside one process.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Handoffs:&lt;/strong&gt; one agent transfers control, usually with the conversation history, to another. A triage agent handing a billing issue to a billing specialist means the user never repeats themselves.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Agent-to-agent protocols:&lt;/strong&gt; for agents across processes or organisations. &lt;strong&gt;A2A&lt;/strong&gt; (Agent2Agent), announced by Google in April 2025 and donated to the Linux Foundation that June, has each agent publish an Agent Card describing its skills and endpoints.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The tidy distinction: &lt;strong&gt;MCP is vertical&lt;/strong&gt; (agent to tools) &lt;strong&gt;and A2A is horizontal&lt;/strong&gt; (agent to agent). Production systems often use both: A2A routes a task to the right specialist, and MCP gives that specialist its tools.&lt;/p&gt;

&lt;h2&gt;
  
  
  The rule to remember
&lt;/h2&gt;

&lt;p&gt;Start at the lowest rung that works: a single call, then a workflow, then an agent, and only then a team of agents. Climb only when the simpler design demonstrably fails.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Originally published on &lt;a href="https://www.techbrosebooks.co.in/blog/ai-agent-orchestration-patterns" rel="noopener noreferrer"&gt;TechBrosEbooks&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;This article is adapted from the ebook &lt;strong&gt;&lt;a href="https://www.techbrosebooks.co.in/books/the-ai-agent-field-manual?utm_source=devto&amp;amp;utm_medium=referral&amp;amp;utm_campaign=ai-agent-orchestration-patterns" rel="noopener noreferrer"&gt;The AI Agent Field Manual&lt;/a&gt;&lt;/strong&gt;, which goes on to memory and RAG, checkpointing, durable execution, queues and retries, observability and evals, security, and a complete support-ticket triage system built end to end.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>agents</category>
      <category>architecture</category>
      <category>llm</category>
    </item>
    <item>
      <title>A Vibe Coding Workflow That Ships: Plan, Code, Test, Deploy</title>
      <dc:creator>Tech Geeks</dc:creator>
      <pubDate>Fri, 06 Nov 2026 18:01:02 +0000</pubDate>
      <link>https://dev.to/tech_geeks_a72ac908b0102d/a-vibe-coding-workflow-that-ships-plan-code-test-deploy-3b3j</link>
      <guid>https://dev.to/tech_geeks_a72ac908b0102d/a-vibe-coding-workflow-that-ships-plan-code-test-deploy-3b3j</guid>
      <description>&lt;p&gt;You've used an AI coding assistant a few times. Sometimes you got something great; sometimes you got something terrible; and you're not sure which to expect next. The difference is rarely the model. It's the workflow around it.&lt;/p&gt;

&lt;p&gt;Let's get the honest version out of the way: AI won't turn you into a 10x engineer. It makes typing about 10x faster and thinking maybe 1.2x faster. Most of this job is thinking, so the gain is smaller than the demos promise, but it's real. The actual shift is that you spend less time &lt;em&gt;producing&lt;/em&gt; code and more time &lt;em&gt;specifying and verifying&lt;/em&gt; it.&lt;/p&gt;

&lt;h2&gt;
  
  
  The loop: plan, code, test, deploy, with a verify after each
&lt;/h2&gt;

&lt;p&gt;This isn't a new lifecycle. It's the four stages you already know, with an assistant plugged into each, plus one step that matters more than anything else: &lt;strong&gt;verify after every stage.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Skip it and errors compound forward. A made-up requirement in planning becomes a wrong function, then a test that certifies the wrong function is correct, and now it's in production. Catching it in planning costs a minute. Catching it after release costs an afternoon.&lt;/p&gt;

&lt;p&gt;The other thing that decides whether this works is how much you ask for at once. Ask for "a user management system" and you'll get 800 lines you'll skim and merge without understanding. Ask for "the POST /users handler, validation only, no database calls yet" and you get 40 lines you can read properly in two minutes.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;If you can't verify the output in five minutes, you asked for too much.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Context is the whole game
&lt;/h2&gt;

&lt;p&gt;Your assistant isn't stupid; it's working blind. It can't see your repo conventions, your team's decisions or your production constraints. Almost everything it gets wrong for apparently silly reasons traces back to something you knew and it didn't.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Write the project rules file once.&lt;/strong&gt; Most AI coding tools read one from the repo root: stack, conventions, and things not to do. Ten minutes writing it saves correcting the same three mistakes forty times.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Paste the real thing.&lt;/strong&gt; The actual schema, real sample data, the exact error message, not a paraphrase from memory.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Say "follow the patterns in this file".&lt;/strong&gt; Paste an existing file from your codebase. A real file is unambiguous where a prose style guide is vague, and this one habit kills most convention drift.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Plan: ask for questions before you ask for a plan
&lt;/h2&gt;

&lt;p&gt;Planning doesn't feel like progress, which is why engineers skip it. It's also the stage that pays best. Don't ask for a plan; ask to be interrogated:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;I need to add recurring expenses to our tracker. Before proposing
anything, ask me the 7 questions that most affect the design. Number them.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You'll get questions like: what happens to future instances when someone deletes the series? What does a monthly rule starting on the 31st do in February? Some you'd have thought of. Some you'd have discovered three days later with the feature half-built.&lt;/p&gt;

&lt;p&gt;Then harvest edge cases, grouped by data model, calendar and timezone, user actions and failure recovery, and triage them yourself into &lt;em&gt;now&lt;/em&gt;, &lt;em&gt;later&lt;/em&gt; and &lt;em&gt;not doing&lt;/em&gt;. That triage is your spec. Ask for trade-offs, never for the answer: you know your team and your deadline, and the model doesn't.&lt;/p&gt;

&lt;p&gt;On a CSV export feature, this step surfaced &lt;strong&gt;CSV injection&lt;/strong&gt;: a user names an expense &lt;code&gt;=HYPERLINK("http://evil.com","click")&lt;/code&gt;, a colleague opens the export in Excel, and it's a live formula. One prompt, forty seconds, and a vulnerability that never shipped.&lt;/p&gt;

&lt;h2&gt;
  
  
  Code: small batches, and read before you run
&lt;/h2&gt;

&lt;p&gt;Match the mode to the task. Autocomplete is for the line you were already going to write. Chat is for self-contained units such as one function or one migration. Agents are for mechanical sweeps with a clear finish line, like a rename everywhere. &lt;strong&gt;The more judgement a task needs, the smaller the batch should be.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Work skeleton first: types, signatures and file layout before any function bodies. Then implement one unit at a time: implement, read, run, and commit at every green point. Scan every block that comes back with four questions:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Does it do what I asked, not what it decided would be nicer?&lt;/li&gt;
&lt;li&gt;What did it invent? Check that every import and method actually exists.&lt;/li&gt;
&lt;li&gt;Where does it break? Empty, null, zero, negative, enormous, concurrent.&lt;/li&gt;
&lt;li&gt;Can I explain every line? If not, learn it or delete it.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;And follow the two-strikes rule. If the second attempt at the same fix didn't work, the third won't either. The model has locked onto a wrong mental model, so reset with a fresh framing or write it yourself.&lt;/p&gt;

&lt;h2&gt;
  
  
  Test: from the spec, never from the code
&lt;/h2&gt;

&lt;p&gt;This is where AI helps most and hurts most. The mistake almost everyone makes once: pointing it at finished code and saying "write tests for this". It reads your implementation and writes tests asserting that your code does exactly what it currently does, &lt;strong&gt;bugs included&lt;/strong&gt;. You now own a suite that locks your bug in place, plus a green CI badge.&lt;/p&gt;

&lt;p&gt;The fix is one sentence: generate tests from the rules, and keep the implementation off-limits.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Write tests for calculateRefund. Here are the business rules — do not
look at my implementation.
- Full refund if cancelled more than 7 days before the event
- 50% between 7 days and 24 hours
- Nothing within 24 hours
- The 2% processing fee is never refunded
- Refunding an already-refunded booking throws AlreadyRefundedError
Include boundary cases at exactly 7 days and exactly 24 hours,
with hardcoded expected values.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;"Hardcoded expected values" matters more than it looks. If a test computes the expected number with the same formula as your code, it's running your bug twice and checking the results match.&lt;/p&gt;

&lt;p&gt;Before you trust a suite, sabotage it: flip a comparison operator on purpose. If nothing goes red, your tests are decoration. And read the assertions: &lt;code&gt;expect(save).toHaveBeenCalled()&lt;/code&gt; tells you far less than &lt;code&gt;expect(saved.amount).toBe(4750)&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Deploy: self-review first, and say what to skip
&lt;/h2&gt;

&lt;p&gt;Run the AI over your diff before you ask a human, and tell it what to ignore:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Review this diff as a senior engineer on this codebase. Focus on unhandled
error paths, race conditions, N+1 queries and missing validation. Cite line
numbers. Skip style nits — the linter handles those.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Leave out the last line and you'll get twelve comments about variable names and nothing about the transaction you forgot to roll back. The AI is good at null paths, off-by-one errors and unclosed resources. It's blind to whether the feature is a good idea, which is why humans stay in the loop.&lt;/p&gt;

&lt;p&gt;PR descriptions and changelogs are free money. In incidents, ask for ranked hypotheses &lt;em&gt;plus a command that would confirm or rule out the top one&lt;/em&gt;, rather than an answer. And scrub emails, tokens and account IDs from logs before pasting them anywhere.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Originally published on &lt;a href="https://www.techbrosebooks.co.in/blog/vibe-coding-workflow-plan-code-test-deploy" rel="noopener noreferrer"&gt;TechBrosEbooks&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;This article is adapted from the ebook &lt;strong&gt;&lt;a href="https://www.techbrosebooks.co.in/books/vibe-code-playbook?utm_source=devto&amp;amp;utm_medium=referral&amp;amp;utm_campaign=vibe-coding-workflow-plan-code-test-deploy" rel="noopener noreferrer"&gt;The Vibe Coding Playbook&lt;/a&gt;&lt;/strong&gt;, which includes a complete 90-minute worked example building a CSV export end to end, guardrails for security, licensing and privacy, the anti-patterns that waste the most time, a 30-day plan, a prompt library and a pre-merge checklist.&lt;br&gt;
~&lt;br&gt;&lt;br&gt;
~&lt;br&gt;&lt;br&gt;
~                      &lt;/p&gt;

</description>
      <category>ai</category>
      <category>productivity</category>
      <category>webdev</category>
      <category>testing</category>
    </item>
    <item>
      <title>Vibe-Coded App Security: A 30-Minute Pre-Launch Checklist</title>
      <dc:creator>Tech Geeks</dc:creator>
      <pubDate>Fri, 06 Nov 2026 17:50:41 +0000</pubDate>
      <link>https://dev.to/tech_geeks_a72ac908b0102d/vibe-coded-app-security-a-30-minute-pre-launch-checklist-f93</link>
      <guid>https://dev.to/tech_geeks_a72ac908b0102d/vibe-coded-app-security-a-30-minute-pre-launch-checklist-f93</guid>
      <description>&lt;p&gt;You built an app with Lovable, Bolt, Cursor or Claude Code. It works, people are signing up, and it might be leaving the doors wide open.&lt;/p&gt;

&lt;p&gt;AI writes code that &lt;em&gt;works&lt;/em&gt;, not code that's &lt;em&gt;safe&lt;/em&gt;, unless you specifically ask. Security is the invisible part of the spec, so the AI skips it, and so do you, because you can't see what's missing.&lt;/p&gt;

&lt;h2&gt;
  
  
  How often this goes wrong
&lt;/h2&gt;

&lt;p&gt;Veracode's 2025 GenAI Code Security Report found that &lt;strong&gt;45% of AI-generated code samples contained an OWASP Top 10 flaw&lt;/strong&gt;, and the number barely moved between older and newer models. (Veracode sells security products, so treat it as directional.) A scan of 5,600 public vibe-coded apps found 2,038 high-impact vulnerabilities and 175 instances of exposed personal data, all live in production.&lt;/p&gt;

&lt;p&gt;The incidents are concrete. In CVE-2025-48757, more than 170 Lovable apps had Supabase databases anyone could read, because Row Level Security was never turned on. In July 2025 the Tea app left about 72,000 images in an unsecured storage bucket. The same month, an AI agent on Replit deleted a live production database during a code freeze.&lt;/p&gt;

&lt;p&gt;None of these were exotic attacks. They were basic, preventable mistakes. Here are the ones that matter most, and how to check each in minutes.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Secrets in the browser
&lt;/h2&gt;

&lt;p&gt;An API key is a password. If it ends up in code that runs in someone's browser, it's public.&lt;/p&gt;

&lt;p&gt;The trap: &lt;code&gt;NEXT_PUBLIC_&lt;/code&gt; (Next.js) and &lt;code&gt;VITE_&lt;/code&gt; (Vite) prefixes deliberately bake a variable into the public JavaScript bundle. AI tools often add that prefix to a secret to fix an "undefined" error, and now your Stripe secret key ships to every visitor. The Supabase &lt;code&gt;service_role&lt;/code&gt; key deserves special fear: it bypasses every Row Level Security rule.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Check it:&lt;/strong&gt; open your live site, press F12, go to Sources, and search the loaded scripts for &lt;code&gt;sk_live&lt;/code&gt;, &lt;code&gt;service_role&lt;/code&gt;, &lt;code&gt;secret&lt;/code&gt; and &lt;code&gt;AKIA&lt;/code&gt;. Any match is exposed. Move it to a server-only variable used from a server route, then &lt;strong&gt;rotate the key&lt;/strong&gt;. Deleting it from the file doesn't remove it from git history, and bots scrape public bundles within minutes.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Database rules that were never turned on
&lt;/h2&gt;

&lt;p&gt;With Supabase and Firebase, your app talks to the database straight from the browser using a public key. The only thing stopping a stranger from reading everyone's data is access rules you must enable yourself. This is the single most common vibe-coding breach.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Supabase:&lt;/strong&gt; security comes entirely from Row Level Security (RLS), and tables have it off by default. Dashboard → Database → Security Advisor flags every table without it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Firebase:&lt;/strong&gt; "test mode" (&lt;code&gt;allow read, write: if true&lt;/code&gt;) lets anyone read and write everything. Replace it before launch.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A subtle trap on both: "logged in" is not "owns this data". A policy of &lt;code&gt;USING (true)&lt;/code&gt;, or a rule that only checks &lt;code&gt;request.auth != null&lt;/code&gt;, lets any signed-up user (including an attacker who just registered) read everyone's rows. Scope every rule to the user, for example &lt;code&gt;(select auth.uid()) = user_id&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Test it:&lt;/strong&gt; create two accounts, sign in as A, and try to fetch B's row. If data comes back, the policy is broken.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. "Change the ID in the URL" bugs
&lt;/h2&gt;

&lt;p&gt;Authentication is who you are; authorization is what you may touch. AI apps usually get login roughly right and authorization badly wrong.&lt;/p&gt;

&lt;p&gt;The most common flaw is &lt;strong&gt;IDOR&lt;/strong&gt; (also called BOLA), number one on the OWASP API Security list. Your app has &lt;code&gt;/api/invoices/1042&lt;/code&gt;; change it to &lt;code&gt;1043&lt;/code&gt; and you see someone else's invoice, because the server checked you were logged in but never that the invoice was yours. Hidden buttons and random UUIDs don't fix this. Anyone can call an endpoint directly, and IDs leak in emails and shared links.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Check it:&lt;/strong&gt; log in as user A, find a request like &lt;code&gt;/api/orders/1001&lt;/code&gt; in the Network tab, copy it as cURL, change the ID, and re-run it. &lt;strong&gt;Fix it&lt;/strong&gt; by putting ownership inside the query (&lt;code&gt;WHERE id = :id AND user_id = :currentUser&lt;/code&gt;) and returning 404 when the record isn't theirs.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Payments the browser controls
&lt;/h2&gt;

&lt;p&gt;Two money mistakes dominate AI-built apps:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Client-set prices.&lt;/strong&gt; If checkout sends an amount from the browser, an attacker changes it to 1. Decide prices on the server from a fixed price ID.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Unverified webhooks.&lt;/strong&gt; Your payment provider tells your server "payment succeeded" by calling a public URL, so anyone can POST a fake event to it. Verify the signature on every webhook, using the raw, unparsed request body, and reject anything invalid.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Then check subscription status server-side before unlocking paid features, not a flag the browser set once.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. Unescaped input
&lt;/h2&gt;

&lt;p&gt;React escapes text safely, but &lt;code&gt;dangerouslySetInnerHTML&lt;/code&gt; turns that protection off. Veracode found AI tools failed to defend against cross-site scripting in &lt;strong&gt;86%&lt;/strong&gt; of relevant cases. Sanitise with DOMPurify, or avoid raw HTML entirely. Use parameterised queries, never SQL glued together from strings. And if your app passes user text to an LLM, never let the model's output trigger a sensitive action without a separate check.&lt;/p&gt;

&lt;h2&gt;
  
  
  6. Endpoints with no limits
&lt;/h2&gt;

&lt;p&gt;If an endpoint that costs you money (an AI call, an email, a signup) has no limit, someone will hit it thousands of times. AI tools almost never add limits unless asked. Layer your defences:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Set a hard monthly spend cap&lt;/strong&gt; in your AI provider's dashboard. Do it today.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Rate-limit per user ID&lt;/strong&gt;, not just per IP.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Require login&lt;/strong&gt; before any expensive action.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cap input size.&lt;/strong&gt; A rate limit controls how often, not how expensive one request is.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  7. Packages that don't exist
&lt;/h2&gt;

&lt;p&gt;AI sometimes recommends packages that don't exist, and attackers register those exact names with malware ("slopsquatting"). A USENIX Security 2025 study found &lt;strong&gt;19.7%&lt;/strong&gt; of packages recommended across 16 models didn't exist. Look up every AI-suggested package on npmjs.com before installing it, and run &lt;code&gt;npm audit&lt;/code&gt; on what you already have.&lt;/p&gt;

&lt;h2&gt;
  
  
  The 30-minute pre-launch routine
&lt;/h2&gt;

&lt;p&gt;You don't need a pentest to catch the big stuff:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Search your bundle for &lt;code&gt;sk_live&lt;/code&gt; and &lt;code&gt;service_role&lt;/code&gt; (5 min)&lt;/li&gt;
&lt;li&gt;Enable RLS everywhere; kill Firebase test mode (5 min)&lt;/li&gt;
&lt;li&gt;Run the two-account IDOR test (5 min)&lt;/li&gt;
&lt;li&gt;Confirm webhook verification and server-side prices (3 min)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;npm audit&lt;/code&gt;, and check for hallucinated packages (3 min)&lt;/li&gt;
&lt;li&gt;Check your grade on securityheaders.com, and make sure errors hide stack traces (3 min)&lt;/li&gt;
&lt;li&gt;Set a hard AI spend cap (3 min)&lt;/li&gt;
&lt;li&gt;Confirm backups work and dev and prod are separate (3 min)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Run it before every launch and after any big change. If you handle health, financial or children's data, or a breach would sink the business, pay a professional for a review as well. And if you're in India, note that the DPDP Act requires reporting personal-data breaches to the Data Protection Board and affected users.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Originally published on &lt;a href="https://www.techbrosebooks.co.in/blog/vibe-coded-app-security-checklist" rel="noopener noreferrer"&gt;TechBrosEbooks&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;This article is adapted from the ebook &lt;strong&gt;&lt;a href="https://www.techbrosebooks.co.in/books/ship-your-vibe-coded-app-without-getting-hacked?utm_source=devto&amp;amp;utm_medium=referral&amp;amp;utm_campaign=vibe-coded-app-security-checklist" rel="noopener noreferrer"&gt;Ship Your Vibe-Coded App Without Getting Hacked&lt;/a&gt;&lt;/strong&gt;, which gives a detection step and a copy-paste fix-it prompt for every risk above, plus security headers, CORS, supply-chain tooling, and a full walkthrough auditing a sample Lovable + Supabase + Stripe app.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>webdev</category>
      <category>supabase</category>
      <category>security</category>
    </item>
  </channel>
</rss>
