<?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: Shridhar Shah</title>
    <description>The latest articles on DEV Community by Shridhar Shah (@shridhar_shah2297).</description>
    <link>https://dev.to/shridhar_shah2297</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%2F4005841%2F20cbe6ff-759d-4040-982d-5be692b089b9.png</url>
      <title>DEV Community: Shridhar Shah</title>
      <link>https://dev.to/shridhar_shah2297</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/shridhar_shah2297"/>
    <language>en</language>
    <item>
      <title>Stop Paying the Worst Case on Every Query: Adaptive Test-Time Compute</title>
      <dc:creator>Shridhar Shah</dc:creator>
      <pubDate>Wed, 05 Aug 2026 16:21:45 +0000</pubDate>
      <link>https://dev.to/shridhar_shah2297/stop-paying-the-worst-case-on-every-query-adaptive-test-time-compute-174o</link>
      <guid>https://dev.to/shridhar_shah2297/stop-paying-the-worst-case-on-every-query-adaptive-test-time-compute-174o</guid>
      <description>&lt;p&gt;&lt;em&gt;Best-of-N spends the same reasoning budget on trivial and brutal questions alike. A difficulty gate plus a verifier concentrates compute on the queries that need it — same accuracy, a fraction of the cost.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;TL;DR:&lt;/strong&gt; The standard way to buy accuracy at inference — &lt;strong&gt;best-of-N&lt;/strong&gt;, sample N reasoning attempts and pick the best — is flat-rate. It burns the full budget on a trivial query and still under-serves a brutal one. &lt;strong&gt;Adaptive test-time compute&lt;/strong&gt; allocates instead: a cheap gate estimates difficulty and a &lt;strong&gt;verifier&lt;/strong&gt; checks samples as they arrive, so easy queries stop after one accepted answer and hard queries keep exploring up to a cap. In a runnable Python simulation, adaptive matched best-of-8's &lt;strong&gt;91% accuracy using 77% fewer samples&lt;/strong&gt; (3,200 → 732; 1.8 samples/query vs 8). 2026 research reports the same effect on real benchmarks (&lt;a href="https://arxiv.org/abs/2602.01070" rel="noopener noreferrer"&gt;adaptive verifier-guided allocation&lt;/a&gt;, &lt;a href="https://arxiv.org/abs/2603.28135" rel="noopener noreferrer"&gt;budgeted metacognitive control&lt;/a&gt;).&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Mental model:&lt;/strong&gt; an exam where you're told to spend exactly 8 minutes on &lt;em&gt;every&lt;/em&gt; question. You waste 7 minutes on the ones you knew instantly and run out of time on the killers. Any real test-taker budgets by difficulty — glance, answer the easy ones, and pour the saved time into the hard tail.&lt;/p&gt;

&lt;h2&gt;
  
  
  The problem: uniform compute is the wrong default
&lt;/h2&gt;

&lt;p&gt;Test-time scaling is one of the biggest levers of the last two years: sample multiple reasoning trajectories, verify or vote, and accuracy climbs. But the common implementations spend &lt;strong&gt;uniformly&lt;/strong&gt; — best-of-N, self-consistency with a fixed sample count, fixed-width beams. Every query gets the same budget regardless of whether it's a lookup or a competition math problem.&lt;/p&gt;

&lt;p&gt;That's doubly wasteful. On the easy majority you pay for samples you never needed — the first answer was already right. On the hard tail, a fixed N may not be enough, and the budget you &lt;em&gt;could&lt;/em&gt; have spent there was squandered on the easy ones. As the 2026 work puts it, useful scaling should be &lt;strong&gt;selective&lt;/strong&gt;: driven by intermediate quality and uncertainty, not spread evenly across trajectories.&lt;/p&gt;

&lt;h2&gt;
  
  
  The pattern: gate, verify, stop early
&lt;/h2&gt;

&lt;p&gt;Two cheap components turn a flat budget into an allocated one:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;A &lt;strong&gt;difficulty gate&lt;/strong&gt; — a fast, approximate estimate of how hard the query is (a small classifier, a confidence probe, a router). It sets the &lt;em&gt;cap&lt;/em&gt;: how many samples this query is even allowed.&lt;/li&gt;
&lt;li&gt;A &lt;strong&gt;verifier&lt;/strong&gt; — a check on each sample (a process reward model, an NLI/consistency check, unit tests for code). It sets the &lt;em&gt;stop&lt;/em&gt;: as soon as a sample is accepted, stop spending.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Easy query → gate says "cap 1", first sample is accepted, done. Hard query → gate raises the cap and the loop keeps exploring until the verifier is satisfied or the cap is hit. The verifier is the same signal both policies could use — adaptive just also uses it to &lt;em&gt;stop&lt;/em&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;adaptive&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;rng&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;queries&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;d&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;queries&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;d_hat&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;clamp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nf"&gt;noise&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;            &lt;span class="c1"&gt;# cheap, noisy difficulty gate
&lt;/span&gt;        &lt;span class="n"&gt;budget&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;round&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;N_MAX&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;d_hat&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c1"&gt;# easy -&amp;gt; 1, hard -&amp;gt; up to N_MAX
&lt;/span&gt;        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;budget&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
            &lt;span class="n"&gt;ok&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;sample_is_correct&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;rng&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nf"&gt;verifier_accepts&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;rng&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ok&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
                &lt;span class="k"&gt;break&lt;/span&gt;                          &lt;span class="c1"&gt;# accepted: stop spending compute here
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  The result
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Adaptive Test-Time Compute — spend reasoning where it pays, not uniformly

  before → after:  3,200 samples for 91% accuracy (uniform best-of-8)  →  732 samples for 91% (77% less compute)

  400 queries, 113 hard / 287 easy; verifier 90% true-accept, 6% false-accept.

   policy                       samples   accuracy
   uniform best-of-8              3,200        91%
   adaptive (verifier-gated)        732        91%

   early stops (solved in 1 sample)    243   (61% of queries)
   avg samples / query                 1.8   (uniform always spends 8.0)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Identical accuracy, less than a quarter of the compute. 61% of queries were resolved in a single sample — the easy majority that best-of-N was over-serving — and the saved budget stays available for the hard tail. The lever is the difficulty &lt;em&gt;distribution&lt;/em&gt;: the more skewed toward easy your traffic, the bigger the win.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Reality check:&lt;/strong&gt; the 77% is from the simulation above — directional, not a benchmark. The 2026 papers report the same effect on real benchmarks — matching or beating uniform best-of-N at a fraction of the compute, with several-fold gains on hard math per unit compute — and your savings scale with how skewed-easy your traffic is and, above all, how good your verifier is (a weak verifier silently caps the whole approach).&lt;/p&gt;

&lt;h2&gt;
  
  
  Why this is where 2026 is heading
&lt;/h2&gt;

&lt;p&gt;Uniform test-time scaling is now understood as leaving compute on the table. &lt;a href="https://arxiv.org/abs/2602.01070" rel="noopener noreferrer"&gt;&lt;em&gt;What If We Allocate Test-Time Compute Adaptively?&lt;/em&gt; (arXiv 2602.01070)&lt;/a&gt; replaces fixed sampling with a process-reward-model signal that guides pruning and expansion &lt;em&gt;within&lt;/em&gt; a query and selection &lt;em&gt;across&lt;/em&gt; iterations, concentrating computation on high-utility reasoning paths and reporting several-fold gains on hard benchmarks per unit of compute. &lt;a href="https://arxiv.org/abs/2603.28135" rel="noopener noreferrer"&gt;&lt;em&gt;CoT2-Meta&lt;/em&gt; (arXiv 2603.28135)&lt;/a&gt; frames it as &lt;strong&gt;metacognitive control&lt;/strong&gt;: a controller decides whether to expand, prune, repair, stop, or abstain on each partial trajectory, separating object-level reasoning from meta-level budget decisions. The same instinct shows up in &lt;strong&gt;Adaptive RAG&lt;/strong&gt;, which routes a query to a direct answer, a single retrieval, or a full agentic loop based on estimated complexity.&lt;/p&gt;

&lt;p&gt;The transferable engineering idea needs no new model: &lt;strong&gt;put a verifier and a difficulty estimate in front of your sampling loop, and make the budget a function of both.&lt;/strong&gt; Even a crude gate (prompt length, a cheap classifier, first-sample confidence) plus a domain verifier (tests, a schema check, self-consistency) captures most of the savings.&lt;/p&gt;

&lt;h2&gt;
  
  
  How faithful is this demo?
&lt;/h2&gt;

&lt;p&gt;It models allocation, not reasoning: a "sample" is a difficulty-weighted coin flip and the verifier is a fixed true/false-accept rate, so it deliberately skips &lt;em&gt;why&lt;/em&gt; a sample is right. Two caveats it makes visible: the verifier isn't perfect (a 6% false-accept rate means adaptive can stop early on a wrong answer — verifier quality is the ceiling on this whole approach), and the difficulty gate is noisy, so some hard queries get under-budgeted. Both are exactly the failure modes the 2026 papers work to control with process reward models and calibrated confidence. Real gains depend on your verifier being better than your generator.&lt;/p&gt;

&lt;h2&gt;
  
  
  When not to use this
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;You don't have a decent verifier.&lt;/strong&gt; The verifier is the ceiling: a weak one stops early on wrong answers and quietly caps accuracy. No trustworthy check → don't gate on it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Traffic is uniformly hard.&lt;/strong&gt; With no easy majority to stop early on, adaptive collapses back to best-of-N — you save nothing.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A single pass already suffices.&lt;/strong&gt; If one sample is reliably right, you don't need test-time scaling at all; adaptive only pays once you're already sampling multiple times.&lt;/li&gt;
&lt;/ul&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;python3 demo.py   &lt;span class="c"&gt;# standard library only&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Sources &amp;amp; further reading
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Papers (2026)&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://arxiv.org/abs/2602.01070" rel="noopener noreferrer"&gt;&lt;em&gt;What If We Allocate Test-Time Compute Adaptively?&lt;/em&gt; (arXiv 2602.01070)&lt;/a&gt; — a verifier-guided framework where a process reward model drives per-query pruning, expansion, and selection instead of uniform sampling; large gains on hard math benchmarks per unit compute.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://arxiv.org/abs/2603.28135" rel="noopener noreferrer"&gt;&lt;em&gt;CoT2-Meta: Budgeted Metacognitive Control for Test-Time Reasoning&lt;/em&gt; (arXiv 2603.28135)&lt;/a&gt; — separates object-level reasoning from a meta-level controller that decides expand / prune / repair / stop / abstain under a budget.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://aclanthology.org/2026.findings-acl.1052.pdf" rel="noopener noreferrer"&gt;&lt;em&gt;Self-Correcting RAG&lt;/em&gt; (ACL Findings 2026)&lt;/a&gt; — casts context selection as a knapsack problem and uses NLI-guided search to spend test-time compute on faithfulness.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Background&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Snell et al., &lt;em&gt;Scaling LLM Test-Time Compute Optimally&lt;/em&gt; (2024), and self-consistency / best-of-N — the uniform baselines this pattern improves on.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://arxiv.org/abs/2403.14403" rel="noopener noreferrer"&gt;Adaptive RAG&lt;/a&gt; — route each query to the cheapest path (direct answer, single retrieval, or agentic loop) that will solve it.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>ai</category>
      <category>python</category>
      <category>architecture</category>
      <category>machinelearning</category>
    </item>
    <item>
      <title>One Long Prompt Shouldn't Freeze Everyone's Tokens: Prefill/Decode Disaggregation</title>
      <dc:creator>Shridhar Shah</dc:creator>
      <pubDate>Wed, 05 Aug 2026 16:21:43 +0000</pubDate>
      <link>https://dev.to/shridhar_shah2297/one-long-prompt-shouldnt-freeze-everyones-tokens-prefilldecode-disaggregation-5dmo</link>
      <guid>https://dev.to/shridhar_shah2297/one-long-prompt-shouldnt-freeze-everyones-tokens-prefilldecode-disaggregation-5dmo</guid>
      <description>&lt;p&gt;&lt;em&gt;An LLM request is two workloads in a trench coat — a heavy, bursty prefill and a stream of tiny latency-sensitive decodes. Running them on the same engines lets one big prompt stall everyone. Splitting them fixes it.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;TL;DR:&lt;/strong&gt; Every LLM request is two very different jobs. &lt;strong&gt;Prefill&lt;/strong&gt; reads the whole prompt — heavy, bursty, and slow for long contexts. &lt;strong&gt;Decode&lt;/strong&gt; then emits tokens one at a time — tiny, but &lt;em&gt;latency-sensitive&lt;/em&gt;. Run them on the same engines and a big prefill jumps ahead of everyone's decodes: &lt;strong&gt;head-of-line blocking&lt;/strong&gt;, and the token stream stutters. &lt;strong&gt;Prefill/decode disaggregation&lt;/strong&gt; puts prefill and decode on separate pools so decodes never queue behind a prefill. In a runnable Go simulation, splitting the pools cut &lt;strong&gt;p99 inter-token latency by 66%&lt;/strong&gt; (88ms → 30ms) — trading a little time-to-first-token for a far smoother stream. This is now standard practice in frontier serving stacks (&lt;a href="https://arxiv.org/abs/2401.09670" rel="noopener noreferrer"&gt;DistServe&lt;/a&gt;, &lt;a href="https://arxiv.org/abs/2311.18677" rel="noopener noreferrer"&gt;Splitwise&lt;/a&gt;, &lt;a href="https://vllm.ai/blog/2026-05-06-mooncake-store" rel="noopener noreferrer"&gt;vLLM × Mooncake&lt;/a&gt;).&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Mental model:&lt;/strong&gt; a coffee shop with one worker who both grinds beans and pours espresso. A customer orders a giant batch grind and everyone waiting for a simple pour is stuck behind it. Split the shop into a &lt;em&gt;grinder station&lt;/em&gt; and a &lt;em&gt;pour station&lt;/em&gt; and the pours keep flowing no matter how big the grind.&lt;/p&gt;

&lt;h2&gt;
  
  
  The problem: two workloads, one queue
&lt;/h2&gt;

&lt;p&gt;Serving an LLM token is not one kind of work — it's two:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Prefill&lt;/strong&gt; processes the entire prompt to build the KV cache. It's a big, compute-bound burst, and it scales with prompt length: a 100k-token context is a genuinely slow operation.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Decode&lt;/strong&gt; generates the response one token at a time, each step cheap but on the &lt;strong&gt;critical path of what the user feels&lt;/strong&gt; — the inter-token latency (ITL) &lt;em&gt;is&lt;/em&gt; the smoothness of the stream.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Colocate them — the default — and they fight for the same compute. Continuous batching helps throughput but doesn't remove the conflict: when the engine runs a long prefill, the decodes it's also hosting have to wait. And they can't flee to a less-busy engine, because &lt;em&gt;this&lt;/em&gt; engine holds their KV cache. So one long-context prompt lands and every active token stream on that engine stutters. Your p99 ITL is hostage to your longest prompt.&lt;/p&gt;

&lt;h2&gt;
  
  
  The pattern: split the pools
&lt;/h2&gt;

&lt;p&gt;Disaggregation (&lt;a href="https://arxiv.org/abs/2401.09670" rel="noopener noreferrer"&gt;DistServe&lt;/a&gt;, &lt;a href="https://arxiv.org/abs/2311.18677" rel="noopener noreferrer"&gt;Splitwise&lt;/a&gt;) separates the two phases onto different hardware:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;A &lt;strong&gt;prefill pool&lt;/strong&gt; does nothing but build KV caches — bursty, compute-heavy work, isolated.&lt;/li&gt;
&lt;li&gt;A &lt;strong&gt;decode pool&lt;/strong&gt; does nothing but stream tokens — steady, latency-sensitive work, isolated.&lt;/li&gt;
&lt;li&gt;The KV cache is &lt;strong&gt;handed off&lt;/strong&gt; from prefill to decode (the expensive-to-move part — this is exactly what fast KV transfer layers like Mooncake exist to make cheap).&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Now a giant prefill can't block anyone's decodes, because it physically runs on a different pool. Each pool can also be tuned and scaled independently for its own SLO (TTFT for prefill, ITL for decode) instead of compromising on one knob for both.&lt;/p&gt;

&lt;p&gt;The simulation pins each request's decodes to the engine that ran its prefill (KV-cache locality) — the constraint that makes colocated blocking unavoidable:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;disaggregated&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;prefill&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;server&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;dur&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;prefill&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="c"&gt;// prefill pool&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;server&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;dur&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;decodeDur&lt;/span&gt;        &lt;span class="c"&gt;// decode pool — never behind a prefill&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;server&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;req&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt;                    &lt;span class="c"&gt;// pinned engine holds this request's KV cache&lt;/span&gt;
    &lt;span class="c"&gt;// ...its decodes are stuck behind whatever prefill lands here&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  The result
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Prefill/Decode Disaggregation — keep long prefills from stalling the token stream
  before → after:  p99 inter-token latency 88ms (colocated)  →  30ms (disaggregated)   (66% lower)
  240 requests, 2 servers, 20% long-context bursts (700–1800ms prefill), 20 decode steps × 5ms.

   layout                  p99 token lat mean token lat    mean TTFT
   colocated (shared)              88 ms          15 ms       426 ms
   disaggregated (split)           30 ms          11 ms      1032 ms
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Same workload, same total hardware (2 engines each). Colocated lets bursty prefills jump ahead of tiny decodes, so the p99 token stutters to 88ms. Disaggregated isolates decodes and holds p99 to 30ms — a &lt;strong&gt;66% smoother&lt;/strong&gt; stream. The honest cost is &lt;strong&gt;TTFT&lt;/strong&gt;: with only one engine dedicated to prefill, first tokens arrive later (426ms → 1032ms). That's the real knob disaggregation gives you — pool sizing lets you buy back TTFT by provisioning prefill and decode independently.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Reality check:&lt;/strong&gt; these are simulated queue latencies, not GPU numbers — directional only. The direction is well-established: DistServe and Splitwise report multiples-higher goodput under latency SLOs from PD disaggregation, and the real-world win hinges on how cheap your KV-cache transfer is and how much prefill actually contends with decode.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why this is where 2026 is heading
&lt;/h2&gt;

&lt;p&gt;Disaggregation went from research idea to default in two years. &lt;a href="https://arxiv.org/abs/2401.09670" rel="noopener noreferrer"&gt;DistServe&lt;/a&gt; showed that separating prefill and decode and sizing each for its own SLO can serve &lt;strong&gt;multiples more requests&lt;/strong&gt; under latency constraints; &lt;a href="https://arxiv.org/abs/2311.18677" rel="noopener noreferrer"&gt;Splitwise&lt;/a&gt; made the same case for splitting the phases across different hardware. By 2026 it's productized: vLLM ships PD disaggregation, and the &lt;a href="https://vllm.ai/blog/2026-05-06-mooncake-store" rel="noopener noreferrer"&gt;vLLM × Mooncake&lt;/a&gt; work pairs it with a distributed KV cache pool so prefill and decode engines — even on different machines — share caches over fast transport. The load-bearing enabler is exactly the KV-cache handoff this demo hand-waves.&lt;/p&gt;

&lt;p&gt;The transferable idea generalizes past LLMs: &lt;strong&gt;when one queue mixes bursty heavy work with steady latency-sensitive work, isolate them.&lt;/strong&gt; It's the same instinct as separating batch from interactive traffic, or OLAP from OLTP — applied at the token level.&lt;/p&gt;

&lt;h2&gt;
  
  
  How faithful is this demo?
&lt;/h2&gt;

&lt;p&gt;It models queueing and head-of-line blocking, not GPUs: "prefill" and "decode" are service times, and it ignores continuous batching, the real (non-zero) cost of KV-cache transfer, and memory pressure — all of which real systems must handle, and which is why cheap KV transport matters so much. Two honest caveats: disaggregation isn't free (you pay a transfer and a TTFT hop, visible above), and it only pays off when prefill bursts actually contend with latency-sensitive decodes. Short, uniform prompts under light load won't show the gap — measure your ITL tail before splitting.&lt;/p&gt;

&lt;h2&gt;
  
  
  When not to use this
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Small scale / a single GPU.&lt;/strong&gt; With nothing to disaggregate across, the KV-transfer hop and the TTFT cost dominate any benefit.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Short, uniform prompts.&lt;/strong&gt; No bursty long prefills means no head-of-line blocking to fix.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;TTFT is your primary SLO.&lt;/strong&gt; Disaggregation trades first-token latency for a smoother stream; if users care most about time-to-first-token, it can be a net loss.&lt;/li&gt;
&lt;/ul&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;go run &lt;span class="nb"&gt;.&lt;/span&gt;   &lt;span class="c"&gt;# standard library only&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Sources &amp;amp; further reading
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Papers&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Zhong et al. — &lt;a href="https://arxiv.org/abs/2401.09670" rel="noopener noreferrer"&gt;&lt;em&gt;DistServe: Disaggregating Prefill and Decoding for Goodput-optimized LLM Serving&lt;/em&gt; (OSDI 2024, arXiv 2401.09670)&lt;/a&gt; — the case for splitting the phases and sizing each pool for its own latency target.&lt;/li&gt;
&lt;li&gt;Patel et al. — &lt;a href="https://arxiv.org/abs/2311.18677" rel="noopener noreferrer"&gt;&lt;em&gt;Splitwise: Efficient Generative LLM Inference Using Phase Splitting&lt;/em&gt; (ISCA 2024, arXiv 2311.18677)&lt;/a&gt; — splits prefill and decode across distinct machines to raise throughput per dollar and per watt.&lt;/li&gt;
&lt;li&gt;Qin et al. — &lt;a href="https://arxiv.org/abs/2407.00079" rel="noopener noreferrer"&gt;&lt;em&gt;Mooncake: A KVCache-centric Disaggregated Architecture for LLM Serving&lt;/em&gt; (FAST 2025, arXiv 2407.00079)&lt;/a&gt; — trades more storage for less compute; the KV-cache pool that makes cross-engine handoff practical.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Engineering&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://vllm.ai/blog/2026-05-06-mooncake-store" rel="noopener noreferrer"&gt;Serving Agentic Workloads at Scale with vLLM × Mooncake (2026)&lt;/a&gt; — production PD disaggregation plus a distributed KV cache pool for multi-turn, agentic serving.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://dreaming.press/posts/kv-cache-offloading-lmcache-vs-mooncake-vs-dynamo.html" rel="noopener noreferrer"&gt;KV Cache Offloading: LMCache vs Mooncake vs Dynamo&lt;/a&gt; — how the KV-transfer tier underneath disaggregation actually works.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>ai</category>
      <category>go</category>
      <category>architecture</category>
      <category>distributedsystems</category>
    </item>
    <item>
      <title>Your Agent Has a Bug You Can't Reproduce. Here's How to Catch It.</title>
      <dc:creator>Shridhar Shah</dc:creator>
      <pubDate>Wed, 05 Aug 2026 16:21:08 +0000</pubDate>
      <link>https://dev.to/shridhar_shah2297/your-agent-has-a-bug-you-cant-reproduce-heres-how-to-catch-it-19mp</link>
      <guid>https://dev.to/shridhar_shah2297/your-agent-has-a-bug-you-cant-reproduce-heres-how-to-catch-it-19mp</guid>
      <description>&lt;p&gt;&lt;em&gt;Deterministic simulation testing drives every fault, clock, and random choice from one seed — so a flaky, once-in-production agent bug becomes a reproducible artifact you can shrink to one line.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;TL;DR:&lt;/strong&gt; The worst agent bugs only appear under a specific interleaving of faults — a tool fails &lt;em&gt;right&lt;/em&gt; after a side effect, a retry fires, and money moves twice. Happy-path tests miss it, and when it hits production you can't reproduce it. &lt;strong&gt;Deterministic simulation testing (DST)&lt;/strong&gt; — the technique behind FoundationDB, TigerBeetle, and Antithesis — makes faults, timing, and randomness a pure function of one seed, so any failure replays exactly and can be shrunk to its minimal cause. In a runnable Python demo, the happy path passes, seeded fuzzing catches a double-charge, replays it identically, and shrinks a 4-fault schedule down to the single fault that matters.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Mental model:&lt;/strong&gt; a flight simulator with a record button. Instead of waiting for a storm to hit a real plane, you conjure storms on demand — and when one crashes the plane, you can replay that exact storm frame-by-frame until you understand it, then strip it down to the one gust that did the damage.&lt;/p&gt;

&lt;h2&gt;
  
  
  The problem: the bugs that matter are the ones you can't reproduce
&lt;/h2&gt;

&lt;p&gt;Agents run in a hostile world. Tools time out, APIs return errors, retries fire, and steps race. Most of the time everything is fine. But somewhere in the space of &lt;em&gt;when exactly does the fault land&lt;/em&gt; hides a bug — a retry that isn't idempotent, a state update that assumes a call succeeded, a compensation that runs twice. It shows up once, in production, moves real money, and then vanishes: you re-run the same input and it works, because the timing was different this time.&lt;/p&gt;

&lt;p&gt;Traditional tests can't help. Example-based tests exercise the happy path. Even randomized tests, if they &lt;em&gt;do&lt;/em&gt; trip the bug, can't tell you how — the randomness that triggered it is gone.&lt;/p&gt;

&lt;h2&gt;
  
  
  The pattern: make nondeterminism a function of a seed
&lt;/h2&gt;

&lt;p&gt;DST flips the model. Every source of nondeterminism — fault injection, the clock, thread scheduling, RNG — is routed through a single &lt;strong&gt;seed&lt;/strong&gt;. That buys three things:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Reproducibility.&lt;/strong&gt; The same seed always produces the same run. A failure is a permanent artifact.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Exploration.&lt;/strong&gt; Sweep thousands of seeds (fast, in simulated time) to explore fault interleavings a human would never think to write by hand.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Shrinking.&lt;/strong&gt; Once you have a failing scenario, mechanically remove pieces until only the minimal trigger remains — turning a chaotic failure into a one-line repro.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here a "fault schedule" is just the set of steps that will fail on their first attempt — the entire source of nondeterminism, made explicit and seedable. The workflow has a real bug: &lt;code&gt;confirm&lt;/code&gt;'s retry re-runs &lt;code&gt;charge&lt;/code&gt; with no idempotency guard.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;step&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;PLAN&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;step&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;confirm&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
            &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="nf"&gt;attempt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;confirm&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="k"&gt;break&lt;/span&gt;
            &lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="n"&gt;Fault&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="nf"&gt;attempt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;charge&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;   &lt;span class="c1"&gt;# &amp;lt;-- the bug: a second, unguarded charge on retry
&lt;/span&gt;    &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;            &lt;span class="c1"&gt;# every other step has a safe, idempotent retry
&lt;/span&gt;            &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="nf"&gt;attempt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;step&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="k"&gt;break&lt;/span&gt;
            &lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="n"&gt;Fault&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="k"&gt;continue&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Because the run is a pure function of its schedule, fuzzing, replay, and shrinking are trivial:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;fuzz&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;seeds&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;seed&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;seeds&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;schedule&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;random_schedule&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;random&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Random&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;seed&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="nf"&gt;invariant_holds&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;run_agent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;schedule&lt;/span&gt;&lt;span class="p"&gt;)):&lt;/span&gt;   &lt;span class="c1"&gt;# property: charges ≤ 1
&lt;/span&gt;            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;seed&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;schedule&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;shrink&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;schedule&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;minimal&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;schedule&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;step&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;list&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;minimal&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="nf"&gt;invariant_holds&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;run_agent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;minimal&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;step&lt;/span&gt;&lt;span class="p"&gt;})):&lt;/span&gt;
            &lt;span class="n"&gt;minimal&lt;/span&gt; &lt;span class="o"&gt;-=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;step&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;       &lt;span class="c1"&gt;# drop faults that aren't needed to trigger the failure
&lt;/span&gt;    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;minimal&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  The result
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;1. happy-path test (no faults):      PASS  &amp;lt;- the bug is invisible here

2. fuzzing seeded fault schedules:   FAIL on seed 1
      schedule = ['analyze', 'confirm', 'notify', 'plan']  -&amp;gt;  charged the customer 2x

3. replay same schedule twice:       2x and 2x charges  -&amp;gt;  identical (reproducible)

4. shrink to the minimal cause:      ['confirm']
      one fault at 'confirm' is all it takes to double-charge.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The happy path passed — that's why this bug would ship. Fuzzing found a failing schedule with four faults, three of them irrelevant noise. Replay proved it reproduces exactly. Shrinking stripped the noise to a one-line repro: &lt;em&gt;a single fault at &lt;code&gt;confirm&lt;/code&gt; double-charges.&lt;/em&gt; That's a bug report a developer can fix in minutes, not a haunted "works on my machine."&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Reality check:&lt;/strong&gt; the state space here is tiny, but the technique isn't a toy — this exact method (FoundationDB, TigerBeetle's VOPR, Antithesis) catches real, money-moving bugs in production databases. At scale the hard part is &lt;em&gt;exploration&lt;/em&gt; — which fault interleavings to try — not the seed-and-replay mechanism shown here.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why this is where 2026 is heading
&lt;/h2&gt;

&lt;p&gt;DST is having a moment. FoundationDB pioneered it; TigerBeetle's VOPR "speeds up time arbitrarily — one minute of simulation equals days of real testing"; Antithesis raised a large round selling a deterministic hypervisor that replays &lt;em&gt;every instruction&lt;/em&gt; to reproduce failures. Nearly every serious database company is now using or evaluating it.&lt;/p&gt;

&lt;p&gt;Agents are the next obvious target, and arguably a better fit: an agent's think→act→observe loop is already a sequence of discrete, mockable steps with well-defined failure points (tool errors, timeouts, partial writes). The engineering shift is to &lt;strong&gt;write the agent so its nondeterminism is injectable&lt;/strong&gt; — clock, retries, and tool faults behind seams you control — and then let a simulator manufacture the chaos. The property you assert ("charges ≤ 1", "no orphaned reservations", "the plan never regresses") becomes the specification of correct behavior under failure.&lt;/p&gt;

&lt;h2&gt;
  
  
  How faithful is this demo?
&lt;/h2&gt;

&lt;p&gt;It's a minimal model — nondeterminism is just "which steps fault first" and the state space is tiny. Real DST is harder in two ways: &lt;strong&gt;determinism is a discipline&lt;/strong&gt; (every clock read and interleaving must route through the seed, which is why Antithesis built a hypervisor to enforce it), and &lt;strong&gt;exploration is the real problem&lt;/strong&gt; (huge state spaces mean DST pairs with property-based testing and guided fuzzing). Start small: make one agent's faults and clock injectable, then assert one invariant across many seeds.&lt;/p&gt;

&lt;h2&gt;
  
  
  When not to use this
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Stateless, single-shot prompts.&lt;/strong&gt; With no faults, retries, or ordering to interleave, there's no nondeterminism to seed — plain example tests are enough.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The bug is model quality, not orchestration.&lt;/strong&gt; DST catches control-flow and fault-handling bugs; it won't tell you the model gave a worse answer.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;You can't make nondeterminism injectable.&lt;/strong&gt; If the clock, retries, and tool faults can't be routed through a seam you control, you can't get determinism — retrofit the seams first.&lt;/li&gt;
&lt;/ul&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;python3 demo.py   &lt;span class="c"&gt;# standard library only&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Sources &amp;amp; further reading
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Platforms &amp;amp; write-ups&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://antithesis.com/docs/resources/deterministic_simulation_testing/" rel="noopener noreferrer"&gt;Antithesis — Deterministic simulation testing: how it works and when to use it&lt;/a&gt; — seeds, fault injection, time-travel debugging, and why DST pairs with property-based testing.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/tigerbeetle/tigerbeetle/blob/main/docs/internals/vopr.md" rel="noopener noreferrer"&gt;TigerBeetle — the VOPR simulator&lt;/a&gt; — stubs out clock/network/disk, injects partitions and corruption, and replays any failure from &lt;code&gt;(seed, commit)&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://apple.github.io/foundationdb/testing.html" rel="noopener noreferrer"&gt;FoundationDB — simulation testing&lt;/a&gt; — the origin of the approach.&lt;/li&gt;
&lt;li&gt;Phil Eaton — &lt;a href="https://notes.eatonphil.com/2024-08-20-deterministic-simulation-testing.html" rel="noopener noreferrer"&gt;What's the big deal about Deterministic Simulation Testing?&lt;/a&gt; — an approachable tour of controlling clocks and randomness.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>ai</category>
      <category>python</category>
      <category>testing</category>
      <category>distributedsystems</category>
    </item>
    <item>
      <title>Stop Making Your Agent Wait: Branch Prediction for Tool Calls</title>
      <dc:creator>Shridhar Shah</dc:creator>
      <pubDate>Wed, 05 Aug 2026 16:21:05 +0000</pubDate>
      <link>https://dev.to/shridhar_shah2297/stop-making-your-agent-wait-branch-prediction-for-tool-calls-1284</link>
      <guid>https://dev.to/shridhar_shah2297/stop-making-your-agent-wait-branch-prediction-for-tool-calls-1284</guid>
      <description>&lt;p&gt;&lt;em&gt;Speculative tool execution guesses the next tool while the model is still reasoning, runs it in parallel, and hides the latency — discarding the guess when it's wrong.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;TL;DR:&lt;/strong&gt; An agent's think→act→observe loop is serial, so it burns a huge share of wall-clock sitting idle while a tool runs. &lt;strong&gt;Speculative tool execution&lt;/strong&gt; borrows branch prediction from CPUs: a cheap predictor guesses the next tool call and runs it &lt;em&gt;during&lt;/em&gt; the model's reasoning. If the guess matches, the result is already there and the wait disappears; if not, it's discarded and the real call runs — never a wrong answer. A confidence gate avoids wasting compute on low-odds guesses. In a runnable Go demo, a 58% hit rate cut wall-clock by &lt;strong&gt;1.3×&lt;/strong&gt; with zero correctness impact. Four 2026 papers (&lt;a href="https://www.cs.columbia.edu/~kkaffes/papers/speculative-actions-iclr26.pdf" rel="noopener noreferrer"&gt;Speculative Actions&lt;/a&gt;, &lt;a href="https://arxiv.org/abs/2607.03333" rel="noopener noreferrer"&gt;SPORK&lt;/a&gt;, &lt;a href="https://arxiv.org/abs/2603.18897" rel="noopener noreferrer"&gt;PASTE&lt;/a&gt;, &lt;a href="https://arxiv.org/abs/2607.25816" rel="noopener noreferrer"&gt;Speculate While You Reason&lt;/a&gt;) report 20–48% real speedups.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Mental model:&lt;/strong&gt; a chef who starts searing the steak they're &lt;em&gt;pretty sure&lt;/em&gt; you'll order while you're still reading the menu. If you order it, dinner is early. If you don't, they toss it and cook what you asked — you never get served the wrong dish, they just did some work in the background.&lt;/p&gt;

&lt;h2&gt;
  
  
  The problem: the agent loop wastes its own time
&lt;/h2&gt;

&lt;p&gt;Agents run a strictly serial loop: reason, emit a tool call, &lt;strong&gt;wait&lt;/strong&gt; for the result, reason again. That wait — a web request, a database query, a code execution — is dead time. The GPU (or your API budget) idles while the tool runs. Prior work measures this idle at 16–37% of wall-clock in typical workloads and up to 61% in tool-heavy ones. For a chatty, multi-step agent, that's the single biggest lever on latency, and no amount of prompt tuning touches it.&lt;/p&gt;

&lt;p&gt;The catch is that the loop is only &lt;em&gt;logically&lt;/em&gt; serial. The model doesn't strictly need to finish reasoning before the tool runs — it just needs the tool's result to be there when it's done.&lt;/p&gt;

&lt;h2&gt;
  
  
  The pattern: predict, pre-execute, verify
&lt;/h2&gt;

&lt;p&gt;CPUs solved this with branch prediction: guess which way a branch goes and execute ahead speculatively, rolling back if wrong. LLM inference reuses the idea in speculative decoding. Applied to agents it becomes &lt;strong&gt;speculative tool execution&lt;/strong&gt;:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Predict&lt;/strong&gt; the next tool call from the trajectory so far (a cheap draft model, a probe on the agent's own logits, or — as here — a learned pattern of recurring tool sequences).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Pre-execute&lt;/strong&gt; the guessed call in parallel &lt;em&gt;while the model keeps reasoning&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Verify&lt;/strong&gt; when the model emits its real call. Exact match → reuse the ready result. Mismatch → discard and run the real one.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The correctness guarantee is the whole point: the agent's actual output is always the ground truth. Speculation can only ever &lt;em&gt;remove waiting&lt;/em&gt;, never change the answer.&lt;/p&gt;

&lt;p&gt;A learned predictor over recurring tool patterns:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;predictor&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;predict&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;last&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;guess&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;confidence&lt;/span&gt; &lt;span class="kt"&gt;float64&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;row&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;counts&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;last&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="n"&gt;best&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;bestN&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;total&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="s"&gt;""&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;tool&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="k"&gt;range&lt;/span&gt; &lt;span class="n"&gt;row&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;total&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;bestN&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;best&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;bestN&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;tool&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;best&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;float64&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bestN&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="kt"&gt;float64&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;total&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;And the speculate-while-thinking core — the guessed tool runs in a goroutine, overlapping the model's reasoning; a confidence gate keeps us from speculating when the odds are poor:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;guess&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;conf&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;pred&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;predict&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;last&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;guess&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="s"&gt;""&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;conf&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="n"&gt;gate&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;specCh&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;make&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;chan&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;go&lt;/span&gt; &lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;specCh&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="n"&gt;runTool&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;}(&lt;/span&gt;&lt;span class="n"&gt;guess&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c"&gt;// runs in parallel with think&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;thinkMS&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Millisecond&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c"&gt;// the model reasons&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;specCh&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;guess&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;actual&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt;&lt;span class="n"&gt;specCh&lt;/span&gt;          &lt;span class="c"&gt;// correct: result already ready — latency hidden&lt;/span&gt;
    &lt;span class="n"&gt;hits&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;runTool&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;actual&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;   &lt;span class="c"&gt;// miss: discard the speculation, run the real tool&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  The result
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Speculative Tool Execution — guess the next tool and run it while the model thinks
  24-step agent loop; think=40ms, tool=60ms per step.

   serial agent loop        2.443s   (think, then wait for the tool, every step)
   speculative loop         1.869s   (14 hits / 4 misses / 1 gated out)

   next-tool hit rate          58%
   wall-clock speedup        1.31x  (tool latency hidden behind reasoning)
   wasted speculations          4   (discarded on a miss — never a wrong answer)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The four misses cost some throwaway background work; the one gated-out step shows the confidence gate declining to gamble. The 14 hits each hid a tool call behind reasoning that was going to happen anyway. Correctness is untouched — every actual tool call still ran (or was proven already run).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Reality check:&lt;/strong&gt; the wall-clock here comes from fixed sleeps (and drifts a little run-to-run), so read the &lt;em&gt;hit rate&lt;/em&gt; and the mechanism, not the exact milliseconds. The direction is real: the 2026 papers report 20–48% speedups on live agents — SPORK predicts the next tool at 74–99% accuracy, PASTE cuts task-completion time ~48% — and your gain scales with how predictable your tool sequences are and how much of each step is actually tool latency.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why this is where 2026 is heading
&lt;/h2&gt;

&lt;p&gt;This jumped from theory to a small research wave in 2026, and the designs converge on the same shape. &lt;a href="https://arxiv.org/abs/2607.03333" rel="noopener noreferrer"&gt;SPORK&lt;/a&gt; forks a probe off the agent's own KV cache to predict the next tool with 74–99% accuracy and gates dispatch on confidence — exactly the gate-and-discard structure above. &lt;a href="https://arxiv.org/abs/2603.18897" rel="noopener noreferrer"&gt;PASTE&lt;/a&gt; mines recurring tool-call &lt;em&gt;patterns&lt;/em&gt; (the assumption this demo's predictor encodes) and reports up to 48% lower task completion time. &lt;a href="https://www.cs.columbia.edu/~kkaffes/papers/speculative-actions-iclr26.pdf" rel="noopener noreferrer"&gt;Speculative Actions&lt;/a&gt; frames it generally: a fast model stages likely actions so that &lt;em&gt;validation, not waiting, is the critical path&lt;/em&gt;. And &lt;a href="https://arxiv.org/abs/2607.25816" rel="noopener noreferrer"&gt;Speculate While You Reason&lt;/a&gt; shows the agent is its own best predictor.&lt;/p&gt;

&lt;p&gt;The transferable engineering idea needs no training: &lt;strong&gt;any time your agent has predictable structure and idle wait, you can overlap them.&lt;/strong&gt; Recurring tool sequences, known data-fetch fan-outs, and retry-then-reopen patterns are all speculatable today with a controller sitting over a normal completion API.&lt;/p&gt;

&lt;h2&gt;
  
  
  How faithful is this demo?
&lt;/h2&gt;

&lt;p&gt;It models control flow and timing, not reasoning: "thinking" and "tool latency" are fixed sleeps and the predictor is a first-order Markov count over tool names — real speculators also predict tool &lt;strong&gt;arguments&lt;/strong&gt; (much harder) and pay for a draft model. Two caveats the papers stress: speculation only helps when tool latency is a real slice of step time, and mispredicted &lt;strong&gt;side effects&lt;/strong&gt; must be safe to discard (a read-only call is free to speculate; a &lt;code&gt;charge_customer&lt;/code&gt; is not). Start by speculating idempotent, read-only tools on your most predictable loops.&lt;/p&gt;

&lt;h2&gt;
  
  
  When not to use this
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Unpredictable next tools.&lt;/strong&gt; A low hit rate means you mostly discard speculative work — you burn extra compute for little latency win.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Side effects that aren't safe to discard.&lt;/strong&gt; Speculate read-only calls freely; never speculate a &lt;code&gt;charge_customer&lt;/code&gt; or any write you can't cleanly roll back.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Tool latency is a small slice of step time.&lt;/strong&gt; If reasoning dominates, there's little wait to hide, and compute is better spent elsewhere.&lt;/li&gt;
&lt;/ul&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;go run &lt;span class="nb"&gt;.&lt;/span&gt;   &lt;span class="c"&gt;# standard library only&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Sources &amp;amp; further reading
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Papers (2026)&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Zhou et al. — &lt;a href="https://www.cs.columbia.edu/~kkaffes/papers/speculative-actions-iclr26.pdf" rel="noopener noreferrer"&gt;&lt;em&gt;Speculative Actions: A Lossless Framework for Faster Agentic Systems&lt;/em&gt; (ICLR 2026)&lt;/a&gt; — fast models predict and stage actions; up to 55% next-action accuracy → up to 20% latency reduction, with a cost–latency analysis for tuning speculative breadth.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://arxiv.org/abs/2607.03333" rel="noopener noreferrer"&gt;&lt;em&gt;SPORK: Self-Speculative Forking to Accelerate Agentic LLM Inference&lt;/em&gt; (arXiv 2607.03333)&lt;/a&gt; — training-free controller; a prefix-cache fork predicts the next tool at 74.6–99.6% accuracy, a confidence gate filters mispredictions, serial fallback on rejection.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://arxiv.org/abs/2603.18897" rel="noopener noreferrer"&gt;&lt;em&gt;Act While Thinking: Pattern-Aware Speculative Tool Execution (PASTE)&lt;/em&gt; (arXiv 2603.18897)&lt;/a&gt; — exploits recurring tool-call sequences and parameter dependencies; 48.5% lower task completion time, 1.8× tool throughput.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://arxiv.org/abs/2607.25816" rel="noopener noreferrer"&gt;&lt;em&gt;Speculate While You Reason: Teaching Agents to Predict Their Next Tool Call via Joint Agent–Speculator RL&lt;/em&gt; (arXiv 2607.25816)&lt;/a&gt; — the agent itself is the speculator; Hit@1 improves from ~44% to ~61% while preserving task success.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Background&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Speculative decoding for LLMs and branch prediction in CPUs — the same predict-execute-verify lineage this pattern descends from.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>ai</category>
      <category>go</category>
      <category>architecture</category>
      <category>concurrency</category>
    </item>
    <item>
      <title>The Agent That Answers Before You Ask</title>
      <dc:creator>Shridhar Shah</dc:creator>
      <pubDate>Wed, 05 Aug 2026 16:20:31 +0000</pubDate>
      <link>https://dev.to/shridhar_shah2297/the-agent-that-answers-before-you-ask-55bi</link>
      <guid>https://dev.to/shridhar_shah2297/the-agent-that-answers-before-you-ask-55bi</guid>
      <description>&lt;p&gt;&lt;em&gt;Sleep-time compute: split the budget so a background worker does the predictable thinking while idle — and the user waits far less when they finally ask.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;TL;DR:&lt;/strong&gt; Most agents only think when a request arrives — the user waits and you pay full latency every time. But between sessions there's idle capacity, and many queries are predictable variants of past ones over context that barely changes. &lt;strong&gt;Sleep-time compute&lt;/strong&gt; (Letta; Lin et al., 2025) splits the budget: a background worker pre-answers likely queries while idle, so the foreground serves warm answers instantly and only falls back to a live call on a miss. A freshness check makes sure a changed document never yields a stale answer. In a tiny demo, foreground latency dropped &lt;strong&gt;57%&lt;/strong&gt; — with novel queries still handled live and stale pre-answers correctly rejected.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Mental model:&lt;/strong&gt; a prep cook who chops the vegetables &lt;em&gt;before&lt;/em&gt; the dinner rush. When orders come in, plating is fast because the prep is already done — and anything that spoiled gets thrown out and re-prepped fresh, never served stale.&lt;/p&gt;

&lt;h2&gt;
  
  
  The problem: you pay full price at the worst possible moment
&lt;/h2&gt;

&lt;p&gt;Interactive inference spends compute at &lt;em&gt;test time&lt;/em&gt; — the exact moment the user is waiting. For one-shot questions over fresh context that's unavoidable. But a huge share of real traffic isn't one-shot: users query the same codebase, the same document set, the same dashboard repeatedly, and the underlying corpus doesn't change between most of those queries. You're re-deriving the same expensive answers on the critical path, over and over.&lt;/p&gt;

&lt;p&gt;Meanwhile the infrastructure sits idle between sessions, with nobody waiting.&lt;/p&gt;

&lt;h2&gt;
  
  
  The pattern: move predictable work to idle time
&lt;/h2&gt;

&lt;p&gt;Sleep-time compute separates &lt;em&gt;compute while serving a query&lt;/em&gt; from &lt;em&gt;compute between queries&lt;/em&gt;. A background worker runs during idle periods and does two things: &lt;strong&gt;distill&lt;/strong&gt; the standing context into dense summaries, and &lt;strong&gt;speculatively pre-answer&lt;/strong&gt; the queries most likely to be asked next.&lt;/p&gt;

&lt;p&gt;Prediction can be simple — the queries you've seen most are the ones you'll likely see again — and each pre-answer is tagged with the &lt;strong&gt;source version&lt;/strong&gt; it was computed against, so freshness can be checked later:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;prepare&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;history&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;top_n&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nc"&gt;Counter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;history&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;most_common&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;top_n&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;     &lt;span class="c1"&gt;# predict likely next queries
&lt;/span&gt;        &lt;span class="n"&gt;ver&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;corpus&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;version&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;query_topic&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;cache&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;))[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;ver&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;    &lt;span class="c1"&gt;# (re)compute if missing or stale
&lt;/span&gt;            &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;cache&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;answer[&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; @v&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;ver&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;]&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ver&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;bg_cost&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;LIVE_COST&lt;/span&gt;                        &lt;span class="c1"&gt;# paid in the background
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;At request time the foreground checks the cache — and serves a pre-answer &lt;strong&gt;only if it's still fresh&lt;/strong&gt;. A miss or a stale entry falls back to a live call:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;serve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;hit&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;cache&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;hit&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;hit&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;corpus&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;version&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;query_topic&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;)]:&lt;/span&gt;  &lt;span class="c1"&gt;# present AND fresh
&lt;/span&gt;        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;hit&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;WARM_MS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;WARM_COST&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;warm&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;   &lt;span class="c1"&gt;# miss or stale -&amp;gt; go live
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  The result
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Sleep-Time Compute — precompute while idle so the user waits far less
  400 queries, 70% predictable / 30% novel, one source update mid-stream.

                           foreground latency   foreground cost
   answer on demand                  320.0s             8.00$
   with sleep-time                   137.2s             3.40$

   warm hits served instantly : 230/400  (58%)
   stale pre-answers rejected  : 1  (freshness check forced a live call — no wrong answer)
   background cost (amortized) : $0.26  spent while idle, off the critical path
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The predictable 70% mostly got answered before the user asked. The novel 30% still went live — as they should. And when a source document changed mid-stream, the stale pre-answers were rejected and recomputed rather than served wrong.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Reality check:&lt;/strong&gt; the 57% is from the toy model above — directional, not a benchmark. The paper behind it reports ~5× less test-time compute for equal accuracy and ~2.5× lower cost per query when a context is shared across queries — and, crucially, the win tracks how &lt;em&gt;predictable&lt;/em&gt; your traffic is (it's pure overhead for genuinely one-shot asks).&lt;/p&gt;

&lt;h2&gt;
  
  
  Why this is where 2026 is heading
&lt;/h2&gt;

&lt;p&gt;The proven part: the associated research (Letta's write-up; Lin et al.) shows that shifting reasoning to &lt;em&gt;before&lt;/em&gt; a query arrives measurably cuts test-time latency and cost &lt;strong&gt;when the work is reused&lt;/strong&gt;. The transferable engineering idea is the &lt;strong&gt;split budget&lt;/strong&gt;: reserve interactive compute for latency-sensitive work, and spend cheap background compute where it can be amortized.&lt;/p&gt;

&lt;p&gt;Where it's heading: as agents accumulate persistent memory, idle time stops being wasted. Expect a foreground agent and a cheaper background agent to &lt;strong&gt;share memory&lt;/strong&gt; — the background one consolidating summaries, reflecting over past sessions, and pre-answering likely follow-ups. The same design shows up as "context distillation" and memory consolidation across 2026 agent stacks.&lt;/p&gt;

&lt;h2&gt;
  
  
  How faithful is this demo?
&lt;/h2&gt;

&lt;p&gt;It's a minimal model of the control flow, not the reasoning: "inference" is a fixed-latency stub, prediction is a frequency count, and freshness is an integer version bump. Real systems predict from richer signals and must guard hard against two failure modes this only gestures at — &lt;strong&gt;serving stale answers&lt;/strong&gt; (freshness must gate every hit) and &lt;strong&gt;privacy leakage&lt;/strong&gt; during background consolidation. And the honest caveat stands: sleep-time compute pays off only when future queries reuse the work — it's pure overhead for one-shot asks.&lt;/p&gt;

&lt;h2&gt;
  
  
  When not to use this
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;One-shot or unpredictable traffic.&lt;/strong&gt; If future queries rarely reuse the work, precompute is pure wasted spend.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Fast-changing context.&lt;/strong&gt; If the underlying data churns constantly, pre-answers go stale faster than you can serve them — you'll pay to recompute anyway.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No cheap idle capacity.&lt;/strong&gt; The whole trick assumes background compute is cheaper than blocking a user; if idle time costs the same, there's no arbitrage.&lt;/li&gt;
&lt;/ul&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;python3 demo.py   &lt;span class="c"&gt;# standard library only&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Sources &amp;amp; further reading
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Paper&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Lin, Snell, Wang, Packer, Wooders, Stoica, Gonzalez — &lt;a href="https://arxiv.org/abs/2504.13171" rel="noopener noreferrer"&gt;&lt;em&gt;Sleep-time Compute: Beyond Inference Scaling at Test-time&lt;/em&gt; (arXiv 2504.13171)&lt;/a&gt; — ~5× less test-time compute for equal accuracy; 2.5× lower cost/query when a context is shared across queries; efficacy correlates with query predictability. &lt;a href="https://github.com/letta-ai/sleep-time-compute" rel="noopener noreferrer"&gt;Code &amp;amp; data&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Engineering blogs&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Letta — &lt;a href="https://www.letta.com/blog/sleep-time-compute/" rel="noopener noreferrer"&gt;Sleep-time Compute&lt;/a&gt; (foreground + background agents sharing memory)&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/agentpatternscatalog/patterns/blob/main/patterns/sleep-time-compute.md" rel="noopener noreferrer"&gt;Sleep-time compute pattern (agent patterns catalog)&lt;/a&gt; — distillation + speculative pre-answering, freshness gating&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://jatinbansal.com/ai-engineering/sleep-time-compute/" rel="noopener noreferrer"&gt;Sleep-Time Compute for AI Agents&lt;/a&gt; (the split-budget framing and rollout advice)&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>ai</category>
      <category>llm</category>
      <category>python</category>
      <category>architecture</category>
    </item>
    <item>
      <title>Your Agent's Context Window Is RAM. Start Paging It.</title>
      <dc:creator>Shridhar Shah</dc:creator>
      <pubDate>Wed, 05 Aug 2026 16:20:28 +0000</pubDate>
      <link>https://dev.to/shridhar_shah2297/your-agents-context-window-is-ram-start-paging-it-34oi</link>
      <guid>https://dev.to/shridhar_shah2297/your-agents-context-window-is-ram-start-paging-it-34oi</guid>
      <description>&lt;p&gt;&lt;em&gt;Treat the context window as a scarce cache: keep the working set resident, evict cold items to a store, and page them back on a fault. Locality keeps the fault rate low and nothing is ever lost.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;TL;DR:&lt;/strong&gt; A long-running agent keeps piling tool results and notes into its context window, but attention is a &lt;strong&gt;fixed budget&lt;/strong&gt; — dilute it and both accuracy and cost degrade. Hard-capping the window and dropping the oldest items loses things the agent needs later. Operating systems solved this with &lt;strong&gt;demand paging&lt;/strong&gt;: keep only the working set resident, evict cold items to a backing store, and page them back on a &lt;strong&gt;fault&lt;/strong&gt; when referenced again. Agent sessions have strong locality, so the fault rate stays low and nothing is lost. In a runnable Go demo, "keep everything" balloons to &lt;strong&gt;7.6× the window budget&lt;/strong&gt;, while an LRU-paged window stays &lt;strong&gt;within budget at a 15% fault rate&lt;/strong&gt; and zero information lost.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Mental model:&lt;/strong&gt; your laptop runs apps that need far more memory than it has RAM, and you never notice, because the OS keeps the pages you're actively using in RAM and quietly parks the rest on disk — fetching them back the instant you touch them. An agent's context window is that RAM.&lt;/p&gt;

&lt;h2&gt;
  
  
  The problem: the window is small, the session is long
&lt;/h2&gt;

&lt;p&gt;The context window is not memory — it's a &lt;strong&gt;cache&lt;/strong&gt;, and a small one. Everything an agent does adds to it: a tool returns 30k tokens, a document gets pasted in, each step leaves notes. Two bad things happen as it fills. First, the &lt;strong&gt;attention tax&lt;/strong&gt;: transformer attention is a fixed budget, and published measurements show accuracy sliding from ~95% to 60–70% as that budget is spread across more tokens. Second, cost and latency scale with tokens in the window, every single step.&lt;/p&gt;

&lt;p&gt;The naive fix — cap the window and drop the oldest content — trades one failure for another. The moment a later step references something you dropped, it's &lt;em&gt;gone&lt;/em&gt;: the agent silently recomputes it (paying for the tool call again) or, worse, hallucinates it.&lt;/p&gt;

&lt;h2&gt;
  
  
  The pattern: demand paging for the context window
&lt;/h2&gt;

&lt;p&gt;Operating systems have run programs whose address space dwarfs physical RAM since the 1960s, using &lt;strong&gt;demand paging&lt;/strong&gt; and Denning's &lt;strong&gt;working-set model&lt;/strong&gt;. The mapping onto agents is direct:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;OS&lt;/th&gt;
&lt;th&gt;Agent&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;RAM&lt;/td&gt;
&lt;td&gt;the resident context window (fixed budget)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Disk&lt;/td&gt;
&lt;td&gt;a backing store (a file, a vector DB)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Page&lt;/td&gt;
&lt;td&gt;a tool result / document / note&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Page fault&lt;/td&gt;
&lt;td&gt;a reference to something evicted → fetch it back&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Keep only the working set resident. When the window is full and something new comes in, &lt;strong&gt;evict&lt;/strong&gt; the least-recently-used items to the store (not the void). When a later step references an evicted item, that's a &lt;strong&gt;page fault&lt;/strong&gt; — page it back in. Nothing is destroyed; it's just moved to a cheaper tier.&lt;/p&gt;

&lt;p&gt;The eviction-to-fit and fault-on-miss logic is the whole pattern:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="k"&gt;range&lt;/span&gt; &lt;span class="n"&gt;stream&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;el&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;resident&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;pos&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt; &lt;span class="n"&gt;resident&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;lru&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;MoveToFront&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;el&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;          &lt;span class="c"&gt;// hit: already in the window&lt;/span&gt;
        &lt;span class="k"&gt;continue&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;faults&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;                          &lt;span class="c"&gt;// miss: page it back in from the store&lt;/span&gt;
    &lt;span class="n"&gt;evictToFit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;                  &lt;span class="c"&gt;// make room by evicting LRU residents (to the store)&lt;/span&gt;
    &lt;span class="n"&gt;tokens&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="n"&gt;pos&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;lru&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PushFront&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;item&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;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;evictToFit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;incoming&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;tokens&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;incoming&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;budgetTokens&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;lru&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Len&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;victim&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;lru&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Back&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Value&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;lru&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Remove&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lru&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Back&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
        &lt;span class="nb"&gt;delete&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pos&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;victim&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;tokens&lt;/span&gt; &lt;span class="o"&gt;-=&lt;/span&gt; &lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;victim&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;        &lt;span class="c"&gt;// evicted to the backing store, not destroyed&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;h2&gt;
  
  
  The result
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Context Demand Paging — the context window is a cache, not infinite memory
  1500-step session, 60 distinct items, 8000-token window budget.

   keep everything resident   60,728 tokens   (7.6× the window — attention tax + cost blowup)
   demand paging (LRU)        7,997 tokens   (stays within budget)

   page faults                  226   (15% of references — the rest hit the working set)
   information lost               0   (faults page back in from the store — nothing destroyed)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Keeping everything resident hits 7.6× the window budget — the exact attention tax the budget was meant to prevent. Demand paging holds the window at budget, and because the agent keeps touching the same working set, only 15% of references miss — each a cheap re-read from the store, never a loss.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Reality check:&lt;/strong&gt; the 7.6× and the 15% fault rate come from the locality model above — directional, not a benchmark, and your fault rate depends entirely on your workload's locality. What's independently real is the attention tax this targets (published long-context accuracy slides from ~95% to 60–70% as the window fills), and the direction of travel: 2026's Neural Paging formalizes the problem and &lt;em&gt;learns&lt;/em&gt; the eviction policy instead of using the plain LRU shown here.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why this is where 2026 is heading
&lt;/h2&gt;

&lt;p&gt;As agents move from single answers to long-horizon work — hours of coding, multi-document research, sessions that outlive many context resets — context management stops being an afterthought and becomes &lt;em&gt;the&lt;/em&gt; systems problem. The field is converging on the OS analogy fast: 2026's &lt;strong&gt;Neural Paging&lt;/strong&gt; formalizes the "Context Paging Problem" and a learned page controller acting as a neural MMU, while practitioner write-ups describe &lt;strong&gt;context offloading&lt;/strong&gt;, &lt;strong&gt;just-in-time context&lt;/strong&gt;, and demand-paged working sets with measured fault rates. The transferable engineering idea: stop treating the window as memory you fill, and start treating it as a cache you &lt;em&gt;manage&lt;/em&gt; — resident working set, cheap backing store, fault-driven recovery, eviction by utility.&lt;/p&gt;

&lt;h2&gt;
  
  
  How faithful is this demo?
&lt;/h2&gt;

&lt;p&gt;It's the paging mechanism, not a real agent: "items" are integers with token sizes, the access stream is a locality model, and the store is assumed cheap and lossless. Real systems earn the two hard parts — &lt;strong&gt;what to evict&lt;/strong&gt; (pure LRU by recency is weak for agents; pin by &lt;em&gt;reference&lt;/em&gt; / working set, since a file read during planning stays relevant all session) and &lt;strong&gt;what the resident handle says&lt;/strong&gt; (a pointer the model can't act on is worse than the payload). Start by offloading big tool results behind a summary+handle and paging them back only when a step needs them.&lt;/p&gt;

&lt;h2&gt;
  
  
  When not to use this
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Short sessions.&lt;/strong&gt; If the whole session fits the window with room to spare, paging is machinery you don't need.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No locality.&lt;/strong&gt; If the agent touches items near-randomly, the fault rate climbs and you're just paying store round-trips — plain truncation or a summary may beat it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A good summary beats the raw item.&lt;/strong&gt; When a distilled note serves later steps as well as the original, consolidate instead of paging the full payload back and forth.&lt;/li&gt;
&lt;/ul&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;go run &lt;span class="nb"&gt;.&lt;/span&gt;   &lt;span class="c"&gt;# standard library only&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Sources &amp;amp; further reading
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Papers &amp;amp; foundations&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://arxiv.org/abs/2603.02228" rel="noopener noreferrer"&gt;&lt;em&gt;Neural Paging: Learning Context Management Policies for Turing-Complete Agents&lt;/em&gt; (arXiv 2603.02228)&lt;/a&gt; — formalizes the Context Paging Problem and a differentiable page controller acting as a "neural MMU."&lt;/li&gt;
&lt;li&gt;Peter J. Denning — &lt;em&gt;The Working Set Model for Program Behavior&lt;/em&gt; (1968) — why pinning the active working set beats evicting by recency.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Engineering write-ups&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://usewire.io/blog/context-offloading-patterns-for-ai-agents/" rel="noopener noreferrer"&gt;Context offloading: 3 patterns for AI agents&lt;/a&gt; — note-taking, sub-agent delegation, just-in-time retrieval; the attention-budget framing.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://usewire.io/blog/context-window-demand-paging/" rel="noopener noreferrer"&gt;Demand paging for the AI context window&lt;/a&gt; — the OS mapping, fault rates, and "pin by reference, not recency."&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.truefoundry.com/es/blog/jit-context-just-in-time-context-agents" rel="noopener noreferrer"&gt;Just-in-Time Context for AI Agents&lt;/a&gt; — keep the window full of pointers, load heavy content only when needed.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://dreaming.press/posts/context-offloading-for-ai-agents.html" rel="noopener noreferrer"&gt;Context Offloading for AI Agents: writing tool results to disk&lt;/a&gt; — deferring the retrieval decision from write-time to read-time.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>ai</category>
      <category>go</category>
      <category>architecture</category>
      <category>agents</category>
    </item>
    <item>
      <title>Your Load Balancer Is Throwing Away the KV Cache</title>
      <dc:creator>Shridhar Shah</dc:creator>
      <pubDate>Wed, 05 Aug 2026 16:19:53 +0000</pubDate>
      <link>https://dev.to/shridhar_shah2297/your-load-balancer-is-throwing-away-the-kv-cache-ole</link>
      <guid>https://dev.to/shridhar_shah2297/your-load-balancer-is-throwing-away-the-kv-cache-ole</guid>
      <description>&lt;p&gt;&lt;em&gt;Round-robin is prefix-blind. KV-cache-aware routing sends requests to the replica that already prefilled their prefix — cutting time-to-first-token without hotspotting.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;TL;DR:&lt;/strong&gt; Before an LLM emits a token it must &lt;strong&gt;prefill&lt;/strong&gt; the whole prompt into a KV cache — the expensive part. In 2026, requests share massive prefixes (system prompts, retrieved documents, the conversation so far). A round-robin load balancer is &lt;strong&gt;prefix-blind&lt;/strong&gt;: it scatters those requests so every replica recomputes the same prefix. &lt;strong&gt;KV-cache-aware routing&lt;/strong&gt; sends a request to the replica that already has its prefix warm. In a tiny Go demo it lifted cache hits from &lt;strong&gt;47% to 85%&lt;/strong&gt;, recomputed &lt;strong&gt;66% fewer&lt;/strong&gt; prefill tokens, and &lt;strong&gt;halved p50 TTFT&lt;/strong&gt; — while keeping load far more even than naïve affinity. No GPU: latencies are simulated.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Mental model:&lt;/strong&gt; a coffee shop that routes you to the barista who already knows your usual. Same regular → same barista → they start immediately. A round-robin queue sends you to a random barista who takes your whole order from scratch every time.&lt;/p&gt;

&lt;h2&gt;
  
  
  The problem: prefill is expensive and prefixes repeat
&lt;/h2&gt;

&lt;p&gt;An LLM request has two phases: &lt;strong&gt;prefill&lt;/strong&gt; (read the whole prompt into the KV cache) and &lt;strong&gt;decode&lt;/strong&gt; (generate tokens). Prefill dominates time-to-first-token, and it scales with prompt length.&lt;/p&gt;

&lt;p&gt;Here's the thing about agent traffic: prompts are mostly &lt;strong&gt;shared prefix&lt;/strong&gt;. The same 2,000-token system prompt. The same retrieved document. The same conversation history, turn after turn. If a replica already prefilled that prefix, its KV cache can be reused and the prefix is essentially free. A round-robin balancer throws that away — it spreads requests evenly and blindly, so the hot prefix gets recomputed on all four replicas instead of once.&lt;/p&gt;

&lt;h2&gt;
  
  
  The pattern: route by prefix affinity, but balance load
&lt;/h2&gt;

&lt;p&gt;Three routers, same request stream:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Round-robin&lt;/strong&gt; — perfect load spread, zero cache awareness:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;roundRobin&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;replica&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;seq&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;seq&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="n"&gt;replicas&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Prefix-affinity&lt;/strong&gt; — same prefix always lands on the same replica, so caches stay warm. But a &lt;em&gt;hot&lt;/em&gt; prefix now hammers one replica:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;prefixAffinity&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;replica&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;req&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;h&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;fnv&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;New32a&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Fprintf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;h&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"%d"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;prefix&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;h&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Sum32&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="n"&gt;replicas&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Cache-aware + balanced&lt;/strong&gt; — the 2026 endpoint-picker idea (llm-d / Gateway API Inference Extension): prefer a replica that already has the prefix warm, but spill to the least-loaded replica if the warm one is slammed. Locality first, then balance:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="c"&gt;// warm replica exists and isn't overloaded -&amp;gt; reuse its cache&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;best&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="kt"&gt;float64&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;reps&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;best&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;load&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="n"&gt;avg&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;overloadFactor&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;best&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="c"&gt;// otherwise send it to the least-loaded replica&lt;/span&gt;
&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;leastLoaded&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;reps&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Time-to-first-token in the sim rewards a warm hit by skipping the prefix prefill:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;prefill&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;suffixTokens&lt;/span&gt;          &lt;span class="c"&gt;// the unique tail always needs prefill&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;has&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;prefix&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;prefill&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;prefixTokens&lt;/span&gt;      &lt;span class="c"&gt;// cold: pay to prefill the whole prefix&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="n"&gt;ttft&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;decodeBase&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="kt"&gt;float64&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;prefill&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;prefillPerTok&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  The result
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;KV-cache-aware routing — reuse warm prefixes instead of recomputing them
  2000 requests, 4 replicas, 40 distinct prefixes (traffic skewed to the hot few)

   router                    hit rate   prefill work    p50 TTFT   load skew
   round-robin                  46.6%   2,809,330 tok       61ms        1.0x
   prefix-affinity              86.0%     893,365 tok       30ms        1.8x
   cache-aware + balanced       84.8%     957,709 tok       30ms        1.2x
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Round-robin has perfect balance (1.0x) but the worst cache behaviour. Blind affinity gets the cache hits but a 1.8x load skew — one replica does nearly twice the work of another. Cache-aware + balanced keeps ~85% of the hits &lt;strong&gt;and&lt;/strong&gt; a gentle 1.2x skew. That's the sweet spot.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Reality check:&lt;/strong&gt; these are simulated latencies, not a GPU benchmark — directional only. The tradeoff is real: production KV-aware routers (SGLang's RadixAttention, llm-d / Gateway API's endpoint picker) report large TTFT and throughput gains from exactly this locality-vs-load balance, and how big the win is depends entirely on how much prefix your traffic actually shares.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why this is where 2026 is heading
&lt;/h2&gt;

&lt;p&gt;The proven part: prefix / prompt caching is already GA across major providers and inference engines (vLLM, SGLang, TensorRT-LLM), and it's a real discount. The open question was always &lt;em&gt;routing&lt;/em&gt; — caching only helps if the request lands where the cache lives.&lt;/p&gt;

&lt;p&gt;Where it's heading: 2026 inference stacks make the router &lt;strong&gt;KV-cache-aware&lt;/strong&gt;. The Gateway API Inference Extension's endpoint picker (EPP) and llm-d schedule replicas by KV-cache locality and load together — exactly the third router here. As context windows grow and agents replay long histories, &lt;em&gt;where&lt;/em&gt; you route becomes as important as &lt;em&gt;what model&lt;/em&gt; you route to.&lt;/p&gt;

&lt;h2&gt;
  
  
  How faithful is this demo?
&lt;/h2&gt;

&lt;p&gt;It's a simulation of serving behaviour, not a GPU benchmark: latencies are a linear &lt;code&gt;tokens × cost&lt;/code&gt; model and the cache is a per-replica LRU of whole prefixes. Real systems match on &lt;strong&gt;prefix blocks&lt;/strong&gt; (shared leading tokens), evict at block granularity, and factor in queue depth and memory pressure — but the qualitative result (affinity wins big, blind affinity hotspots, locality-plus-balance is the sweet spot) is exactly what production routers target. The sharp edge to watch: a single very hot prefix can still overwhelm the one replica that caches it, so the router must be willing to trade cache reuse for load — spill to a colder replica under pressure — or you simply swap recompute cost for queueing latency.&lt;/p&gt;

&lt;h2&gt;
  
  
  When not to use this
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Your prompts share little prefix.&lt;/strong&gt; Short, unique requests get almost no cache reuse, so affinity routing buys nothing and just adds complexity.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;You run a single replica.&lt;/strong&gt; There's no routing decision to make.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Autoscaling is aggressive.&lt;/strong&gt; Sticky, cache-aware routing fights elastic scale-in/out; you'll need to weigh cache locality against how often replicas churn.&lt;/li&gt;
&lt;/ul&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;go run &lt;span class="nb"&gt;.&lt;/span&gt;   &lt;span class="c"&gt;# standard library only&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Sources &amp;amp; further reading
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Papers&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Zheng et al. — &lt;a href="https://par.nsf.gov/servlets/purl/10524135" rel="noopener noreferrer"&gt;&lt;em&gt;SGLang: Efficient Execution of Structured Language Model Programs&lt;/em&gt;&lt;/a&gt; (NeurIPS 2024) — RadixAttention: automatic KV-cache reuse via a radix tree + cache-aware scheduling.&lt;/li&gt;
&lt;li&gt;Srivatsa et al. — &lt;em&gt;Preble: Efficient Distributed Prompt Scheduling for LLM Serving&lt;/em&gt; (2024) — prefix-aware scheduling that places requests near their cached KV state.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://arxiv.org/abs/2602.11688" rel="noopener noreferrer"&gt;&lt;em&gt;GORGO: Maximizing KV-Cache Reuse While Minimizing Network Latency in Cross-Region LLM Load Balancing&lt;/em&gt; (arXiv 2602.11688)&lt;/a&gt; (2026) — treats prefix locality as one input to a latency cost model.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Engineering blogs &amp;amp; docs&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.truefoundry.com/blog/kv-cache-routing-why-standard-load-balancers-break-prefix-caching-and-how-to-fix-it" rel="noopener noreferrer"&gt;KV Cache Routing: Why Standard Load Balancers Break Prefix Caching (and How to Fix It)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;LMSYS — &lt;a href="https://www.lmsys.org/blog/2024-01-17-sglang/" rel="noopener noreferrer"&gt;Fast and Expressive LLM Inference with RadixAttention and SGLang&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://gateway-api-inference-extension.sigs.k8s.io/" rel="noopener noreferrer"&gt;Gateway API Inference Extension — endpoint picker (EPP) &amp;amp; InferencePool&lt;/a&gt; · &lt;a href="https://llm-d.ai/" rel="noopener noreferrer"&gt;llm-d&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>llm</category>
      <category>go</category>
      <category>architecture</category>
      <category>machinelearning</category>
    </item>
    <item>
      <title>Stop Streaming Tools Through Your LLM</title>
      <dc:creator>Shridhar Shah</dc:creator>
      <pubDate>Wed, 05 Aug 2026 16:19:51 +0000</pubDate>
      <link>https://dev.to/shridhar_shah2297/stop-streaming-tools-through-your-llm-2f1i</link>
      <guid>https://dev.to/shridhar_shah2297/stop-streaming-tools-through-your-llm-2f1i</guid>
      <description>&lt;p&gt;&lt;em&gt;The 2026 shift from tool-calling to Code Mode: let the agent write one script instead of narrating fifty tool calls — and watch context tokens drop ~99%.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;TL;DR:&lt;/strong&gt; The classic agent loop loads &lt;em&gt;every&lt;/em&gt; tool definition into the context window and pipes &lt;em&gt;every&lt;/em&gt; intermediate result back through the model. Connect a few dozen tools and the context is full before the user even speaks. The 2026 move — &lt;strong&gt;Code Mode&lt;/strong&gt; — is to let the agent write one short script that calls tools directly; bulk data stays in a sandbox and only the final answer comes back. In a tiny runnable demo it cut context from &lt;strong&gt;36,781 tokens to 222&lt;/strong&gt; — a &lt;strong&gt;99.4%&lt;/strong&gt; reduction. Same answer, no API key.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Mental model:&lt;/strong&gt; instead of reading a worker every page of 50 manuals and every row of a spreadsheet out loud, you hand them the 3 manuals the job needs and let them do the math at their own desk. You only get back the final answer — not the raw data.&lt;/p&gt;

&lt;h2&gt;
  
  
  The problem: tool-calling doesn't scale with tool count
&lt;/h2&gt;

&lt;p&gt;Function/tool-calling is how most agents act today. It works beautifully with five tools. But the whole tool surface gets serialized into the context window &lt;em&gt;on every request&lt;/em&gt;, and every intermediate result the model asks for is streamed back through the context too.&lt;/p&gt;

&lt;p&gt;So a task like &lt;em&gt;"count open support tickets per plan tier and save the report"&lt;/em&gt; looks like:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Load all 50 connected tool schemas into context.&lt;/li&gt;
&lt;li&gt;Call &lt;code&gt;list_tickets&lt;/code&gt; → 2,000 rows come back &lt;strong&gt;through the model&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Call &lt;code&gt;get_customers&lt;/code&gt; → 400 rows come back &lt;strong&gt;through the model&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;The model joins and counts these blobs &lt;em&gt;in its head&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;Call &lt;code&gt;save_report&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The model paid for 50 schemas it mostly didn't need, and for 2,400 rows of raw data it only needed to &lt;em&gt;aggregate&lt;/em&gt;, not &lt;em&gt;read&lt;/em&gt;. Anthropic measured a real Google-Drive-to-Salesforce task at &lt;strong&gt;150,000 tokens&lt;/strong&gt;; Cloudflare hit &lt;strong&gt;~1.17M tokens&lt;/strong&gt; of tool definitions on a 2,500-endpoint API.&lt;/p&gt;

&lt;h2&gt;
  
  
  The pattern: write code that calls tools
&lt;/h2&gt;

&lt;p&gt;Code Mode (Anthropic's "code execution with MCP", Cloudflare's "Code Mode") flips the loop:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Tools become a code API&lt;/strong&gt; — a filesystem of typed functions, one per tool.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Progressive disclosure&lt;/strong&gt; — the agent reads only the few signatures the task needs.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The model emits one script&lt;/strong&gt;, not a stream of tool calls.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A sandbox runs it.&lt;/strong&gt; Intermediate data lives in the sandbox; only the final result returns.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here's the entire script the "model" writes in the demo — the 2,000 tickets and 400 customers are joined &lt;em&gt;inside the sandbox&lt;/em&gt; and never touch the context:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;tickets&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;list_tickets&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;open&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;            &lt;span class="c1"&gt;# 2000 rows: fetched and joined entirely in the sandbox
&lt;/span&gt;&lt;span class="n"&gt;plan&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;id&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;plan&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;get_customers&lt;/span&gt;&lt;span class="p"&gt;()}&lt;/span&gt;
&lt;span class="n"&gt;counts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;free&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;pro&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;enterprise&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;
&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;tk&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;tickets&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;counts&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;plan&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;tk&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;customer_id&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]]]&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
&lt;span class="n"&gt;rows&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;tier&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;open_tickets&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;counts&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;]}&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;counts&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;save_report&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;open_by_tier&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;rows&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The sandbox exposes only the tool API — no builtins, no imports — so the script can compose tools but can't reach the rest of the process:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;api&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;list_tickets&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;list_tickets&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;get_customers&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;get_customers&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;save_report&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;save_report&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="n"&gt;sandbox&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;__builtins__&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{},&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;api&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nf"&gt;exec&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;script&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;sandbox&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;      &lt;span class="c1"&gt;# only the script text + final answer ever cross the context window
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  The result
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Code Mode — write code that calls tools, don't stream tools through the model

  Task: count open tickets per plan tier over 2000 tickets / 400 customers.
  Tools connected to the agent: 50 (this task needs 3).

   classic tool-calling    36,781 context tokens   (all schemas + raw data pass through)
   code mode                  222 context tokens   (3 signatures + one script + answer)
   ------------------------------------------------
   context reduction        99.4%

  Same result either way: [free: 720, pro: 596, enterprise: 684]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The gap isn't a constant — it &lt;strong&gt;compounds&lt;/strong&gt; with tool count and data size.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Reality check:&lt;/strong&gt; the exact figure is from the toy model above — treat it as directional, not a benchmark. The &lt;em&gt;shape&lt;/em&gt; is real and measured in production: Anthropic's Drive→Salesforce task dropped from ~150k to ~2k tokens, and independent reproductions land anywhere from 78% to 99.9% depending on tool count and data size.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why this is where 2026 is heading
&lt;/h2&gt;

&lt;p&gt;The proven part: LLMs are extremely good at writing code, and a code API is a far denser way to express "do these five things and combine the results" than five separate tool-call round trips. Anthropic, Cloudflare, and an &lt;a href="https://arxiv.org/abs/2602.15945" rel="noopener noreferrer"&gt;independent study of MCP design choices&lt;/a&gt; all converge on the same finding — token usage becomes roughly &lt;strong&gt;constant in tool count&lt;/strong&gt; because the model only reads what it opens.&lt;/p&gt;

&lt;p&gt;Where it's heading: as agents connect to hundreds of MCP servers, "load everything up front" simply stops being viable, and the tool-calling layer moves &lt;em&gt;onto the computer&lt;/em&gt;. Expect the sandbox — not the tool-call — to become the default action primitive, with tool schemas synced to a filesystem and disclosed on demand.&lt;/p&gt;

&lt;h2&gt;
  
  
  How faithful is this demo?
&lt;/h2&gt;

&lt;p&gt;It's a minimal model, not a benchmark: "tokens" are a &lt;code&gt;chars/4&lt;/code&gt; proxy, the "model" writes a fixed script, and the sandbox is a restricted &lt;code&gt;exec&lt;/code&gt;. Real systems generate the script with an LLM and isolate it far more aggressively (gVisor, containers, V8 isolates) — which is the pattern's main cost: &lt;strong&gt;you now run untrusted, model-written code&lt;/strong&gt;, so sandboxing and limits are mandatory. The token economics, though, are exactly what production reports show.&lt;/p&gt;

&lt;h2&gt;
  
  
  When not to use this
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;You have a handful of tools and small results.&lt;/strong&gt; If the whole tool surface and its data already fit comfortably in context, code-gen plus a sandbox is pure overhead — just call the tools.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The task is a single tool call.&lt;/strong&gt; There's nothing to compose, so there's nothing to save.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;You can't sandbox safely.&lt;/strong&gt; Code Mode means executing model-written code; without real isolation (gVisor/containers/isolates) and resource limits, don't ship it.&lt;/li&gt;
&lt;/ul&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;python3 demo.py   &lt;span class="c"&gt;# standard library only&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Sources &amp;amp; further reading
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Papers&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Wang et al. — &lt;a href="https://arxiv.org/abs/2602.15945" rel="noopener noreferrer"&gt;&lt;em&gt;From Tool Orchestration to Code Execution: A Study of MCP Design Choices&lt;/em&gt; (arXiv 2602.15945)&lt;/a&gt; — benchmarks the "context-decoupled execution model" and shows token use becomes roughly constant in tool count.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Engineering blogs&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Anthropic — &lt;a href="https://www.anthropic.com/engineering/code-execution-with-mcp" rel="noopener noreferrer"&gt;Code execution with MCP: building more efficient AI agents&lt;/a&gt; (the 150k → 2k token result)&lt;/li&gt;
&lt;li&gt;Cloudflare — &lt;a href="https://blog.cloudflare.com/code-mode/" rel="noopener noreferrer"&gt;Code Mode: the better way to use MCP&lt;/a&gt; and &lt;a href="https://blog.cloudflare.com/code-mode-mcp/" rel="noopener noreferrer"&gt;give agents an entire API in 1,000 tokens&lt;/a&gt; (typed API from MCP schemas, executed in a V8 isolate)&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://particula.tech/blog/code-execution-mcp-token-reduction-pattern" rel="noopener noreferrer"&gt;Code Execution With MCP: Cut Tool Tokens up to 98%&lt;/a&gt; (independent reproductions across tool counts)&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>ai</category>
      <category>llm</category>
      <category>python</category>
      <category>architecture</category>
    </item>
    <item>
      <title>AI Agents That Live Inside a Dreamed-Up World</title>
      <dc:creator>Shridhar Shah</dc:creator>
      <pubDate>Tue, 21 Jul 2026 05:51:55 +0000</pubDate>
      <link>https://dev.to/shridhar_shah2297/ai-agents-that-live-inside-a-dreamed-up-world-3n4j</link>
      <guid>https://dev.to/shridhar_shah2297/ai-agents-that-live-inside-a-dreamed-up-world-3n4j</guid>
      <description>&lt;p&gt;&lt;em&gt;An agent watches a game, learns to hallucinate the next frame, then plays inside its own dream — but only the model that knows players react to each other stays true.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;TL;DR:&lt;/strong&gt; The hottest idea in agents right now: don't feed them the real world — let them &lt;strong&gt;dream&lt;/strong&gt; it. An agent watches some footage, learns to hallucinate the next frame, and practices inside its own head. I built a tiny one, and found the catch: a dream only stays true if it knows the players &lt;strong&gt;react to each other.&lt;/strong&gt; Runs on a laptop.&lt;/p&gt;




&lt;h2&gt;
  
  
  The world
&lt;/h2&gt;

&lt;p&gt;Two players in an 11-cell corridor: a predator steps toward the prey, the prey steps away. Every move is a &lt;em&gt;reaction&lt;/em&gt;. An agent watches random games, then closes its eyes and &lt;strong&gt;dreams 15 frames ahead&lt;/strong&gt;, feeding each prediction back in as the next input. I built two dreamers from the exact same footage:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;single-player&lt;/strong&gt; — predicts each player from its own position alone&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;multiplayer&lt;/strong&gt; — predicts both positions &lt;em&gt;together&lt;/em&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Training an agent inside its own learned dream goes back to Ha &amp;amp; Schmidhuber's &lt;a href="https://arxiv.org/abs/1803.10122" rel="noopener noreferrer"&gt;&lt;em&gt;World Models&lt;/em&gt;&lt;/a&gt; (2018); the open frontier is making that dream &lt;strong&gt;multiplayer&lt;/strong&gt; — modeling agents &lt;em&gt;reacting to each other&lt;/em&gt;, not just physics.&lt;/p&gt;

&lt;h2&gt;
  
  
  The 10-second version
&lt;/h2&gt;

&lt;p&gt;% of the dream still matching reality, this many frames ahead:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;frames ahead&lt;/th&gt;
&lt;th&gt;1&lt;/th&gt;
&lt;th&gt;3&lt;/th&gt;
&lt;th&gt;5&lt;/th&gt;
&lt;th&gt;10&lt;/th&gt;
&lt;th&gt;15&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;single-player dream&lt;/td&gt;
&lt;td&gt;11&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;9&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;multiplayer dream&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;100&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;100&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;100&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;100&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;100&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The single-player dream falls apart almost immediately; the multiplayer one stays locked to reality. That gap is the whole point — and, as we'll see, it comes down to what each model is even &lt;em&gt;able&lt;/em&gt; to represent.&lt;/p&gt;

&lt;h2&gt;
  
  
  How it works
&lt;/h2&gt;

&lt;p&gt;The real world is one tiny rule — predator steps toward prey, prey steps away:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;real_next&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;                     &lt;span class="c1"&gt;# p = predator cell, q = prey cell
&lt;/span&gt;    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;clamp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nf"&gt;sign&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;q&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt; &lt;span class="nf"&gt;clamp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;q&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nf"&gt;sign&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;q&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The agent never sees that rule. It just &lt;em&gt;watches&lt;/em&gt; random games and counts what follows what. The only design choice is the shape of the memory it keeps — and that's the whole story:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;multi&lt;/span&gt;&lt;span class="p"&gt;[(&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="p"&gt;)][(&lt;/span&gt;&lt;span class="n"&gt;p2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;q2&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;   &lt;span class="c1"&gt;# multiplayer: "when BOTH are here, both go there"
&lt;/span&gt;&lt;span class="n"&gt;one_p&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;p2&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;           &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;    &lt;span class="c1"&gt;# single-player: "when the predator is here, it goes there"
&lt;/span&gt;&lt;span class="n"&gt;one_q&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;q2&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;           &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;    &lt;span class="c1"&gt;# single-player: "when the prey is here, it goes there"
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To &lt;strong&gt;dream&lt;/strong&gt;, it rolls its own predictions forward — feeding each guessed frame back in as the next input — and we check how long the dream keeps matching reality:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;real&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;dream&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;start&lt;/span&gt;
&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;15&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;real&lt;/span&gt;  &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;real_next&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;real&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;   &lt;span class="c1"&gt;# what actually happens
&lt;/span&gt;    &lt;span class="n"&gt;dream&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;model&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;dream&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;      &lt;span class="c1"&gt;# the model predicting on its OWN last frame
&lt;/span&gt;    &lt;span class="n"&gt;match&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dream&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;real&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Same footage, same loop. The only difference is whether the model remembered the two players &lt;strong&gt;together&lt;/strong&gt; or apart.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why single-player collapses
&lt;/h2&gt;

&lt;p&gt;The prey moves &lt;em&gt;because&lt;/em&gt; the predator moved. A single-player model looks at each player in isolation, so it structurally &lt;strong&gt;can't represent that reaction&lt;/strong&gt; — its errors compound each frame until the dream is fiction. The multiplayer model conditions on both, so it captures the coupling. To be fair, this isn't a surprising empirical result so much as a demonstration: the corridor is deterministic, so the outcome really follows from what each model is &lt;em&gt;allowed to see&lt;/em&gt;. That's exactly why the framing matters.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;A dream you can act in is a superpower — an agent can practice a thousand risky moves for free. But a dream that forgets everyone else reacts to you isn't practice. It's a delusion.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Why it's exciting
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;The proven part:&lt;/strong&gt; training agents inside a learned dream works — from &lt;a href="https://arxiv.org/abs/1803.10122" rel="noopener noreferrer"&gt;&lt;em&gt;World Models&lt;/em&gt;&lt;/a&gt; (2018) to &lt;a href="https://arxiv.org/abs/2301.04104" rel="noopener noreferrer"&gt;DreamerV3&lt;/a&gt; (2023) mastering 150+ tasks, and &lt;a href="https://arxiv.org/abs/2402.15391" rel="noopener noreferrer"&gt;Genie&lt;/a&gt; (2024) learning playable worlds from video alone. Dreamed worlds let agents rehearse infinitely, safely, at zero real-world cost.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Where it's heading:&lt;/strong&gt; those dreams are mostly single-agent today. The 2026 push is &lt;strong&gt;multiplayer&lt;/strong&gt; — worlds where agents model each other. The lesson from this demo is the whole ballgame: model the reactions or the dream drifts. Get it right and agents can plan &lt;em&gt;against each other&lt;/em&gt; entirely in imagination.&lt;/p&gt;

&lt;h2&gt;
  
  
  How faithful is this?
&lt;/h2&gt;

&lt;p&gt;A real world model learns from raw pixels with a neural net, in a noisy, stochastic world. This is that mechanism stripped to its core — a frequency table over a tiny, deterministic game. It's built to make the intuition concrete, not to reproduce the papers; those (linked below) do the heavy, learned version.&lt;/p&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;git clone https://github.com/Shridhar-2205/secret-lives-of-agents
&lt;span class="nb"&gt;cd &lt;/span&gt;secret-lives-of-agents/03-dreamed-world &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; python demo.py
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  The series — &lt;em&gt;The Secret Lives of AI Agents&lt;/em&gt;
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;a href="https://dev.to/shridhar_shah2297/i-watched-two-ai-agents-invent-their-own-language-51n2"&gt;Agents invent their own language&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/shridhar_shah2297/i-gave-3-ai-agents-a-decaying-notepad-and-they-built-a-culture-1n3n"&gt;Agents build a culture on a decaying notepad&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Agents that live inside dreamed-up worlds&lt;/strong&gt; (you're here)&lt;/li&gt;
&lt;/ol&gt;




&lt;p&gt;&lt;strong&gt;Shridhar Shah&lt;/strong&gt; — Senior Software Engineer on the AI team at Cisco. &lt;a href="https://github.com/Shridhar-2205" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt; · &lt;a href="https://www.linkedin.com/in/shridhar-shah-220b1721b/" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Sources &amp;amp; further reading:&lt;/strong&gt; Ha &amp;amp; Schmidhuber, &lt;a href="https://arxiv.org/abs/1803.10122" rel="noopener noreferrer"&gt;&lt;em&gt;World Models&lt;/em&gt;&lt;/a&gt; (2018) — the "train inside a dream" idea · Hafner et al., &lt;a href="https://arxiv.org/abs/2301.04104" rel="noopener noreferrer"&gt;&lt;em&gt;Mastering Diverse Domains through World Models&lt;/em&gt;&lt;/a&gt; (DreamerV3, 2023) · Bruce et al., &lt;a href="https://arxiv.org/abs/2402.15391" rel="noopener noreferrer"&gt;&lt;em&gt;Genie: Generative Interactive Environments&lt;/em&gt;&lt;/a&gt; (2024).&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>ai</category>
      <category>machinelearning</category>
      <category>llm</category>
      <category>python</category>
    </item>
    <item>
      <title>I Gave 3 AI Agents a Decaying Notepad and They Built a Culture</title>
      <dc:creator>Shridhar Shah</dc:creator>
      <pubDate>Tue, 21 Jul 2026 05:51:51 +0000</pubDate>
      <link>https://dev.to/shridhar_shah2297/i-gave-3-ai-agents-a-decaying-notepad-and-they-built-a-culture-1n3n</link>
      <guid>https://dev.to/shridhar_shah2297/i-gave-3-ai-agents-a-decaying-notepad-and-they-built-a-culture-1n3n</guid>
      <description>&lt;p&gt;&lt;em&gt;One shared memory that keeps fading, three minimal agents, no boss — and a story that outlives every note that carried it.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;TL;DR:&lt;/strong&gt; Give a few bare-bones agents nothing but a shared notepad that constantly fades, and they spontaneously build a &lt;strong&gt;culture&lt;/strong&gt; — a story they keep alive together, long after any single note has decayed to nothing. No coordinator, one tiny rule. Runs on a laptop.&lt;/p&gt;




&lt;h2&gt;
  
  
  The setup
&lt;/h2&gt;

&lt;p&gt;Three agents share one whiteboard. Every tick, everything on it fades; a note left alone dies in &lt;strong&gt;~4 ticks&lt;/strong&gt;. Each tick an agent scribbles a noisy observation, and a &lt;strong&gt;swarm&lt;/strong&gt; agent also reinforces whatever's currently strongest. That's the whole rule. It's &lt;strong&gt;stigmergy&lt;/strong&gt; — how termites build cathedrals by reacting to each other's mud (Grassé, 1959) — and the same dynamic that lets populations of agents settle on shared conventions (&lt;a href="https://arxiv.org/abs/2403.08882" rel="noopener noreferrer"&gt;Perez et al., 2024&lt;/a&gt;).&lt;/p&gt;

&lt;h2&gt;
  
  
  The 10-second version
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;❌ Each on its own&lt;/th&gt;
&lt;th&gt;✅ The swarm&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;A shared story exists&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;11%&lt;/strong&gt; of ticks&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;100%&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Same story tick-to-tick&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;3%&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;99%&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  How it works
&lt;/h2&gt;

&lt;p&gt;No agent has a memory of its own. The only shared state is &lt;code&gt;pad&lt;/code&gt; — a dict of &lt;code&gt;note -&amp;gt; strength&lt;/code&gt; that fades every tick. Each tick, three agents scribble a noisy observation, and the "culture" rule is a single line: &lt;strong&gt;reinforce whatever the group is already backing.&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;pad&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;                                    &lt;span class="c1"&gt;# the shared, fading notepad
&lt;/span&gt;
&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;tick&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;note&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;list&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pad&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;                  &lt;span class="c1"&gt;# 1. everything decays; faint notes are forgotten
&lt;/span&gt;        &lt;span class="n"&gt;pad&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;note&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;*=&lt;/span&gt; &lt;span class="mf"&gt;0.5&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;pad&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;note&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mf"&gt;0.1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;del&lt;/span&gt; &lt;span class="n"&gt;pad&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;note&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;                       &lt;span class="c1"&gt;# 2. three agents act this tick
&lt;/span&gt;        &lt;span class="n"&gt;obs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;random&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;choice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;FACTS&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;           &lt;span class="c1"&gt;#    each jots a weak, noisy observation
&lt;/span&gt;        &lt;span class="n"&gt;pad&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;obs&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pad&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;obs&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mf"&gt;0.3&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;imitate&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;                          &lt;span class="c1"&gt;#    the ENTIRE culture rule:
&lt;/span&gt;            &lt;span class="n"&gt;leader&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;max&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pad&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;pad&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;   &lt;span class="c1"&gt;#      reinforce what the group already backs
&lt;/span&gt;            &lt;span class="n"&gt;pad&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;leader&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mf"&gt;1.0&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Flip &lt;code&gt;imitate&lt;/code&gt; off and you get pure noise. Flip it on and a single story takes over — chosen by no one, kept alive by everyone.&lt;/p&gt;

&lt;h2&gt;
  
  
  The part that got me
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Tick 0:   group rallies around  "water down"
Tick 100: group still holds     "water down"
   ...but that original note faded to ~8e-31 within a few ticks.
   It survived only because the agents rewrote it 300 times.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The story is 100 ticks old; the note that started it has been gone since tick ~4. What persists isn't any note — it's the &lt;em&gt;meaning&lt;/em&gt;, re-inscribed by the group. It's the Ship of Theseus: no original plank left, yet the ship sails on. Reseed and a different story wins — the agreement is what's real.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why it matters
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;The proven part:&lt;/strong&gt; stigmergy — coordination through traces left in a shared medium — is old biology (Grassé, 1959), and populations of LLM agents have already been shown to form and transmit shared conventions (&lt;a href="https://arxiv.org/abs/2403.08882" rel="noopener noreferrer"&gt;Perez et al., 2024&lt;/a&gt;). This demo distills it to a single rule on a decaying pad.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Where it's heading:&lt;/strong&gt; we keep trying to fix agent memory with bigger storage. This points the other way — a &lt;strong&gt;group&lt;/strong&gt; of forgetful agents in 2026 can hold knowledge no single one could, just by reminding each other. Persistence becomes a property of the &lt;em&gt;society&lt;/em&gt;, not the context window.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;These agents can't remember much alone. Together, on a whiteboard that won't stop erasing itself, they keep a story alive as long as they care to. That's culture.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  How faithful is this?
&lt;/h2&gt;

&lt;p&gt;This is stigmergy distilled to one reinforcement rule on a decaying dictionary — not LLM agents reasoning in language. It shows the &lt;em&gt;dynamic&lt;/em&gt; (a shared story outliving the notes that carried it); the cited work studies it with real populations of generative agents.&lt;/p&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;git clone https://github.com/Shridhar-2205/secret-lives-of-agents
&lt;span class="nb"&gt;cd &lt;/span&gt;secret-lives-of-agents/02-emergent-culture &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; python demo.py
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  The series — &lt;em&gt;The Secret Lives of AI Agents&lt;/em&gt;
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;a href="https://dev.to/shridhar_shah2297/i-watched-two-ai-agents-invent-their-own-language-51n2"&gt;Agents invent their own language&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Agents build a culture on a decaying notepad&lt;/strong&gt; (you're here)&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/shridhar_shah2297/ai-agents-that-live-inside-a-dreamed-up-world-3n4j"&gt;Agents that live inside dreamed-up worlds&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;




&lt;p&gt;&lt;strong&gt;Shridhar Shah&lt;/strong&gt; — Senior Software Engineer on the AI team at Cisco. &lt;a href="https://github.com/Shridhar-2205" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt; · &lt;a href="https://www.linkedin.com/in/shridhar-shah-220b1721b/" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Sources &amp;amp; further reading:&lt;/strong&gt; Stigmergy (Grassé, 1959) — the biology of indirect coordination · Park et al., &lt;a href="https://arxiv.org/abs/2304.03442" rel="noopener noreferrer"&gt;&lt;em&gt;Generative Agents: Interactive Simulacra of Human Behavior&lt;/em&gt;&lt;/a&gt; (2023) · Perez et al., &lt;a href="https://arxiv.org/abs/2403.08882" rel="noopener noreferrer"&gt;&lt;em&gt;Cultural Evolution in Populations of Large Language Models&lt;/em&gt;&lt;/a&gt; (2024).&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>ai</category>
      <category>machinelearning</category>
      <category>llm</category>
      <category>python</category>
    </item>
    <item>
      <title>I Watched Two AI Agents Invent Their Own Language</title>
      <dc:creator>Shridhar Shah</dc:creator>
      <pubDate>Tue, 21 Jul 2026 05:46:59 +0000</pubDate>
      <link>https://dev.to/shridhar_shah2297/i-watched-two-ai-agents-invent-their-own-language-51n2</link>
      <guid>https://dev.to/shridhar_shah2297/i-watched-two-ai-agents-invent-their-own-language-51n2</guid>
      <description>&lt;p&gt;&lt;em&gt;No shared words, no dictionary — just two agents that negotiate a private code from scratch and hit ~97%.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;TL;DR:&lt;/strong&gt; Give two AI agents a reason to coordinate and they'll make up their own language — one we never designed. I built the tiniest version: two agents, zero shared words, and from "did we understand each other?" alone they invent a private code and hit &lt;strong&gt;~97%&lt;/strong&gt;. Runs on a laptop, no API key.&lt;/p&gt;




&lt;h2&gt;
  
  
  The game
&lt;/h2&gt;

&lt;p&gt;A &lt;strong&gt;sender&lt;/strong&gt; sees a secret object (say 🍎) and holds up one of a few random shapes: ◇ △ ○ ☆ □. A &lt;strong&gt;receiver&lt;/strong&gt; sees only the shape and guesses the object. Right guess → both remember that pairing. No dictionary, no translator. This is the classic &lt;strong&gt;Lewis signaling game&lt;/strong&gt; — the cleanest way to watch language appear from nothing.&lt;/p&gt;

&lt;h2&gt;
  
  
  The 10-second version
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;❌ No memory&lt;/th&gt;
&lt;th&gt;✅ Remembers&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;After 2,000 rounds&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;~56%&lt;/strong&gt; (chance)&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;~97%&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;A language formed?&lt;/td&gt;
&lt;td&gt;no&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;yes&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Blind guess = 20%. Watch it crystallize:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;round    1:   0%
round  500:  94%
round 2000:  97%   apple=◇  banana=□  cherry=△  grape=☆  lemon=○
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  How it works
&lt;/h2&gt;

&lt;p&gt;There's no neural network here — just two habit tables per agent and one rule: &lt;strong&gt;when a guess lands, both sides strengthen the exact link they just used.&lt;/strong&gt; That's the entire learning algorithm.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Agent&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="c1"&gt;# habit tallies, both directions, all starting at zero
&lt;/span&gt;        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;obj_to_sym&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;o&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;0.0&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;SYMBOLS&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;o&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;OBJECTS&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sym_to_obj&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;o&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;0.0&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;o&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;OBJECTS&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;SYMBOLS&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;pick&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;habits&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="c1"&gt;# mostly reuse the strongest habit; occasionally explore something new
&lt;/span&gt;        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;random&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;random&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;explore&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;random&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;choice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;list&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;habits&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;max&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;habits&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;habits&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;say&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;   &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pick&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;obj_to_sym&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;   &lt;span class="c1"&gt;# object -&amp;gt; symbol
&lt;/span&gt;    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;guess&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;sym&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pick&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sym_to_obj&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;sym&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;   &lt;span class="c1"&gt;# symbol -&amp;gt; object
&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;reward&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;sym&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;          &lt;span class="c1"&gt;# a win: reinforce the SAME link on both maps
&lt;/span&gt;        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;obj_to_sym&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;sym&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sym_to_obj&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;sym&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And the whole game is just:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;obj&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;random&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;choice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;OBJECTS&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;          &lt;span class="c1"&gt;# sender sees a secret object
&lt;/span&gt;&lt;span class="n"&gt;sym&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;sender&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;say&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;                 &lt;span class="c1"&gt;# sender picks a symbol for it
&lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;receiver&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;guess&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sym&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;        &lt;span class="c1"&gt;# receiver decodes it — did they match?
&lt;/span&gt;    &lt;span class="n"&gt;sender&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;reward&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;sym&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;           &lt;span class="c1"&gt;# yes: both lock in that pairing
&lt;/span&gt;    &lt;span class="n"&gt;receiver&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;reward&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;sym&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's it. Run it a few thousand times and a clean one-to-one code falls out. Reseed and they invent a &lt;em&gt;different&lt;/em&gt; code (&lt;code&gt;apple=☆ …&lt;/code&gt;) — arbitrary, but agreed. And memory is what makes it stick: agents that only recall the last few rounds never settle, exactly as this referential game — introduced by &lt;a href="https://arxiv.org/abs/1612.07182" rel="noopener noreferrer"&gt;Lazaridou, Peysakhovich &amp;amp; Baroni (2017)&lt;/a&gt; — predicts.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why it's exciting (and a little eerie)
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;The proven part:&lt;/strong&gt; two neural agents reliably invent a working code from scratch — shown since &lt;a href="https://arxiv.org/abs/1612.07182" rel="noopener noreferrer"&gt;Lazaridou et al. (2017)&lt;/a&gt; and surveyed in &lt;a href="https://arxiv.org/abs/2006.02419" rel="noopener noreferrer"&gt;Lazaridou &amp;amp; Baroni (2020)&lt;/a&gt;. This demo just strips the idea to 100 lines so you can watch it happen.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Where it's heading:&lt;/strong&gt; the systems we're shipping in 2026 are LLM &lt;em&gt;swarms&lt;/em&gt; that talk to each other nonstop. A private, compressed code lets them coordinate faster and cheaper than plain English — a real efficiency win. The flip side: if agents settle on a protocol we didn't design, we may not be able to &lt;strong&gt;read what they tell each other.&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;A language is just a bet that a symbol means the same thing on both ends. These agents make that bet round by round, with nobody refereeing.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  How faithful is this?
&lt;/h2&gt;

&lt;p&gt;This is the classic referential game in ~100 lines — reinforcement over simple habit tables, not a neural network. It captures the &lt;em&gt;mechanism&lt;/em&gt; (a shared code emerging from feedback alone); the papers below scale the same idea to real networks and richer, compositional languages.&lt;/p&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;git clone https://github.com/Shridhar-2205/secret-lives-of-agents
&lt;span class="nb"&gt;cd &lt;/span&gt;secret-lives-of-agents/01-invented-language &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; python demo.py
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  The series — &lt;em&gt;The Secret Lives of AI Agents&lt;/em&gt;
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Agents invent their own language&lt;/strong&gt; (you're here)&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/shridhar_shah2297/i-gave-3-ai-agents-a-decaying-notepad-and-they-built-a-culture-1n3n"&gt;Agents build a culture on a decaying notepad&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/shridhar_shah2297/ai-agents-that-live-inside-a-dreamed-up-world-3n4j"&gt;Agents that live inside dreamed-up worlds&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;




&lt;p&gt;&lt;strong&gt;Shridhar Shah&lt;/strong&gt; — Senior Software Engineer on the AI team at Cisco. &lt;a href="https://github.com/Shridhar-2205" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt; · &lt;a href="https://www.linkedin.com/in/shridhar-shah-220b1721b/" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Sources &amp;amp; further reading:&lt;/strong&gt; Lewis, &lt;em&gt;Convention&lt;/em&gt; (1969) — the original signaling game · Lazaridou, Peysakhovich &amp;amp; Baroni, &lt;a href="https://arxiv.org/abs/1612.07182" rel="noopener noreferrer"&gt;&lt;em&gt;Multi-Agent Cooperation and the Emergence of (Natural) Language&lt;/em&gt;&lt;/a&gt; (ICLR 2017) · Havrylov &amp;amp; Titov, &lt;a href="https://arxiv.org/abs/1705.11192" rel="noopener noreferrer"&gt;&lt;em&gt;Emergence of Language with Multi-agent Games&lt;/em&gt;&lt;/a&gt; (NeurIPS 2017) · Lazaridou &amp;amp; Baroni, &lt;a href="https://arxiv.org/abs/2006.02419" rel="noopener noreferrer"&gt;&lt;em&gt;Emergent Multi-Agent Communication in the Deep Learning Era&lt;/em&gt;&lt;/a&gt; (2020, survey).&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>ai</category>
      <category>machinelearning</category>
      <category>llm</category>
      <category>python</category>
    </item>
    <item>
      <title>Agents Are Learning to Write Their Own SKILL.md Files</title>
      <dc:creator>Shridhar Shah</dc:creator>
      <pubDate>Sat, 27 Jun 2026 21:53:22 +0000</pubDate>
      <link>https://dev.to/shridhar_shah2297/agents-are-learning-to-write-their-own-skillmd-files-3foo</link>
      <guid>https://dev.to/shridhar_shah2297/agents-are-learning-to-write-their-own-skillmd-files-3foo</guid>
      <description>&lt;p&gt;&lt;em&gt;The Agent Skills open standard today, and the 2026 research on agents that write their own skills.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;TL;DR:&lt;/strong&gt; I've been using skills in Claude Code daily, and one question stuck with me: what happens when the agent writes them itself? Quick background: "Agent Skills" (late 2025) are a dead-simple way to teach an agent a task — a folder with a &lt;code&gt;SKILL.md&lt;/code&gt; file of Markdown instructions, now an open standard. The wild part is what's coming next: agents that &lt;strong&gt;write their own skills.&lt;/strong&gt; I built a demo where an agent solves a task the hard way once, saves a real &lt;code&gt;SKILL.md&lt;/code&gt;, and then reuses it — cutting its total effort almost in half. No API key.&lt;/p&gt;




&lt;h2&gt;
  
  
  First, what's a "skill"?
&lt;/h2&gt;

&lt;p&gt;If you've used Claude Code or similar tools lately, you've probably seen &lt;code&gt;SKILL.md&lt;/code&gt; files. The idea is refreshingly low-tech. A "skill" is just a folder with a Markdown file that says &lt;em&gt;how to do something&lt;/em&gt;:&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="nn"&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;csv-to-markdown&lt;/span&gt;
&lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Turn comma-separated text into a Markdown table. Use when the input looks&lt;/span&gt;
  &lt;span class="s"&gt;like CSV and the user wants a table.&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;

&lt;span class="c1"&gt;# CSV to Markdown&lt;/span&gt;

&lt;span class="c1"&gt;## Instructions&lt;/span&gt;
&lt;span class="s"&gt;Split the text into rows on newlines and columns on commas. Make the first row the&lt;/span&gt;
&lt;span class="s"&gt;header, add a `---` divider row, then format every row as `| a | b | c |`.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's it. No SDK, no config. Anthropic introduced this in October 2025 and then published it as an &lt;strong&gt;open standard&lt;/strong&gt; (&lt;a href="https://agentskills.io" rel="noopener noreferrer"&gt;agentskills.io&lt;/a&gt;) in December 2025, so the same skill folder now works across ~30+ different agent tools (Claude Code, Cursor, Copilot, and more).&lt;/p&gt;

&lt;p&gt;The full rules are short (&lt;a href="https://agentskills.io/specification" rel="noopener noreferrer"&gt;agentskills.io/specification&lt;/a&gt;): the only &lt;strong&gt;required&lt;/strong&gt; fields are &lt;code&gt;name&lt;/code&gt; (1–64 chars, lowercase-with-hyphens, and it must match the folder name) and &lt;code&gt;description&lt;/code&gt; (≤1024 chars, saying &lt;em&gt;what it does and when to use it&lt;/em&gt;). Everything else — &lt;code&gt;license&lt;/code&gt;, &lt;code&gt;metadata&lt;/code&gt;, &lt;code&gt;compatibility&lt;/code&gt;, &lt;code&gt;allowed-tools&lt;/code&gt; — is optional. That's the whole spec. The &lt;code&gt;SKILL.md&lt;/code&gt; files my demo writes follow it to the letter, so they'd load unmodified in any compatible CLI.&lt;/p&gt;

&lt;h2&gt;
  
  
  The clever trick: progressive disclosure
&lt;/h2&gt;

&lt;p&gt;Here's the smart part. If you just dumped 50 skills' worth of instructions into the agent's context, you'd fill it up and leave no room for actual work. So skills load in &lt;strong&gt;stages&lt;/strong&gt;:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Always loaded:&lt;/strong&gt; just the &lt;code&gt;name&lt;/code&gt; and one-line &lt;code&gt;description&lt;/code&gt; of every skill (tiny).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Loaded only when it matches:&lt;/strong&gt; the full instructions, once a task actually needs them.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Loaded only if referenced:&lt;/strong&gt; extra files or scripts the skill bundles.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;So the agent can have &lt;em&gt;hundreds&lt;/em&gt; of skills installed and barely pay for it — it only reads the short descriptions until one matches, then pulls in the details. My demo shows the math: to use 1 skill out of 3 installed, loading everything costs ~1500 "tokens"; the SKILL.md way costs ~560. That gap gets huge as your library grows.&lt;/p&gt;

&lt;p&gt;This is also why people say skills and &lt;strong&gt;MCP&lt;/strong&gt; are teammates, not rivals: MCP is how an agent &lt;em&gt;connects to tools&lt;/em&gt;; a skill is how an agent &lt;em&gt;knows the procedure&lt;/em&gt; for using them.&lt;/p&gt;

&lt;h2&gt;
  
  
  The frontier: agents that write their own skills
&lt;/h2&gt;

&lt;p&gt;Today, humans write &lt;code&gt;SKILL.md&lt;/code&gt; files. The 2026 research is about agents that write their &lt;strong&gt;own&lt;/strong&gt; — and get better over time as their skill library grows. This goes back to &lt;strong&gt;Voyager&lt;/strong&gt; (2023), an agent that played Minecraft and saved working code as reusable skills, getting dramatically faster at the game. The new wave makes it general:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://arxiv.org/html/2605.27366" rel="noopener noreferrer"&gt;MUSE-Autoskill&lt;/a&gt;&lt;/strong&gt; (2026) treats a skill as a &lt;em&gt;living asset&lt;/em&gt; with a full lifecycle — create it, give it its own memory file, manage it, test it, and refine it. Each skill even keeps a &lt;code&gt;.memory.md&lt;/code&gt; of notes about itself.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://arxiv.org/pdf/2603.18743v1" rel="noopener noreferrer"&gt;Memento-Skills&lt;/a&gt;&lt;/strong&gt; (2026) stores skills as Markdown files that double as the agent's evolving memory, and turns task &lt;em&gt;failures&lt;/em&gt; into new skills automatically.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://arxiv.org/abs/2602.01869" rel="noopener noreferrer"&gt;Skill-Pro&lt;/a&gt;&lt;/strong&gt; (2026) defines a skill as "when to use it + how to do it + when to stop," and only keeps a new skill if it passes a quality gate — so the library improves instead of filling up with junk.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The common thread: &lt;strong&gt;solve it once, save the recipe, reuse it forever&lt;/strong&gt; — and let the collection get smarter on its own.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;📄 &lt;strong&gt;The "this is the future" link:&lt;/strong&gt; Anthropic's own writeup, &lt;a href="https://www.anthropic.com/engineering/equipping-agents-for-the-real-world-with-agent-skills" rel="noopener noreferrer"&gt;&lt;em&gt;Equipping agents for the real world with Agent Skills&lt;/em&gt;&lt;/a&gt;, and the open standard at &lt;strong&gt;&lt;a href="https://agentskills.io" rel="noopener noreferrer"&gt;agentskills.io&lt;/a&gt;&lt;/strong&gt;. For the research direction, &lt;a href="https://arxiv.org/abs/2605.27366" rel="noopener noreferrer"&gt;MUSE-Autoskill (arXiv:2605.27366)&lt;/a&gt; and &lt;a href="https://arxiv.org/abs/2602.01869" rel="noopener noreferrer"&gt;Skill-Pro (arXiv:2602.01869)&lt;/a&gt; are the clearest reads on agents that grow their own skill libraries.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  You can do this &lt;em&gt;today&lt;/em&gt; in the Claude Code CLI
&lt;/h2&gt;

&lt;p&gt;This isn't theoretical — the exact pattern from my demo already ships in coding CLIs. In &lt;strong&gt;Claude Code&lt;/strong&gt;, a skill is just a folder under &lt;code&gt;.claude/skills/&lt;/code&gt; in your repo:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Anywhere in your project — drop a skill in and the CLI auto-discovers it&lt;/span&gt;
&lt;span class="nb"&gt;mkdir&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; .claude/skills/csv-to-markdown
&lt;span class="nv"&gt;$EDITOR&lt;/span&gt; .claude/skills/csv-to-markdown/SKILL.md   &lt;span class="c"&gt;# same SKILL.md format as my demo&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now the agent loads only that skill's one-line &lt;code&gt;description&lt;/code&gt; until a task matches — then pulls in the full instructions (that's progressive disclosure doing its job). Type &lt;code&gt;/skills&lt;/code&gt; inside the CLI to see what's loaded.&lt;/p&gt;

&lt;p&gt;The best part: because it's an &lt;strong&gt;open standard&lt;/strong&gt;, the &lt;em&gt;same&lt;/em&gt; folder works unmodified across tools. You're not locked in:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://www.anthropic.com/engineering/equipping-agents-for-the-real-world-with-agent-skills" rel="noopener noreferrer"&gt;Claude Code&lt;/a&gt;&lt;/strong&gt; — Anthropic's CLI, where the format started.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://github.com/sst/opencode" rel="noopener noreferrer"&gt;opencode&lt;/a&gt;&lt;/strong&gt; — a popular open-source terminal agent.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://github.com/block/goose" rel="noopener noreferrer"&gt;Goose&lt;/a&gt;&lt;/strong&gt; — Block's open-source agent.&lt;/li&gt;
&lt;li&gt;Plus Cursor, GitHub Copilot, and 30+ others.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Write the skill once, use it everywhere. The future bit my demo points at: instead of &lt;em&gt;you&lt;/em&gt; hand-writing that file, the agent writes it for itself after solving the task the first time — and from then on, your repo quietly accumulates a library of skills your agent earned.&lt;/p&gt;

&lt;h2&gt;
  
  
  The 10-second version (my demo)
&lt;/h2&gt;

&lt;p&gt;Same stream of 7 tasks. "Cost" is how much effort each one took.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;No-skills agent&lt;/th&gt;
&lt;th&gt;Skill-writing agent&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;What it does&lt;/td&gt;
&lt;td&gt;re-solves everything from scratch&lt;/td&gt;
&lt;td&gt;learns a task once, saves a &lt;code&gt;SKILL.md&lt;/code&gt;, reuses it&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Total cost&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;35&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;19&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Both correct?&lt;/td&gt;
&lt;td&gt;7/7&lt;/td&gt;
&lt;td&gt;7/7&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[5] csv-to-markdown  learned it and wrote SKILL.md
[5] slugify          learned it and wrote SKILL.md
[1] csv-to-markdown  reused skill 'csv-to-markdown'   ← cheap now
[5] extract-emails   learned it and wrote SKILL.md
[1] slugify          reused skill 'slugify'
[1] csv-to-markdown  reused skill 'csv-to-markdown'
[1] extract-emails   reused skill 'extract-emails'
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It writes &lt;strong&gt;real &lt;code&gt;SKILL.md&lt;/code&gt; files&lt;/strong&gt; into a &lt;code&gt;./skills&lt;/code&gt; folder you can open. The first time it sees a task it pays full price; after that, it finds its own saved skill and reuses it for cheap.&lt;/p&gt;

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

&lt;p&gt;Two big reasons engineers should care:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Agents stop repeating themselves.&lt;/strong&gt; Right now most agents re-derive the same thing over and over, paying for it every time. A skill library means "figure it out once, then it's free" — like a teammate who writes things down instead of relearning them daily.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;A whole new ecosystem.&lt;/strong&gt; There are already 65,000+ shared skills and a scramble to build "the npm of agent skills" — registries and marketplaces where you install a skill like a package. Skills are becoming a unit of &lt;em&gt;shareable expertise&lt;/em&gt;: a senior engineer's know-how, packaged in a folder, that any agent can pick up.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;blockquote&gt;
&lt;p&gt;Tools tell an agent &lt;em&gt;what it can do&lt;/em&gt;. Skills tell it &lt;em&gt;how to do things well&lt;/em&gt; — and soon, agents will write that part themselves, and trade it with each other.&lt;/p&gt;
&lt;/blockquote&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;git clone https://github.com/Shridhar-2205/living-software
&lt;span class="nb"&gt;cd &lt;/span&gt;living-software/06-agent-skills
python demo.py
&lt;span class="nb"&gt;cat &lt;/span&gt;skills/csv-to-markdown/SKILL.md   &lt;span class="c"&gt;# a skill the agent wrote itself&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Honest note: this is a POC. Real systems decide &lt;em&gt;when&lt;/em&gt; a new skill is worth saving, test it, and refine it over time (that's exactly what the 2026 papers above tackle). Mine keeps that part simple so the core idea — &lt;em&gt;learn once, save a SKILL.md, reuse it&lt;/em&gt; — is easy to see.&lt;/p&gt;

&lt;h2&gt;
  
  
  The rest of the series — &lt;em&gt;Toward Living Software&lt;/em&gt;
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;a href="https://dev.to/shridhar_shah2297/i-built-an-ai-agent-that-rewrites-its-own-code-in-150-lines-3jjo"&gt;I built an AI agent that rewrites its own code&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/shridhar_shah2297/do-ai-agents-need-to-sleep-i-built-one-that-does-53c4"&gt;Do AI agents need to sleep?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/shridhar_shah2297/can-an-ai-agent-pass-the-test-we-give-4-year-olds-5825"&gt;Can an AI agent pass the Sally-Anne test?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/shridhar_shah2297/i-built-an-ai-agent-that-gets-curious-on-its-own-4oe1"&gt;An AI agent that gets curious on its own&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/shridhar_shah2297/how-do-you-trust-an-ai-agent-with-your-money-you-dont-you-check-its-receipt-38ff"&gt;How do you trust an AI agent with your money?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Agents that write their own SKILL.md files&lt;/strong&gt; (you're reading it)&lt;/li&gt;
&lt;/ol&gt;




&lt;p&gt;&lt;strong&gt;Shridhar Shah&lt;/strong&gt; — Senior Software Engineer on the AI team at Cisco. Part 6 of &lt;em&gt;Toward Living Software&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/Shridhar-2205" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt; · &lt;a href="https://www.linkedin.com/in/shridhar-shah-220b1721b/" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Sources:&lt;/strong&gt; Anthropic, "Equipping agents for the real world with Agent Skills" (2025) and the Agent Skills open standard (agentskills.io); Voyager (arXiv:2305.16291); MUSE-Autoskill (arXiv:2605.27366); Memento-Skills (arXiv:2603.18743); Skill-Pro (arXiv:2602.01869); MemSkill (arXiv:2602.02474).&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>ai</category>
      <category>llm</category>
      <category>programming</category>
      <category>python</category>
    </item>
  </channel>
</rss>
