<?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: Mohammad Jawad (Kasir) Barati</title>
    <description>The latest articles on DEV Community by Mohammad Jawad (Kasir) Barati (@kasir-barati).</description>
    <link>https://dev.to/kasir-barati</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%2F595495%2F146d2ca6-6004-437f-9be2-8edaa5a35d34.png</url>
      <title>DEV Community: Mohammad Jawad (Kasir) Barati</title>
      <link>https://dev.to/kasir-barati</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/kasir-barati"/>
    <language>en</language>
    <item>
      <title>Vibe Engineering -- Responsible use of LLMs</title>
      <dc:creator>Mohammad Jawad (Kasir) Barati</dc:creator>
      <pubDate>Sat, 22 Aug 2026 10:31:57 +0000</pubDate>
      <link>https://dev.to/kasir-barati/vibe-engineering-responsible-use-of-llms-3o1o</link>
      <guid>https://dev.to/kasir-barati/vibe-engineering-responsible-use-of-llms-3o1o</guid>
      <description>&lt;p&gt;I sometimes hear about vibe coding and honestly I do NOT believe you as a professional developer need to do it. The journey of using LLMs is interesting, it's useful, you pick up new skills. BUT I wish devs would not stop there and go deeper, get more pro and know what LLM is doing/writing.&lt;/p&gt;

&lt;p&gt;I read &lt;a href="https://simonwillison.net/2025/Oct/7/vibe-engineering/" rel="noopener noreferrer"&gt;Vibe Engineering&lt;/a&gt; post from Simon Willison. There he says:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;I feel like &lt;strong&gt;vibe coding&lt;/strong&gt; is &lt;a href="https://simonwillison.net/2025/Mar/19/vibe-coding/" rel="noopener noreferrer"&gt;pretty well established now&lt;/a&gt; as covering the fast, loose and irresponsible way of building software with AI—entirely prompt-driven, and with no attention paid to how the code actually works. This leaves us with a terminology gap: what should we call the other end of the spectrum, where seasoned professionals accelerate their work with LLMs while staying proudly and confidently accountable for the software they produce?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;And I wholeheartedly agree with him. It's about being &lt;strong&gt;highly productive&lt;/strong&gt;, &lt;strong&gt;highly effective&lt;/strong&gt;, and &lt;strong&gt;impactful&lt;/strong&gt; whilst keeping &lt;strong&gt;accountability&lt;/strong&gt; for the code you build. Doing it in a &lt;strong&gt;bulletproof&lt;/strong&gt; way.&lt;/p&gt;

&lt;h2&gt;
  
  
  tl;dr
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;If you're going to really exploit the capabilities of these new tools, you need to be operating at the top of your game. You're not just responsible for writing the code—you're researching approaches, deciding on high-level architecture, writing specifications, defining success criteria, &lt;a href="https://simonwillison.net/2025/Sep/30/designing-agentic-loops/" rel="noopener noreferrer"&gt;designing agentic loops&lt;/a&gt;, planning QA, managing a growing army of weird digital interns who will absolutely cheat if you give them a chance, and spending so much time on code review.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;You are responsible for what LLMs generate:&lt;/p&gt;

&lt;p&gt;&lt;a href="//./assets/vibe-engineering-resposible-use-of-llms/claude-security-note.png"&gt;You are responsible for what LLMs generate&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Happy engineering.&lt;/em&gt; 🚀&lt;/p&gt;




&lt;h2&gt;
  
  
  The Evolution of AI Coding 🐒➡️🧍
&lt;/h2&gt;

&lt;p&gt;So I believe we all started from vibe coding, then start to see the short comings and became skeptical. That was when I believe most of us started to "plan, execute, and review" what LLMs write as oppose to YOLO mode where you just let LLM do whatever. But for me the key takeaway is (from the &lt;em&gt;Jellyfin&lt;/em&gt; post):  &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The golden rule is this: &lt;strong&gt;do not just let an LLM loose on the codebase with a vague vibe prompt and then commit the results as-is&lt;/strong&gt;. This is lazy development, will &lt;strong&gt;always&lt;/strong&gt; result in a &lt;strong&gt;poor-quality contribution&lt;/strong&gt; from our perspective, and we are not at all interested in such slop. &lt;strong&gt;Make an effort&lt;/strong&gt; or please do not bother. And again, you are free to use LLMs to assist you, but not as the sole source of code changes.&lt;/p&gt;

&lt;p&gt;— &lt;a href="https://jellyfin.org/docs/general/contributing/llm-policies/" rel="noopener noreferrer"&gt;Ref&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In short it is &lt;strong&gt;your job&lt;/strong&gt; and &lt;strong&gt;my job&lt;/strong&gt; to deliver code that we are &lt;strong&gt;accountable&lt;/strong&gt; for.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Vibe Engineering Mindset
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;✅ &lt;strong&gt;Automated testing&lt;/strong&gt;: write and make sure to write tests who are valuable and serve as a spec for your code.&lt;/li&gt;
&lt;li&gt;✅ &lt;strong&gt;Planning in advance&lt;/strong&gt;: make sure to write a &lt;code&gt;plan.md&lt;/code&gt; always and review it first. There you can break a big task into smaller chunks and potentially you can finish each step separately in a fresh context window (although you might wanna read &lt;a href="https://gist.github.com/kasir-barati/38da1204d1aa79e2cce487df4a1cf220/" rel="noopener noreferrer"&gt;this gist about costs&lt;/a&gt; first).&lt;/li&gt;
&lt;li&gt;✅ &lt;strong&gt;Comprehensive documentation&lt;/strong&gt;: make sure to document what matters and do NOT let LLMs to write whatever they wanted. In my experience they tend to go rogue and just write a ton o stuff. Make sure to look at my &lt;a href="https://gist.github.com/kasir-barati/7de961cbbefb8f18bb8683cade5773f5" rel="noopener noreferrer"&gt;AGENTS.md&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;✅ &lt;strong&gt;Good version control&lt;/strong&gt;: in Claude they just create snapshots (essentially they are just git stashes) before making changes after receiving a prompt. We can do it too, e.g. when you wanna diverge and make a drastic change you can stash your changes and then refactor.&lt;/li&gt;
&lt;li&gt;✅ &lt;strong&gt;Code review&lt;/strong&gt;: make the LLM review its own work. Usually you might wanna ask a different LLM to do the code review. So you are getting a second opinion.&lt;/li&gt;
&lt;li&gt;✅ &lt;strong&gt;A weird form of management&lt;/strong&gt;: getting good results feels like managing a human collaborator, but with quirks.&lt;/li&gt;
&lt;li&gt;✅ &lt;strong&gt;Manual QA&lt;/strong&gt;: don't rely only on automation entirely. Test things yourself before asking QA team to take over.&lt;/li&gt;
&lt;li&gt;✅ &lt;strong&gt;Strong research skills&lt;/strong&gt;: when you hit a wall, step back and try a different approach. Try to start fresh, it really sometimes can help. You cn see a prime example of this &lt;a href="https://gist.github.com/kasir-barati/38da1204d1aa79e2cce487df4a1cf220/" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;✅ &lt;strong&gt;Instinct for what to keep an eye on&lt;/strong&gt;, when we have:

&lt;ul&gt;
&lt;li&gt;A pretty standard &lt;strong&gt;frontend&lt;/strong&gt; we can delegate freely. The LLM will build it, you give feedback, it improves.&lt;/li&gt;
&lt;li&gt;But &lt;strong&gt;Backend&lt;/strong&gt; is different beast. LLMs often struggle, make bad design decisions, violate DRY principle, use tools that are not the best options out there.&lt;/li&gt;
&lt;li&gt;Also writing sensible tests sometimes prove to be difficult for LLMs.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Estimating Tickets/Features
&lt;/h2&gt;

&lt;p&gt;In &lt;a href="https://www.mindstudio.ai/blog/software-1-0-2-0-3-0-ai-programming-paradigm" rel="noopener noreferrer"&gt;software 1.0&lt;/a&gt; we had most of the times a got feeling &amp;amp; some criteria as to how to estimate how much effort goes into developing it. But now we have LLMs which can generate 5000 lines of code in minutes until you hit a road blocker such as LLMs going rogue, a complicated/complex feature is not working due to some tiny decision LLM made (in short it is a logical issue).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;So do NOT get caught up in the hype about 10x productivity boost&lt;/strong&gt;.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>llm</category>
      <category>productivity</category>
    </item>
    <item>
      <title>Switched to VCS Instead of the Crappy UI of DEV.to</title>
      <dc:creator>Mohammad Jawad (Kasir) Barati</dc:creator>
      <pubDate>Sat, 22 Aug 2026 08:39:38 +0000</pubDate>
      <link>https://dev.to/kasir-barati/switched-to-vcs-instead-of-the-crappy-ui-of-devto-26p4</link>
      <guid>https://dev.to/kasir-barati/switched-to-vcs-instead-of-the-crappy-ui-of-devto-26p4</guid>
      <description>&lt;h2&gt;
  
  
  How this Started?
&lt;/h2&gt;

&lt;p&gt;I initially wrote a post on DEV.to a couple of days ago (2026.08.17). Then today (2026.08.21) I edited it. But then DEV.to jumbled it up.&lt;/p&gt;

&lt;h2&gt;
  
  
  Solution
&lt;/h2&gt;

&lt;p&gt;I asked Deepseek about what I can do, it suggested to using Wordpress, or Ghost. But when I asked it that even those platforms are 3rd part solutions and I might end up seeing the same thing. So I asked it how can I utilize git and VCS instead. Then it said to me about gitops for blogging approach. Then when I googled it I found this post: &lt;a href="https://dev.to/kanywst/hello-world-managing-devto-articles-with-gitops-5594"&gt;https://dev.to/kanywst/hello-world-managing-devto-articles-with-gitops-5594&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;So kudos to &lt;a href="https://dev.to/kanywst"&gt;kanywst&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;You can see how the repo looked like when I started it here:&lt;/p&gt;

</description>
      <category>blogging</category>
      <category>gitops</category>
    </item>
    <item>
      <title>Stop Copy-Pasting Parts in Docker Compose</title>
      <dc:creator>Mohammad Jawad (Kasir) Barati</dc:creator>
      <pubDate>Thu, 20 Aug 2026 03:46:23 +0000</pubDate>
      <link>https://dev.to/kasir-barati/stop-copy-pasting-parts-in-docker-compose-71m</link>
      <guid>https://dev.to/kasir-barati/stop-copy-pasting-parts-in-docker-compose-71m</guid>
      <description>&lt;p&gt;Imagine you have a complex microservice. For local development, you need it connected to a message queue, a telemetry collector, and a database. But for your E2E testing, you need a slightly modified version (different env vars, an extra mock dependency, maybe a different port).&lt;/p&gt;

&lt;p&gt;Most engineers solve this by maintaining two massive, almost-identical YAML files. It is a nightmare to sync changes.&lt;/p&gt;

&lt;p&gt;Or they simply do this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;docker compose &lt;span class="nt"&gt;-f&lt;/span&gt; compose.yml &lt;span class="nt"&gt;-f&lt;/span&gt; e2e-compose.yml up &lt;span class="nt"&gt;--build&lt;/span&gt; &lt;span class="nt"&gt;-d&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I do NOT like neither of them. Instead use &lt;a href="https://support.atlassian.com/bitbucket-cloud/docs/yaml-anchors/" rel="noopener noreferrer"&gt;YAML Anchors (&amp;amp;)&lt;/a&gt;, &lt;a href="https://yaml.org/type/merge.html" rel="noopener noreferrer"&gt;Merge Keys (&amp;lt;&amp;lt;:)&lt;/a&gt;, and Compose Profiles to create a single, DRY (Don't Repeat Yourself) configuration file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# ------------------------------------------------------------&lt;/span&gt;
&lt;span class="c1"&gt;# 1. REUSABLE BUILDING BLOCKS (Anchors)&lt;/span&gt;
&lt;span class="c1"&gt;# ------------------------------------------------------------&lt;/span&gt;
&lt;span class="na"&gt;x-backend-depends-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="nl"&gt;&amp;amp;backend-depends-on&lt;/span&gt;
  &lt;span class="na"&gt;message-queue&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;condition&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;service_healthy&lt;/span&gt;
  &lt;span class="na"&gt;telemetry-collector&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;condition&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;service_started&lt;/span&gt;

&lt;span class="na"&gt;x-backend-config&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="nl"&gt;&amp;amp;backend-config&lt;/span&gt;
  &lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;.&lt;/span&gt;
  &lt;span class="na"&gt;user&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;1000:1000"&lt;/span&gt;
  &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;3000:$PORT"&lt;/span&gt;
  &lt;span class="na"&gt;env_file&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;.env&lt;/span&gt;
  &lt;span class="na"&gt;healthcheck&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;test&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;CMD"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;curl"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;-f"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;http://localhost:${PORT:-3000}/health"&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
    &lt;span class="na"&gt;interval&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;5s&lt;/span&gt;
    &lt;span class="na"&gt;timeout&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;5s&lt;/span&gt;
    &lt;span class="na"&gt;retries&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;12&lt;/span&gt;
    &lt;span class="na"&gt;start_period&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;10s&lt;/span&gt;
  &lt;span class="na"&gt;depends_on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;*app-depends-on&lt;/span&gt;

&lt;span class="c1"&gt;# ------------------------------------------------------------&lt;/span&gt;
&lt;span class="c1"&gt;# 2. SERVICES&lt;/span&gt;
&lt;span class="c1"&gt;# ------------------------------------------------------------&lt;/span&gt;
&lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="c1"&gt;# --- Production / Dev Service ---&lt;/span&gt;
  &lt;span class="na"&gt;backend&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;*backend-config&lt;/span&gt;
    &lt;span class="na"&gt;profiles&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;dev"&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;

  &lt;span class="c1"&gt;# --- E2E Test Variant ---&lt;/span&gt;
  &lt;span class="na"&gt;backend-e2e&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;*app-config&lt;/span&gt;
    &lt;span class="na"&gt;profiles&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;e2e"&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;   &lt;span class="c1"&gt;# Only starts when explicitly called&lt;/span&gt;
    &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;        &lt;span class="c1"&gt;# Override specific ENV vars for testing&lt;/span&gt;
      &lt;span class="na"&gt;RETRY_DELAY_MS&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;100"&lt;/span&gt;
      &lt;span class="na"&gt;TIMEOUT_MS&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;200"&lt;/span&gt;
    &lt;span class="na"&gt;depends_on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;*app-depends-on&lt;/span&gt;            &lt;span class="c1"&gt;# Inherit all base dependencies&lt;/span&gt;
      &lt;span class="na"&gt;e2e-fixture&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;                   &lt;span class="c1"&gt;# ADD an extra dependency for testing&lt;/span&gt;
        &lt;span class="na"&gt;condition&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;service_healthy&lt;/span&gt;
  &lt;span class="c1"&gt;# ...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So now how this changes your workflow:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Local: &lt;code&gt;docker compose --profile dev up&lt;/code&gt; starts only backend + services in default/dev profile.&lt;/li&gt;
&lt;li&gt;E2E testing: &lt;code&gt;docker compose --profile e2e up&lt;/code&gt; automatically swaps in backend-e2e, overrides timeouts/retries.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>docker</category>
      <category>yaml</category>
      <category>programming</category>
    </item>
    <item>
      <title>Designing Fault-Tolerant Async Architectures</title>
      <dc:creator>Mohammad Jawad (Kasir) Barati</dc:creator>
      <pubDate>Fri, 14 Aug 2026 16:25:17 +0000</pubDate>
      <link>https://dev.to/kasir-barati/designing-failure-tolerant-asynchronous-work-9a3</link>
      <guid>https://dev.to/kasir-barati/designing-failure-tolerant-asynchronous-work-9a3</guid>
      <description>&lt;p&gt;Building an asynchronous TTS endpoint sounds straightforward: accept some text, return the job ID, generate the audio in the background, and upload the result to a presigned URL.&lt;/p&gt;

&lt;p&gt;The interesting part starts when you wonder what should you do:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;When things fail:

&lt;ul&gt;
&lt;li&gt;What happens if your messaging broker restarts while a worker is processing a job? &lt;/li&gt;
&lt;li&gt;What happens if the service restarts?&lt;/li&gt;
&lt;li&gt;Who should be responsible for retrying when the presigned URL expires?&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;About responsibilities of each service?&lt;/li&gt;
&lt;li&gt;About retries?&lt;/li&gt;
&lt;li&gt;Around observability topic?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This post explores one deliberately simple design for answering those questions without turning a small asynchronous service into a distributed-systems science project 😉.&lt;/p&gt;

&lt;h2&gt;
  
  
  tl;dr
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;POST /synthesize&lt;/code&gt; endpoint returns 202 HTTP status code.

&lt;ul&gt;
&lt;li&gt;This means "the request has been accepted for asynchronous processing".&lt;/li&gt;
&lt;li&gt;This does &lt;strong&gt;NOT&lt;/strong&gt; mean "this operation will definitely complete".&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;RabbitMQ is used as durable, persistent job state, so we won't be losing any message.&lt;/li&gt;
&lt;li&gt;The client owns the output destination. It supplies the presigned URL; the TTS service simply uploads to it.&lt;/li&gt;
&lt;li&gt;Instead of client asking about a job, I reversed the data flow. In other words TTS service now is sending the state of a job to the client.&lt;/li&gt;
&lt;li&gt;The client is responsible for choosing a presigned URL with a suitable lifetime. The TTS service should measure how long TTS generation takes and whether uploads fail, so you can detect if the service is routinely taking longer than the URLs remain valid.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  The Service
&lt;/h2&gt;

&lt;p&gt;Let's start with a deliberately small API. The client sends:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight http"&gt;&lt;code&gt;&lt;span class="err"&gt;POST /synthesize
Content-Type: application/json

{
  "text": "Hello world, this is a test of the asynchronous synthesis API.",
  "genUploadUrl": "https://your-server.example/generate-upload-url",
  "statusCallbackUrl": "https://your-server.example/synthesis-status"
}
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The service immediately responds:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight http"&gt;&lt;code&gt;&lt;span class="k"&gt;HTTP&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="m"&gt;1.1&lt;/span&gt; &lt;span class="m"&gt;202&lt;/span&gt; &lt;span class="ne"&gt;Accepted&lt;/span&gt;
&lt;span class="na"&gt;Content-Type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;application/json&lt;/span&gt;

&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"jobId"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"550e8400-e29b-41d4-a716-446655440000"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;HTTP &lt;code&gt;202 Accepted&lt;/code&gt; is specifically intended for requests that have been accepted for processing but whose processing has not completed yet. The important part is that 202 is intentionally non-committal.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;"Non-committal" does not mean that 202 is a bad or unreliable response.&lt;/p&gt;

&lt;p&gt;It means that the HTTP response does not commit the server to a particular eventual outcome.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://owasp.org/www-community/attacks/Server_Side_Request_Forgery" rel="noopener noreferrer"&gt;&lt;strong&gt;Server-Side Request Forgery&lt;/strong&gt; Attack&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;Traffic between services could be intercepted/tampered on the way. That is exactly why you need to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Reject loopback/private/link-local after DNS resolution: if &lt;code&gt;statusCallbackUrl&lt;/code&gt;/&lt;code&gt;genUploadUrl&lt;/code&gt; is attacker-influenced in any way (or even just misconfigured), you must resolve the hostname to an IP before connecting and check the actual IP isn't 127.0.0.1, 169.254.x.x, 10.x.x.x, 192.168.x.x, etc.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Checking the hostname string alone isn't enough because DNS rebinding lets a public-looking hostname resolve to an internal IP. This matters because TTS service is about to make an outbound HTTP call to a URL it didn't choose. That's the textbook SSRF setup.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Allow-list: since we can enumerate valid callback hosts ahead of time (it's a known service), just allow-list them and skip most of the DNS-resolution complexity.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Callback Authentication
&lt;/h3&gt;

&lt;p&gt;This is about proving the callback is legitimate when TTS service calls whoever who is on the receiving end.&lt;/p&gt;

&lt;p&gt;When client calls &lt;code&gt;POST /synthesize&lt;/code&gt;, it includes a token in the &lt;a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Authorization" rel="noopener noreferrer"&gt;Authorization header&lt;/a&gt;, TTS service adds it as an extra header to the message published on RabbitMQ.&lt;/p&gt;

&lt;p&gt;So when TTS service later calls back client, it echoes that same token back. Client then checks the token matches what it issued for that job before trusting the callback payload.&lt;/p&gt;

&lt;p&gt;Why this is simpler than PAT/token exchange?&lt;/p&gt;

&lt;p&gt;&lt;a href="https://zitadel.com/blog/new-personal-access-token" rel="noopener noreferrer"&gt;PATs&lt;/a&gt; and &lt;a href="https://www.keycloak.org/securing-apps/token-exchange#_standard-token-exchange" rel="noopener noreferrer"&gt;token exchange&lt;/a&gt; solve a different problem: "how does Service B authenticate itself as an identity to call arbitrary APIs on Service A, with scoped permissions, revocability, audit trails tied to a principal".&lt;/p&gt;

&lt;p&gt;That's real infrastructure for a general-purpose service-to-service trust relationship. What I need here is much narrower: client service needs to verify that a callback claiming to be about &lt;code&gt;jobId=123&lt;/code&gt; is actually about the job it submitted, not an attacker (or a misbehaving other tenant) spoofing a callback.&lt;/p&gt;

&lt;p&gt;That's not identity, it's a per-job shared secret, more like a webhook signing secret than an OAuth token. This is exactly the same pattern every webhook-based system uses, and none require the receiver to know which IdP the client service uses.&lt;/p&gt;

&lt;h2&gt;
  
  
  System Boundaries
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;TTS service&lt;/th&gt;
&lt;th&gt;Client&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Accepts the TTS request&lt;/td&gt;
&lt;td&gt;Owns the request ID&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Generates the audio&lt;/td&gt;
&lt;td&gt;Dictates the output destination&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Reports success/failure&lt;/td&gt;
&lt;td&gt;Generates the presigned URL&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Tries to upload&lt;/td&gt;
&lt;td&gt;Handles the retry logic&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The benefits of this system design:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The TTS service doesn't need to know anything about the client's storage architecture.&lt;/li&gt;
&lt;li&gt;Simpler than having an outbox/inbox pattern. Instead of saying we should NOT reprocess the same job twice we say we do NOT care. We process it anyway. But of course this is possible since we are offloading the whole logic of retry and what if we override a newer version of text with an older one to the client which does make sense to me.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Why RabbitMQ?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;DLQ feature.&lt;/li&gt;
&lt;li&gt;Easy to scale by utilizing KEDA.&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Tip&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In TTS service when you pick up a message from RabbitMQ to process you have to think about when to NOT retry and drop the message. So when we call the callbacks and get a:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;4xx in general = client error = "this request is malformed and retrying it unchanged won't help." A 400 on our callback because the payload doesn't match client's schema, a 404 because the job was deleted on client's side, a 401/403 because the token is wrong. None of these get better by trying again in 30 seconds. Retrying them just burns our attempt budget on something that will fail identically three times.&lt;/li&gt;
&lt;li&gt;408 (Request Timeout) and 429 (Too Many Requests) are the exceptions because they're not really about our request being wrong, they're the server saying "I couldn't process this in time" or "slow down, I'm rate-limiting you." Both are explicitly transient by design (429 typically comes with a Retry-After header for exactly this reason) worth honoring that header if present rather than always waiting our fixed 30s, since Service A is telling you exactly how long to back off.&lt;/li&gt;
&lt;li&gt;5xx and network errors (timeouts, connection refused) are always retryable, these mean the server (or network) failed, not that our request was invalid, so retrying is the correct default behavior for all of them, no exceptions to enumerate the way there is for 4xx.&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Presigned URL Expiration
&lt;/h2&gt;

&lt;p&gt;A presigned URL is intentionally temporary. The client creates the URL, so the client is responsible for choosing an appropriate lifetime.&lt;/p&gt;

&lt;p&gt;This way we have two benefits:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;If our TTS service if takes too long to generate and upload the audio file we can look at the logs (OTel is crucial) and see the issue. For example it might be our service whom is too slow or maybe our code is implemented poorly.&lt;/li&gt;
&lt;li&gt;Client gets to choose different TTL for each presigned URL based on how many words we have, load, etc. In other words we have more room to maneuver.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Observability
&lt;/h2&gt;

&lt;p&gt;For an asynchronous service like this, I'd want traces and metrics around at least these phases:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;request accepted
    │
    ▼
job queued
    │
    ▼
job started
    │
    ▼
TTS generation started
    │
    ▼
TTS generation finished
    │
    ▼
upload started
    │
    ▼
upload finished
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And when I say I want traces and metrics I am talking about:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Queue wait time. &lt;/li&gt;
&lt;li&gt;TTS generation duration. &lt;/li&gt;
&lt;li&gt;Upload duration. &lt;/li&gt;
&lt;li&gt;Total job duration. &lt;/li&gt;
&lt;li&gt;Job failures. &lt;/li&gt;
&lt;li&gt;Redis failures. &lt;/li&gt;
&lt;li&gt;Upload failures. &lt;/li&gt;
&lt;li&gt;Expired/rejected presigned URLs. &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And this is where OTel really shines.&lt;/p&gt;

&lt;h3&gt;
  
  
  Trace-to-Log
&lt;/h3&gt;

&lt;p&gt;So I wanted to have the ability to connect a log and trace. Thus I switched to Grafana stack: Tempo for traces, Loki for logs, Grafana for visualization and OTel collector for collecting and sending logs /traces to Grafana.&lt;/p&gt;

&lt;p&gt;And man, I love the outcome:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://dev-to-uploads.s3.us-east-2.amazonaws.com/uploads/articles/cw53blqwd00v62ijwkwt.png" rel="noopener noreferrer"&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%2Faxkttfw1adnh9bk25z1m.png" alt="Search for a trace or select one in Explorer" width="799" height="398"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://dev-to-uploads.s3.us-east-2.amazonaws.com/uploads/articles/0iiuyill7ixsv9b57h5j.png" rel="noopener noreferrer"&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%2Fwu6nqnyqs346qex7unhw.png" alt="Click on Logs for this span button" width="800" height="434"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://dev-to-uploads.s3.us-east-2.amazonaws.com/uploads/articles/048pvrcw6lic4f4i0pxx.png" rel="noopener noreferrer"&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%2F7jl3rmt535q24kkrztme.png" alt="Now you should be able to see the logs" width="800" height="431"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What About Duplicate TTS Generation?
&lt;/h2&gt;

&lt;p&gt;The client decides where the generated audio should go by providing the presigned URL. In short client handles where it wanted to store the final result.&lt;/p&gt;

&lt;p&gt;So client can generate presigned URLs for the same job to upload them to the same place, effectively overriding the old results. But this is a decision that client has to make!&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Tip&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Overriding is fine even if you need a durable audit trail. I mean client can handle that on its own. The TTS service should NOT concern itself with that.&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;┌────────────────────────────┐
| more guarantees            |      ┌───────────────────────────┐
|        │                   |      | simpler system            |
|        ▼                   |      |       │                   |
| more state                 |      |       ▼                   |
| more coordination          |  VS. | occasional duplicate work |
| more complexity            |      |       │                   |
| more failure modes         |      |       ▼                   |
|        │                   |      | client-driven retry       |
|        ▼                   |      └───────────────────────────┘
| fewer duplicate operations |
└────────────────────────────┘
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  When This Design Stops Being Good Enough
&lt;/h2&gt;

&lt;p&gt;This approach isn't universal. For example if:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Duplicate work is unacceptable:

&lt;ul&gt;
&lt;li&gt;For example the TTS generation is expensive. Expensive can mean scenarios such as:

&lt;ul&gt;
&lt;li&gt;Jobs can run for hours.&lt;/li&gt;
&lt;li&gt;We make external API calls.&lt;/li&gt;
&lt;li&gt;It is computationally intensive.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Or imagine your are charging customers for each TTS generation, and if we do that for no reason they will soon enough realize it.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Every accepted request must eventually complete.&lt;/li&gt;
&lt;li&gt;Clients cannot safely retry.&lt;/li&gt;
&lt;li&gt;The output operation has irreversible side effects.&lt;/li&gt;
&lt;li&gt;You need exactly-once-like business semantics.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  GitHub
&lt;/h2&gt;

&lt;p&gt;My &lt;a href="https://github.com/kasir-barati/piper-tts-rest-api" rel="noopener noreferrer"&gt;piper-tts-rest-api&lt;/a&gt; project has this architecture implemented: &lt;a href="https://github.com/kasir-barati/piper-tts-rest-api/compare/v3.0.0...v4.0.0" rel="noopener noreferrer"&gt;https://github.com/kasir-barati/piper-tts-rest-api/compare/v3.0.0...v4.0.0&lt;/a&gt;&lt;/p&gt;

</description>
      <category>systemdesign</category>
      <category>microservices</category>
      <category>architecture</category>
      <category>programming</category>
    </item>
    <item>
      <title>Pragmatic Agentic Programmer</title>
      <dc:creator>Mohammad Jawad (Kasir) Barati</dc:creator>
      <pubDate>Fri, 14 Aug 2026 01:05:41 +0000</pubDate>
      <link>https://dev.to/kasir-barati/pragmatic-agentic-programmer-994</link>
      <guid>https://dev.to/kasir-barati/pragmatic-agentic-programmer-994</guid>
      <description>&lt;p&gt;The rise of LLMs has been explosive. Tools like Claude Code and GitHub Copilot give both seasoned devs and juniors superpowers. But there's a catch.&lt;/p&gt;

&lt;p&gt;Two deep‑dives (&lt;a href="https://www.anthropic.com/research/AI-assistance-coding-skills" rel="noopener noreferrer"&gt;one from Anthropic&lt;/a&gt;, one from the &lt;a href="https://jellyfin.org/docs/general/contributing/llm-policies/" rel="noopener noreferrer"&gt;Jellyfin project&lt;/a&gt;) lay out the uncomfortable trade‑offs we all need to see and keep in mind.&lt;/p&gt;

&lt;h2&gt;
  
  
  tl;dr
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;AI is a tool, NOT a replacement&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Be able to explain the architecture and code without the LLM.&lt;/li&gt;
&lt;li&gt;Test and iterate manually.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  &lt;a href="https://www.anthropic.com/research/AI-assistance-coding-skills" rel="noopener noreferrer"&gt;Anthropic Study&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;In a study ran by Anthropic with this setup:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;52 junior developers were split into two groups.&lt;/li&gt;
&lt;li&gt;Both had to learn an unfamiliar Python library (Trio for async programming).&lt;/li&gt;
&lt;li&gt;One group used AI assistants; the other didn't.&lt;/li&gt;
&lt;li&gt;After completing a coding task, everyone took a quiz on the library.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The results were striking:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://dev-to-uploads.s3.us-east-2.amazonaws.com/uploads/articles/uc7sihyvavpy03ehp5o2.png" rel="noopener noreferrer"&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%2Fmeohecimv93ri7y2es9l.png" alt="AI‑assisted group average quiz score: 50%. Unaided group average quiz score: 67%." width="799" height="431"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The AI group had only a small productivity gain on the task itself, but a significant negative impact on learning. The tool let them skip the deep understanding that comes from struggling through the code.&lt;/p&gt;

&lt;p&gt;That's a sobering wake-up call for anyone who leans on AI for every &lt;br&gt;
line!&lt;/p&gt;

&lt;p&gt;But I believe we can still mitigate this to some extend by prompting LLM with something like this for a ReactJS project:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Please now write me a comprehensive tutorial in Markdown that's suitable for a complete beginner in frontend coding to walk me through what you've done here. Include a summary of the technology, a high-level walkthrough, a detailed code review with code samples, and end with five suggestions for the ways the code could be improved based on a self-review.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In fact this would go nicely hand in hand with what "Jellyfin Guideline" ask devs to be able to do.&lt;/p&gt;




&lt;h2&gt;
  
  
  &lt;a href="https://jellyfin.org/docs/general/contributing/llm-policies/" rel="noopener noreferrer"&gt;Jellyfin Guideline&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/jellyfin/jellyfin" rel="noopener noreferrer"&gt;The Jellyfin project&lt;/a&gt; (a popular open‑source media platform) recently published a policy for AI‑generated code contributions. It’s refreshingly blunt.&lt;/p&gt;

&lt;p&gt;They start by acknowledging the rise of LLMs, but then:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;We are seeing a precipitous rise in contributors using AI … as well as criticism and concern about LLMs generally.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Here's the golden rule from their policy:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Do not just let an LLM loose on the codebase with a vague vibe prompt and then commit the results as is. This is lazy development and will always result in a poor quality contribution … we are not at all interested in such slop.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Their full guidelines (paraphrased):&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Rule&lt;/th&gt;
&lt;th&gt;Why&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;No LLM output in communication (issues, PRs, forum posts) - except for translations&lt;/td&gt;
&lt;td&gt;Avoids noise and extra work for other devs&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;PRs must be concise &amp;amp; focused - if it touches unrelated files, it’s rejected&lt;/td&gt;
&lt;td&gt;Prevents shotgun‑blast changes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;You must be able to explain every change without referencing the LLM&lt;/td&gt;
&lt;td&gt;Ensures you actually understand the code&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Test your code, follow formatting, and break PRs into small commits&lt;/td&gt;
&lt;td&gt;Basic quality hygiene&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Reviewers have final discretion - they don’t care if it’s AI‑generated; they care about quality&lt;/td&gt;
&lt;td&gt;Quality over source&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;And the kicker:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;If you &lt;strong&gt;can't&lt;/strong&gt; explain what the LLM did, we are not interested in the change.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Open Question
&lt;/h2&gt;

&lt;p&gt;So I believe the fair question now would be YOLO mode vs. owning the Code.&lt;/p&gt;

&lt;p&gt;Many of us love the YOLO vibe - just let the agent go and watch the magic happen. And that's fun, and often effective. But there's an asymmetry:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It takes seconds to generate hundreds of lines of AI code.&lt;/li&gt;
&lt;li&gt;It takes hours/days for another devs or you to review, understand, and fix that code if something goes wrong.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The Jellyfin policy is a stand against that asymmetry. It says: "Make an effort, or please do not bother".&lt;/p&gt;

</description>
      <category>ai</category>
      <category>programming</category>
      <category>pragmatism</category>
    </item>
    <item>
      <title>Agentic Programming -- Principles for Successful Vibe Engineering</title>
      <dc:creator>Mohammad Jawad (Kasir) Barati</dc:creator>
      <pubDate>Thu, 13 Aug 2026 22:52:10 +0000</pubDate>
      <link>https://dev.to/kasir-barati/agentic-programming-principles-for-successful-vibe-engineering-p3c</link>
      <guid>https://dev.to/kasir-barati/agentic-programming-principles-for-successful-vibe-engineering-p3c</guid>
      <description>&lt;p&gt;In this post, I cover the five core principles for effective AI agentic engineering. The golden rule? Always "be the boss." From writing a concise &lt;code&gt;AGENTS.md&lt;/code&gt;/&lt;code&gt;PLAN.md&lt;/code&gt;/prompt to &lt;strong&gt;staying skeptical&lt;/strong&gt; and managing expectations.&lt;/p&gt;

&lt;p&gt;Also keep in mind it does NOT matter if you are senior/junior developer.&lt;/p&gt;




&lt;p&gt;If you’ve been experimenting with AI coding assistants (Claude, Cursor, etc.), you've likely experienced both wonder and frustration 😉. For me there were times when the assistant one shot a feature in minutes, and other times when it got stuck in a loop of repeated mistakes.&lt;/p&gt;

&lt;h2&gt;
  
  
  Spend Time on Your &lt;code&gt;AGENTS.md&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;This is your project's command center. Keep it concise and structured around:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The style of your project: define the coding style, architecture, and approach.&lt;/li&gt;
&lt;li&gt;A short intro into the project/repo.&lt;/li&gt;
&lt;li&gt;Project structure.&lt;/li&gt;
&lt;li&gt;Testing strategies.&lt;/li&gt;
&lt;li&gt;Limitations and constraints you want LLM to always keep in mind.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I have seen &lt;a href="https://github.com/xixu-me/xget/blob/main/CLAUDE.md" rel="noopener noreferrer"&gt;this example on GitHub&lt;/a&gt; which can give you a good sense of what you might wanna have. But keep in mind it is not Bible.&lt;/p&gt;

&lt;h2&gt;
  
  
  Spend Time on Your Prompt
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Section&lt;/th&gt;
&lt;th&gt;Purpose&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Spec&lt;/td&gt;
&lt;td&gt;Clearly define what needs to be built.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Success Criteria&lt;/td&gt;
&lt;td&gt;State exactly how success will be measured.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Work Incrementally
&lt;/h2&gt;

&lt;p&gt;Stay disciplined:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Start simple.&lt;/li&gt;
&lt;li&gt;Work step-by-step.&lt;/li&gt;
&lt;li&gt;Validate success criteria after every major change.&lt;/li&gt;
&lt;li&gt;Create a feedback loop: Test → Fix → Iterate.

&lt;ul&gt;
&lt;li&gt;Iterations can be adding more features, cleaning up, addressing known bugs or todos.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This way we ensure that we never progress more than a few steps beyond a known-good state.&lt;/p&gt;

&lt;p&gt;But before going into more details I would like to first have a definition for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Complicated/deterministic&lt;/strong&gt;: many parts, but the relationships between them are sufficiently predictable that expertise can determine how to solve the problem.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Complex/adaptive&lt;/strong&gt;: many interacting parts whose behavior changes in response to one another, so you cannot reliably determine the solution in advance.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You might have heard of "don't boil the ocean" idiom. Based on what I have &lt;strong&gt;read&lt;/strong&gt; this is a good advice for deterministic problems but &lt;strong&gt;NOT&lt;/strong&gt; for adaptive problems. And &lt;strong&gt;honestly I believe it is spot on&lt;/strong&gt; with a small deviation, we will talk about this shortly.&lt;/p&gt;

&lt;p&gt;I just like to start with a some examples of what I consider complex and what is complicated &lt;strong&gt;in this context&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Complex/adaptive problem to solve:

&lt;ul&gt;
&lt;li&gt;How does this entire system behave under changing traffic, failures, retries, recovery, scaling, network availability, and the behavior of hundreds of independent robots?.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Complicated/deterministic problem to solve:

&lt;ul&gt;
&lt;li&gt;We need idempotency because RabbitMQ may deliver an event twice.&lt;/li&gt;
&lt;li&gt;How do we guarantee a data isn't lost if the robot loses power during upload?&lt;/li&gt;
&lt;li&gt;How do we ensure event ordering in an event-driven architecture?&lt;/li&gt;
&lt;li&gt;How do we implement exactly-once event processing in an event-driven architecture?&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So, for adaptive problems, you need to discern the overall architecture and consider what might go wrong - obviously, we can't cover or anticipate every single scenario - but you should still try to form a coherent plan that addresses the most likely issues.&lt;/p&gt;

&lt;p&gt;Once you have that plan, you should be able to break it down into smaller, implementable steps. This is what I meant by "a small deviation". However, now that I think about it, I suppose you might be applying the same approach even to complicated/deterministic issues, since this way of thinking helps you maintain a broader perspective.&lt;/p&gt;

&lt;h3&gt;
  
  
  Deterministic Problems
&lt;/h3&gt;

&lt;p&gt;So if I had to give you a concrete example I would say "migrating a 10 TB PostgreSQL database to a new cluster with zero data loss and less than 30 seconds of downtime." is a deterministic/complicated problem since there may be:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Thousands of tables.&lt;/li&gt;
&lt;li&gt;Replication.&lt;/li&gt;
&lt;li&gt;Custom extensions.&lt;/li&gt;
&lt;li&gt;Enormous datasets.&lt;/li&gt;
&lt;li&gt;Legacy applications.&lt;/li&gt;
&lt;li&gt;Tricky dependencies.&lt;/li&gt;
&lt;li&gt;Performance constraints.&lt;/li&gt;
&lt;li&gt;Rollback requirements.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The important thing is that the problem doesn't fundamentally change its nature because I am solving it.&lt;/p&gt;

&lt;p&gt;Here we can analyze the system, understand the dependencies, develop a procedure, test it, and execute it. There is a discoverable technical solution and for sure we can break it apart and solve it incrementally (remember, divide and conquer).&lt;/p&gt;

&lt;h3&gt;
  
  
  Adaptive Problems
&lt;/h3&gt;

&lt;p&gt;Imagine you are developing a solution for robots to inspect industrial equipments. The pipeline would be:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Robot
  ↓
Upload inspection
  ↓
Backend
  ↓
"InspectionUploaded" event
  ↓
Message broker
  ↓
Processing service
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And suppose you have 500 robots. Normally:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;100 inspections/minute
        ↓
100 events/minute
        ↓
Downstream processing service keeps up
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Everything is fine. Then your downstream processing service becomes temporarily slow. Perhaps its database is overloaded. So processing goes from:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;100 inspections/min → 60/min
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The queue starts growing. So you have:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Incoming: 100/min
Processing: 60/min

Queue growth: +40/min
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It is still fine and manageable. But now something interesting happens. &lt;strong&gt;The downstream processing service has a timeout&lt;/strong&gt;. When processing takes too long, &lt;strong&gt;it assumes failure&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;So &lt;strong&gt;it retries&lt;/strong&gt;. Now you aren't actually receiving 100 pieces of work per minute anymore. You're receiving:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;100 new inspections
+
40 retries
+
some additional retries from previous failures
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now the service is trying to process 150-200 operations/minute. That makes the database even slower. Which causes more timeouts. Which causes more retries. Which creates even more load.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fr7ge1q89gmqgimonu4ii.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%2Fr7ge1q89gmqgimonu4ii.png" alt="Destructive loop" width="800" height="1167"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now add the robots. This gets even more interesting. Suppose robots normally upload immediately. But a factory has terrible Wi-Fi. So robots store inspections locally and upload them when connectivity returns. At 10:00 AM, connectivity comes back.&lt;/p&gt;

&lt;p&gt;Suddenly:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://dev-to-uploads.s3.us-east-2.amazonaws.com/uploads/articles/h6nxdxeub3qto9uc8pa5.png" rel="noopener noreferrer"&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%2Fes0tx1sz34y2tht4dh7u.png" alt="When robot is uploading its data at once" width="800" height="1163"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now you might say "Every component has sensible behavior. Why is the overall system behaving terribly?".&lt;/p&gt;

&lt;p&gt;Because the interaction between individually reasonable mechanisms can produce behavior that nobody intended.&lt;/p&gt;

&lt;p&gt;And this will be reported as a bug ticket with a description like this:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;At 10:37 AM, the system entered a state where throughput collapsed, retries exploded, queue depth increased exponentially, autoscaling oscillated between 20 and 200 instances, database resource usage spiked, and the system recovered 45 minutes later after traffic naturally decreased.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That's a complex behavior, there may not be one broken component. Instead: &lt;code&gt;A → influences B → influences C → changes A&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;And the overall behavior emerges from those interactions.&lt;/p&gt;

&lt;h2&gt;
  
  
  Don't Get Lazy -- YOLO Trap
&lt;/h2&gt;

&lt;p&gt;LLM gave you a few wins and then you're overconfident in its ability. Suddenly, you ask it to YOLO a big task and come back later, hoping everything worked.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Spoiler alert, it probably won't.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;ul&gt;
&lt;li&gt;Challenge your &lt;strong&gt;assistant&lt;/strong&gt;, even when it sounds confident.&lt;/li&gt;
&lt;li&gt;If the AI says it fixed a bug, ask for evidence, root cause, and test results.&lt;/li&gt;
&lt;li&gt;Don't let your guard down, unless you want your project to derail 😉.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Manage the Frustration
&lt;/h2&gt;

&lt;p&gt;There will be times when the model makes the same mistake repeatedly, despite explicit instructions. You'll want to pull your hair out.&lt;/p&gt;

&lt;p&gt;That's normal 🥲🥹.&lt;/p&gt;

&lt;p&gt;These moments are not signs of failure, they're signs of limitations in the model or hitting context window limitation (imagining the model is NOT compacting it for you automatically). Your role is to detect, manage, and work around them.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Anticipate chaos.&lt;/li&gt;
&lt;li&gt;Treat frustration as a signal to reset or reframe the problem.&lt;/li&gt;
&lt;li&gt;Keep going, this is where real growth happens.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Advise for
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Junior engineers:

&lt;ul&gt;
&lt;li&gt;This is a learning tool - not a replacement for understanding.&lt;/li&gt;
&lt;li&gt;Challenge the AI with questions so you can follow what's happening.&lt;/li&gt;
&lt;li&gt;Stay skeptical. The AI can be confidently wrong 😂.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Senior engineers:

&lt;ul&gt;
&lt;li&gt;You can already smell BS when the AI makes it up (I imagine you are looking at what it is writing).&lt;/li&gt;
&lt;li&gt;Use the tool to do more, not to replace your joy of building.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>ai</category>
      <category>programming</category>
      <category>vibeengineering</category>
    </item>
    <item>
      <title>Agentic Programming -- Picking a Model</title>
      <dc:creator>Mohammad Jawad (Kasir) Barati</dc:creator>
      <pubDate>Thu, 13 Aug 2026 15:06:00 +0000</pubDate>
      <link>https://dev.to/kasir-barati/agentic-programming-picking-a-model-125p</link>
      <guid>https://dev.to/kasir-barati/agentic-programming-picking-a-model-125p</guid>
      <description>&lt;p&gt;Honestly ever since I started using LLMs I was always thinking of how good would it be to have a practical guide to picking the right AI model.&lt;/p&gt;

&lt;p&gt;That's what this post is all about 😁.&lt;/p&gt;

&lt;h2&gt;
  
  
  tl;dr
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Pick intelligence over speed&lt;/strong&gt;: choose the smartest model you can afford. Fast models save time upfront but cost you in debugging hell later.&lt;/li&gt;
&lt;li&gt;YOLO only with frontier models.&lt;/li&gt;
&lt;li&gt;Baby-step everything else, including critical services you wanna vibe engineer.&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I believe I've mentioned this a couple of times already, but just to be absolutely clear: do NOT YOLO a mission-critical service that will be deployed to production.&lt;/p&gt;

&lt;p&gt;If you're deploying to a QA or development environment, and you're confident that even if it fails, the consequences will be limited and won't result in significant harm, loss, or damage to anything of real value, then sure, YOLO away.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Open-source Models
&lt;/h2&gt;

&lt;p&gt;You &lt;strong&gt;must&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Supervise it&lt;/strong&gt;: keep an eye on the diffs.&lt;/li&gt;
&lt;li&gt;The prompt needs to be:

&lt;ul&gt;
&lt;li&gt;Much more precise.&lt;/li&gt;
&lt;li&gt;Much more detailed.&lt;/li&gt;
&lt;li&gt;A clear specification as to what needs to be accomplished.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Also you might not be YOLOing excluding the risk factor. You might have to do more iteration. As of now I have NOT been using open-source models. But I like to know what you think.&lt;/p&gt;

&lt;p&gt;But if you wanna use them like I do like to use them we only have to break a big semi abstract prompt into smaller manageable prompts.&lt;/p&gt;

&lt;h2&gt;
  
  
  💰 The Budget Question
&lt;/h2&gt;

&lt;p&gt;Trying to save money with a cheaper model? Usually that ends up costing more. &lt;strong&gt;Why?&lt;/strong&gt; Because you'll spend hours debugging nonsense outputs, rewriting prompts, and iterating endlessly. That time drain isn't free, and it's mentally exhausting 😑.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>programming</category>
      <category>llm</category>
      <category>agents</category>
    </item>
    <item>
      <title>When LLMs Make You Want to Throw Your Laptop Out the Window</title>
      <dc:creator>Mohammad Jawad (Kasir) Barati</dc:creator>
      <pubDate>Thu, 13 Aug 2026 09:56:41 +0000</pubDate>
      <link>https://dev.to/kasir-barati/when-llms-make-you-want-to-throw-your-laptop-out-the-window-3444</link>
      <guid>https://dev.to/kasir-barati/when-llms-make-you-want-to-throw-your-laptop-out-the-window-3444</guid>
      <description>&lt;p&gt;You are vibe engineering. You type a perfectly reasonable prompt, and the agent responds with utter nonsense. It invents APIs that don't exist, deletes stuff it should not, fix unit tests by changing the code in way that is just pure madness 🥲.&lt;/p&gt;

&lt;h2&gt;
  
  
  Key Takeaway
&lt;/h2&gt;

&lt;p&gt;Remember: the agent is a collaborator, not a magician. Your job is to guide it, correct it, sometimes override it, and verify it's done what it claims. That's what makes you the engineer.&lt;/p&gt;




&lt;p&gt;Now I would walk you through 3 things you can do to get the most out of agentic programming.&lt;/p&gt;

&lt;h2&gt;
  
  
  Patience + Feedback Loop
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Breathe. Seriously, it helps.&lt;/li&gt;
&lt;li&gt;Give specific feedback. Tell the agent why its suggestion is wrong. For example:

&lt;ul&gt;
&lt;li&gt;"The current database design is needlessly expensive, we have this getAllProducs API which defaults to sort by a field which you create inside an aggregation operation. So I would suggest denormalizing the data and storing it in the database since this is a data which is created once but read often."&lt;/li&gt;
&lt;li&gt;"Your code didn't handle the edge case where the array is empty. Please add a guard clause."&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Iterate. The agent learns from your corrections. Often, after a few rounds of back‑and‑forth, it'll converge on a working solution.&lt;/li&gt;
&lt;/ol&gt;

&lt;blockquote&gt;
&lt;p&gt;🆘 &lt;strong&gt;Disclaimer&lt;/strong&gt; 🆘&lt;/p&gt;

&lt;p&gt;I have found myself that sometime I prefer to intervene and change some parts manually since fixing the issue is way faster and productive. Then I just tell the agent I had made some changes and that it should NOT revert them (at least in my experience with Copilot and OpenCode I had to tell it explicitly if I wanted to continue working on that same session/context window).&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Simplify, Simplify, Simplify
&lt;/h2&gt;

&lt;p&gt;This is the single most powerful trick in your arsenal. When the agent spirals into complexity, reduce the scope. &lt;strong&gt;Break your problem into the smallest possible piece that can work and be tested&lt;/strong&gt;, and build from there.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Instead of "build a full Kanban board with drag‑and‑drop, authentication, and real‑time updates", start with: "create a static HTML page that shows three columns".&lt;/li&gt;
&lt;li&gt;Once that works, add "allow moving cards between columns".&lt;/li&gt;
&lt;li&gt;Then add persistence, then auth, then real‑time.&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;💡 &lt;strong&gt;Key Takeaway&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;If you can't get a tiny piece to work, it's unlikely you'll get the whole thing to work.&lt;/li&gt;
&lt;li&gt;And as for big architectural decisions or database design you can always brain storm first with a top model, have a semi-concrete big picture in mind. Then break that big picture into &lt;a href="https://en.wikipedia.org/wiki/SMART_criteria" rel="noopener noreferrer"&gt;SMART&lt;/a&gt; steps.&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Delete, Restart, or Switch
&lt;/h2&gt;

&lt;p&gt;Sometimes, despite your best efforts, the agent is just stuck in a rut. It keeps circling back to the same flawed approach. When that happens:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Delete everything and start fresh. I guess this is a no-brainer, a clean context window whom does NOT have the subtle biases accumulated in the previous context window can save you.&lt;/p&gt;

&lt;p&gt;If you are in the middle of a context window, feel free to summarize and compact the previous context window into a markdown file if you believe you would be needing it.&lt;/p&gt;

&lt;p&gt;Sometime it also is quite helpful when your first shot misses the target, just undo whatever it did. Tweak your prompt/AGENTS.md/plan and ask it again.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;If that fails, switch products. ATM we have an embarrassment of riches: Cursor, GitHub Copilot, Codex, Antigravity, Claude Code, and more. Each has its own strengths and quirks. One might be better at frontend, another at backend.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Never forget&lt;/strong&gt;: you can always fall back to writing code yourself. The agent is a tool, not a replacement for your brain 😉.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://dev-to-uploads.s3.us-east-2.amazonaws.com/uploads/articles/dlwbfep3galx8kxh405i.png" rel="noopener noreferrer"&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%2F15tjv65ajhcgazxwwgc0.png" alt="To make this more concrete, here's a visual decision tree you can keep pinned to your mental whiteboard" width="800" height="678"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Classic Move of LLMs When you Ask them to Fix Something
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;It &lt;strong&gt;guesses&lt;/strong&gt; what the problem is!&lt;/p&gt;

&lt;p&gt;This shows itself even more when you have a logical issue which is not generating any error logs. So you are not able to feed it any logs and you are just asking it and explaining what the problem is.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Changes some code.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Claims victory 🫠.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;I guess you do NOT need me to tell you what will usually happen next, right? The bug is still there!&lt;/p&gt;

&lt;p&gt;The issue is that it &lt;strong&gt;guessed&lt;/strong&gt; the problem, it did NOT &lt;strong&gt;prove&lt;/strong&gt; the problem by reproducing it! Now it should try to fix it (and prove the code which was changed was the root cause of the issue), and finally test and demonstrates it has been fixed!&lt;/p&gt;

&lt;p&gt;So your prompt will be something similar to this:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;...please first reproduce the problem. prove, you've reproduced it. Find the root cause. Fix it. And prove you fixed it.&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>ai</category>
      <category>programming</category>
      <category>llm</category>
    </item>
    <item>
      <title>Agentic Programming -- Basics</title>
      <dc:creator>Mohammad Jawad (Kasir) Barati</dc:creator>
      <pubDate>Thu, 13 Aug 2026 08:20:03 +0000</pubDate>
      <link>https://dev.to/kasir-barati/agentic-programming-basics-2bgb</link>
      <guid>https://dev.to/kasir-barati/agentic-programming-basics-2bgb</guid>
      <description>&lt;h2&gt;
  
  
  What is an LLM?
&lt;/h2&gt;

&lt;p&gt;A Large Language Model like GPT is a statistical pattern-matching engine designed to predict what text should come after an input sequence. Think of it as autocomplete on steroids 😅.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://dev-to-uploads.s3.us-east-2.amazonaws.com/uploads/articles/rmx2b5gpvd1w6pypkub3.png" rel="noopener noreferrer"&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%2F4ar1ktd9f9fpemqbwk4p.png" alt="LLM token prediction" width="800" height="425"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The model:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Takes an input sequence of tokens (chunks of text, often parts of words).&lt;/li&gt;
&lt;li&gt;Outputs probability scores for every possible next token.&lt;/li&gt;
&lt;li&gt;Generates responses one token at a time through a process called inference.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Key Tricks in Agentic Programming
&lt;/h2&gt;

&lt;p&gt;Here are the four tricks we use in agentic programming. In fact these are applicable to any agentic workflow:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://dev-to-uploads.s3.us-east-2.amazonaws.com/uploads/articles/hrvmvww8d0nwyd03l6n4.png" rel="noopener noreferrer"&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%2Fmf8g0x7wew1gto9v4u45.png" alt="4 main trick in agentic programming" width="800" height="375"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Context Engineering
&lt;/h3&gt;

&lt;p&gt;The output of an LLM is based entirely on its input (the "context"). &lt;strong&gt;Getting this right is everything&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://dev-to-uploads.s3.us-east-2.amazonaws.com/uploads/articles/t1sic3oum8ph0d4ze7id.png" rel="noopener noreferrer"&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%2F38ndifg7lacqqo5ns2hz.png" alt="Context window" width="800" height="674"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The context gets rebuilt for each call, you remember about LLMs being stateless, right? So when you use GitHub Copilot the extension constructs and sends the context window.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Turn N: [system + tools + history (reasoning, tools called, etc) + user message]
   ↓
Turn N+1: [system + tools + updated history (reasoning, tools called, etc) + new user message]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I know I am repeating myself, but just to be sure you are getting it: the important distinction is that the model request contains the prior conversation(s) again on the next call, but the new call is &lt;strong&gt;not "the previous request duplicated"&lt;/strong&gt;. It is a new request assembled from the conversation state plus the new material.&lt;/p&gt;

&lt;p&gt;When the context window gets tight (&lt;strong&gt;don't&lt;/strong&gt; wait for it to be &lt;br&gt;
filled to the brim) you have two options:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Summarize everything that as been done in that session and open a new empty session.&lt;/li&gt;
&lt;li&gt;Rely on Claude or whatever you're using yo automatically start a compaction when the estimated request exceeds the context limit ( some even have a configured output/buffer allowance).&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://dev-to-uploads.s3.us-east-2.amazonaws.com/uploads/articles/67ngzygjq8qcp4argrru.png" rel="noopener noreferrer"&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%2Fozjtxwadge1b058sdt0x.png" alt="request compaction" width="800" height="190"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h4&gt;
  
  
  &lt;code&gt;AGENTS.md&lt;/code&gt;
&lt;/h4&gt;

&lt;p&gt;A Markdown file that prepares your agent with project-specific information.&lt;/p&gt;

&lt;p&gt;Key Principles:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Natural Language&lt;/strong&gt;: write like you're prompting an LLM.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Concise &amp;amp; Crisp&lt;/strong&gt;: every word counts (precious context window space 😁).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Focus on Positives&lt;/strong&gt;: I always have this nagging feeling that when I have too many &lt;strong&gt;not to dos&lt;/strong&gt; LLMs tend to perform worse. So try to use NOT only in a selected few places.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Hierarchical&lt;/strong&gt;: root directory for global rules, subdirectories for specific overrides.&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Be assertive&lt;/strong&gt;: direct, commanding language that leaves no room for interpretation or negotiation.&lt;br&gt;
Avoid writing:&lt;br&gt;
&lt;/p&gt;

&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="gh"&gt;# Project Guidelines&lt;/span&gt;
&lt;span class="p"&gt;
-&lt;/span&gt; It would be nice if you could try to use type hints when you remember to do so.
&lt;span class="p"&gt;-&lt;/span&gt; Maybe consider keeping the code simple if that's possible.
&lt;span class="p"&gt;-&lt;/span&gt; Please try not to add too many comments if you don't need to".
&lt;/code&gt;&lt;/pre&gt;



&lt;p&gt;Instead write:&lt;br&gt;
&lt;/p&gt;

&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="gh"&gt;# Project Guidelines&lt;/span&gt;

&lt;span class="gu"&gt;## MUST DO&lt;/span&gt;
&lt;span class="p"&gt;
-&lt;/span&gt; Use type hints for all function signatures.
&lt;span class="p"&gt;-&lt;/span&gt; Keep code simple. No unnecessary abstractions.
&lt;span class="p"&gt;-&lt;/span&gt; Add comments ONLY for complex business logic.
&lt;span class="p"&gt;-&lt;/span&gt; Use uv for all package management.
&lt;/code&gt;&lt;/pre&gt;


&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Here you can find &lt;a href="https://gist.github.com/kasir-barati/7de961cbbefb8f18bb8683cade5773f5" rel="noopener noreferrer"&gt;my &lt;code&gt;AGENTS.md&lt;/code&gt;&lt;/a&gt;, if you like it feel free to use it.&lt;/p&gt;

&lt;h3&gt;
  
  
  Two Approaches in Agentic Programming
&lt;/h3&gt;

&lt;p&gt;Which Approach is Right? But before answering that keep in mind that &lt;strong&gt;it is your job is to deliver code that's proven to work. You CANNOT blame the LLM. Check it works!&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Fun story, I asked someone whom uses AI intensively to code about how good LLMs and top models make decisions since I had somewhat bad experience with it. Here is what he said:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;I personally find the &lt;strong&gt;top models usually make good architecture and design choices&lt;/strong&gt;. but not always. &lt;strong&gt;Perhaps 70% of the time?&lt;/strong&gt; If you're not mentally prepared for the 30% painful miss, then it's going to be tiresome when it happens. And you might think "Why is everyone so impressed with this?".&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
    &lt;thead&gt;
        &lt;tr&gt;
            &lt;th&gt;Project&lt;/th&gt;
            &lt;th&gt;Use&lt;/th&gt;
        &lt;/tr&gt;
    &lt;/thead&gt;
    &lt;tbody&gt;
        &lt;tr&gt;
            &lt;td&gt;
                &lt;ul&gt;
                    &lt;li&gt;Mission Critical Projects&lt;/li&gt;
                    &lt;li&gt;Enterprise software&lt;/li&gt;
                    &lt;li&gt;Large codebases&lt;/li&gt;
                    &lt;li&gt;Highly innovative code&lt;/li&gt;
                &lt;/ul&gt;
            &lt;/td&gt;
            &lt;td&gt;Trust, but Verify&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
            &lt;td&gt;
                &lt;ul&gt;
                    &lt;li&gt;MVPs &amp;amp; Prototypes&lt;/li&gt;
                    &lt;li&gt;Building from scratch&lt;/li&gt;
                    &lt;li&gt;Boilerplate-heavy&lt;/li&gt;
                    &lt;li&gt;Risk-tolerant&lt;/li&gt;
                &lt;/ul&gt;
            &lt;/td&gt;
            &lt;td&gt;Let It Go&lt;/td&gt;
        &lt;/tr&gt;
    &lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h4&gt;
  
  
  Trust, but Verify
&lt;/h4&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;TODO List&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Micromanagement&lt;/td&gt;
&lt;td&gt;Approve everything, frequent resets, detailed instructions&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Plan → Execute&lt;/td&gt;
&lt;td&gt;Planning mode for finer control, then execution in phases&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Spec-Driven&lt;/td&gt;
&lt;td&gt;Specify precisely, trust the system, verify at the end&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h4&gt;
  
  
  Let It Go
&lt;/h4&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;TODO List&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;YOLO&lt;/td&gt;
&lt;td&gt;No approvals needed, let it run (great for hobby projects)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Ralph Loops&lt;/td&gt;
&lt;td&gt;Wrap the entire process in bigger loops; run overnight&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Multi-Agent Swarms&lt;/td&gt;
&lt;td&gt;Specialized agents (testing, feedback, managers) working together&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;blockquote&gt;
&lt;p&gt;⚠️ &lt;strong&gt;Warning&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;There &lt;a href="https://arxiv.org/html/2604.13536v1" rel="noopener noreferrer"&gt;security concerns with giving LLMs control over what they are creating with YOLO mode&lt;/a&gt;. Honestly I do NOT think you need to worry about it ATM. But I felt like mentioning it here.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Quick Reference Card
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Concept&lt;/th&gt;
&lt;th&gt;Key Takeaway&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;LLM&lt;/td&gt;
&lt;td&gt;Statistical engine predicting next tokens&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Tokens&lt;/td&gt;
&lt;td&gt;Chunks of text (words or parts of words)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Context&lt;/td&gt;
&lt;td&gt;Everything passed to the LLM (prompt + history + tools)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Agent&lt;/td&gt;
&lt;td&gt;LLM using tools in a loop to achieve goals&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;agents.md&lt;/td&gt;
&lt;td&gt;Markdown file with project rules and standards&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Compacting&lt;/td&gt;
&lt;td&gt;Summarizing history to fit in context window&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Ralph Loops&lt;/td&gt;
&lt;td&gt;Nested loops for long-running tasks&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;YOLO&lt;/td&gt;
&lt;td&gt;Zero-permission approach for trusted tasks&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Learn More
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://www.anthropic.com/engineering/building-effective-agents" rel="noopener noreferrer"&gt;Building Effective Agents - Anthropic's definitive guide&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://artificialanalysis.ai" rel="noopener noreferrer"&gt;Artificial Analysis - Compare model intelligence, speed, and price&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>ai</category>
      <category>programming</category>
      <category>llm</category>
      <category>agents</category>
    </item>
    <item>
      <title>How AI Models Work for Dummies</title>
      <dc:creator>Mohammad Jawad (Kasir) Barati</dc:creator>
      <pubDate>Wed, 12 Aug 2026 14:27:19 +0000</pubDate>
      <link>https://dev.to/kasir-barati/how-ai-models-work-for-dummies-4n3k</link>
      <guid>https://dev.to/kasir-barati/how-ai-models-work-for-dummies-4n3k</guid>
      <description>&lt;p&gt;AI models live two lives. First, they learn. Second, they perform.&lt;/p&gt;

&lt;p&gt;We call these &lt;strong&gt;Training&lt;/strong&gt; and &lt;strong&gt;Inferencing&lt;/strong&gt;. If training is the four years of medical school, inferencing is the actual surgery. In short all that knowledge it learned is put to the test against real, messy, unseen data.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Two Stages of an AI Model
&lt;/h2&gt;

&lt;p&gt;Every AI model goes through two primary phases. Think of it as &lt;strong&gt;learning&lt;/strong&gt; versus &lt;strong&gt;doing&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://dev-to-uploads.s3.us-east-2.amazonaws.com/uploads/articles/oi9dgjk364rrv3k4vgiv.png" rel="noopener noreferrer"&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%2Fghnqc9h7d60pk7ckbi7i.png" alt="The transition from Training (learning) to Inferencing (application)" width="798" height="174"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;During &lt;strong&gt;training&lt;/strong&gt;, a model processes millions of labeled examples. It figures out the statistical relationships between data points and encodes those relationships into &lt;strong&gt;model weights&lt;/strong&gt;. Weights are the digital "neurons" that connect ideas.&lt;/p&gt;

&lt;p&gt;During &lt;strong&gt;inferencing&lt;/strong&gt;, we feed the model &lt;em&gt;new&lt;/em&gt; data (like a user's query or a fresh email). The model uses its stored weights to make a prediction or generate an answer.&lt;/p&gt;

&lt;h3&gt;
  
  
  Example
&lt;/h3&gt;

&lt;p&gt;Let's make this concrete with a classic use case: &lt;strong&gt;Spam Detection&lt;/strong&gt;.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Training&lt;/strong&gt;: we feed the model thousands of emails already labeled "Spam" or "Not Spam." It learns that words like &lt;em&gt;"lottery,"&lt;/em&gt; &lt;em&gt;"urgent,"&lt;/em&gt; and excessive "!!!" usually mean trouble 😁.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Inferencing&lt;/strong&gt;: a new email arrives in your inbox. The model compares this email to the patterns it learned and spits out a probability score.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://dev-to-uploads.s3.us-east-2.amazonaws.com/uploads/articles/l90m0okd0gbnwrf4apkh.png" rel="noopener noreferrer"&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%2Fl4ktb640772izsue1p36.png" alt="The inference pipeline for a spam filter" width="799" height="151"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The magic of inferencing is &lt;strong&gt;generalization&lt;/strong&gt;. The model can &lt;strong&gt;predict&lt;/strong&gt; a spam email it has &lt;em&gt;never&lt;/em&gt; seen before, just because it shares characteristics with past spam.&lt;/p&gt;

&lt;h2&gt;
  
  
  Cost
&lt;/h2&gt;

&lt;p&gt;Honestly I had this vague impression of training being super duper expensive. But then I got to know &lt;strong&gt;as expensive as training can be, it is dwarfed by the expense of inferencing 🥲&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Training a frontier model can cost tens or even hundreds of millions of dollars. But guess what? That can become pocket change compared to the aggregate cost of serving billions of user queries over the model's lifetime.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Scale&lt;/strong&gt;: training is a relatively infrequent, concentrated expense. Inference happens millions of times per day.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Speed&lt;/strong&gt;: we expect answers almost instantly. That requires powerful (and power-hungry 😅) accelerators running continuously.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Complexity&lt;/strong&gt;: LLMs have billions of parameters. A standard dense model uses essentially all of its parameters for each token it processes.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Carbon Footprint&lt;/strong&gt;: unlike training, inference is an ongoing source of energy consumption. At sufficient scale, it can account for a substantial share of a model's lifetime energy use.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;One nuance: &lt;strong&gt;"inference can dwarf training" is not universally true&lt;/strong&gt;. For a model that is trained but barely used, training will obviously dominate.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://dev-to-uploads.s3.us-east-2.amazonaws.com/uploads/articles/xvvr4hsdr7tzot4wue6o.png" rel="noopener noreferrer"&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%2F20lz5g9uznxmswubxwlx.png" alt="cost visualization" width="800" height="629"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;💡 &lt;strong&gt;Tip&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;A token is the smallest chunk of text that an AI model actually reads or generates. It is &lt;strong&gt;not&lt;/strong&gt; always whole word. For example:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;"unbelievable" → generates 2 tokens when using &lt;a href="https://huggingface.co/google/gemma-7b" rel="noopener noreferrer"&gt;&lt;code&gt;google/gemma-7b&lt;/code&gt;&lt;/a&gt; ["un", "believable"].&lt;/li&gt;
&lt;li&gt;"How are you?" → generates 4 tokens when using &lt;a href="https://huggingface.co/codellama/CodeLlama-7b-hf" rel="noopener noreferrer"&gt;&lt;code&gt;codellama/CodeLlama-7b-hf&lt;/code&gt;&lt;/a&gt;: &lt;code&gt;["How", " are", " you", "?"]&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can play with it here: &lt;a href="https://tokenizer.model.box" rel="noopener noreferrer"&gt;https://tokenizer.model.box&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why you actually care?&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Cost&lt;/strong&gt;: most AI pricing (OpenAI, Anthropic, etc.) is billed per token (input + output). More tokens = more money spent.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Speed&lt;/strong&gt;: inference speed is measured in tokens per second. Bigger outputs take longer.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Memory&lt;/strong&gt;: models have a "context window" (e.g., 128k tokens). Hit that limit, and the model forgets the start of the conversation.&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;

</description>
      <category>llm</category>
      <category>ai</category>
      <category>programming</category>
    </item>
    <item>
      <title>From Prompt Engineering to Context Engineering</title>
      <dc:creator>Mohammad Jawad (Kasir) Barati</dc:creator>
      <pubDate>Tue, 11 Aug 2026 19:17:57 +0000</pubDate>
      <link>https://dev.to/kasir-barati/from-prompt-engineering-to-context-engineering-ie1</link>
      <guid>https://dev.to/kasir-barati/from-prompt-engineering-to-context-engineering-ie1</guid>
      <description>&lt;h2&gt;
  
  
  tl;dr
&lt;/h2&gt;

&lt;p&gt;When I first started building with LLMs, I thought the game was all about crafting the perfect prompt. Find the right words, and the model will do what you want. But then I came across &lt;a href="https://drive.google.com/file/d/1JW6Q_wwvBjMz9xzOtTldFfPiF7BrdEeQ/view" rel="noopener noreferrer"&gt;Context Engineering: Sessions &amp;amp; Memory&lt;/a&gt; whitepaper from Kimberly Milam and Antonio Gulli.&lt;/p&gt;

&lt;p&gt;If you're building agentic AI systems that actually need to work in production, this shift in thinking - from prompt engineering to context engineering - might be the most important thing you learn.&lt;/p&gt;




&lt;h2&gt;
  
  
  Context Engineering
&lt;/h2&gt;

&lt;p&gt;LLMs are fundamentally constrained. They have a fixed context window (the maximum number of tokens they can process and pay attention to at once). Everything you want the model to consider has to fit in that window:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The conversation history.&lt;/li&gt;
&lt;li&gt;System prompts and instructions.&lt;/li&gt;
&lt;li&gt;Tool descriptions and their results.&lt;/li&gt;
&lt;li&gt;RAG-retrieved information.&lt;/li&gt;
&lt;li&gt;The user's current prompt.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The more you shove in context window, the more you risk losing what's called coherence (the model's ability to generate outputs consistent with your goals).&lt;/p&gt;

&lt;p&gt;Stuff it full of tools, instructions, and context, and you'll get less predictable, less accurate results. And that is where you start feeling frustrated 😠🥲.&lt;/p&gt;

&lt;p&gt;So what's the alternative?&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Designe and build dynamic systems that provides the right information and tools, in the right format, at the right time, to give an LLM everything it needs to accomplish a task.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Actually that is what context engineering is all about.&lt;/p&gt;

&lt;p&gt;An AI Developer Experience engineer at Google called Philipp Schmid DeepMind popularized this in his seminal blog post &lt;a href="https://www.philschmid.de/context-engineering" rel="noopener noreferrer"&gt;The New Skill in AI is Not Prompting, It's Context Engineering&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The Context Engineering visualizes the problem beautifully, showing everything you pack into your input context:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://dev-to-uploads.s3.us-east-2.amazonaws.com/uploads/articles/8rv1oodjm54wivc9iiha.png" rel="noopener noreferrer"&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%2Fkl2xpve8v01b8dd2ujad.png" alt="context engineering visualized" width="799" height="172"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The elements that make up your context include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Instructions/System Prompts: which are initial settings and rules that define basic AI behavior.&lt;/li&gt;
&lt;li&gt;User Prompts.&lt;/li&gt;
&lt;li&gt;Short-term memory: the flow of the conversation.&lt;/li&gt;
&lt;li&gt;Long-term memory: user preferences and knowledge from previous interactions.&lt;/li&gt;
&lt;li&gt;RAG: retrieved external data from documents, databases, APIs.&lt;/li&gt;
&lt;li&gt;Available tools: functions the AI can execute.&lt;/li&gt;
&lt;li&gt;Structured output.&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;Most agent failures are not model failures anymore, they are context failures.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Philipp Schmid&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;

&lt;p&gt;Schmid estimates that around 80% of agent failures trace back to broken or missing context - not the model itself being inadequate.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Experimentation Mindset
&lt;/h2&gt;

&lt;p&gt;You might be asking: "Okay, so what's the process? What's the step-by-step waterfall for optimizing context?"&lt;/p&gt;

&lt;p&gt;There isn't one. In fact if you remember I wrote about this in &lt;a href="https://dev.to/kasir-barati/prompts-matter-in-agentic-workflows-2c6e"&gt;Prompts Matter in Agentic Workflows&lt;br&gt;
&lt;/a&gt;. Even when you do prompt engineering you need to do experiment and measure each change.&lt;/p&gt;

&lt;p&gt;Context engineering is fundamentally about R&amp;amp;D, trial and error. Here's the only reliable approach:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Metrics&lt;/strong&gt;: define something that measures how effective your agent is toward your business objective.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Experiment&lt;/strong&gt;: test different approaches, different tool combinations, different ways of using RAG.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Measure&lt;/strong&gt;: compare results against your metric.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Iterate&lt;/strong&gt;: keep what works, discard what doesn't.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;BTW do &lt;strong&gt;NOT&lt;/strong&gt; forget to add &lt;strong&gt;traceability&lt;/strong&gt; to your agentic workflow.&lt;/p&gt;




&lt;h2&gt;
  
  
  Subagents: Dividing to Conquer
&lt;/h2&gt;

&lt;p&gt;One of the most powerful techniques in agentic programming is using subagents, breaking your larger agentic problem into &lt;strong&gt;smaller&lt;/strong&gt;, &lt;strong&gt;independently testable&lt;/strong&gt; steps.&lt;/p&gt;

&lt;p&gt;So how you should create subagents?&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Context optimization&lt;/strong&gt;: if you've got 12 tools equipped to the same model, it might start losing coherence. Group related tools into a subagent, and now your main agent only sees one tool (the subagent itself). Your context window becomes dramatically more efficient.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Reusability&lt;/strong&gt;: Build a subagent once, test it, validate it, and reuse it across multiple agentic flows.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Independent testability&lt;/strong&gt;: Each subagent can be evaluated on its own, making debugging and improvement much easier.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://dev-to-uploads.s3.us-east-2.amazonaws.com/uploads/articles/uiz607875qr68pdq20ro.png" rel="noopener noreferrer"&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%2Fehk4zbeh7jd53n4s4y0t.png" alt="Business development" width="799" height="244"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here is the working example in n8n: &lt;a href="https://gist.github.com/kasir-barati/66f1284f2027e53c78bba3dacac7feed" rel="noopener noreferrer"&gt;https://gist.github.com/kasir-barati/66f1284f2027e53c78bba3dacac7feed&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  The Trade-off
&lt;/h3&gt;

&lt;p&gt;Subagents reduce flexibility in exchange for reliability. You're constraining how the problem gets solved by organizing it into fixed building blocks. The main agent can't decide to call tools in a different order, it's on rails.&lt;/p&gt;

&lt;p&gt;This is a trade-off between autonomy, flexibility and bulletproof reliability.&lt;/p&gt;

&lt;h3&gt;
  
  
  Subagents in n8n
&lt;/h3&gt;

&lt;p&gt;In n8n, implementing subagents is straightforward using sub-workflows. A sub-workflow can be triggered by another workflow, making it a clean, elegant subagent implementation.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://dev-to-uploads.s3.us-east-2.amazonaws.com/uploads/articles/x153ejmn23lbt5i3h82d.png" rel="noopener noreferrer"&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%2Fk8ri24rko4t9lcs1rkr8.png" alt="Subagents in n8n" width="799" height="440"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  The Human Trap -- Anthropomorphizing
&lt;/h2&gt;

&lt;p&gt;One common anti-pattern is anthropomorphizing agents. People create agents with human-like roles (Analyst, Strategist, etc.) because "that's how the org is structured."&lt;/p&gt;

&lt;p&gt;This is backwards. Divide into subagents because it:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Gives you independently testable steps.&lt;/li&gt;
&lt;li&gt;Improves your evals.&lt;/li&gt;
&lt;li&gt;Fixes a specific context problem.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Not&lt;/strong&gt; just because it sounds like human responsibilities.&lt;/p&gt;




&lt;h2&gt;
  
  
  &lt;a href="https://martinfowler.com/articles/agentic-ai-security.html#lethal-trifecta" rel="noopener noreferrer"&gt;The Lethal Trifecta&lt;/a&gt; -- The Security Vulnerability You Must Know
&lt;/h2&gt;

&lt;p&gt;This is the one vulnerability unique to agentic AI, and it was popularized by the &lt;a href="https://simonwillison.net/2025/Jun/16/the-lethal-trifecta/" rel="noopener noreferrer"&gt;Simon Willison&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Simon coined the term "lethal trifecta", three capabilities that, when combined in a single AI agent, create a near-guaranteed path to exploitation through indirect prompt injection.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://dev-to-uploads.s3.us-east-2.amazonaws.com/uploads/articles/mrtjxv8adj4dnffngu9i.png" rel="noopener noreferrer"&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%2Flk81ylrq94p98rsnguby.png" alt="The Lethal Trifecta visualization" width="800" height="587"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Access to private data: the agent can see sensitive information (bank accounts, sales numbers, API keys).&lt;/li&gt;
&lt;li&gt;Ability to communicate externally: the agent can give information to someone other than you.&lt;/li&gt;
&lt;li&gt;Exposure to untrusted content: some of the agent's input comes from sources you don't control.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Any two of these might be fine on their own. Many systems handle private data and have multiple users. Many systems communicate externally. Many systems ingest untrusted content.&lt;/p&gt;

&lt;p&gt;But all three together? That's where the vulnerability emerges.&lt;/p&gt;

&lt;p&gt;The untrusted content could contain instructions that deceive your LLM into exposing private data to a third party. And because LLMs are non-deterministic, you can't simply "patch" this vulnerability like you would in traditional software.&lt;/p&gt;

&lt;p&gt;The only way to reliably prevent this attack is to cut off one of the three legs. Generally the easiest leg to remove is the ability for the LLM agent to transmit stolen data back to the attacker (AKA &lt;a href="https://www.cyberhaven.com/blog/data-exfiltration-methods" rel="noopener noreferrer"&gt;exfiltration vector&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://cybernews.com/security/github-mcp-vulnerability-has-far-reaching-consequences/" rel="noopener noreferrer"&gt;A real-world example&lt;/a&gt; was when GitHub built an MCP server that allowed agents to read and write from both public and private repos. It ticked all three boxes.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Makes a Strong Agentic Solution?
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
    &lt;thead&gt;
        &lt;tr&gt;
            &lt;th&gt;Category&lt;/th&gt;
            &lt;th&gt;❌ Anti-Pattern&lt;/th&gt;
            &lt;th&gt;✅ Best Practice&lt;/th&gt;
            &lt;th&gt;Why It Matters&lt;/th&gt;
        &lt;/tr&gt;
    &lt;/thead&gt;
    &lt;tbody&gt;
        &lt;tr&gt;
            &lt;td&gt;Starting Point&lt;/td&gt;
            &lt;td&gt;
                &lt;strong&gt;Solution-Focused:&lt;/strong&gt;&lt;br&gt;"I want an
                agent to write emails."
            &lt;/td&gt;
            &lt;td&gt;
                &lt;strong&gt;Problem-Focused:&lt;/strong&gt;&lt;br&gt;"We are losing
                leads because follow-ups are slow. We need to reduce
                response time from 24h to 1h."
            &lt;/td&gt;
            &lt;td&gt;
                Ensures you build a tool that actually solves a
                business pain, not just a cool demo.
            &lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
            &lt;td&gt;Agent Identity&lt;/td&gt;
            &lt;td&gt;
                &lt;strong&gt;Anthropomorphization:&lt;/strong&gt;&lt;br&gt;"Act like
                a senior sales manager with 20 years of experience."
            &lt;/td&gt;
            &lt;td&gt;
                &lt;strong&gt;Functional Role:&lt;/strong&gt;&lt;br&gt;"Act as a data
                processor. Extract contact info, check CRM status, and
                draft a follow-up."
            &lt;/td&gt;
            &lt;td&gt;
                Prevents the agent from mimicking human "personality"
                which leads to unpredictable or hallucinated advice.
            &lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
            &lt;td&gt;Success Criteria&lt;/td&gt;
            &lt;td&gt;
                &lt;strong&gt;Vague Outcome:&lt;/strong&gt;&lt;br&gt;"Make the emails
                sound professional."
            &lt;/td&gt;
            &lt;td&gt;
                &lt;strong&gt;Quantifiable Metric:&lt;/strong&gt;&lt;br&gt;"Achieve a
                15% reply rate on automated emails."
            &lt;/td&gt;
            &lt;td&gt;
                "Professional" is subjective; "15% reply rate" is
                measurable and verifiable.
            &lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
            &lt;td&gt;Content Goal&lt;/td&gt;
            &lt;td&gt;
                &lt;strong&gt;Generation as Goal:&lt;/strong&gt;&lt;br&gt;"Generate a
                10-page market strategy report."
            &lt;/td&gt;
            &lt;td&gt;
                &lt;strong&gt;Accuracy &amp;amp; Verification:&lt;/strong&gt;&lt;br&gt;"Analyze Q3 sales data, identify top 3 growth
                drivers, and cite specific data sources for each."
            &lt;/td&gt;
            &lt;td&gt;
                LLMs are great at sounding plausible but bad at being
                accurate. You must force verification.
            &lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
            &lt;td&gt;Testing&lt;/td&gt;
            &lt;td&gt;
                &lt;strong&gt;Human Review Only:&lt;/strong&gt;&lt;br&gt;"I'll read
                the output and see if it looks right."
            &lt;/td&gt;
            &lt;td&gt;
                &lt;strong&gt;Rigorous Automated Testing:&lt;/strong&gt;&lt;br&gt;"Run
                1,000 test cases. If accuracy &amp;lt; 95%, add a
                verification tool or rule."
            &lt;/td&gt;
            &lt;td&gt;
                Humans miss subtle hallucinations. Automated tests
                catch errors at scale before deployment.
            &lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
            &lt;td&gt;Control&lt;/td&gt;
            &lt;td&gt;
                &lt;strong&gt;Autonomous "Thinking":&lt;/strong&gt;&lt;br&gt;"Let the
                agent decide the best price to offer the customer."
            &lt;/td&gt;
            &lt;td&gt;
                &lt;strong&gt;Tool-Based Execution:&lt;/strong&gt;&lt;br&gt;"Agent
                calculates price based on margin rules. Human approves
                any discount &amp;gt; 10%."
            &lt;/td&gt;
            &lt;td&gt;
                Removes the risk of the agent making expensive,
                unauthorized decisions based on "guesses."
            &lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
            &lt;td&gt;Scope&lt;/td&gt;
            &lt;td&gt;
                &lt;strong&gt;Broad &amp;amp; Open-Ended:&lt;/strong&gt;&lt;br&gt;"An agent
                that handles all customer support."
            &lt;/td&gt;
            &lt;td&gt;
                &lt;strong&gt;Narrow &amp;amp; Concrete:&lt;/strong&gt;&lt;br&gt;"An agent
                that handles &lt;em&gt;only&lt;/em&gt; password resets and billing
                status checks."
            &lt;/td&gt;
            &lt;td&gt;
                Narrow scope reduces error rates and makes it easier
                to prove the agent works.
            &lt;/td&gt;
        &lt;/tr&gt;
    &lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

</description>
      <category>ai</category>
      <category>promptengineering</category>
      <category>contextengineering</category>
      <category>llm</category>
    </item>
    <item>
      <title>MCP: The USB-C Port for AI Applications</title>
      <dc:creator>Mohammad Jawad (Kasir) Barati</dc:creator>
      <pubDate>Tue, 11 Aug 2026 00:07:58 +0000</pubDate>
      <link>https://dev.to/kasir-barati/mcp-the-usb-c-port-for-ai-applications-34hd</link>
      <guid>https://dev.to/kasir-barati/mcp-the-usb-c-port-for-ai-applications-34hd</guid>
      <description>&lt;p&gt;The first time I heard about MCPs I was quite flabbergasted. I was like what are they. But today thanks to n8n I know them like the back of my hand 😁.&lt;/p&gt;

&lt;h2&gt;
  
  
  tl;dr
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;MCP stands for Model Context Protocol.&lt;/li&gt;
&lt;li&gt;The real innovation in Agentic AI isn't MCP, it's tools.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Tools are the game-changer. The ability for an LLM to decide, based on the tokens it generates, that it wants to call a function or API. MCP is simply &lt;strong&gt;an standard that makes sharing and reusing these tools much easier&lt;/strong&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Use structured output as much as possible instead of simple strings returned usually by LLMs since we can work a lot easier with JSON.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you ask me to summarize it I'd say let's imagine we wanna create a lead hunter tool. I do NOT care how it works internally, I just wanna give it a prompt like this: "I wanna sell a CO2 calculator and optimizer to south east Asian countries. Gimme 10 top major compnaies/organizations" and then get a structured response back with direct contact info as accurate as possible.&lt;/p&gt;

&lt;p&gt;So you go to n8n and create a &lt;strong&gt;published&lt;/strong&gt; workflow like:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://dev-to-uploads.s3.us-east-2.amazonaws.com/uploads/articles/1hq3s6pwblryv4cw019u.png" rel="noopener noreferrer"&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%2Ft6uh7knni4a8bcladffa.png" alt="Lead hunter subagent" width="800" height="301"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Then you need to create a separate published workflow which exposes the new MCP server&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fsd0ybcjm7ttbszam1bbm.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%2Fsd0ybcjm7ttbszam1bbm.png" alt="Expose MCP server pon n8n" width="800" height="877"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Then you just need to add it to your agent or you can for example add it to Claude:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fm7j4e99v582q1lhqvfo2.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%2Fm7j4e99v582q1lhqvfo2.png" alt="Add the new MCP to Claude" width="800" height="314"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can see the n8n workflows here: &lt;a href="https://gist.github.com/kasir-barati/eb1059bbd85abf6cadd83a10c35f4cf4" rel="noopener noreferrer"&gt;https://gist.github.com/kasir-barati/eb1059bbd85abf6cadd83a10c35f4cf4&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Also pay close attention to have we declared what our MCP is capable of in n8n so Claude knows what it needs to send to the MCP server and what it should expect to receive in response:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://dev-to-uploads.s3.us-east-2.amazonaws.com/uploads/articles/5srbk3pjhd8l1171zg1n.png" rel="noopener noreferrer"&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%2Fpmqm79rx4qcx68sm6jtm.png" alt="How we tell the client what the MCP server is capable of" width="800" height="462"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Fun Fact&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The builtin n8n tools are all MCP servers with accurate and neat descriptions similar to what we had done for our little MCP server. That is why LLMs know which tool they have to call!&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;So the full flow of our little MCP would look like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://dev-to-uploads.s3.us-east-2.amazonaws.com/uploads/articles/8n2ocv1yyu6kkv9mhbxn.png" rel="noopener noreferrer"&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%2Fqlxc9h8tp9v8c43jn98x.png" alt="Full flow" width="800" height="252"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And the Claude part is just the client whom initiate the request, receives the response, and finally visualize it to the user.&lt;/p&gt;




&lt;h2&gt;
  
  
  What is MCP?
&lt;/h2&gt;

&lt;p&gt;Anthropic create MCP and released in late 2024. It took off around March-April 2025 and has become a major force in the AI ecosystem.&lt;/p&gt;

&lt;p&gt;Anthropic describes MCP as the USB-C port for AI applications (&lt;a href="https://modelcontextprotocol.io/docs/2026-07-28/getting-started/intro" rel="noopener noreferrer"&gt;ref&lt;/a&gt;), a good analogy for a protocol designed to standardize how AI applications connect to external systems.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Three-Part Architecture
&lt;/h3&gt;

&lt;p&gt;MCP consists of three key components:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;MCP Host&lt;/strong&gt;: The overall environment where your agents run (e.g., Claude desktop app, an n8n workflow, or any AI application).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;MCP Client&lt;/strong&gt;: A component within the host that connects to MCP servers.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;MCP Server&lt;/strong&gt;: The actual tool provider that exposes functionality to LLMs.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://dev-to-uploads.s3.us-east-2.amazonaws.com/uploads/articles/sg9fisp110263cu3a0pj.png" rel="noopener noreferrer"&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%2F5axgrg5heaumj4hesv4y.png" alt="MCP components" width="800" height="380"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Transport Mechanisms
&lt;/h3&gt;

&lt;p&gt;MCP clients and servers can communicate in three ways:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;stdio&lt;/strong&gt; (Standard Input/Output): The simplest method, but only works when server runs on the same computer as the host.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;SSE&lt;/strong&gt; (Server-Sent Events): Deprecated.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Streamable HTTP&lt;/strong&gt;: The modern replacement for SSE, supports remote connections (server can run anywhere).&lt;/li&gt;
&lt;/ol&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Important&lt;/strong&gt; ⚠️&lt;/p&gt;

&lt;p&gt;n8n currently &lt;strong&gt;only&lt;/strong&gt; supports Streamable HTTP and SSE, not Stdio.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Why MCP Matters
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;What MCP &lt;strong&gt;is&lt;/strong&gt;:

&lt;ul&gt;
&lt;li&gt;An easy way to use tools that someone else built.&lt;/li&gt;
&lt;li&gt;A standard for sharing tools across AI applications.&lt;/li&gt;
&lt;li&gt;Open source.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;What MCP is &lt;strong&gt;NOT&lt;/strong&gt;:

&lt;ul&gt;
&lt;li&gt;The tools themselves (it's the glue between LLMs and tools).&lt;/li&gt;
&lt;li&gt;Technically innovative (it uses proven technologies).&lt;/li&gt;
&lt;li&gt;Guaranteed to be the final word (alternatives like &lt;a href="https://support.claude.com/en/articles/12512176-what-are-skills" rel="noopener noreferrer"&gt;Claude Skills&lt;/a&gt; and &lt;a href="https://github.com/universal-tool-calling-protocol/code-mode" rel="noopener noreferrer"&gt;Code Mode&lt;/a&gt; are emerging).&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But even then I believe knowing MCP will enable us to have an easier time adopting and moving to Code Mode or any other standard. As the old saying goes: same song, different verse.&lt;/p&gt;

&lt;p&gt;Learning MCP gives you the "melody", so picking up Code Mode is just learning the "new verse".&lt;/p&gt;




&lt;h2&gt;
  
  
  Reference Resources
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://www.anthropic.com/news/model-context-protocol" rel="noopener noreferrer"&gt;Anthropic MCP Announcement&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://modelcontextprotocol.io/specification/2025-11-25" rel="noopener noreferrer"&gt;MCP Specification&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://docs.firecrawl.dev/mcp-server" rel="noopener noreferrer"&gt;Firecrawl MCP Server&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://hunter.io/api-documentation/v2#mcp" rel="noopener noreferrer"&gt;Hunter.io MCP Integration&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://code.claude.com/docs/en/mcp-quickstart" rel="noopener noreferrer"&gt;Claude Desktop MCP Setup&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>mcp</category>
      <category>ai</category>
      <category>agents</category>
    </item>
  </channel>
</rss>
