<?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: Susheem Koul</title>
    <description>The latest articles on DEV Community by Susheem Koul (@susheem-k).</description>
    <link>https://dev.to/susheem-k</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%2F3400154%2Fcbd57c42-b444-4478-965d-0243e3ea9e5a.jpg</url>
      <title>DEV Community: Susheem Koul</title>
      <link>https://dev.to/susheem-k</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/susheem-k"/>
    <language>en</language>
    <item>
      <title>How coding agents like Cursor quietly cut input costs by reusing KV states across turns — and what actually breaks the cache</title>
      <dc:creator>Susheem Koul</dc:creator>
      <pubDate>Thu, 30 Jul 2026 19:11:26 +0000</pubDate>
      <link>https://dev.to/susheem-k/how-coding-agents-like-cursor-quietly-cut-input-costs-by-reusing-kv-states-across-turns-and-what-49fe</link>
      <guid>https://dev.to/susheem-k/how-coding-agents-like-cursor-quietly-cut-input-costs-by-reusing-kv-states-across-turns-and-what-49fe</guid>
      <description>&lt;h2&gt;
  
  
  Why my Cursor bill looked weird
&lt;/h2&gt;

&lt;p&gt;I was poking around my usage dashboard in Cursor and noticed a metric I'd never paid attention to before: &lt;strong&gt;Cache Read&lt;/strong&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Date            Type       Model    Tokens
May 2, 06:50 PM  Included   auto     898K   → Cache Read
May 2, 06:49 PM  Included   auto     1.4M   → Cache Write
May 2, 06:47 PM  Included   auto     346.8K → Input / Output
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Almost 99% of my input tokens for that session were served from cache. That sent me down a rabbit hole on what prompt caching actually &lt;em&gt;is&lt;/em&gt;, and why it matters so much for agentic coding tools specifically. Here's what I found.&lt;/p&gt;

&lt;h2&gt;
  
  
  What prompt caching actually is
&lt;/h2&gt;

&lt;p&gt;Agentic coding tools ship a &lt;em&gt;lot&lt;/em&gt; of context on every single call — system instructions, workspace rules, file contents, conversation history, the works. LLMs are stateless by default, so naively, all of that gets reprocessed from scratch on every request.&lt;/p&gt;

&lt;p&gt;Prompt caching short-circuits this. It saves the intermediate computation from the transformer's prefill stage — specifically the Key/Value states — so that when a later request shares the same leading sequence of tokens, the model reuses those states instead of recomputing them.&lt;/p&gt;

&lt;p&gt;One important caveat: &lt;strong&gt;this only applies to input tokens.&lt;/strong&gt; Output generation is still sequential, token-by-token, and gets no speedup from caching.&lt;/p&gt;

&lt;h2&gt;
  
  
  How the payload is actually built
&lt;/h2&gt;

&lt;p&gt;Coding agents don't just fire your question at the model. They assemble a large composite prompt, and — critically — they structure it with the most static content first and the most volatile content last:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;system_instructions&amp;gt;&lt;/span&gt; You are an expert coding assistant... &lt;span class="nt"&gt;&amp;lt;/system_instructions&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;project_rules&amp;gt;&lt;/span&gt; Use functional React components... &lt;span class="nt"&gt;&amp;lt;/project_rules&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;file_context_1&amp;gt;&lt;/span&gt; ... &lt;span class="nt"&gt;&amp;lt;/file_context_1&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;file_context_2&amp;gt;&lt;/span&gt; ... &lt;span class="nt"&gt;&amp;lt;/file_context_2&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;conversation_history&amp;gt;&lt;/span&gt; ... &lt;span class="nt"&gt;&amp;lt;/conversation_history&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;user_input&amp;gt;&lt;/span&gt; Refactor this function to handle edge cases. &lt;span class="nt"&gt;&amp;lt;/user_input&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once that sequence hits the model, the transformer tokenizes it and starts computing attention. For every token, it derives a Key (K) and a Value (V) — essentially a map of how that token relates to every other token before it. This is the expensive part: attention computation scales quadratically with sequence length, so a big context window (lots of files, long history) gets disproportionately costly to prefill.&lt;/p&gt;

&lt;p&gt;The model doesn't refer back to your raw text when generating a response — it refers to these computed KV matrices. That's the artifact caching actually preserves.&lt;/p&gt;

&lt;p&gt;Providers typically charge less for input tokens than output tokens, but agentic coding tools push such enormous input payloads that shaving cost off the input side is still very much worth doing.&lt;/p&gt;

&lt;h2&gt;
  
  
  Turn 1 vs. every turn after
&lt;/h2&gt;

&lt;p&gt;Here's the flow, roughly:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Turn 1 (cold start):&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Build the prompt: system instructions + project rules + file context + your first message.&lt;/li&gt;
&lt;li&gt;No cache exists yet → full prefill. The model computes KV states for &lt;em&gt;every&lt;/em&gt; token (the expensive O(n²) pass).&lt;/li&gt;
&lt;li&gt;Those KV states get written to cache storage.&lt;/li&gt;
&lt;li&gt;Generation proceeds normally.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Turn 2...N (warm):&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Build the new prompt: same system instructions + same files + prior conversation + your new message.&lt;/li&gt;
&lt;li&gt;Check for a prefix cache hit against system + context.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Hit:&lt;/strong&gt; read the cached KV states for the unchanged prefix, and only compute &lt;em&gt;new&lt;/em&gt; KV states for the incremental conversation turn + your latest input.&lt;/li&gt;
&lt;li&gt;Concatenate cached + new KV states, then generate.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;So instead of re-running the full O(n²) prefill on every message, only the marginal new tokens get freshly processed. That's the whole trick, and it's why long coding sessions don't get proportionally slower and more expensive turn after turn.&lt;/p&gt;

&lt;p&gt;Most major providers now do this optimization implicitly under the hood. Google's Vertex AI docs on &lt;a href="https://docs.cloud.google.com/vertex-ai/generativeai/docs/context-cache/context-cache-overview" rel="noopener noreferrer"&gt;context caching&lt;/a&gt; are a good primary-source reference if you want to see how one provider exposes this explicitly.&lt;/p&gt;

&lt;h2&gt;
  
  
  What breaks the cache
&lt;/h2&gt;

&lt;p&gt;Caching depends entirely on &lt;strong&gt;prefix stability&lt;/strong&gt;. The moment a token diverges from what's cached, everything downstream of that point has to be recomputed. In practice, here's what kills your hit rate:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Dynamic injections&lt;/strong&gt; — a timestamp or other changing value stuffed near the top of the prompt invalidates the prefix on every single request.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Context reordering&lt;/strong&gt; — shuffling the order in which files or context blocks get loaded prevents prefix matching entirely.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Upstream file edits&lt;/strong&gt; — editing a file that sits early in the prompt structure invalidates the cache for that file &lt;em&gt;and everything that comes after it&lt;/em&gt; in the sequence.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Most systems rely on exact token-prefix matches, though some providers (Google's docs linked above, for instance) expose more explicit cache handles or partial-reuse mechanisms.&lt;/p&gt;

&lt;h2&gt;
  
  
  The part that confused me: why appending doesn't break the cache
&lt;/h2&gt;

&lt;p&gt;This is the part that seemed contradictory at first. If attention connects every token to every other token, shouldn't adding a new message at the &lt;em&gt;end&lt;/em&gt; of the prompt ripple backward and change how the &lt;em&gt;earlier&lt;/em&gt; tokens (system instructions, file context) get attended to?&lt;/p&gt;

&lt;p&gt;It would — if the model attended in both directions. But modern generative LLMs are &lt;strong&gt;decoder-only&lt;/strong&gt; and use &lt;strong&gt;causal (masked) self-attention&lt;/strong&gt;: a token can only attend to tokens that came &lt;em&gt;before&lt;/em&gt; it, never after.&lt;/p&gt;

&lt;p&gt;That one architectural detail is what makes caching possible at all. We're not caching a fragile, bidirectional global attention matrix — we're caching the &lt;strong&gt;KV tensors of the prefix&lt;/strong&gt;. Those K and V states for the early context are computed once and never change, no matter what you append afterward. New tokens just generate their own Queries and attend against the already-cached Keys of everything before them.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where this goes next
&lt;/h2&gt;

&lt;p&gt;Prompt caching solves the "don't recompute what hasn't changed" problem. It doesn't solve the separate problem of &lt;em&gt;what to put in the context window in the first place&lt;/em&gt;. Instead of stuffing every file into the prompt and hoping for a cache hit, coding agents increasingly rely on retrieval — RAG-style embeddings over the codebase — to selectively pull in only the relevant slices of code.&lt;/p&gt;

&lt;p&gt;That's next on my list to dig into: how coding tools build queryable views of a codebase with embeddings, and what that does to the cost equation.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;If you want the deeper transformer-architecture background behind KV caching and attention, &lt;a href="https://www.3blue1brown.com" rel="noopener noreferrer"&gt;3Blue1Brown's "Large Language Models explained briefly"&lt;/a&gt; is a genuinely excellent, low-jargon primer.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Originally posted on &lt;a href="https://susheemk.substack.com/p/prompt-caching-and-context-optimization" rel="noopener noreferrer"&gt;Susheem's Jottings&lt;/a&gt; — cross-posting here for the dev.to crowd.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>webdev</category>
      <category>llm</category>
    </item>
  </channel>
</rss>
