<?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: Adeline</title>
    <description>The latest articles on DEV Community by Adeline (@a_e9d710dc0b575ff2fb87a3a).</description>
    <link>https://dev.to/a_e9d710dc0b575ff2fb87a3a</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%2F3931881%2F7437cd83-6db8-492e-9676-cb4eaf472aa3.png</url>
      <title>DEV Community: Adeline</title>
      <link>https://dev.to/a_e9d710dc0b575ff2fb87a3a</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/a_e9d710dc0b575ff2fb87a3a"/>
    <language>en</language>
    <item>
      <title>Your agent's memory remembers what you chose. Does it remember what you rejected?</title>
      <dc:creator>Adeline</dc:creator>
      <pubDate>Mon, 13 Jul 2026 10:10:35 +0000</pubDate>
      <link>https://dev.to/a_e9d710dc0b575ff2fb87a3a/your-agents-memory-remembers-what-you-chose-does-it-remember-what-you-rejected-2931</link>
      <guid>https://dev.to/a_e9d710dc0b575ff2fb87a3a/your-agents-memory-remembers-what-you-chose-does-it-remember-what-you-rejected-2931</guid>
      <description>&lt;p&gt;Every memory benchmark I've seen asks the same question: &lt;em&gt;did the right item come back?&lt;/em&gt; Recall@k, MRR, hit rate. All measuring whether retrieval surfaces the thing you stored.&lt;/p&gt;

&lt;p&gt;That's not the question that costs teams money.&lt;/p&gt;

&lt;p&gt;The one that costs money is: &lt;strong&gt;you already tried Redis for session caching, it fell over under load, and you ruled it out. Three months later someone asks the agent to "add a caching layer for session data." Does it propose Redis again?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Your memory system stored the &lt;em&gt;choice&lt;/em&gt; — "we use Postgres for X." Did it store the &lt;em&gt;veto&lt;/em&gt; — "we evaluated Redis and rejected it because of Y"? And if it stored it, does that veto survive long enough to actually stop the re-proposal?&lt;/p&gt;

&lt;p&gt;That's what &lt;a href="https://github.com/adelinamart/robrain/tree/main/packages/vetobench" rel="noopener noreferrer"&gt;VetoBench&lt;/a&gt; measures. It's small, fully reproducible, and — this matters — checked in with every retrieved context, agent reply, and verdict committed to the repo. You don't have to take my word for any number below.&lt;/p&gt;

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

&lt;p&gt;24 synthetic engineering decisions. 10 of them carry a structured &lt;code&gt;rejected[]&lt;/code&gt; field with the reason — an incident, a failed spike, a rolled-back migration. Then 10 scenarios, each posing a task that naturally invites one of those rejected approaches:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;direct traps&lt;/strong&gt; — the task asks for the rejected thing outright ("Add Redux Toolkit to manage global state")&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;implicit traps&lt;/strong&gt; — the task merely invites it ("propose a caching layer for session data" → Redis)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The judge is &lt;strong&gt;deterministic — no LLM judge.&lt;/strong&gt; A violation is counted when the rejected option shows up in the agent's &lt;code&gt;key_technologies&lt;/code&gt; (the proposal actually relies on it), or a conservative regex matches the prose &lt;em&gt;and&lt;/em&gt; the agent didn't list it under &lt;code&gt;acknowledged_rejections&lt;/code&gt;. Naming an approach while declining it is a reference, not a proposal. The bias is deliberate: violations are undercounted, never over.&lt;/p&gt;

&lt;h2&gt;
  
  
  The floor: no memory
&lt;/h2&gt;

&lt;p&gt;Same 10 scenarios, agent (&lt;code&gt;claude-haiku-4-5&lt;/code&gt;) sees nothing:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;none&lt;/code&gt;&lt;/strong&gt; — &lt;strong&gt;80–90%&lt;/strong&gt; violation rate across 5 runs&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;With no memory, the agent re-proposed a previously rejected approach in &lt;strong&gt;8 or 9 out of 10 tasks.&lt;/strong&gt; That's the problem worth solving. Everything else is measured against this floor.&lt;/p&gt;

&lt;p&gt;Add the vetoes to context — even as a flat dump, no retrieval — and it drops to &lt;strong&gt;0% across all 50 cells&lt;/strong&gt;, with the agent naming the prior rejection every single time. So &lt;em&gt;storing the veto&lt;/em&gt; is doing the heavy lifting. Which brings us to the interesting part.&lt;/p&gt;

&lt;h2&gt;
  
  
  The head-to-head: RoBrain vs Mem0
&lt;/h2&gt;

&lt;p&gt;Here's where I have to be honest, because the benchmark is.&lt;/p&gt;

&lt;p&gt;I ran &lt;a href="https://github.com/mem0ai/mem0" rel="noopener noreferrer"&gt;Mem0&lt;/a&gt; — the real thing, &lt;code&gt;mem0ai@3.0.13&lt;/code&gt; OSS, its own &lt;code&gt;infer: true&lt;/code&gt; LLM extraction (gpt-4o-mini) and its own semantic search. Mem0 got the &lt;strong&gt;same information as session-transcript prose&lt;/strong&gt;: the decision, the rationale, and every rejected option with its reason. Its pipeline decides what becomes a memory; its search retrieves top-5.&lt;/p&gt;

&lt;p&gt;Mem0's headline number is good, and I'll say so plainly:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;mem0&lt;/code&gt;&lt;/strong&gt; — &lt;strong&gt;0–20%&lt;/strong&gt; violation rate across 5 runs (individual runs: 20, 20, 0, 20, 0)&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Mem0 handles most of this corpus fine. If I stopped at the violation rate, the story would be "roughly a wash." But the archived retrieval contexts tell a subtler story — and it's the one that matters at scale.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;I checked all 50 cells for whether the recorded rejection actually survived into what Mem0 retrieved.&lt;/strong&gt; In &lt;strong&gt;19 of 50 cells (38%), the veto was simply absent&lt;/strong&gt; from the retrieved context — lost during LLM fact-extraction, or not retrieved. For three scenarios it was gone in &lt;em&gt;all five runs&lt;/em&gt;: Express (s01), axios (s04), GraphQL (s10).&lt;/p&gt;

&lt;p&gt;And the violations concentrate exactly there:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;26% violation rate (5/19) when the veto was absent&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;3% violation rate (1/31) when the veto was present&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The cleanest exhibit is s01. Mem0's retrieved memories say &lt;em&gt;"settled on Hono for its middleware model"&lt;/em&gt; — and nothing, anywhere, about Express having been evaluated and declined, or why. Five runs, never once acknowledged. For s04, where the axios veto was likewise lost every run, the agent proposed axios for the billing integration in &lt;strong&gt;3 of 5 runs.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Here's the thing: a veto that doesn't survive ingestion isn't just uncitable. It eventually stops protecting you. Fact-extraction pipelines are built to summarize what was &lt;em&gt;decided&lt;/em&gt; — "team uses Hono." The rejected alternative is exactly the kind of negative-space detail that summarization drops, because it doesn't look like a fact worth keeping. Until the day it is.&lt;/p&gt;

&lt;h2&gt;
  
  
  The fair fight
&lt;/h2&gt;

&lt;p&gt;You might object — and you'd be right — that comparing Mem0's full pipeline against a corpus that arrives with &lt;code&gt;rejected[]&lt;/code&gt; already structured is rigged. Mem0 had to run its own extraction; RoBrain should have to as well.&lt;/p&gt;

&lt;p&gt;So it does. The &lt;code&gt;robrain-e2e&lt;/code&gt; condition pushes the &lt;strong&gt;byte-identical transcripts&lt;/strong&gt; given to Mem0 through RoBrain's real production extractor — the exact prompt Sensing and Perception run in production, same Haiku 4.5 — and whatever &lt;em&gt;that&lt;/em&gt; produces becomes the corpus. Same input, same burden.&lt;/p&gt;

&lt;p&gt;Five archived runs:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Extraction&lt;/strong&gt; — &lt;strong&gt;100/100 vetoes survived&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Retrieval&lt;/strong&gt; — veto present in &lt;strong&gt;50/50&lt;/strong&gt; contexts&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Behavior&lt;/strong&gt; — &lt;strong&gt;0/50 violations&lt;/strong&gt;, 100% acknowledgement&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Side by side, on identical input: Mem0's ingestion lost the veto from 38% of retrieved contexts and violated in 0–20% of tasks per run. RoBrain's full pipeline — extraction included — lost none and violated in none.&lt;/p&gt;

&lt;p&gt;The reason isn't magic retrieval. It's structural: &lt;strong&gt;RoBrain's extraction prompt asks for &lt;code&gt;rejected[]&lt;/code&gt; as a first-class output field.&lt;/strong&gt; Keeping the veto is the extractor's &lt;em&gt;job&lt;/em&gt;, not a lucky side effect of summarizing what happened. When retrieval later surfaces a decision, its rejections come attached — they can't arrive stripped.&lt;/p&gt;

&lt;h2&gt;
  
  
  What this does NOT show (read before you quote it)
&lt;/h2&gt;

&lt;p&gt;The benchmark's own honesty section is longer than its results section, and I'm going to honor that here:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;flatfile&lt;/code&gt; ties &lt;code&gt;robrain&lt;/code&gt; at this corpus size.&lt;/strong&gt; 24 decisions fit in any context window, so dumping everything works as well as retrieving the right five. RoBrain's retrieval advantage is claimed at &lt;em&gt;real&lt;/em&gt; corpus sizes — hundreds of decisions across months — which this fixture set doesn't reach. What this benchmark isolates cleanly is: &lt;strong&gt;vetoes-in-context vs not&lt;/strong&gt;, and whether they &lt;strong&gt;survive ingestion.&lt;/strong&gt; Not retrieval quality at scale.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;n = 10 scenarios. Synthetic fixtures, authored by the RoBrain team.&lt;/strong&gt; Realistic, but chosen by us. The antidote is that they're all checked in — read them, dispute them, add harder ones.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Variance is real.&lt;/strong&gt; Across nine runs the &lt;code&gt;none&lt;/code&gt; floor ranged 70–90%. Always run 3×+ and quote the range with the date and model.&lt;/li&gt;
&lt;li&gt;The Mem0 veto-absence check is a string match, so it can't perfectly separate "lost at extraction" from "not retrieved." Archiving Mem0's full store per run would — PRs welcome.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Try to make it look bad
&lt;/h2&gt;

&lt;p&gt;VetoBench takes third-party adapters. You implement one interface (&lt;code&gt;MemoryAdapter&lt;/code&gt;): an &lt;code&gt;init()&lt;/code&gt; that runs your system's real ingestion over the corpus once, and a &lt;code&gt;buildContext()&lt;/code&gt; that returns what your system would put in front of the agent. The Mem0 adapter in-tree is the reference — copy its shape and its fairness contract.&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;# offline, deterministic, no API key&lt;/span&gt;
pnpm &lt;span class="nt"&gt;--filter&lt;/span&gt; @robrain/vetobench bench

&lt;span class="c"&gt;# behavioral, needs an LLM key&lt;/span&gt;
node dist/run.js &lt;span class="nt"&gt;--live&lt;/span&gt; &lt;span class="nt"&gt;--adapters&lt;/span&gt; none,robrain,mem0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;PRs adding adapters for other memory tools are explicitly welcome — &lt;strong&gt;including ones that make RoBrain look bad.&lt;/strong&gt; That's what the benchmark is for.&lt;/p&gt;




&lt;p&gt;RoBrain is open source: &lt;a href="https://github.com/adelinamart/robrain" rel="noopener noreferrer"&gt;github.com/adelinamart/robrain&lt;/a&gt;. If your agent has ever cheerfully re-proposed the thing your team spent a week ruling out, that's the gap it's built to close.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>memory</category>
      <category>opensource</category>
      <category>benchmark</category>
    </item>
    <item>
      <title>Teaching My AI Agents to Push Back: Why I Built RoBrain</title>
      <dc:creator>Adeline</dc:creator>
      <pubDate>Thu, 14 May 2026 23:04:20 +0000</pubDate>
      <link>https://dev.to/a_e9d710dc0b575ff2fb87a3a/teaching-my-ai-agents-to-push-back-why-i-built-robrain-23e</link>
      <guid>https://dev.to/a_e9d710dc0b575ff2fb87a3a/teaching-my-ai-agents-to-push-back-why-i-built-robrain-23e</guid>
      <description>&lt;p&gt;Claude Code’s auto-memory is a game-changer for solo coding, but it hits a wall the second you add a teammate. Memory is trapped in local files (e.g., ~/.claude/projects/.../memory/), meaning my agent is oblivious to what my teammate's agent has learned. Furthermore, if she switches to Cursor or Copilot, that knowledge silo becomes even deeper.&lt;/p&gt;

&lt;p&gt;To solve this, I built RoBrain—a shared institutional memory for AI teams. It keeps the "passive capture" magic (no manual note-taking required) but moves the storage to a shared Postgres instance accessible via MCP, working seamlessly across Claude Code, Cursor, and Copilot.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Capturing the "Why Not": The rejected[] Field
Most memory systems only record what you did. RoBrain records what you ruled out. Every decision includes a structured rejected[] field:&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;JSON&lt;br&gt;
{&lt;br&gt;
  "decision": "Use Zustand for state management",&lt;br&gt;
  "rejected": [&lt;br&gt;
    { "option": "Redux", "reason": "re-render perf issues in cart" }&lt;br&gt;
  ]&lt;br&gt;
}&lt;br&gt;
Six weeks later, when an agent suggests Redux, RoBrain doesn't just say "we use Zustand"—it pushes back with: "You already considered Redux and ruled it out because of performance issues". Decisions also have a lifecycle; when you switch technologies, the old record is linked and invalidated rather than deleted, preserving the "why" behind your team's evolution.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The "Always-On" Cross-Tool Summary
Shared memory is only useful if it’s available the moment you start typing. At the start of every session, the MCP server automatically fetches and injects a pre-compressed summary of your project’s approved decisions.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Tuesday's Cursor decision is automatically known by Wednesday's Claude Code session.&lt;/p&gt;

&lt;p&gt;No manual copy-pasting or specific "inject" commands are required for the default path.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Background "Synthesis": The System’s Sleep Cycle
While capture is reactive and isolated, RoBrain periodically runs a "synthesis" pass to reconcile the entire corpus. This batch job performs three critical functions that reactive systems miss:&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Contradiction Scanning: It flags sessions that provide conflicting instructions (e.g., "idempotent API calls" vs. "fire-and-forget webhooks").&lt;/p&gt;

&lt;p&gt;Drift Detection: It notices when your team’s stance on architecture is silently shifting across unrelated files.&lt;/p&gt;

&lt;p&gt;Entity Promotion: It identifies recurring proper nouns and elevates them into first-class planning blocks.&lt;/p&gt;

&lt;p&gt;Honest Tradeoffs&lt;br&gt;
Heavier Setup: Requires Docker, Postgres, and two API keys.&lt;/p&gt;

&lt;p&gt;Triage Needed: Passive capture can have false positives; you'll occasionally need to use robrain review.&lt;/p&gt;

&lt;p&gt;Scale Dependent: Synthesis provides the most value once you hit the 100+ decision mark.&lt;/p&gt;

&lt;p&gt;RoBrain is Apache 2.0 and fully self-hostable.&lt;/p&gt;

&lt;p&gt;I’d love your thoughts: Does a background reconciliation pass for agent memory feel like the right approach, or is it overengineered? And what would make you trust an automated rejected[] field in your daily workflow?&lt;/p&gt;

&lt;p&gt;Check it out here: &lt;a href="https://github.com/adelinamart/robrain" rel="noopener noreferrer"&gt;https://github.com/adelinamart/robrain&lt;/a&gt;&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.amazonaws.com%2Fuploads%2Farticles%2Frslr6easjur1nh83qrpc.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.amazonaws.com%2Fuploads%2Farticles%2Frslr6easjur1nh83qrpc.png" alt=" " width="800" height="347"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>opensource</category>
      <category>agents</category>
    </item>
  </channel>
</rss>
