<?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: Linford Reyes</title>
    <description>The latest articles on DEV Community by Linford Reyes (@linfordr).</description>
    <link>https://dev.to/linfordr</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%2F4073123%2Feb2d5167-7b6e-4a6b-baea-b9fb9650e4ed.jpg</url>
      <title>DEV Community: Linford Reyes</title>
      <link>https://dev.to/linfordr</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/linfordr"/>
    <language>en</language>
    <item>
      <title>Context compaction is silently destroying your LLM agent's memory</title>
      <dc:creator>Linford Reyes</dc:creator>
      <pubDate>Tue, 11 Aug 2026 17:05:24 +0000</pubDate>
      <link>https://dev.to/linfordr/context-compaction-is-silently-destroying-your-llm-agents-memory-2pg2</link>
      <guid>https://dev.to/linfordr/context-compaction-is-silently-destroying-your-llm-agents-memory-2pg2</guid>
      <description>&lt;h1&gt;
  
  
  Context compaction is silently destroying your LLM agent's memory
&lt;/h1&gt;

&lt;p&gt;&lt;strong&gt;Tl;dr:&lt;/strong&gt; Long-session LLM agents lose governing rules, todos, and decisions when context compaction runs — and the loss is usually silent. I built a zero-dependency Python library (&lt;a href="https://github.com/44334433/memory-anchor" rel="noopener noreferrer"&gt;memory-anchor&lt;/a&gt;) that snapshots that state verbatim before compaction and re-injects it after, plus a CLI to audit how much a compaction actually destroyed.&lt;/p&gt;

&lt;h2&gt;
  
  
  The problem nobody measures
&lt;/h2&gt;

&lt;p&gt;Run any agent long enough and it hits the context window. The fix everyone reaches for is compaction: old turns get summarized into a paragraph and the summary replaces them. Cheap summarizers — especially the fast flash models everyone uses to keep costs down — flatten detail. In my own agent's logs:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;a governing rule got paraphrased (the agent started behaving differently and nobody noticed why)&lt;/li&gt;
&lt;li&gt;a pending todo vanished ("what was I doing?")&lt;/li&gt;
&lt;li&gt;a decision's rationale was rewritten (settled questions got re-litigated)&lt;/li&gt;
&lt;li&gt;a verification path disappeared (half-verified work got reported as done)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That last one is the scary one. After a 35% compaction pass, my agent forgot it had delegated a subtask and never collected the result. Not a hallucination — a &lt;em&gt;silent state loss&lt;/em&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why existing memory systems don't cover this
&lt;/h2&gt;

&lt;p&gt;The current memory stack (mem0, Letta, Hindsight, and friends) remembers &lt;em&gt;facts&lt;/em&gt; — entities, preferences, retrieval chunks. None of them guarantee that the &lt;em&gt;rules and work state governing this session&lt;/em&gt; survive a compaction byte-for-byte. Research-backed systems like MemGPT treat memory as a tiered store, and Claude's own compaction is a black box — you don't get to see what it threw away.&lt;/p&gt;

&lt;p&gt;There are components everywhere, but no off-the-shelf, framework-agnostic answer. So I built one.&lt;/p&gt;

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



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;preserve(ctx) ─► manifest (4 lists, verbatim) ─► [summarizer runs] ─► recover(ctx) ─► recovery block injected at head of messages
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Four small pieces, pure stdlib, zero dependencies:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;StateManifest&lt;/strong&gt; — rules / todos / decisions / progress, serialized to JSON, with incremental &lt;code&gt;merge()&lt;/code&gt;: done todos never resurrect, superseded decisions never reappear.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;MemoryStore&lt;/strong&gt; — atomic (tmp+rename) local JSON persistence, per-session indexed.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;RecoveryInjector&lt;/strong&gt; — rebuilds the recovery block; L1 (immutable rules) is &lt;em&gt;never&lt;/em&gt; trimmed.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;CompactableMemory&lt;/strong&gt; — a two-line facade:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;pathlib&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Path&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;memory_anchor&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;CompactableMemory&lt;/span&gt;

&lt;span class="n"&gt;mem&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;CompactableMemory&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;base_dir&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nc"&gt;Path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;.memory&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="n"&gt;mem&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;preserve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;                              &lt;span class="c1"&gt;# before compaction
&lt;/span&gt;&lt;span class="n"&gt;messages&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;mem&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;recover&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;summary&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;# after compaction
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  The part I'm most proud of: auditing compaction damage
&lt;/h2&gt;

&lt;p&gt;v0.3 added &lt;code&gt;cam judge&lt;/code&gt; — point it at your pre-compaction manifest and the summary that replaced it, and it classifies every item as &lt;strong&gt;verbatim&lt;/strong&gt; (survived), &lt;strong&gt;paraphrased&lt;/strong&gt; (semantics preserved), or &lt;strong&gt;lost&lt;/strong&gt;. It's a CI gate, not a vibes check:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;cam judge &lt;span class="nt"&gt;--before&lt;/span&gt; manifest.json &lt;span class="nt"&gt;--after&lt;/span&gt; summary.txt &lt;span class="nt"&gt;--min-verbatim&lt;/span&gt; 90
&lt;span class="c"&gt;# exit code 1 if fewer than 90% of items survived byte-for-byte&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The numbers from my own system are not flattering to the status quo. Running the same 8KB briefing through two compressors:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;compressor&lt;/th&gt;
&lt;th&gt;verbatim survival&lt;/th&gt;
&lt;th&gt;outcome&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;extractive (built-in)&lt;/td&gt;
&lt;td&gt;~60%&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;2 governing rules silently lost&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;caveman (aggressive)&lt;/td&gt;
&lt;td&gt;100%&lt;/td&gt;
&lt;td&gt;all items survived byte-for-byte&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The judge didn't just measure the damage — it &lt;em&gt;exposed&lt;/em&gt; it. That extractive pass was silently eating rules every single run, and nothing in the pipeline was looking.&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/44334433/memory-anchor
&lt;span class="nb"&gt;cd &lt;/span&gt;memory-anchor &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; pip &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="nb"&gt;.&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; pytest   &lt;span class="c"&gt;# 31 tests&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or script it into your cron/CI without Python:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;cam before my-session &lt;span class="nt"&gt;--rule&lt;/span&gt; &lt;span class="s2"&gt;"R1|never paraphrase governing rules|100"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--todo&lt;/span&gt; &lt;span class="s2"&gt;"ship v0.2|pending|run the drill"&lt;/span&gt;
&lt;span class="c"&gt;# ...compaction happens...&lt;/span&gt;
cam after my-session &lt;span class="nt"&gt;--messages&lt;/span&gt; messages.json &lt;span class="nt"&gt;--budget&lt;/span&gt; 2000
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Honest limitations
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;This is not a semantic memory system. It preserves &lt;em&gt;work state you explicitly declare&lt;/em&gt; — it won't infer what matters on your behalf (yet).&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;judge&lt;/code&gt; uses diff-based matching, not semantics. A truly reworded rule may count as "paraphrased" rather than "lost" — the threshold (45%) is a documented heuristic.&lt;/li&gt;
&lt;li&gt;It's framework-agnostic by design: bring your own summarizer, hook the two calls wherever your pipeline compacts.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;If your agent has ever "forgotten" something after compaction, you already know this pain.&lt;/strong&gt; Anchor the state that must survive — and start measuring what your summarizer is destroying. Star/watch the repo if you want to see the framework adapters (LangChain, Claude Code, OpenHands) land — I'm holding off until real integrations ask for them.&lt;/p&gt;

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