<?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>Forem: Avi Fenesh</title>
    <description>The latest articles on Forem by Avi Fenesh (@avifenesh).</description>
    <link>https://forem.com/avifenesh</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1406394%2F53fd4ce6-829e-4132-bb74-bde79c256679.jpeg</url>
      <title>Forem: Avi Fenesh</title>
      <link>https://forem.com/avifenesh</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/avifenesh"/>
    <language>en</language>
    <item>
      <title>If you build your AI coding system</title>
      <dc:creator>Avi Fenesh</dc:creator>
      <pubDate>Sat, 28 Mar 2026 15:55:29 +0000</pubDate>
      <link>https://forem.com/avifenesh/if-you-build-your-ai-coding-system-2154</link>
      <guid>https://forem.com/avifenesh/if-you-build-your-ai-coding-system-2154</guid>
      <description>&lt;div class="ltag__link--embedded"&gt;
  &lt;div class="crayons-story "&gt;
  &lt;a href="https://dev.to/avifenesh/how-ai-workloads-changed-the-queue-i-was-already-building-5989" class="crayons-story__hidden-navigation-link"&gt;How AI workloads changed the queue I was already building&lt;/a&gt;


  &lt;div class="crayons-story__body crayons-story__body-full_post"&gt;
    &lt;div class="crayons-story__top"&gt;
      &lt;div class="crayons-story__meta"&gt;
        &lt;div class="crayons-story__author-pic"&gt;

          &lt;a href="/avifenesh" class="crayons-avatar  crayons-avatar--l  "&gt;
            &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1406394%2F53fd4ce6-829e-4132-bb74-bde79c256679.jpeg" alt="avifenesh profile" class="crayons-avatar__image" width="460" height="460"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
        &lt;div&gt;
          &lt;div&gt;
            &lt;a href="/avifenesh" class="crayons-story__secondary fw-medium m:hidden"&gt;
              Avi Fenesh
            &lt;/a&gt;
            &lt;div class="profile-preview-card relative mb-4 s:mb-0 fw-medium hidden m:inline-block"&gt;
              
                Avi Fenesh
                
              
              &lt;div id="story-author-preview-content-3421420" class="profile-preview-card__content crayons-dropdown branded-7 p-4 pt-0"&gt;
                &lt;div class="gap-4 grid"&gt;
                  &lt;div class="-mt-4"&gt;
                    &lt;a href="/avifenesh" class="flex"&gt;
                      &lt;span class="crayons-avatar crayons-avatar--xl mr-2 shrink-0"&gt;
                        &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1406394%2F53fd4ce6-829e-4132-bb74-bde79c256679.jpeg" class="crayons-avatar__image" alt="" width="460" height="460"&gt;
                      &lt;/span&gt;
                      &lt;span class="crayons-link crayons-subtitle-2 mt-5"&gt;Avi Fenesh&lt;/span&gt;
                    &lt;/a&gt;
                  &lt;/div&gt;
                  &lt;div class="print-hidden"&gt;
                    
                      Follow
                    
                  &lt;/div&gt;
                  &lt;div class="author-preview-metadata-container"&gt;&lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
            &lt;/div&gt;

          &lt;/div&gt;
          &lt;a href="https://dev.to/avifenesh/how-ai-workloads-changed-the-queue-i-was-already-building-5989" class="crayons-story__tertiary fs-xs"&gt;&lt;time&gt;Mar 28&lt;/time&gt;&lt;span class="time-ago-indicator-initial-placeholder"&gt;&lt;/span&gt;&lt;/a&gt;
        &lt;/div&gt;
      &lt;/div&gt;

    &lt;/div&gt;

    &lt;div class="crayons-story__indention"&gt;
      &lt;h2 class="crayons-story__title crayons-story__title-full_post"&gt;
        &lt;a href="https://dev.to/avifenesh/how-ai-workloads-changed-the-queue-i-was-already-building-5989" id="article-link-3421420"&gt;
          How AI workloads changed the queue I was already building
        &lt;/a&gt;
      &lt;/h2&gt;
        &lt;div class="crayons-story__tags"&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/ai"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;ai&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/queue"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;queue&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/valkey"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;valkey&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/orchestration"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;orchestration&lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="crayons-story__bottom"&gt;
        &lt;div class="crayons-story__details"&gt;
          &lt;a href="https://dev.to/avifenesh/how-ai-workloads-changed-the-queue-i-was-already-building-5989" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left"&gt;
            &lt;div class="multiple_reactions_aggregate"&gt;
              &lt;span class="multiple_reactions_icons_container"&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/sparkle-heart-5f9bee3767e18deb1bb725290cb151c25234768a0e9a2bd39370c382d02920cf.svg" width="24" height="24"&gt;
                  &lt;/span&gt;
              &lt;/span&gt;
              &lt;span class="aggregate_reactions_counter"&gt;1&lt;span class="hidden s:inline"&gt; reaction&lt;/span&gt;&lt;/span&gt;
            &lt;/div&gt;
          &lt;/a&gt;
            &lt;a href="https://dev.to/avifenesh/how-ai-workloads-changed-the-queue-i-was-already-building-5989#comments" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left flex items-center"&gt;
              Comments


              &lt;span class="hidden s:inline"&gt;Add Comment&lt;/span&gt;
            &lt;/a&gt;
        &lt;/div&gt;
        &lt;div class="crayons-story__save"&gt;
          &lt;small class="crayons-story__tertiary fs-xs mr-2"&gt;
            5 min read
          &lt;/small&gt;
            
              &lt;span class="bm-initial"&gt;
                

              &lt;/span&gt;
              &lt;span class="bm-success"&gt;
                

              &lt;/span&gt;
            
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;/div&gt;


</description>
      <category>ai</category>
      <category>queue</category>
      <category>valkey</category>
      <category>orchestration</category>
    </item>
    <item>
      <title>How AI workloads changed the queue I was already building</title>
      <dc:creator>Avi Fenesh</dc:creator>
      <pubDate>Sat, 28 Mar 2026 15:50:18 +0000</pubDate>
      <link>https://forem.com/avifenesh/how-ai-workloads-changed-the-queue-i-was-already-building-5989</link>
      <guid>https://forem.com/avifenesh/how-ai-workloads-changed-the-queue-i-was-already-building-5989</guid>
      <description>&lt;p&gt;I did not start glide-mq because of AI.&lt;/p&gt;

&lt;p&gt;I started it because I needed a queue, wanted mechanics I liked better than what was out there, and wanted it built on top of Valkey Glide.&lt;/p&gt;

&lt;p&gt;Up through v0.13, that is basically what it was: a feature-rich queue.&lt;/p&gt;

&lt;p&gt;Then I kept building AI systems on top of it.&lt;/p&gt;

&lt;p&gt;That is where the shape started changing.&lt;/p&gt;

&lt;p&gt;The queue itself was usually fine. The pain was everything around it. Long-running jobs that were not actually stuck. Streaming that wanted to be part of the job instead of a side channel. Budget checks that needed to happen before the spend, not after. Token-aware rate limits. Pause/resume because real flows sometimes need a human or have to wait for CI.&lt;/p&gt;

&lt;p&gt;Different project. Same pile of glue.&lt;/p&gt;

&lt;p&gt;After enough rounds, the pattern stops looking normal. The queue is doing the easy part. Everything AI-specific is leaking out around it.&lt;/p&gt;

&lt;p&gt;That is what pushed glide-mq in a different direction.&lt;/p&gt;

&lt;h2&gt;
  
  
  AI workloads expose the wrong assumptions in normal queue design
&lt;/h2&gt;

&lt;p&gt;Most queues were built for ordinary background work.&lt;/p&gt;

&lt;p&gt;AI workloads are not ordinary background work.&lt;/p&gt;

&lt;p&gt;They stream. They run long without being stuck. They spend money while they execute. They wait on humans. They hit limits based on tokens, not job count. They can fail semantically while every operational metric stays green.&lt;/p&gt;

&lt;p&gt;If the queue does not understand that shape, the missing behavior does not disappear. It ends up patched on from the outside.&lt;/p&gt;

&lt;p&gt;That is the part that started feeling wrong to me.&lt;/p&gt;

&lt;p&gt;Not because queues are bad. Because a lot of the assumptions underneath them were built for a different class of workload.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Locks are the wrong model for long AI jobs
&lt;/h2&gt;

&lt;p&gt;Most queues assume the worker proves it is alive by renewing a lock. Miss the renewal, retry the job.&lt;/p&gt;

&lt;p&gt;That is reasonable for short jobs.&lt;/p&gt;

&lt;p&gt;It is a bad model for LLM workloads.&lt;/p&gt;

&lt;p&gt;A long generation is not dead. A reasoning-heavy call sitting on a hard prompt for 90 seconds is not dead. But a normal queue cannot tell the difference, so it retries, and now you are paying twice for the same work.&lt;/p&gt;

&lt;p&gt;Nothing crashed. Nothing exploded. You just had the wrong execution model.&lt;/p&gt;

&lt;p&gt;The usual workaround is increasing a global lock timeout.&lt;/p&gt;

&lt;p&gt;That is also wrong.&lt;/p&gt;

&lt;p&gt;A tiny classifier and a two-minute generation should not share the same timeout assumptions just because they live in the same queue.&lt;/p&gt;

&lt;p&gt;So in glide-mq, lock duration is per job:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;queue&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;classify&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;short&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;lockDuration&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="nx"&gt;_000&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;queue&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;research&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;topic&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;complex&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;lockDuration&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;180&lt;/span&gt;&lt;span class="nx"&gt;_000&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Same queue. Different expectations.&lt;/p&gt;

&lt;p&gt;That should be normal.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Budget control belongs in the execution path
&lt;/h2&gt;

&lt;p&gt;The ugly failures in agent systems are often not technical failures.&lt;/p&gt;

&lt;p&gt;The requests succeed.&lt;br&gt;
The responses are valid.&lt;br&gt;
The logs look clean.&lt;br&gt;
The dashboards stay green.&lt;/p&gt;

&lt;p&gt;And meanwhile the system is stuck in some useless loop spending money.&lt;/p&gt;

&lt;p&gt;That is why budget control does not belong only in dashboards, analytics, or some side service that tells you later what happened. By then the spend is already gone.&lt;/p&gt;

&lt;p&gt;The queue is the choke point. Every step passes through it. That is where the budget check belongs.&lt;/p&gt;

&lt;p&gt;So I put budgets on flows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;flowProducer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;pipeline&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;queueName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;ai&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;topic&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;research&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="na"&gt;children&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;search&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;queueName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;ai&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;analyze&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;queueName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;ai&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;draft&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;queueName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;ai&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;budget&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;maxTotalTokens&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="nx"&gt;_000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;maxTotalCost&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;2.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;tokenWeights&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;reasoning&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;2.0&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="na"&gt;onExceeded&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;fail&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When a job reports usage, the budget check happens atomically in Valkey. If the flow is out of budget, the next step stops there.&lt;/p&gt;

&lt;p&gt;Not later. Not after the invoice. At the point where it still matters.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Streaming should not be a second system
&lt;/h2&gt;

&lt;p&gt;If the model is producing the result incrementally, that stream is part of the job.&lt;/p&gt;

&lt;p&gt;Treating it as a separate system is already the smell.&lt;/p&gt;

&lt;p&gt;But most queues only understand one shape: job starts, job finishes, here is the result.&lt;/p&gt;

&lt;p&gt;LLMs do not behave like that.&lt;/p&gt;

&lt;p&gt;So people bolt on pub/sub. Or WebSockets. Or SSE through some different route. Then reconnect logic. Then ordering. Then another pile of glue to keep the stream state and the job state from drifting apart.&lt;/p&gt;

&lt;p&gt;Now the job lives in one place and the live output lives somewhere else.&lt;/p&gt;

&lt;p&gt;That split is artificial.&lt;/p&gt;

&lt;p&gt;So in glide-mq, the stream stays on the job:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;worker&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Worker&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;ai&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;job&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="k"&gt;await &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;token&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nf"&gt;generateTokens&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;job&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;prompt&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;job&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;streamChunk&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;token&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;token&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;job&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;streamChunk&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;done&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;completed&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;connection&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;chunks&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;queue&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;readStream&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;jobId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;block&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;5000&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No extra pub/sub layer. No second system just to watch a job do its work. The stream is attached to the job, stored in Valkey, and resumable after disconnect.&lt;/p&gt;

&lt;p&gt;That is the model that actually matches the workload.&lt;/p&gt;

&lt;h2&gt;
  
  
  The rest is the same mismatch in different clothes
&lt;/h2&gt;

&lt;p&gt;Once you accept that AI workloads are a different class of work, the rest stops looking like extra features and starts looking like missing queue behavior.&lt;/p&gt;

&lt;p&gt;Pause/resume for human approval.&lt;br&gt;
Wake the flow back up when CI finishes.&lt;br&gt;
Fallbacks across models.&lt;br&gt;
Rate limiting based on tokens instead of job count.&lt;br&gt;
Usage tracking that does not break when the next model adds a new token category.&lt;/p&gt;

&lt;p&gt;These are not edge cases. They are part of the shape of the work.&lt;/p&gt;

&lt;h2&gt;
  
  
  That is what v0.14 is really about
&lt;/h2&gt;

&lt;p&gt;Not AI branding. Not pretending glide-mq started as an AI queue from day one.&lt;/p&gt;

&lt;p&gt;It did not.&lt;/p&gt;

&lt;p&gt;It started as the queue I wanted to have.&lt;/p&gt;

&lt;p&gt;Then building real AI systems on top of it kept exposing the same gaps, and eventually patching around them started feeling like the wrong move.&lt;/p&gt;

&lt;h2&gt;
  
  
  So v0.14 moves those behaviors into the queue
&lt;/h2&gt;

&lt;p&gt;That is what changed.&lt;/p&gt;

&lt;p&gt;glide-mq is still a queue. But v0.14 is where it started absorbing the behaviors that AI systems kept forcing into side systems.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Per-job &lt;code&gt;lockDuration&lt;/code&gt; so long jobs stop fighting short ones.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;job.reportUsage()&lt;/code&gt; so budgets and accounting live in the execution path.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;job.streamChunk()&lt;/code&gt; so streaming stays attached to the job.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;job.suspend()&lt;/code&gt; and &lt;code&gt;queue.signal()&lt;/code&gt; for human-in-the-loop flows.&lt;/li&gt;
&lt;li&gt;Ordered fallbacks.&lt;/li&gt;
&lt;li&gt;Token-aware throttling.&lt;/li&gt;
&lt;li&gt;Flow budgets that fail before the spend gets worse.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That is the direction now.&lt;/p&gt;

&lt;p&gt;Not queue plus five things you will bolt on later anyway.&lt;/p&gt;

&lt;p&gt;The queue should understand more of the workload it is running.&lt;/p&gt;

&lt;h2&gt;
  
  
  Final thought
&lt;/h2&gt;

&lt;p&gt;I do not think this is only a glide-mq story.&lt;/p&gt;

&lt;p&gt;I think AI workloads are exposing the wrong assumptions in a lot of older tooling.&lt;/p&gt;

&lt;p&gt;The problem is not just that queues need a few more integrations. The problem is that many of the abstractions we still lean on were designed for ordinary jobs, requests, and background work. AI systems have a different shape, and when the abstraction does not match, the missing behavior leaks out into glue.&lt;/p&gt;

&lt;p&gt;That is the part I stopped wanting to patch from the outside.&lt;/p&gt;






&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install &lt;/span&gt;glide-mq
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://github.com/avifenesh/glide-mq" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt; | &lt;a href="https://github.com/avifenesh/glidemq-examples" rel="noopener noreferrer"&gt;Examples&lt;/a&gt; | &lt;a href="https://glidemq.dev" rel="noopener noreferrer"&gt;Docs&lt;/a&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>queue</category>
      <category>valkey</category>
      <category>orchestration</category>
    </item>
    <item>
      <title>Your AI agent configs are probably silently broken -- I built a linter that catches it</title>
      <dc:creator>Avi Fenesh</dc:creator>
      <pubDate>Thu, 12 Feb 2026 00:54:18 +0000</pubDate>
      <link>https://forem.com/avifenesh/your-ai-agent-configs-are-probably-silently-broken-i-built-a-linter-that-catches-it-5g78</link>
      <guid>https://forem.com/avifenesh/your-ai-agent-configs-are-probably-silently-broken-i-built-a-linter-that-catches-it-5g78</guid>
      <description>&lt;div class="ltag__link"&gt;
  &lt;a href="/avifenesh" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__pic"&gt;
      &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1406394%2F53fd4ce6-829e-4132-bb74-bde79c256679.jpeg" alt="avifenesh"&gt;
    &lt;/div&gt;
  &lt;/a&gt;
  &lt;a href="https://dev.to/avifenesh/your-ai-agent-configs-are-probably-broken-and-you-dont-know-it-16n1" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__content"&gt;
      &lt;h2&gt;Your AI Agent Configs Are Probably Broken (and You Don't Know It)&lt;/h2&gt;
      &lt;h3&gt;Avi Fenesh ・ Feb 12&lt;/h3&gt;
      &lt;div class="ltag__link__taglist"&gt;
        &lt;span class="ltag__link__tag"&gt;#ai&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#tooling&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#devtools&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#opensource&lt;/span&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/a&gt;
&lt;/div&gt;


</description>
      <category>ai</category>
      <category>tooling</category>
      <category>devtools</category>
      <category>opensource</category>
    </item>
    <item>
      <title>Your AI Agent Configs Are Probably Broken (and You Don't Know It)</title>
      <dc:creator>Avi Fenesh</dc:creator>
      <pubDate>Thu, 12 Feb 2026 00:51:42 +0000</pubDate>
      <link>https://forem.com/avifenesh/your-ai-agent-configs-are-probably-broken-and-you-dont-know-it-16n1</link>
      <guid>https://forem.com/avifenesh/your-ai-agent-configs-are-probably-broken-and-you-dont-know-it-16n1</guid>
      <description>&lt;p&gt;I've spent the last year wiring up AI coding tools: Claude Code, Cursor, Copilot, Cline, Codex CLI, and friends. Skills, hooks, memory files, MCP servers, agent defs, plugin manifests — the whole stack.&lt;/p&gt;

&lt;p&gt;Here's the annoying truth: a huge chunk of these configs are silently broken. And the tools mostly don't tell you.&lt;/p&gt;

&lt;h2&gt;
  
  
  The problem nobody talks about
&lt;/h2&gt;

&lt;p&gt;If you misconfigure ESLint, it screams. If you misconfigure a &lt;code&gt;SKILL.md&lt;/code&gt;, nothing happens. The skill just… never triggers. No error. No warning. It's like the file doesn't exist.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://vercel.com/blog/agents-md-outperforms-skills-in-our-agent-evals" rel="noopener noreferrer"&gt;Vercel even measured this&lt;/a&gt;: skills invoke at &lt;strong&gt;0%&lt;/strong&gt; without correct syntax. Not "less often". Zero. One wrong frontmatter field and your carefully written skill is invisible to the agent.&lt;/p&gt;

&lt;p&gt;And then you get the classic "almost right" output. &lt;a href="https://survey.stackoverflow.co/2025/ai" rel="noopener noreferrer"&gt;Stack Overflow's 2025 developer survey&lt;/a&gt; has 66% of devs calling "almost right" their biggest AI frustration — and honestly, misconfigured agents produce exactly that. You think you gave the model the right rules/tools, but you didn't (or you did, just in the wrong format).&lt;/p&gt;

&lt;p&gt;It gets worse if you use multiple tools. Cursor for editing, Claude Code for terminal work, maybe Copilot for inline completions. Now you're maintaining parallel configs in different formats that are supposed to stay consistent. A rule that works in &lt;code&gt;.cursor/rules/testing.mdc&lt;/code&gt; might contradict what you put in &lt;code&gt;CLAUDE.md&lt;/code&gt;. Nobody catches it.&lt;/p&gt;

&lt;h2&gt;
  
  
  What actually goes wrong in the real world
&lt;/h2&gt;

&lt;p&gt;After digging through official specs, research, and a lot of "why is this not working?" debugging, the failure modes repeat:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Skills that never trigger:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;YAML frontmatter is missing / malformed (most common)&lt;/li&gt;
&lt;li&gt;Name is &lt;code&gt;PascalCase&lt;/code&gt; instead of &lt;code&gt;kebab-case&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;No trigger phrases → agent has no way to discover it&lt;/li&gt;
&lt;li&gt;Invalid values in model/context fields&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Skills that trigger when they shouldn't:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A deploy/publish/delete skill without &lt;code&gt;disable-model-invocation: true&lt;/code&gt; — Claude can auto-trigger it without you asking&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Hooks that quietly fail:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Event name is wrong (&lt;code&gt;PreToolExecution&lt;/code&gt; instead of &lt;code&gt;PreToolUse&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;command&lt;/code&gt; missing (so the hook is basically a comment)&lt;/li&gt;
&lt;li&gt;Script path points to nothing&lt;/li&gt;
&lt;li&gt;Dangerous commands sneaking in (&lt;code&gt;rm -rf&lt;/code&gt; in a hook with no guard… yeah)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Memory files that make the agent worse:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Generic fluff like "be helpful and accurate" (wastes context; the model already knows)&lt;/li&gt;
&lt;li&gt;Important rules buried mid-file (&lt;a href="https://en.wikipedia.org/wiki/Serial-position_effect" rel="noopener noreferrer"&gt;primacy/recency&lt;/a&gt; applies to LLM context too)&lt;/li&gt;
&lt;li&gt;Files that are too long for the tool to reliably respect — Windsurf caps rules files at 12,000 chars, Copilot global instructions work best under ~4,000 — past those ceilings the tool either truncates or deprioritizes your instructions&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Cross-tool conflicts:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Your &lt;code&gt;CLAUDE.md&lt;/code&gt; says &lt;code&gt;npm test&lt;/code&gt; but your &lt;code&gt;AGENTS.md&lt;/code&gt; says &lt;code&gt;pnpm test&lt;/code&gt; — one agent runs tests correctly, the other doesn't&lt;/li&gt;
&lt;li&gt;Cursor rules allow unrestricted &lt;code&gt;Bash&lt;/code&gt;, but your &lt;code&gt;CLAUDE.md&lt;/code&gt; disallows it — the agent's permissions depend on which tool you're using&lt;/li&gt;
&lt;li&gt;Multiple instruction layers with contradictions (and good luck knowing which one actually takes precedence)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;MCP servers with protocol violations:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Missing required fields in tool defs&lt;/li&gt;
&lt;li&gt;Invalid transport config&lt;/li&gt;
&lt;li&gt;Schema mismatches that lead to tools "existing" but not actually working&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  So I built a linter for this
&lt;/h2&gt;

&lt;p&gt;I couldn't find a tool that just tells you, plainly, across tools: "this config won't work".&lt;/p&gt;

&lt;p&gt;So I made one.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/avifenesh/agnix" rel="noopener noreferrer"&gt;agnix&lt;/a&gt; is a linter for AI agent configurations. It validates skills, hooks, memory files, plugins, MCP configs, and agent definitions across Claude Code, Cursor, GitHub Copilot, Cline, Codex CLI, OpenCode, and Gemini CLI.&lt;/p&gt;

&lt;p&gt;It's currently 156 rules. Every rule links to its source — an official spec, vendor docs, or research paper — with RFC 2119 severity levels (MUST vs SHOULD vs BEST_PRACTICE) so you know what's a hard requirement vs a recommendation. It's not "trust me bro".&lt;/p&gt;

&lt;p&gt;What it looks like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;npx agnix &lt;span class="nb"&gt;.&lt;/span&gt;
&lt;span class="go"&gt;
CLAUDE.md:15:1 warning: Generic instruction 'Be helpful and accurate' [fixable]
  help: Remove generic instructions. Claude already knows this.

.claude/skills/review/SKILL.md:3:1 error: Invalid name 'Review-Code' [fixable]
  help: Use lowercase letters and hyphens only (e.g., 'code-review')

.claude/settings.json:12:5 error: Script file not found: './scripts/lint.sh'
  help: Create the file or fix the path

.cursor/rules/testing.mdc:1:1 error: Missing required frontmatter
  help: Add YAML frontmatter with description, globs, and alwaysApply fields

Found 3 errors, 1 warning
  2 issues are automatically fixable

hint: Run with --fix to apply fixes
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It also auto-fixes.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;agnix --fix .&lt;/code&gt; rewrites configs to comply with specs&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;agnix --fix-safe .&lt;/code&gt; applies only high-certainty fixes (things like normalizing a skill name to kebab-case — not changes that might alter semantic meaning)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What it covers
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Claude Code:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;CLAUDE.md&lt;/code&gt;, hooks, agents, plugins, skills&lt;/li&gt;
&lt;li&gt;Frontmatter errors, invalid models, broken script paths, generic instructions, dangerous auto-invocation, manifest issues&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Cursor:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;.cursor/rules/*.mdc&lt;/code&gt;, &lt;code&gt;.cursorrules&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Missing frontmatter, invalid globs, deprecated formats, boolean-vs-string &lt;code&gt;alwaysApply&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;GitHub Copilot:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;.github/copilot-instructions.md&lt;/code&gt;, &lt;code&gt;.github/instructions/*.instructions.md&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Empty files, missing &lt;code&gt;applyTo&lt;/code&gt; frontmatter in scoped instructions, invalid glob patterns, file length limits&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;MCP:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;*.mcp.json&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Protocol violations, schema errors, transport config&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;AGENTS.md:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;AGENTS.md&lt;/code&gt;, &lt;code&gt;AGENTS.local.md&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Tool-specific size limits, platform-specific features without guards, nesting issues&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Cline:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;.clinerules&lt;/code&gt;, &lt;code&gt;.clinerules/*.md&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Structure + validation&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Codex CLI:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;.codex/config.toml&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Config validation&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;OpenCode:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;opencode.json&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Schema validation&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Gemini CLI:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;GEMINI.md&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Format validation&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;There are also cross-platform rules (XP-*) that detect conflicts between tools, and prompt-engineering rules (PE-*) that catch patterns that consistently degrade behavior.&lt;/p&gt;

&lt;h2&gt;
  
  
  How it works (quick)
&lt;/h2&gt;

&lt;p&gt;It's written in Rust.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Walk the repo (respect &lt;code&gt;.gitignore&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Detect file type by path (&lt;code&gt;SKILL.md&lt;/code&gt;, &lt;code&gt;.mdc&lt;/code&gt;, &lt;code&gt;settings.json&lt;/code&gt;, etc.)&lt;/li&gt;
&lt;li&gt;Validate in parallel across CPU cores&lt;/li&gt;
&lt;li&gt;Emit diagnostics + suggested fixes&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Typical performance: single file under 10ms, 100-file project ~200ms, 1000-file project ~2s.&lt;/p&gt;

&lt;p&gt;The rules stay current — a CI workflow monitors upstream specs weekly and flags when vendor documentation drifts from what agnix expects.&lt;/p&gt;

&lt;h2&gt;
  
  
  Not just a CLI
&lt;/h2&gt;

&lt;p&gt;agnix also runs as an LSP, so you get real-time validation in your editor:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;VS Code&lt;/strong&gt;: &lt;a href="https://marketplace.visualstudio.com/items?itemName=avifenesh.agnix" rel="noopener noreferrer"&gt;Extension on the marketplace&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;JetBrains&lt;/strong&gt;: &lt;a href="https://plugins.jetbrains.com/plugin/30087-agnix" rel="noopener noreferrer"&gt;Plugin on the marketplace&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Neovim&lt;/strong&gt;: plugin available&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Zed&lt;/strong&gt;: extension available&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;There's also an MCP server (agents can lint their own configs), plus a GitHub Action for CI:&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="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Validate agent configs&lt;/span&gt;
  &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;avifenesh/agnix@v0&lt;/span&gt;
  &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;target&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;claude-code'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Try it
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx agnix &lt;span class="nb"&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's it. Run it on your repo. In my experience, almost every repo with agent configs has a few issues — and they're usually the silent ones that have been dragging quality down for weeks.&lt;/p&gt;

&lt;p&gt;If you want a "real" install:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-g&lt;/span&gt; agnix          &lt;span class="c"&gt;# npm&lt;/span&gt;
brew tap avifenesh/agnix &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; brew &lt;span class="nb"&gt;install &lt;/span&gt;agnix  &lt;span class="c"&gt;# Homebrew&lt;/span&gt;
cargo &lt;span class="nb"&gt;install &lt;/span&gt;agnix-cli       &lt;span class="c"&gt;# Cargo&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;MIT/Apache-2.0, open source: &lt;a href="https://github.com/avifenesh/agnix" rel="noopener noreferrer"&gt;github.com/avifenesh/agnix&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Why I think this matters
&lt;/h2&gt;

&lt;p&gt;The ecosystem is fragmenting fast. Every tool invented its own format, its own conventions, and its own special ways to fail quietly.&lt;/p&gt;

&lt;p&gt;We have linters for code. For configs. For IaC. But the layer that tells AI agents how to behave — the stuff sitting between you and basically every AI interaction — had nothing.&lt;/p&gt;

&lt;p&gt;agnix doesn't tell you what to write. It tells you when what you wrote won't work.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;agnix is open source and free. &lt;a href="https://github.com/avifenesh/agnix" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt; | &lt;a href="https://avifenesh.github.io/agnix/" rel="noopener noreferrer"&gt;Docs&lt;/a&gt; | &lt;a href="https://www.npmjs.com/package/agnix" rel="noopener noreferrer"&gt;npm&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>tooling</category>
      <category>devtools</category>
      <category>opensource</category>
    </item>
  </channel>
</rss>
