<?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: Nam Bok Rodriguez</title>
    <description>The latest articles on DEV Community by Nam Bok Rodriguez (@nambok).</description>
    <link>https://dev.to/nambok</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%2F4042892%2Fe2b91a52-44ff-45b8-b6e7-2ba1a978b427.jpg</url>
      <title>DEV Community: Nam Bok Rodriguez</title>
      <link>https://dev.to/nambok</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/nambok"/>
    <language>en</language>
    <item>
      <title>Infinite Context Window for AI with Memory</title>
      <dc:creator>Nam Bok Rodriguez</dc:creator>
      <pubDate>Mon, 27 Jul 2026 13:00:00 +0000</pubDate>
      <link>https://dev.to/nambok/infinite-context-window-for-ai-with-memory-4f60</link>
      <guid>https://dev.to/nambok/infinite-context-window-for-ai-with-memory-4f60</guid>
      <description>&lt;p&gt;There is a number hiding in every AI coding setup that nobody looks at. It is the size of the instruction file, the CLAUDE.md or AGENTS.md or .cursorrules that gets pasted into the model's context on every single turn. Some of these files reach seventy kilobytes. That is roughly 17,500 tokens, paid again on every message, forever. And the reality we measured is simple: at that size, the model stops following the file anyway.&lt;/p&gt;

&lt;p&gt;We ran an experiment to find out what actually happens when instruction files grow, and whether a memory database can replace them, using real public files rather than anything we wrote ourselves.&lt;/p&gt;

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

&lt;p&gt;We took four agent instruction files from public repositories, copied verbatim and attributed:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The AGENTS.md from OpenAI's codex repository, about 22 KB&lt;/li&gt;
&lt;li&gt;The AGENTS.md from Kiali, a service mesh console used with Istio, about 70 KB, the biggest file in the test&lt;/li&gt;
&lt;li&gt;The AGENTS.md from Temporal, the workflow engine, about 8 KB&lt;/li&gt;
&lt;li&gt;The AGENTS.md from Freerouting, a PCB routing tool, about 51 KB, held out completely, more on that below&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For each file we picked rules that can be verified with plain string checks, so there is no judge and no interpretation involved. Did the output contain &lt;code&gt;make lint&lt;/code&gt;, did it avoid &lt;code&gt;interface{}&lt;/code&gt;, did the commit message carry a conventional prefix. Anyone can rerun these checks and get the same pass or fail.&lt;/p&gt;

&lt;p&gt;Then a model performed real tasks from each repository's world under three conditions, five trials each:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;The whole file in context.&lt;/strong&gt; The best case for the file, the way most people run agents today.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;MenteDB.&lt;/strong&gt; The file is ingested once into memory. On each task the agent retrieves a few relevant rules, writes a draft, then retrieval runs again against what it wrote and the agent fixes anything it missed. Two passes, a few hundred to two thousand tokens total.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Nothing.&lt;/strong&gt; No instructions at all. This is the control that keeps everyone honest: if the model passes a rule with no instructions, that rule proves nothing about retrieval.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The nothing condition scored between 22 and 40 percent. These rules cannot be guessed. Whatever compliance appears above that line comes from delivery.&lt;/p&gt;

&lt;h2&gt;
  
  
  The results
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;file&lt;/th&gt;
&lt;th&gt;whole file in context&lt;/th&gt;
&lt;th&gt;MenteDB&lt;/th&gt;
&lt;th&gt;nothing&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;OpenAI codex, 22 KB&lt;/td&gt;
&lt;td&gt;100% at ~5,600 tokens per turn&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;100% at ~1,700 tokens&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;27%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Kiali, 70 KB, the biggest&lt;/td&gt;
&lt;td&gt;80% at ~17,500 tokens per turn&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;100% at ~2,200 tokens&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;40%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Temporal, 8 KB&lt;/td&gt;
&lt;td&gt;89% at ~2,100 tokens per turn&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;100% at ~900 tokens&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;22%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Freerouting, 51 KB, held out&lt;/td&gt;
&lt;td&gt;100% at ~12,700 tokens per turn&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;100% at ~2,200 tokens&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;22%&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F9dbojcc1dhwh6fon6jy0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F9dbojcc1dhwh6fon6jy0.png" alt="Every arrow goes from the whole file in context to memory: fewer tokens, equal or better compliance" width="800" height="393"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Read the 70 KB row twice. With the entire file sitting in context, the model followed 80 percent of the file's own rules. It had everything and still lost things. That is the quiet failure of big instruction files: they do not just cost tokens, they stop working. The 39 rules across all four files came through the memory path at 100 percent, at somewhere between 2.4 and 8 times fewer tokens.&lt;/p&gt;

&lt;p&gt;This is what we mean by an infinite context window. It is not a bigger window, it is a window that never fills, because the cost per turn stays flat at a few hundred to two thousand tokens whether your rules weigh 8 KB, 70 KB or a megabyte.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fkf3kd7lvv3d8ifxksn89.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fkf3kd7lvv3d8ifxksn89.png" alt="Cumulative instruction tokens over a fifty turn session, the file against memory" width="800" height="423"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The rule that proves the point
&lt;/h2&gt;

&lt;p&gt;Here is a real trace from the 70 KB file's run. The task was small: add a Refresh button to a React component. The draft came back the way any model writes it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Button&lt;/span&gt; &lt;span class="na"&gt;onClick&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;handleRefresh&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Refresh&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Button&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Kiali has a rule that all user visible strings go through the &lt;code&gt;t&lt;/code&gt; function for translation. Notice that the task never mentions translation, and neither does the draft in any word you could search for. No retrieval on the task description alone can find that rule, and we tried everything, including a reranker. The rule's relevance only exists in the output.&lt;/p&gt;

&lt;p&gt;That is why the memory side runs two passes. After the draft, retrieval runs again against what was actually written. A button with a hardcoded label is exactly the shape the translation rule lives near, the rule comes back, and the revision wraps the label in &lt;code&gt;t()&lt;/code&gt;. The whole exchange costs a couple thousand tokens. The seventy kilobyte file, carried on every turn since the beginning of the session, missed rules like this one anyway.&lt;/p&gt;

&lt;p&gt;The same run caught the reverse failure too. Asked what to run before finishing a Go change, the model with the whole file in context answered with a broken merge of two commands. The memory side delivered the one rule that mattered and the answer was just &lt;code&gt;make lint&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;One row in the table deserves a special mention. The Freerouting file was held out completely: it never touched the system while we built it, its rule list was written before the first run, and it still scored 100 percent on the first try. The tasks are ours since someone has to write them, but the rules and checkers anchor to verbatim text from the files, and everything needed to rerun the benchmark or write your own tasks is public.&lt;/p&gt;

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

&lt;p&gt;The whole benchmark, fixtures, mechanical checkers, parse caches and both runners, lives in the open source &lt;a href="https://github.com/nambok/mentedb/tree/main/benchmarks/agent_file" rel="noopener noreferrer"&gt;MenteDB repository&lt;/a&gt; under &lt;code&gt;benchmarks/agent_file&lt;/code&gt;. Ingesting your own agent file takes one call, and files of any size now parse in the background:&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="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;mentedb&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;MenteDB&lt;/span&gt;

&lt;span class="n"&gt;db&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;MenteDB&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;api_key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&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;report&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ingest_agent_file&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;AGENTS.md&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;read&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;span class="c1"&gt;# 606 memories, 96 action triggers, 0 pinned to every prompt
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Your rules stop being a tax on every turn and start being memories that show up when they matter, including the ones that only matter after the code is written. You can try it in your browser at &lt;a href="https://demo.mentedb.com/agent-files" rel="noopener noreferrer"&gt;demo.mentedb.com/agent-files&lt;/a&gt;: pick a real public agent file or paste your own, give the agent a task, and watch which rules arrive.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>claude</category>
      <category>webdev</category>
      <category>opensource</category>
    </item>
    <item>
      <title>Your agent knows your preferences. It just never uses them</title>
      <dc:creator>Nam Bok Rodriguez</dc:creator>
      <pubDate>Fri, 24 Jul 2026 20:15:19 +0000</pubDate>
      <link>https://dev.to/nambok/your-agent-knows-your-preferences-it-just-never-uses-them-3ho5</link>
      <guid>https://dev.to/nambok/your-agent-knows-your-preferences-it-just-never-uses-them-3ho5</guid>
      <description>&lt;p&gt;There is a way for agent memory to fail that is worse than forgetting, and it took me a while to even recognize it as a failure. The preference is sitting right there in the store, and if I ask the agent what my commit style is, it answers correctly: single line, conventional prefix, no emojis. But the moment it actually fixes a bug and commits, the message comes out four lines long with an emoji in the subject, because knowing a rule and using it at the right moment turn out to be completely different problems.&lt;/p&gt;

&lt;p&gt;Nothing here is technically broken, which is exactly why it hides so well. Memory lookups are driven by the conversation: embed what the user said, find similar memories. A rule about commit style shares no words and no meaning with the sentence fix the login bug, so the one moment the rule matters, right before the commit runs, is exactly the moment similarity search cannot find it.&lt;/p&gt;

&lt;p&gt;There are two obvious ways out, and both are bad. You can pin the rule so it gets injected into every single turn, which works until you have thirty rules and every prompt drags all of them along, mostly irrelevant. Token bloat is the number one reason people rip memory systems out. Or you can put the rules in a static config file, which works until it does not: nobody updates it, it does not travel across machines, and when you change your mind the old rule just sits there.&lt;/p&gt;

&lt;p&gt;The thing I eventually understood is that these preferences are not facts about topics at all. They are rules about actions. And rules about actions should be retrieved by the action, not by the conversation. You remember how your team writes commit messages when you are writing one, not when someone mentions login bugs. So the fix is a third way to look things up, next to the two everyone has: recall by topic for facts, a tiny set of rules that ride along on every turn, and now rules that fire on the action itself.&lt;/p&gt;

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

&lt;p&gt;A rule gets a tag naming the action it governs: &lt;code&gt;trigger:git-commit&lt;/code&gt;, &lt;code&gt;trigger:pr-create&lt;/code&gt;. That is everything you do to store one. On the read side there is one call, &lt;code&gt;recall_for_action&lt;/code&gt;. It looks the tag up in the index, checks who can see it the same way every other lookup does, drops anything superseded, and returns the rules newest first:&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="c1"&gt;# a preference about HOW to commit, tagged with the action it governs
&lt;/span&gt;&lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;store&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;commit messages: single line, conventional prefix, no emojis&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;memory_type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;procedural&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;tags&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;trigger:git-commit&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="c1"&gt;# right before the agent runs a commit, its hook asks:
&lt;/span&gt;&lt;span class="n"&gt;rules&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;recall_for_action&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;git-commit&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;6&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;r&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;rules&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;content&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;   &lt;span class="c1"&gt;# injected into context at the moment of the commit
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The retrieval is deterministic: no embedding of the query, no similarity threshold to tune, no model call, just the action name as the key. That matters because this lookup runs at the worst possible moment to be slow or flaky, directly in front of the user's command.&lt;/p&gt;

&lt;h2&gt;
  
  
  The hook that asks at the right moment
&lt;/h2&gt;

&lt;p&gt;The missing half is knowing when to ask, and the agent already knows: it is about to run the command. For Claude Code, setup installs a hook that looks at each command right before it runs, and when it is a commit or a PR, fetches the matching rules and drops them into context in that exact moment:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx mentedb-mcp@latest setup claude-code
&lt;span class="c"&gt;# installs a PreToolUse hook matched to Bash. Before a git commit or&lt;/span&gt;
&lt;span class="c"&gt;# gh pr create, it fetches your trigger:git-commit / trigger:pr-create&lt;/span&gt;
&lt;span class="c"&gt;# rules and injects them as context. Anything else: silence.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Most of the engineering here is in what the hook must never do. It never blocks or approves anything, it only adds context. It has a hard time budget, and on any failure, memory down, old server, timeout, it prints nothing and the commit runs untouched. A memory system that can break your git workflow gets uninstalled the same day, so the failure mode is always silence.&lt;/p&gt;

&lt;p&gt;The parsing turned out to be where the real bugs hide. A rule firing on the wrong command erodes trust the same way a wrong memory does, so the matcher parses the command instead of grepping it: &lt;code&gt;git -c commit.gpgsign=false commit&lt;/code&gt; fires, because the subcommand is commit. &lt;code&gt;git config commit.gpgsign false&lt;/code&gt; does not, because the subcommand is config, even though the word commit appears twice. &lt;code&gt;echo "git commit"&lt;/code&gt; does not, because it is quoted text. &lt;code&gt;cd repo &amp;amp;&amp;amp; git commit&lt;/code&gt; fires, because each segment of a compound command is checked on its own, and every one of those shapes has its own test in the suite.&lt;/p&gt;

&lt;h2&gt;
  
  
  Corrections work the way you would hope
&lt;/h2&gt;

&lt;p&gt;These rules are ordinary memories, so everything from &lt;a href="https://mentedb.com/blog/why-your-agent-keeps-repeating-facts-you-already-corrected" rel="noopener noreferrer"&gt;the last post&lt;/a&gt; about corrections applies to them too. Tell the agent you switched from squash merges to rebase, and the old rule is superseded: it stops showing up at commit time the moment you say so, and the history is still there if you ever ask what the old rule was. Rules also come back newest first, so if two versions of a rule are still around, the later one leads.&lt;/p&gt;

&lt;p&gt;That is the part I care about most: the rule surfaces at the moment it applies, and the version that surfaces is the one you meant.&lt;/p&gt;

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

&lt;p&gt;The engine call is &lt;code&gt;recall_for_action&lt;/code&gt; in &lt;a href="https://github.com/nambok/mentedb" rel="noopener noreferrer"&gt;mentedb&lt;/a&gt; 0.27.2, the hosted API exposes it as the &lt;code&gt;get_action_rules&lt;/code&gt; tool, and &lt;code&gt;npx mentedb-mcp@latest setup&lt;/code&gt; installs the hook. Tag a commit rule, ask for a commit, and watch it show up at exactly the right moment. The live demo at &lt;a href="https://demo.mentedb.com" rel="noopener noreferrer"&gt;demo.mentedb.com&lt;/a&gt; has the rest of the memory graph to explore.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>opensource</category>
      <category>webdev</category>
      <category>claude</category>
    </item>
    <item>
      <title>Why your agent keeps repeating facts you already corrected</title>
      <dc:creator>Nam Bok Rodriguez</dc:creator>
      <pubDate>Thu, 23 Jul 2026 13:00:00 +0000</pubDate>
      <link>https://dev.to/nambok/why-your-agent-keeps-repeating-facts-you-already-corrected-3abo</link>
      <guid>https://dev.to/nambok/why-your-agent-keeps-repeating-facts-you-already-corrected-3abo</guid>
      <description>&lt;p&gt;Every agent I build eventually does the same thing. It repeats a fact I already corrected, stated with full confidence, as if the correction never happened. I tell it my coffee order changed from a black coffee to a latte, and a few turns later it hands me the black coffee. The memory didn't exactly fail. It retrieved something, it retrieved the version I had already replaced, because a raw vector store can tell you two facts are similar and has no idea that one of them replaced the other.&lt;/p&gt;

&lt;p&gt;You can fix that, and the usual way is to put a language model in front of the store: on each new message it reads the text, compares it to what is saved, and decides whether to add, update, or delete. Corrections collapse into the current fact. But now it also means a model call and a network round trip on every single write, usually across a few services you now run. It works, it just costs you a model call every time you remember something.&lt;/p&gt;

&lt;p&gt;That is the one of the parts I wanted to change. Not the retrieval, the deciding. Whether a new fact is a duplicate, a correction, a conflict, or something genuinely new is the real job of a memory, and I did not want that job living in code on top of a store, or using a model I have to call on every write. A model call per write is slow, it costs money, it pulls in more services to run, and it can answer a little differently on a bad day.&lt;/p&gt;

&lt;p&gt;And most of these calls are not that subtle once you look at the text. A correction usually keeps the whole sentence and just swaps the value. That is a rule you can write down, not a judgment you need a model for. So I wrote &lt;a href="https://mentedb.com" rel="noopener noreferrer"&gt;MenteDB&lt;/a&gt;, a single embeddable engine in Rust, and I put the deciding inside it. When the latte arrives, it sees the same fact with a changed value and supersedes the black coffee. Same answer every time, no model asked.&lt;/p&gt;

&lt;h2&gt;
  
  
  What supersession does under the hood
&lt;/h2&gt;

&lt;p&gt;The old fact isn't deleted. It gets a &lt;code&gt;Supersedes&lt;/code&gt; edge in the graph, and recall stops returning it because superseded memories are excluded by belief propagation, so the history stays queryable while your prompt only sees the current value.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;process_turn&lt;/code&gt; wraps this in one call: embed the message, run hybrid recall, store the turn, reconcile against what is already there, and return context for the next prompt. Here it is end to end using the API:&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="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;

&lt;span class="n"&gt;MENTEDB&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://api.mentedb.com&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="n"&gt;H&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;Authorization&lt;/span&gt;&lt;span class="sh"&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;Bearer &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;environ&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;MENTEDB_API_KEY&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&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;_n&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;turn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;assistant&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;""&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;global&lt;/span&gt; &lt;span class="n"&gt;_n&lt;/span&gt;
    &lt;span class="n"&gt;_n&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;post&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="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;MENTEDB&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;/v1/process_turn&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;H&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;json&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;user_message&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;assistant_response&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;assistant&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;turn_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;_n&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;agent_id&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;demo-user&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="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="nf"&gt;turn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;My coffee order is a black coffee&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;turn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Actually I switched to lattes&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;turn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;What&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;s my coffee order?&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;m&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;context&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;content&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Supersession is the sharpest example because it is obvious when it goes wrong, but it is one of many. Deciding that a memory has gone stale and should fade, that two are near duplicates and should merge, that one user's memories must never surface for another, that this handful is what is actually relevant to the current turn: those are the same kind of decision, made continuously, about what the agent should see right now. A raw vector store leaves all of that to your application code. The model on every write approach pays a model for it. I wanted it to be what the database does, so decay, deduplication, owner isolation, and relevance ordered recall are engine operations, not things you deal with.&lt;/p&gt;

&lt;h2&gt;
  
  
  One engine, not a stack of services
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;process_turn&lt;/code&gt; handles recall for you. It blends vector similarity with keyword search, so a query catches both the meaning and the exact words, and it puts the most relevant memories at the start and end of the context window, where the model pays the most attention. It only sends what changed since the last turn instead of replaying everything every message.&lt;/p&gt;

&lt;p&gt;All of that is one Rust crate. Its own page based storage and WAL, its own HNSW index, its own graph. No external vector database to run alongside it, no separate graph store, no Postgres to manage. That is the part I actually care about, memory as a single dependency you embed, not a distributed system you operate.&lt;/p&gt;

&lt;h2&gt;
  
  
  Run it three ways, same engine
&lt;/h2&gt;

&lt;p&gt;Hosted, if you just want a key:&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="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;MENTEDB_API_KEY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;mdb_your_key   &lt;span class="c"&gt;# from app.mentedb.com&lt;/span&gt;
&lt;span class="c"&gt;# then POST to https://api.mentedb.com/v1/process_turn (above)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Self host, one container, local embeddings bundled, no keys, nothing leaves the box:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker run &lt;span class="nt"&gt;-p&lt;/span&gt; 6677:6677 &lt;span class="nt"&gt;-v&lt;/span&gt; mentedb-data:/data &lt;span class="se"&gt;\&lt;/span&gt;
  ghcr.io/nambok/mentedb:latest
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Embed the engine directly (Python over the Rust core):&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="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;mentedb&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;MenteDB&lt;/span&gt;

&lt;span class="n"&gt;db&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;MenteDB&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;./data&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;embedding_provider&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;candle&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;   &lt;span class="c1"&gt;# local, no key
&lt;/span&gt;&lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;store&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;The user prefers dark mode&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;store&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;The user&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;s editor is Neovim&lt;/span&gt;&lt;span class="sh"&gt;"&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="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;process_turn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;what are their UI preferences?&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;turn_id&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="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;content&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Same engine underneath all three. The hosted product is that engine on managed infra.&lt;/p&gt;

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

&lt;p&gt;I created a demo here: &lt;a href="https://demo.mentedb.com" rel="noopener noreferrer"&gt;demo.mentedb.com&lt;/a&gt;. Add facts, ask questions, and explore the memory graph they build.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>rust</category>
      <category>webdev</category>
      <category>opensource</category>
    </item>
  </channel>
</rss>
