<?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: Edward Izgorodin</title>
    <description>The latest articles on DEV Community by Edward Izgorodin (@izgorodin).</description>
    <link>https://dev.to/izgorodin</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%2F3989589%2F15cb8fb8-9785-496a-be83-65c3061529d2.jpeg</url>
      <title>DEV Community: Edward Izgorodin</title>
      <link>https://dev.to/izgorodin</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/izgorodin"/>
    <language>en</language>
    <item>
      <title>Your Agent Remembered the Fact. It Answered Like a Stranger.</title>
      <dc:creator>Edward Izgorodin</dc:creator>
      <pubDate>Tue, 08 Sep 2026 12:11:00 +0000</pubDate>
      <link>https://dev.to/izgorodin/recall-is-the-easy-half-of-agent-memory-the-hard-half-is-using-a-fact-nobody-asked-about-37e8</link>
      <guid>https://dev.to/izgorodin/recall-is-the-easy-half-of-agent-memory-the-hard-half-is-using-a-fact-nobody-asked-about-37e8</guid>
      <description>&lt;p&gt;A memory system can return the exact fact a request depends on whenever that fact is named, and still let the request be answered the way a stranger with no memory would have answered it.&lt;/p&gt;

&lt;p&gt;The numbers below are from InMind, &lt;a href="https://arxiv.org/abs/2607.24368" rel="noopener noreferrer"&gt;arXiv 2607.24368v1&lt;/a&gt;, 27 July 2026, CC BY 4.0, by Ruizhe Li, Mingxuan Du, Benfeng Xu and Zhendong Mao, read from the &lt;a href="https://arxiv.org/html/2607.24368v1" rel="noopener noreferrer"&gt;HTML text&lt;/a&gt; on 7 September 2026. I have not run the benchmark.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Condition, same 125 tasks&lt;/th&gt;
&lt;th&gt;Result (%)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Direct question naming the fact, six memory systems&lt;/td&gt;
&lt;td&gt;76.0 to 100.0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Indirect request, fact present in the answerer context, six memory systems&lt;/td&gt;
&lt;td&gt;0.8 to 12.0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Indirect request scored end to end, six memory systems&lt;/td&gt;
&lt;td&gt;at most 14.4&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Indirect request scored end to end, best of three Naive RAG controls&lt;/td&gt;
&lt;td&gt;16.0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Indirect request, fact placed in context by hand&lt;/td&gt;
&lt;td&gt;84.0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Indirect request, the always-in-state probe&lt;/td&gt;
&lt;td&gt;68.8&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The numbers are theirs and the grouping is mine: rows one to three are ranges across the twelve memory-system configurations of their Table 1, row four is a single control from the same table, and rows five and six are single rows. The authors call the last row a diagnostic, not a controlled ablation.&lt;/p&gt;

&lt;h2&gt;
  
  
  Two abilities travel under one word
&lt;/h2&gt;

&lt;p&gt;Sylwia Laskowska published a glossary of agent terms on 3 September 2026 (&lt;a href="https://dev.to/sylwia-lask/20-agentic-ai-terms-every-developer-should-know-explained-simply-jii"&gt;the post&lt;/a&gt;). Her definition names the hard half, which is not having to explain the same thing for the tenth time. Her example shows the easy half, with a founder whose other company builds rockets: three weeks after saying he wants to buy an AI coding company, he asks what it was, and the agent tells him.&lt;/p&gt;

&lt;p&gt;That question named the thing to look for. Change the request and keep the store identical: put together an offer for that coding company, with whatever budget the rocket program leaves. Nothing there points back at the earlier note, and that note is the price.&lt;/p&gt;

&lt;p&gt;I left the distinction in her comments (&lt;a href="https://dev.to/izgorodin/comment/3e881"&gt;comment 3e881&lt;/a&gt;). The test fits in a line: ask the agent for something that depends on what it knows without naming it, then compare with what a stranger would have written. If they match, the store is full and the memory is not working.&lt;/p&gt;

&lt;h2&gt;
  
  
  The gap is access, not ability
&lt;/h2&gt;

&lt;p&gt;The table rules out two comfortable explanations. The tasks do not outrun the model. With the fact placed in context by hand, the same model answers 84.0 percent of the indirect requests, and the authors put it in one sentence: "What separates 84.0% from 16.0% is access, not ability." Nor is the fact lost: a direct question returns it at up to 100.0 percent after 38 sessions of intervening traffic.&lt;/p&gt;

&lt;p&gt;Resolution does not settle it either: an embedding with eight times the dimensionality raises the measured presence of the fact for all six systems, and no query-time configuration goes above 16.0 percent end to end. What is left is selection, and the authors call that open problem routing: deciding which facts stay visible before anyone asks.&lt;/p&gt;

&lt;p&gt;Their own diagnostic for it is the last row: one markdown file capped at 200 lines, placed in the prompt before the query arrives. They offer it as a measurement, not an architecture, since a file that size fills up and facts start pushing each other out as the store grows.&lt;/p&gt;

&lt;h2&gt;
  
  
  A fourth condition for the test battery
&lt;/h2&gt;

&lt;p&gt;Sergei Parfenov proposed a battery for the same failure (&lt;a href="https://dev.to/p0rt/can-your-ai-use-what-it-remembers-57c"&gt;his post&lt;/a&gt;): independent copies of the same starting state, one getting the direct question, one the task alone, one the task with the constraint written in, plus requests where the constraint should not apply. The one run he reports is narrower and he says so: a local BM25 probe over 12 fixtures, 12 of 12 on direct questions and 4 of 12 on indirect tasks, with no model in the loop.&lt;/p&gt;

&lt;p&gt;He names the same hazard and handles it his way, by recording the context the model actually received. I would add a fourth copy: the same state with the decisive fact replaced by a decoy of the same shape and length, or removed outright. What you report is then a difference, with the fact minus without the fact, and it needs no view into the retrieved context.&lt;/p&gt;

&lt;p&gt;He argues that from the answer-only scores in the same paper, and those scores show why a level misleads. Scored on the answer alone, without requiring that the fact reached the model, the retrieval configurations land between 18.4 and 29.6 percent in their Table 4, against 3.2 to 16.0 percent scored end to end in Table 1. In one audited case the answer carried the relevant allergen warning, a generic caution rather than a personalized one, while the retrieved context held no mention of the allergy: it came from general knowledge about macarons. Without a copy to subtract, that credit lands on a memory that delivered nothing.&lt;/p&gt;

&lt;h2&gt;
  
  
  What this does not prove
&lt;/h2&gt;

&lt;p&gt;InMind is 125 constructed tasks, 113 of them grounded in citable public sources, and pairs where an ordinary retrieval cue would have given the answer away were filtered out on purpose. It stresses one failure mode rather than sampling ordinary traffic.&lt;/p&gt;

&lt;p&gt;GPT-5-mini both answers and judges. The authors call an independent judge model their most significant methodological gap, and their audit of 100 records puts the context-aware application judge at 85.0 percent accuracy, all 15 errors false positives. Their scoring pays for applying the fact and charges nothing for over-eagerness, which is the failure the negative controls in the battery above are aimed at.&lt;/p&gt;

&lt;p&gt;None of this measures a particular deployed assistant, including any system I work on, and the argument gives no exemption to whoever makes it: a store that fires only when the query names the fact fails regardless of who ships it. The fourth condition is a proposal for which I have published no run.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Disclosure: I work on &lt;a href="https://mnemoverse.com" rel="noopener noreferrer"&gt;Mnemoverse&lt;/a&gt;, a memory engine for AI agents connected over MCP, so weigh the argument accordingly.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>agents</category>
      <category>llm</category>
      <category>machinelearning</category>
    </item>
    <item>
      <title>Hypergraph or Hyperbolic Graph? They Are Two Different Axes, and Only One of Them Ships</title>
      <dc:creator>Edward Izgorodin</dc:creator>
      <pubDate>Mon, 07 Sep 2026 11:39:00 +0000</pubDate>
      <link>https://dev.to/izgorodin/hypergraph-or-hyperbolic-graph-they-are-two-different-axes-and-only-one-of-them-ships-bi7</link>
      <guid>https://dev.to/izgorodin/hypergraph-or-hyperbolic-graph-they-are-two-different-axes-and-only-one-of-them-ships-bi7</guid>
      <description>&lt;p&gt;These two get used interchangeably in agent-memory discussions, and they are not the same idea. They are not even the same kind of idea.&lt;/p&gt;

&lt;p&gt;An ordinary graph makes two commitments at once. Every &lt;strong&gt;edge&lt;/strong&gt; joins exactly two vertices, and the whole thing lives in ordinary Euclidean &lt;strong&gt;space&lt;/strong&gt;. Loosen either commitment and you get a different structure. Loosen the other and you get another one. They are orthogonal, so there are four boxes, not two.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Structure&lt;/th&gt;
&lt;th&gt;An edge joins&lt;/th&gt;
&lt;th&gt;Lives in&lt;/th&gt;
&lt;th&gt;What it buys&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Plain graph&lt;/td&gt;
&lt;td&gt;2 vertices&lt;/td&gt;
&lt;td&gt;Euclidean&lt;/td&gt;
&lt;td&gt;general pairwise links&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Hypergraph&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;many vertices&lt;/td&gt;
&lt;td&gt;Euclidean&lt;/td&gt;
&lt;td&gt;n-ary facts as one relation&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Hyperbolic graph&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;2 vertices&lt;/td&gt;
&lt;td&gt;hyperbolic&lt;/td&gt;
&lt;td&gt;hierarchy with low distortion&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Hyperbolic hypergraph&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;many vertices&lt;/td&gt;
&lt;td&gt;hyperbolic&lt;/td&gt;
&lt;td&gt;both at once&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Two different pressures push you to two different rows, and knowing which pressure you are under is most of the decision.&lt;/p&gt;

&lt;h2&gt;
  
  
  Hierarchy pressure pushes you to change the space
&lt;/h2&gt;

&lt;p&gt;Euclidean space embeds deep hierarchies badly, and the reason is dimensional rather than incidental. A tree's node count explodes exponentially with depth while flat volume grows only polynomially, so nodes pile up on each other and the distances start lying to you.&lt;/p&gt;

&lt;p&gt;Hyperbolic space fixes that by construction: volume grows exponentially with radius, which is the shape a tree already has.&lt;/p&gt;

&lt;p&gt;This part is settled prior art and none of it is new. A weighted tree embeds in the hyperbolic plane with arbitrarily small distortion (Sarkar, 2011), that embedding reaches near-perfect precision in as few as two dimensions (Sala et al., 2018), and learned Poincaré embeddings beat Euclidean ones on hierarchical data (Nickel and Kiela, 2017). Hyperbolic graph convolutions cut link-prediction error by up to &lt;strong&gt;63.1 percent in ROC AUC&lt;/strong&gt; against Euclidean GCN baselines (Chami et al., 2019, &lt;a href="https://arxiv.org/abs/1910.12933" rel="noopener noreferrer"&gt;arXiv:1910.12933&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;A hyperbolic graph puts that to work while leaving edges alone: still two vertices per edge, laid out in the Poincaré ball instead of flat space.&lt;/p&gt;

&lt;p&gt;So the first cue is short. &lt;strong&gt;If the dominant relation in your memory is "X is part of, or a kind of, Y", you want the hyperbolic axis, and you change the space rather than the edge.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The wall in front of that axis is not mathematical
&lt;/h2&gt;

&lt;p&gt;Here is the part that does not show up in the papers, and it is the reason this axis is mostly theoretical in production today.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Every mainstream production text-embedding model emits Euclidean vectors compared by cosine similarity.&lt;/strong&gt; OpenAI &lt;code&gt;text-embedding-3&lt;/code&gt;, Cohere Embed, Voyage, Gemini Embedding, the open sentence-transformer family. I could not find a widely available model that natively outputs Poincaré-ball vectors.&lt;/p&gt;

&lt;p&gt;Native hyperbolic NLP exists and is moving, but it is research-stage: Poincaré GloVe, hyperbolic fine-tuning (&lt;a href="https://arxiv.org/abs/2410.04010" rel="noopener noreferrer"&gt;HypLoRA&lt;/a&gt;), and the first billion-parameter fully-hyperbolic language models (&lt;a href="https://arxiv.org/abs/2505.24722" rel="noopener noreferrer"&gt;HELM, NeurIPS 2025&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;And the geometry does not bolt on afterwards. The obvious workaround is to read a Euclidean vector as a tangent vector at the origin and apply the exponential map into the ball. The HypLoRA analysis shows what that actually does: it chains maps that cancel, and the composition reduces to an approximately Euclidean transformation. An encoder trained in Euclidean space never learned hyperbolic structure, and projecting its output does not teach it any.&lt;/p&gt;

&lt;p&gt;That is a real constraint, not a preference. Anyone claiming hyperbolic memory on top of a standard embedding model is claiming a geometry their encoder does not have.&lt;/p&gt;

&lt;h2&gt;
  
  
  N-ary pressure pushes you to change the edge
&lt;/h2&gt;

&lt;p&gt;The other axis leaves space flat and changes what an edge &lt;em&gt;is&lt;/em&gt;. A &lt;strong&gt;hyperedge&lt;/strong&gt; is a set: one relation joining many vertices at once.&lt;/p&gt;

&lt;p&gt;As the HyperGraphRAG authors put it, "each edge in an ordinary graph connects only two entities, limiting their ability to represent the n-ary relations" (Luo et al., NeurIPS 2025, &lt;a href="https://arxiv.org/abs/2503.21322" rel="noopener noreferrer"&gt;arXiv:2503.21322&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;For agent memory this is the who-did-what-with-what-and-got-what problem. "Agent A used tool T on resource R in session X and got outcome O" is one fact about five entities, and a pairwise graph has two ways to stand in for it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Clique expansion&lt;/strong&gt; wires all five participants to each other. It is lossy in a specific and nasty way: a five-clique is indistinguishable from five unrelated pairs, so membership in the relation is simply gone.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Star expansion&lt;/strong&gt; adds one node standing in for the relation and links every participant to it. This one is &lt;strong&gt;lossless for membership&lt;/strong&gt;, because the encoding is a bijection and you can always recover which entities belong to which relation.&lt;/p&gt;

&lt;p&gt;So the second cue: &lt;strong&gt;if your facts routinely bind three or more entities into one irreducible relation, you are feeling n-ary pressure, and you change the edge rather than the space.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The bridge most people miss
&lt;/h2&gt;

&lt;p&gt;You do not need a hypergraph to &lt;em&gt;store&lt;/em&gt; an n-ary fact on a pairwise graph.&lt;/p&gt;

&lt;p&gt;Star expansion has been reinvented under several names because it keeps being the right answer: it is the incidence or Levi graph in graph theory, the &lt;a href="https://www.w3.org/TR/swbp-n-aryRelations/" rel="noopener noreferrer"&gt;W3C n-ary relation node&lt;/a&gt;, RDF reification, and the event node of formal semantics.&lt;/p&gt;

&lt;p&gt;The price is concrete and small. One extra node per relation. One hop of indirection, so participants sit at distance two rather than adjacent. And a plain graph model will not exploit hyperedge-level structure the way a purpose-built hypergraph network would.&lt;/p&gt;

&lt;p&gt;Which means n-ary is not a capability wall for a pairwise engine. It is a modelling choice with a known, cheap, lossless bridge if the workload ever demands it. The same cannot be said for the hyperbolic axis, where the bridge provably collapses.&lt;/p&gt;

&lt;p&gt;That asymmetry is the practical takeaway. One of these axes you can defer and cross later. The other one you cannot fake.&lt;/p&gt;

&lt;h2&gt;
  
  
  Both at once
&lt;/h2&gt;

&lt;p&gt;Because the axes are orthogonal, you can loosen both. A hyperbolic hypergraph has many-vertex hyperedges &lt;em&gt;and&lt;/em&gt; curved space, which is the natural home for knowledge that is n-ary and hierarchical at the same time: a five-way event that also sits at a particular depth in a taxonomy.&lt;/p&gt;

&lt;p&gt;It is an active research line rather than a shipping option. Hyperbolic hypergraph networks operate in hyperbolic space "to capture the tree-like hierarchy" while keeping the hyperedge's n-ary structure (Li et al., 2024, &lt;a href="https://arxiv.org/abs/2412.12158" rel="noopener noreferrer"&gt;arXiv:2412.12158&lt;/a&gt;).&lt;/p&gt;

&lt;h2&gt;
  
  
  The two questions
&lt;/h2&gt;

&lt;p&gt;Before reaching for either word:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Is my dominant relation hierarchical?&lt;/strong&gt; Then the pressure is on the space, and the honest state of the art is that native hyperbolic embeddings are not yet available off the shelf.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Do my facts bind three or more entities irreducibly?&lt;/strong&gt; Then the pressure is on the edge, and star expansion stores them losslessly on a pairwise graph today.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Answering "both" is legitimate, and it puts you in a research area rather than a product decision. Answering neither means a plain graph is doing its job and the vocabulary is not your problem.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Disclosure: I work on &lt;a href="https://mnemoverse.com" rel="noopener noreferrer"&gt;Mnemoverse&lt;/a&gt;, a memory engine for AI agents. Every figure above is from a linked paper by other people, and the 63.1 percent is Chami et al. on their own benchmarks, not a measurement of any product. The longer version is on the &lt;a href="https://mnemoverse.com/docs/library/hypergraph-vs-hyperbolic-graph" rel="noopener noreferrer"&gt;original page&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>architecture</category>
      <category>machinelearning</category>
      <category>graphs</category>
    </item>
    <item>
      <title>Interpretability Built an Instrument to Prove a Signal Is Actually Used. Agent Memory Has Nothing Like It.</title>
      <dc:creator>Edward Izgorodin</dc:creator>
      <pubDate>Sat, 05 Sep 2026 11:15:00 +0000</pubDate>
      <link>https://dev.to/izgorodin/interpretability-built-an-instrument-to-prove-a-signal-is-actually-used-agent-memory-has-nothing-2mnf</link>
      <guid>https://dev.to/izgorodin/interpretability-built-an-instrument-to-prove-a-signal-is-actually-used-agent-memory-has-nothing-2mnf</guid>
      <description>&lt;p&gt;A model can contain a decodable signal and not use it to produce its answer.&lt;/p&gt;

&lt;p&gt;That sentence is the whole problem with interpretability, and it took me an embarrassingly long time to feel its weight. A linear probe recovers a concept from an activation. A sparse autoencoder isolates a direction that correlates with it. Neither shows that the direction did any work. The information is present. Whether it is load-bearing is a different question, and the two get conflated constantly.&lt;/p&gt;

&lt;p&gt;Anthropic's Global Workspace paper is built around an instrument designed to separate them, and the instrument is more interesting to me than the findings. It is called the Jacobian lens.&lt;/p&gt;

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

&lt;p&gt;The logit lens decodes a hidden state by pushing it through the model's unembedding matrix. Cheap, unsupervised, and brittle. In the workspace paper's framing, that amounts to setting the Jacobian to the identity: you assume the path from this layer to the output is a straight line, when it is not.&lt;/p&gt;

&lt;p&gt;The tuned lens improves on that by training a small affine probe per block to match the output distribution. More reliable, and still correlational: it tells you what a layer's state resembles, not what the model does with it.&lt;/p&gt;

&lt;p&gt;The Jacobian lens replaces the identity with the model's own averaged Jacobian from each layer to the final layer, computed over many prompts. That change is what makes its directions testable rather than merely readable.&lt;/p&gt;

&lt;h2&gt;
  
  
  Four operations, and only one of them matters for trust
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;READ&lt;/strong&gt; projects a hidden state through the Jacobian, normalizes, and unembeds it into a vocabulary distribution.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;WRITE&lt;/strong&gt; adds a scaled lens vector into the residual stream.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;PATCH&lt;/strong&gt; swaps the coordinates of two lens vectors inside the activation.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;ABLATE&lt;/strong&gt; zeroes the projection of the residual stream onto the most active lens vectors across a chosen band of layers.&lt;/p&gt;

&lt;p&gt;READ is the one that looks like the other lenses. The other three are the point. An interpretability claim earns trust when someone &lt;strong&gt;edits the internal quantity and observes the predicted behavior change, selectively&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The selectivity is not decoration. Swapping the internal pattern for "spider" to "ant" changes the model's arithmetic answer from eight to six. Swapping Soccer to Rugby flips the verbal report. A rhyming-couplet plan swap from Fight to Light shifts words that appear &lt;em&gt;earlier&lt;/em&gt; in the line. In each case adjacent capabilities stay intact, which is what separates a real intervention from breaking the model and calling the damage a finding.&lt;/p&gt;

&lt;h2&gt;
  
  
  Two numbers that travel badly
&lt;/h2&gt;

&lt;p&gt;This is where I want to slow down, because both of these get repeated without their scope, and I have seen both quoted flat.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The hundredfold connectivity.&lt;/strong&gt; The sentence people cite is real: J-space patterns are read from and written to far more than ordinary patterns, "in some parts of the network by a factor of about a hundred." That phrasing is from Anthropic's plain-language research page. The technical paper reports the same property &lt;strong&gt;qualitatively&lt;/strong&gt;, saying these vectors compose with downstream weights more broadly than other representational vectors. If you are citing the number, cite the overview, and keep "in some parts of the network" attached to it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The ablation collapse.&lt;/strong&gt; Remove J-space and multi-step reasoning drops to near zero. That is the headline, and it is accurate for that task. What travels less well is the other half of the same result: without its J-space the model still "speaks fluently, classifies sentiment, answers multiple-choice questions, and pulls facts out of passages roughly as before."&lt;/p&gt;

&lt;p&gt;So the collapse is selective, not general. And there is a further wrinkle worth keeping: on grade-school math, chain-of-thought solving is substantially more robust to ablation than answering the same problems directly. The model externalizes its reasoning onto the page, and what is on the page does not need the workspace.&lt;/p&gt;

&lt;p&gt;That last detail is the most interesting sentence in the whole area, and it almost never gets quoted.&lt;/p&gt;

&lt;h2&gt;
  
  
  The authors' limits, in their words
&lt;/h2&gt;

&lt;p&gt;The paper is unusually forthright, and the limits are sharper than most summaries admit.&lt;/p&gt;

&lt;p&gt;The lens only identifies vectors for concepts that are &lt;strong&gt;single tokens&lt;/strong&gt; in the vocabulary. "San Francisco" and "machine learning" have no single unembedding direction. The limit is structural: the vocabulary indexes the lens.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Small integers fail to swap reliably, and the cause is unresolved.&lt;/strong&gt; The paper leaves both hypotheses open: the model may compute over small integers outside the workspace, or its working representation of them may simply not align with the lens vectors. The evidence does not choose.&lt;/p&gt;

&lt;p&gt;In roughly the &lt;strong&gt;first third of the model&lt;/strong&gt;, readouts are noisy and largely uninterpretable. Whether that silence is genuine absence or lens degeneracy is explicitly left open.&lt;/p&gt;

&lt;p&gt;And the summary judgment is theirs, not mine: the Jacobian lens is "an imperfect tool, which we believe only approximately and incompletely captures the model's underlying workspace structure."&lt;/p&gt;

&lt;p&gt;There is also a circularity worth naming out loud. The lens is constructed to find verbalizable content, and then evaluated for further properties of that content.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why any of this matters outside a weights lab
&lt;/h2&gt;

&lt;p&gt;Here is the part I keep turning over.&lt;/p&gt;

&lt;p&gt;An agent memory system has exactly the same problem, one layer up. You retrieve a fact and put it in the context. Did the model use it, or did it answer from its prior and leave your retrieved atom sitting there inert?&lt;/p&gt;

&lt;p&gt;Retrieval metrics do not answer that. Hit rate says the record could be reached. Relevance scores say it resembled the query. Neither is the question. The question is whether the atom was load-bearing, and it is the same distinction the Jacobian lens was built to settle inside the network.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The instrument does not transfer.&lt;/strong&gt; It needs weights, activations, and gradients. A production assistant is a black box: no weights, no activations, often not even per-token logprobs.&lt;/p&gt;

&lt;p&gt;The obvious analogue is behavioral rather than mechanistic. Run the reader three times with the atom &lt;strong&gt;present&lt;/strong&gt;, &lt;strong&gt;removed&lt;/strong&gt;, and &lt;strong&gt;minimally corrupted&lt;/strong&gt;, and judge the answer each time. If the atom entered the working set, the full condition differs from the other two in a predictable way. It is causal mediation applied to retrieval, and it would yield per-atom labels rather than a score: load-bearing, redundant, inert, harmful, contested.&lt;/p&gt;

&lt;p&gt;I want to be careful about the status of that idea. &lt;strong&gt;It is a research question, not a method, and nobody ships it.&lt;/strong&gt; The framing is mine and it is not a product.&lt;/p&gt;

&lt;p&gt;The caveats are real, too. The removed arm is ambiguous: an atom can look ignored because it was unused, or because the answer was overdetermined by the model's prior and the atom simply had nothing left to contribute. The only mitigation I can think of is probing with facts the base model cannot know, which is more work than it sounds and which nobody has quantified.&lt;/p&gt;

&lt;p&gt;So the honest summary is not a proposal. It is a gap.&lt;/p&gt;

&lt;p&gt;Interpretability spent years learning that a decodable signal is not a used signal, and built an instrument that can tell the difference by intervention. Agent memory has not had that argument yet. We measure whether a fact can be found and call it done, and the distance between storing a fact and proving it was used is currently unmeasured.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Disclosure: I work on &lt;a href="https://mnemoverse.com" rel="noopener noreferrer"&gt;Mnemoverse&lt;/a&gt;, a memory engine for AI agents, so the last section is the one to weigh most carefully. Every claim about the Jacobian lens above comes from the paper or Anthropic's own research page, both linked, and the longer technical explainer is on the &lt;a href="https://mnemoverse.com/docs/research/jacobian-lens-explained" rel="noopener noreferrer"&gt;original page&lt;/a&gt;. Sources: &lt;a href="https://transformer-circuits.pub/2026/workspace" rel="noopener noreferrer"&gt;the workspace paper&lt;/a&gt;, &lt;a href="https://www.anthropic.com/research/global-workspace" rel="noopener noreferrer"&gt;Anthropic's overview&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>machinelearning</category>
      <category>llm</category>
      <category>agents</category>
    </item>
    <item>
      <title>Best AI Agent Memory in 2026: A Decision Map, Not a Ranking</title>
      <dc:creator>Edward Izgorodin</dc:creator>
      <pubDate>Thu, 03 Sep 2026 12:47:35 +0000</pubDate>
      <link>https://dev.to/izgorodin/best-ai-agent-memory-in-2026-a-decision-map-not-a-ranking-4n35</link>
      <guid>https://dev.to/izgorodin/best-ai-agent-memory-in-2026-a-decision-map-not-a-ranking-4n35</guid>
      <description>&lt;p&gt;Disclosure up front: Mnemoverse publishes this post, and Mnemoverse is one of the seven tools on it, so read every row knowing the author holds a position. With that on the table, the honest answer to the question in the title has not changed all year: &lt;strong&gt;there is no single best AI agent memory in 2026.&lt;/strong&gt; There is a best answer to one prior question, and it decides more than any feature list: &lt;strong&gt;how much of your application should the memory system own?&lt;/strong&gt; This post turns that question into a decision map. The deep, dated per-system read lives in &lt;a href="https://mnemoverse.com/docs/library/ai-memory-solutions-2026-q3" rel="noopener noreferrer"&gt;Mem0 vs Zep vs Letta vs Cognee vs Supermemory&lt;/a&gt;; head-to-head pages live on the &lt;a href="https://mnemoverse.com/compare" rel="noopener noreferrer"&gt;comparison hub&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;TL;DR&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;No single best exists. The boundary question (how much of the app the memory system owns) sorts the field faster than any benchmark.&lt;/li&gt;
&lt;li&gt;Seven systems, seven different jobs: embeddable SDK, temporal fact graph, self-editing runtime, ingestion pipeline, managed context engine, framework primitive, cross-tool managed memory.&lt;/li&gt;
&lt;li&gt;A tool chosen by ranking gets replaced; a tool chosen by job stays.&lt;/li&gt;
&lt;li&gt;Every claim here was checked against the vendors' public pages in July and August 2026, and these products change fast: verify against their own docs before you commit.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The decision map
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;The boundary question&lt;/strong&gt; is the one-sentence filter this map runs on: how much of your application should the memory system own? Answer it first, and most of the table collapses to one or two rows.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Your job&lt;/th&gt;
&lt;th&gt;Start with&lt;/th&gt;
&lt;th&gt;The cost you accept&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Embed an open-source memory SDK inside one application you fully own&lt;/td&gt;
&lt;td&gt;Mem0&lt;/td&gt;
&lt;td&gt;You wire it into each app yourself; Apache-2.0 self-hosting is real&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Track facts that change over time, with valid-from and valid-to history&lt;/td&gt;
&lt;td&gt;Zep&lt;/td&gt;
&lt;td&gt;You operate Graphiti with a Neo4j backend, or take the managed cloud&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Build an agent that curates and edits its own memory as first-class behavior&lt;/td&gt;
&lt;td&gt;Letta&lt;/td&gt;
&lt;td&gt;You adopt a full runtime from the MemGPT line, not just a memory API&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Turn documents and data sources into a queryable knowledge graph&lt;/td&gt;
&lt;td&gt;Cognee&lt;/td&gt;
&lt;td&gt;Pipeline thinking: Extract, Cognify, Load, plus ontology work&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;A managed context engine over your documents, mail, and drives, with a local single-machine option&lt;/td&gt;
&lt;td&gt;Supermemory&lt;/td&gt;
&lt;td&gt;The local mode is a prebuilt binary, engine source closed, connectors cloud-only&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Memory primitives inside an agent you are building on LangGraph&lt;/td&gt;
&lt;td&gt;LangMem&lt;/td&gt;
&lt;td&gt;An early-stage SDK, and you are inside the LangChain stack&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;One memory shared across Claude Code, Cursor, VS Code, and ChatGPT, with recall that learns from outcomes&lt;/td&gt;
&lt;td&gt;Mnemoverse&lt;/td&gt;
&lt;td&gt;A managed service: the engine is closed with no self-host path today; the client libraries are MIT&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Local-first, single-user persistence with full data control&lt;/td&gt;
&lt;td&gt;A local memory MCP server&lt;/td&gt;
&lt;td&gt;Your own operations; start from the &lt;a href="https://mnemoverse.com/docs/library/memory-mcp-servers-compared" rel="noopener noreferrer"&gt;thirteen-server comparison&lt;/a&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  What each row means, honestly
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Mem0&lt;/strong&gt; is the strongest answer when memory should live inside one application and you want to own the whole layer. The open-source core is Apache-2.0 and genuinely self-hostable. Its current extraction pipeline is ADD-only, so conflicting facts accumulate and retrieval ranking surfaces the current one; the &lt;a href="https://mnemoverse.com/docs/library/ai-memory-solutions-2026-q3" rel="noopener noreferrer"&gt;dated comparison&lt;/a&gt; covers what that means in practice.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Zep&lt;/strong&gt; owns the sharpest technical divider in the field: facts in its Graphiti engine carry validity windows, so the graph can answer what was true and when it stopped being true. If your central question is fact history, nothing else on this page is purpose-built for it. The cost is graph operations: self-hosting needs Neo4j, and the cloud is metered.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Letta&lt;/strong&gt; treats memory as part of the runtime: the model itself moves items between memory tiers and edits them through tools, continuing the MemGPT line of work. Choose it when self-editing memory is the product you are building, and accept that you are adopting an agent framework, not adding a layer to the one you have.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Cognee&lt;/strong&gt; answers a different question than the rest: not "what did my agent learn" but "how do I turn these sources into a structured, queryable graph." It is Apache-2.0 with embedded stores by default, it carries more than thirty integrations, and it rewards pipeline discipline: sources in, ontology applied, graph out.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Supermemory&lt;/strong&gt; is a managed context engine built around ingesting your documents, mail, and drives, with MIT-licensed clients. Since June 2026 it also offers a free local single-machine mode, which is genuinely useful and honestly limited: the binary is prebuilt, the engine source is not public, and connectors stay cloud-only.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;LangMem&lt;/strong&gt; is the natural row if you are already building on LangGraph and want memory primitives from the same vendor. It is early-stage, and that is the trade: framework fit over maturity.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Mnemoverse&lt;/strong&gt; is the vendor entry, last on purpose. It is a managed persistent-memory API reachable over MCP: one API key or OAuth sign-in gives Claude Code, Cursor, VS Code, Windsurf, ChatGPT, Python, and REST the same memory. Importance is scored on write, associations between concepts strengthen as they are recalled together (Hebbian, tuned by a Rescorla-Wagner update), and reporting outcomes re-ranks what comes back next, so recall improves with use rather than staying frozen. Consolidation is built into the engine and switched off on the hosted service today: what keeps recall relevant is ranking rather than removal. The engine is closed with no self-host path today, and the client libraries are MIT. If your agents live in more than one tool, this is the job it is built for; if your job matches another row, another row is the better choice.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to decide in one afternoon
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Answer the boundary question in writing.&lt;/strong&gt; One sentence: the memory system should own this much of my application. Most disagreements about "best" are two people answering this question differently.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Test the failure that actually hurt you.&lt;/strong&gt; Write a fact in one session, recall it after a restart. Supersede a fact and check which version comes back. Tell the system a recalled memory was wrong and check whether it comes back anyway. One afternoon of this beats any leaderboard screenshot, and it is exactly the test we invite you to run against Mnemoverse first, strictly.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Verify claims against the vendor's own pages, with dates.&lt;/strong&gt; Licenses, prices, and self-host reality on this page were checked in July and August 2026 and will drift. A comparison without an as-of date is an opinion.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Why this is not a ranking
&lt;/h2&gt;

&lt;p&gt;A single ordered list has to collapse different jobs into one score, and the score answers a question nobody wrote down. Vendor benchmark numbers in this category have not survived independent reproduction well, and the reproductions themselves are mostly run by vendors; the &lt;a href="https://mnemoverse.com/docs/library/ai-memory-solutions-2026-q3" rel="noopener noreferrer"&gt;dated comparison&lt;/a&gt; documents one such case with sources. A ranking also rots silently: these products ship monthly, and the list keeps its order long after the facts moved. A decision map rots more slowly, because jobs change less often than feature lists.&lt;/p&gt;

&lt;p&gt;If the cross-tool row is yours: the free tier is 1,000 queries a day and 10,000 memories, no credit card, at &lt;a href="https://console.mnemoverse.com/sign-up?utm_source=devto&amp;amp;utm_medium=article&amp;amp;utm_campaign=best-memory-2026" rel="noopener noreferrer"&gt;console.mnemoverse.com&lt;/a&gt;. Take the strict test from step two with you.&lt;/p&gt;

&lt;p&gt;The maintained original of this decision map lives in &lt;a href="https://mnemoverse.com/docs/library/best-ai-agent-memory-2026" rel="noopener noreferrer"&gt;our library&lt;/a&gt; and will be updated there first.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>agents</category>
      <category>llm</category>
      <category>mcp</category>
    </item>
    <item>
      <title>Your Agent Memory Records When. Four Older Fields Already Solved Who.</title>
      <dc:creator>Edward Izgorodin</dc:creator>
      <pubDate>Wed, 02 Sep 2026 14:36:00 +0000</pubDate>
      <link>https://dev.to/izgorodin/your-agent-memory-records-when-four-older-fields-already-solved-who-4gmk</link>
      <guid>https://dev.to/izgorodin/your-agent-memory-records-when-four-older-fields-already-solved-who-4gmk</guid>
      <description>&lt;p&gt;A memory system can preserve every relevant timestamp and still lose the information needed to judge a claim.&lt;/p&gt;

&lt;p&gt;The gap stays invisible while one process owns every write. "The system learned this" and "someone asserted this" look like the same sentence. They stop being the same sentence the moment several agents, accounts, or documents write into one shared store. At that point a contradiction is not a temporal event. It is a conflict between assertions, and no clock can adjudicate it.&lt;/p&gt;

&lt;p&gt;What follows is the part I find uncomfortable: four mature bodies of work already named the missing piece, the oldest of them in 1979, and none of the agent-memory systems I have read adopts any of them explicitly.&lt;/p&gt;

&lt;h2&gt;
  
  
  Bi-temporal memory answers when, not who
&lt;/h2&gt;

&lt;p&gt;The good version of temporal memory splits time in two. Valid time asks when a claim held in the world. Transaction time asks when the store came to hold it. Both are needed to reconstruct change, and most systems do not even ship the second one.&lt;/p&gt;

&lt;p&gt;Now take a record: &lt;em&gt;Alice lives in Berlin.&lt;/em&gt; A bi-temporal store can say when Alice lived in Berlin and when the system learned it. But the learning event had a source. An agent extracted the claim, or a user stated it, or a document supplied it. The timestamp keeps that event's place in time and drops the identity behind it.&lt;/p&gt;

&lt;p&gt;With one writer, the omission is easy to miss, because the sole writer is implicitly responsible for everything. Shared memory removes the shortcut.&lt;/p&gt;

&lt;p&gt;Suppose one writer stores &lt;em&gt;Alice lives in Berlin&lt;/em&gt;, and another later stores &lt;em&gt;Alice lives in London&lt;/em&gt;. The later timestamp establishes sequence. It does not establish truth. The second writer may have newer evidence. It may also have copied an outdated document, misread a message, or written under the wrong account context. The first writer may be an authoritative system of record.&lt;/p&gt;

&lt;p&gt;Recency answers "which assertion arrived last?" Conflict resolution needs a different question: whose assertion should the system accept, and why?&lt;/p&gt;

&lt;p&gt;Which gives the compact form of the problem. &lt;strong&gt;Bi-temporality is a degenerate provenance model. It preserves the &lt;em&gt;when&lt;/em&gt; of an assertion event and discards the &lt;em&gt;who&lt;/em&gt;.&lt;/strong&gt; "Degenerate" is doing real work in that sentence: a transaction timestamp keeps exactly one coordinate of the assertion event, and drops the responsible party, the supporting evidence, and the derivation chain needed to evaluate it.&lt;/p&gt;

&lt;h2&gt;
  
  
  What a shipped implementation actually keeps
&lt;/h2&gt;

&lt;p&gt;This is not a thought experiment. Zep and Graphiti resolve temporally overlapping contradictions by closing the older edge's validity window (&lt;a href="https://arxiv.org/abs/2501.13956" rel="noopener noreferrer"&gt;arXiv:2501.13956&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;Credit where it is due: that graph does keep extraction provenance. Edges and their source episodes hold bidirectional indices, which is more than most.&lt;/p&gt;

&lt;p&gt;But the invalidated edge records only a temporal boundary. Nothing in it says whose assertion won the conflict, or on what grounds. It is an operational answer without an epistemic explanation, and it is one of the better ones in the field.&lt;/p&gt;

&lt;h2&gt;
  
  
  Four fields that already named the missing piece
&lt;/h2&gt;

&lt;p&gt;None of these has to be adopted wholesale. The point is narrower and, to me, more damning: each one already makes first-class the thing agent memory keeps discarding.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;W3C PROV-O, Recommendation dated 30 April 2013.&lt;/strong&gt; It defines three core classes: &lt;code&gt;prov:Entity&lt;/code&gt;, &lt;code&gt;prov:Activity&lt;/code&gt;, and &lt;code&gt;prov:Agent&lt;/code&gt;, where an agent is something that &lt;em&gt;bears responsibility&lt;/em&gt; for an activity or entity. Responsibility is a primitive modelling concept, not an annotation added afterwards. The lesson for agent memory is modest and specific: represent responsibility instead of inferring it from write order.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Nanopublications.&lt;/strong&gt; A nanopublication is a publishable knowledge unit composed of three named graphs: assertion, provenance, and publication information. Provenance is structural rather than optional, because the smallest publishable unit contains all three, so the assertion cannot travel alone. Agent memory inverts this. The fact is the unit, and source context is metadata, if it is kept at all.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;AGM belief revision&lt;/strong&gt; (Alchourrón, Gärdenfors and Makinson, &lt;em&gt;Journal of Symbolic Logic&lt;/em&gt;, 1985). Three operations on a belief set: expansion, contraction, revision, under rationality postulates. Contraction forces a choice about which belief to surrender, and the postulates constrain that choice. Any memory system that invalidates a claim on contradiction is already doing belief revision. Without an explicit policy, "newer wins" is not a decision. It is an accidental rule with no record of what was surrendered or why.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Truth maintenance systems.&lt;/strong&gt; Doyle introduced justification-based TMS in 1979. De Kleer's assumption-based variant followed in 1986, tracing contradictions back through the justification network instead of recomputing from scratch. A belief survives only while at least one justification stays valid. That justification slot records why a statement is believed and what supports it, which is exactly where an agent-memory source belongs: the writer, the evidence, the dependency chain.&lt;/p&gt;

&lt;p&gt;"Invalidate on observed contradiction" without that slot is truth maintenance with the justifications removed.&lt;/p&gt;

&lt;p&gt;Taken together the four make the design choice plain. A memory record should not contain only a proposition and its clocks. &lt;strong&gt;It should retain the assertion event that put the proposition there.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What to record at write time
&lt;/h2&gt;

&lt;p&gt;A shared-memory write should attach a typed source link to each assertion. At minimum: the writing agent's identity, the account or principal context, a document pointer or other evidence reference, and the derivation method.&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="na"&gt;assertion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Alice&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;lives&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;in&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;London"&lt;/span&gt;
&lt;span class="na"&gt;source&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;agent&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;research-agent"&lt;/span&gt;
  &lt;span class="na"&gt;principal&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;account-context"&lt;/span&gt;
  &lt;span class="na"&gt;evidence&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;document-reference"&lt;/span&gt;
  &lt;span class="na"&gt;derivation&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;extracted-from-source"&lt;/span&gt;
&lt;span class="na"&gt;decision&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;status&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;active"&lt;/span&gt;
  &lt;span class="na"&gt;reason&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;accepted&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;under&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;source&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;policy"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The field names are implementation choices. The persistence rule is not.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Source context must survive conflict resolution.&lt;/strong&gt; When a later assertion wins, keep the losing one, its author, its evidence, and the reason it lost. That single rule converts a silent overwrite into an auditable decision, and it lets a later review reverse the call without excavating context that no longer exists.&lt;/p&gt;

&lt;h2&gt;
  
  
  Identity and authority are two different systems
&lt;/h2&gt;

&lt;p&gt;This is the distinction that took me longest to hold steady, and it is the one that makes the rest tractable.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Identity is stored evidence about who wrote. Authority is the decision about whose claim should prevail.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;They fail differently. A system without identity cannot attribute an assertion at all, so no policy can run, however good the policy is. A system with identity but no authority rules can attribute both sides of a contradiction and still cannot explain which one it accepted.&lt;/p&gt;

&lt;p&gt;The useful consequence is that they can be built in that order. Recording who wrote does not require agreement on a universal authority ranking, and it is the prerequisite for any ranking arriving later. What the memory layer owes a future policy is not the policy. It is enough preserved information for one to operate.&lt;/p&gt;

&lt;h2&gt;
  
  
  The part I do not have
&lt;/h2&gt;

&lt;p&gt;I am not going to pretend the second half is solved. Deciding whose assertion outranks whose, across agents that were never designed together, under accounts with different trust levels, is an open problem and I have not seen a convincing shipped answer to it.&lt;/p&gt;

&lt;p&gt;What is not open is the first half. The prior art runs from thirteen to forty-seven years old, it is well documented, and it says the same thing four different ways: keep the asserter.&lt;/p&gt;

&lt;p&gt;Losing it is a choice, not a constraint.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Disclosure: I work on &lt;a href="https://mnemoverse.com" rel="noopener noreferrer"&gt;Mnemoverse&lt;/a&gt;, a memory engine for AI agents connected over MCP, so weigh the argument accordingly. Every source above is linked and dated, and the longer version with the full citations is on the &lt;a href="https://mnemoverse.com/docs/library/provenance-in-agent-memory" rel="noopener noreferrer"&gt;original page&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>agents</category>
      <category>architecture</category>
      <category>llm</category>
    </item>
    <item>
      <title>My Analytics Panel Says AI Assistants Are Desperate for /wp-config.php</title>
      <dc:creator>Edward Izgorodin</dc:creator>
      <pubDate>Tue, 01 Sep 2026 15:16:00 +0000</pubDate>
      <link>https://dev.to/izgorodin/my-analytics-panel-says-ai-assistants-are-desperate-for-wp-configphp-3lae</link>
      <guid>https://dev.to/izgorodin/my-analytics-panel-says-ai-assistants-are-desperate-for-wp-configphp-3lae</guid>
      <description>&lt;p&gt;One finding, and it is about an instrument rather than a threat.&lt;/p&gt;

&lt;p&gt;Cloudflare's AI Crawl Control has an Optimization tab. It shows two tables. The first is labelled "Understand what content is used in AI answers." The second is labelled, word for word:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Check what AI Assistants are trying to access, but can't.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Read that second label the way it is written. It says these are the things assistants want from you and are not getting. It reads like a content backlog.&lt;/p&gt;

&lt;p&gt;Here is the top of that table on a site I work on:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight toml"&gt;&lt;code&gt;&lt;span class="err"&gt;/config.toml&lt;/span&gt;
&lt;span class="err"&gt;/local.settings.json&lt;/span&gt;
&lt;span class="err"&gt;/@fs/app/.env&lt;/span&gt;
&lt;span class="err"&gt;/wp-config.php~&lt;/span&gt;
&lt;span class="err"&gt;/config.env&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Further down: &lt;code&gt;id_ed25519&lt;/code&gt;, &lt;code&gt;gcp-key.json&lt;/code&gt;, &lt;code&gt;service_account.json&lt;/code&gt;, &lt;code&gt;terraform.tfstate&lt;/code&gt;, &lt;code&gt;aws-exports.js&lt;/code&gt;, &lt;code&gt;backend/settings.py&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Those are not unmet demand. That is a credential scanner working through a wordlist.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why they are in there
&lt;/h2&gt;

&lt;p&gt;The answer is in Cloudflare's own documentation for the same feature, and it is not hidden:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;On the free plan, AI Crawl Control identifies AI crawlers based on their user agent strings.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Verification of who a crawler actually is, through bot-management detection, is a paid-plan feature. On the free plan, "AI assistant" means a request that wrote &lt;code&gt;User-Agent: ChatGPT-User&lt;/code&gt; about itself.&lt;/p&gt;

&lt;p&gt;A scanner sets that header and is counted as an AI assistant. Every probe it makes becomes a data point about what AI assistants want.&lt;/p&gt;

&lt;h2&gt;
  
  
  How much of the panel this is
&lt;/h2&gt;

&lt;p&gt;On the sample I checked, over a single day: &lt;strong&gt;79 percent of the "most visited pages" table, and 94 percent of the "demand signals" table, are requests for paths that do not exist and never have.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The provider breakdown says the same thing from another angle. One provider accounts for 92.5 percent of the volume, and it is the one whose user-agent string is the cheapest to imitate. The three providers that are harder to impersonate come to a couple of hundred requests between them, which is a far more believable number for genuine assistant traffic.&lt;/p&gt;

&lt;h2&gt;
  
  
  The part that is actually dangerous
&lt;/h2&gt;

&lt;p&gt;A metrics panel that mislabels traffic is an annoyance. A metrics panel that mislabels traffic &lt;strong&gt;and then tells you what to do about it&lt;/strong&gt; is something else.&lt;/p&gt;

&lt;p&gt;"Check what AI Assistants are trying to access, but can't" is an instruction. Followed literally, on the data it is presenting, it says: create &lt;code&gt;/config.toml&lt;/code&gt;. Create &lt;code&gt;/wp-config.php&lt;/code&gt;. Publish &lt;code&gt;/.env&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Nothing in the interface marks those rows as probes. There is no flag, no separate bucket, no note. They sit in the same table as your documentation pages, sorted by the same column, styled the same way.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I would do with it
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Do not act on that table.&lt;/strong&gt; Not one row, not ever.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Filter with an allowlist, not a blocklist.&lt;/strong&gt; I tried a blocklist first, pattern-matching the obvious probe shapes, and it let &lt;code&gt;id_ed25519&lt;/code&gt; and &lt;code&gt;terraform.tfstate&lt;/code&gt; through as legitimate. Listing the paths that actually exist on the site is the only filter that holds, because the probe wordlist is longer than your imagination.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Then keep what survives.&lt;/strong&gt; Underneath the noise there is a genuinely useful signal that no other instrument gives you: which of your pages assistants actually fetch, as distinct from which pages rank. Those are different lists, and the difference is worth knowing.&lt;/p&gt;

&lt;p&gt;The panel is not useless. It is just reporting the wrong thing loudly and the right thing quietly, and the label on top points at the loud half.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Disclosure: I work on &lt;a href="https://mnemoverse.com" rel="noopener noreferrer"&gt;Mnemoverse&lt;/a&gt;, a memory engine for AI agents. The percentages above come from one day of one site's own export. The Cloudflare documentation quoted is public and says the same thing to anyone who opens it.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>webdev</category>
      <category>security</category>
      <category>analytics</category>
    </item>
    <item>
      <title>I Opened All Thirteen Memory MCP Servers. Every Public Signal I Trusted Was Wrong.</title>
      <dc:creator>Edward Izgorodin</dc:creator>
      <pubDate>Mon, 31 Aug 2026 14:06:00 +0000</pubDate>
      <link>https://dev.to/izgorodin/i-opened-all-thirteen-memory-mcp-servers-every-public-signal-i-trusted-was-wrong-1i1g</link>
      <guid>https://dev.to/izgorodin/i-opened-all-thirteen-memory-mcp-servers-every-public-signal-i-trusted-was-wrong-1i1g</guid>
      <description>&lt;p&gt;I went looking for a memory MCP server the way anyone does. Sort by stars, check the registry, read the README, pick one.&lt;/p&gt;

&lt;p&gt;Then I opened all thirteen that actually ship, and every one of those four signals turned out to measure something other than what I thought it measured. Not one of them is a lie. Each is a real number pointing at a real thing. The problem is that the thing is rarely the server you are about to install.&lt;/p&gt;

&lt;p&gt;Here is what each signal actually reports, with the cases where the gap is widest.&lt;/p&gt;

&lt;h2&gt;
  
  
  The star count often belongs to a different project
&lt;/h2&gt;

&lt;p&gt;The largest number in this field is about 90,100 stars, and it belongs to claude-mem. That one is honest: the stars sit on the repository that ships the thing.&lt;/p&gt;

&lt;p&gt;Two of the best-known entries are not.&lt;/p&gt;

&lt;p&gt;Mem0's memory MCP server lives inside an umbrella repository carrying roughly 62,800 stars. Those stars cover the engine, the SDKs, the docs, and everything else in the monorepo. Supermemory has the same shape: about 28,800 stars on the monorepo where its MCP v2 lives, while the deprecated v1 repository sits near 1,700.&lt;/p&gt;

&lt;p&gt;Memori is the sharpest case. Its engine has around 15,700 stars. Its MCP wrapper, the part you would actually connect to a client, has &lt;strong&gt;two&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;None of that makes those projects worse. Mem0 and Supermemory are serious, mature systems, and Memori's engine has earned its count. But if you shortlist by star count without asking which repository the number is attached to, you have ranked engines against wrappers against monorepos and called it a comparison.&lt;/p&gt;

&lt;p&gt;The check takes ten seconds: open the repository the install command actually points at, and read the count there.&lt;/p&gt;

&lt;h2&gt;
  
  
  The registry is a form, not a review
&lt;/h2&gt;

&lt;p&gt;The official MCP Registry looks like a filter. It is not one. Publishing to it is self-service: a maintainer fills in a form. Nobody reviews the server, tests it, or checks that it does what the description says.&lt;/p&gt;

&lt;p&gt;The absence side is worse. &lt;strong&gt;The largest project in the whole comparison, claude-mem at roughly 90,100 stars, has no registry entry at all.&lt;/strong&gt; Neither does MemPalace at about 58,200. Meanwhile some of the smallest projects in the registry have almost no users.&lt;/p&gt;

&lt;p&gt;So a registry entry tells you one thing: MCP-aware clients that browse the registry can find this server. That is genuinely useful, because such a client cannot find what is not listed. It is just not a quality signal, and reading it as one inverts the field.&lt;/p&gt;

&lt;h2&gt;
  
  
  Download counts measure the reference implementation, not the field
&lt;/h2&gt;

&lt;p&gt;The most-downloaded package in this comparison is the official &lt;code&gt;server-memory&lt;/code&gt;, at roughly 390,000 npm downloads a month. That is more than an order of magnitude above anything else here.&lt;/p&gt;

&lt;p&gt;Its own README calls it "a basic implementation."&lt;/p&gt;

&lt;p&gt;That is not false modesty. It stores a knowledge graph in a single local JSONL file, searches by substring, and serves one user. It is actively maintained and it is a reasonable first experiment. It is also the thing people install to try MCP memory once, which is exactly why its download number looks the way it does.&lt;/p&gt;

&lt;p&gt;Downloads measure trial, and trial concentrates on whatever is easiest to install. Engine libraries distort the picture further: &lt;code&gt;mem0ai&lt;/code&gt; on PyPI counts far higher than anything in this list, but it is an engine, not an MCP server, and comparing the two is comparing a library to a service.&lt;/p&gt;

&lt;h2&gt;
  
  
  A README is a snapshot, and sub-projects disappear
&lt;/h2&gt;

&lt;p&gt;An earlier version of the comparison page behind this article pointed readers at OpenMemory as Mem0's local Docker path. That path was removed from the monorepo in July 2026. Mem0's documented MCP entry point today is a hosted server.&lt;/p&gt;

&lt;p&gt;Nothing was hidden. The project moved, as projects do. But the sentence had been true when it was written, and it was still sitting there being read after it stopped being true.&lt;/p&gt;

&lt;p&gt;The same failure mode is waiting in &lt;code&gt;memento-mcp&lt;/code&gt;. Its README describes a knowledge graph with vector embeddings and temporal decay over Neo4j, and that description is accurate. What the README does not say is that the last commit to main was &lt;strong&gt;10 May 2025&lt;/strong&gt;, and npm downloads sit around 127 a month. You would be adopting abandoned code and, in this case, forking it.&lt;/p&gt;

&lt;p&gt;Before adopting any of these, check the last commit date and whether the sub-project you are citing still exists in the repository. Both checks are faster than reading the feature list.&lt;/p&gt;

&lt;h2&gt;
  
  
  One of the most-searched names is not a product
&lt;/h2&gt;

&lt;p&gt;Searches for a memory MCP server called "gmemory" return confident results. There is no such shipped server. The term points at G-Memory, a multi-agent memory research framework on arXiv, paper 2506.07398.&lt;/p&gt;

&lt;p&gt;It is a paper. It is a good paper. It is not something you can connect to a client.&lt;/p&gt;

&lt;p&gt;The nearest shipped SQL-native option is Memori, from MemoriLabs, formerly GibsonAI, and that is a different project entirely, with the engine-versus-wrapper split described above.&lt;/p&gt;

&lt;h2&gt;
  
  
  Free does not mean free, and free does not mean self-hosted
&lt;/h2&gt;

&lt;p&gt;Most of this field converges on roughly $15 to $30 a month for a hosted tier, and several projects have no paid tier at all. Two entries break that pattern in opposite directions.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;memento-mcp&lt;/code&gt; is listed as free and it is, in the sense that the code costs nothing. Running it requires your own Neo4j 5.13+ instance and a paid OpenAI key for embeddings. The bill exists. It is just not on the invoice you were reading.&lt;/p&gt;

&lt;p&gt;Memori is the outlier the other way. Its first paid step is quoted from &lt;strong&gt;$60,000 a year&lt;/strong&gt;, with nothing self-serve between the free open-source path and that. It is not a more expensive version of the same purchase. It is a different purchase.&lt;/p&gt;

&lt;p&gt;The distinction worth holding: free and self-hosted are not the same property. &lt;code&gt;mcp-memory-service&lt;/code&gt; is both, with local embeddings and no cloud bill. &lt;code&gt;memento-mcp&lt;/code&gt; is neither, once you count what it needs to run.&lt;/p&gt;

&lt;h2&gt;
  
  
  The one filter that actually narrows the field
&lt;/h2&gt;

&lt;p&gt;After all thirteen, the question that did the most work was not on any feature grid.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Does memory need to stay on one machine you control, or must several clients and users share one store?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;That single question splits the field before any other comparison applies, because it sets the trust boundary and the operating burden. Local-first means backups, versioning, and portability become your job. Hosted means the agent's memory lives on someone else's infrastructure.&lt;/p&gt;

&lt;p&gt;And one caution inside the local branch that took me too long to see. &lt;code&gt;basic-memory&lt;/code&gt; connects to many client applications, Obsidian included. That is a genuine strength, and it is often read as multi-user support. It is not. It serves one user's files across many clients. &lt;strong&gt;"Works with many clients" and "isolates many users" are different properties&lt;/strong&gt;, and the second one is a deployment concern in every hosted case here, never an automatic guarantee.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I would check now instead
&lt;/h2&gt;

&lt;p&gt;Four questions, all faster than reading a feature comparison:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Which repository does the star count belong to?&lt;/strong&gt; Open the one the install command points at.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;When was the last commit to main?&lt;/strong&gt; Not the last release. The last commit.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Does the sub-project in the README still exist?&lt;/strong&gt; Search the repository for it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;What does "free" require you to run?&lt;/strong&gt; A database and an embeddings key are a bill.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;None of that tells you which server is best. Nothing does, because the answer depends on the deployment question above. What it does is stop you shortlisting on numbers that describe something else.&lt;/p&gt;

&lt;p&gt;The full comparison of all thirteen, with three tables and every number dated and sourced, is on the &lt;a href="https://mnemoverse.com/docs/library/memory-mcp-servers-compared" rel="noopener noreferrer"&gt;original page&lt;/a&gt;. One of the thirteen is ours. It is flagged as a vendor entry there and ordered first on purpose, so it can be discounted in one glance rather than quietly benefiting from the company it keeps.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Disclosure: I work on &lt;a href="https://mnemoverse.com" rel="noopener noreferrer"&gt;Mnemoverse&lt;/a&gt;, a memory engine for AI agents connected over MCP, and it is one of the thirteen servers in the comparison this article draws on. Every number above is dated and checkable on the source page. Free key: &lt;a href="https://console.mnemoverse.com" rel="noopener noreferrer"&gt;console.mnemoverse.com&lt;/a&gt; · &lt;a href="https://mnemoverse.com/pricing" rel="noopener noreferrer"&gt;Plans and limits&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>mcp</category>
      <category>agents</category>
      <category>opensource</category>
    </item>
    <item>
      <title>The Same GraphRAG Comparison Wins and Loses. It Depends Which Instrument Judged It.</title>
      <dc:creator>Edward Izgorodin</dc:creator>
      <pubDate>Sat, 29 Aug 2026 17:49:00 +0000</pubDate>
      <link>https://dev.to/izgorodin/the-same-graphrag-comparison-wins-and-loses-it-depends-which-instrument-judged-it-fm9</link>
      <guid>https://dev.to/izgorodin/the-same-graphrag-comparison-wins-and-loses-it-depends-which-instrument-judged-it-fm9</guid>
      <description>&lt;p&gt;One finding, and it is not about graphs. It is about how the result you are quoting was produced.&lt;/p&gt;

&lt;p&gt;For breadth-oriented sensemaking questions, GraphRAG community summaries reached &lt;strong&gt;72 to 83 percent comprehensiveness&lt;/strong&gt; and &lt;strong&gt;62 to 82 percent diversity&lt;/strong&gt; win rates, and root-level summaries cut answer tokens by about 97 percent (&lt;a href="https://arxiv.org/abs/2404.16130" rel="noopener noreferrer"&gt;arXiv:2404.16130&lt;/a&gt;). Those are the numbers the category quotes.&lt;/p&gt;

&lt;p&gt;They were produced by an LLM judge, with no gold answers.&lt;/p&gt;

&lt;p&gt;Score the same kind of comparison against ground truth and it turns over. On ROUGE-2 against gold answers, GraphRAG loses to plain RAG: &lt;strong&gt;6.99 against 10.08 on SQuALITY&lt;/strong&gt;, and &lt;strong&gt;3.23 against 6.32 on QMSum&lt;/strong&gt;. The same paper reports that summary-ordering position bias can flip the LLM judge's preference on its own (&lt;a href="https://arxiv.org/abs/2502.11371" rel="noopener noreferrer"&gt;arXiv:2502.11371&lt;/a&gt;).&lt;/p&gt;

&lt;h2&gt;
  
  
  Both results are true
&lt;/h2&gt;

&lt;p&gt;That is the part worth sitting with. Neither number is wrong and neither paper is sloppy.&lt;/p&gt;

&lt;p&gt;One measures which answer a model prefers. The other measures overlap with a gold answer. They are different questions, so they are allowed to have different answers, and a comparison that looks decisive is often just one of the two questions asked loudly.&lt;/p&gt;

&lt;p&gt;The same seam runs through the retrieval verdicts. On GraphRAG-Bench, "RAG (w rerank)" beat "GraphRAG (local)" &lt;strong&gt;60.92 to 49.29&lt;/strong&gt; on fact retrieval, while "HippoRAG2" beat "RAG (w rerank)" &lt;strong&gt;53.38 to 42.93&lt;/strong&gt; on complex reasoning (&lt;a href="https://arxiv.org/abs/2506.05690" rel="noopener noreferrer"&gt;arXiv:2506.05690&lt;/a&gt;). One table, two verdicts, depending on which row of it you were looking for.&lt;/p&gt;

&lt;h2&gt;
  
  
  Cost has the same problem
&lt;/h2&gt;

&lt;p&gt;"Graph equals expensive" is too crude to act on. On the Novel split of the same benchmark, query cost spans &lt;strong&gt;more than two orders of magnitude within the graph methods themselves&lt;/strong&gt;: about 331,375 total query tokens for "MS-GraphRAG(global)", about 100,832 for LightRAG, about 4,204 for Fast-GraphRAG, about 1,008 for "HippoRAG2", against about 879 for vanilla RAG.&lt;/p&gt;

&lt;p&gt;Index build shows the same spread: roughly 9.2 million tokens for "HippoRAG2" against roughly 115.5 million for GraphRAG, about twelvefold (&lt;a href="https://arxiv.org/abs/2502.14802" rel="noopener noreferrer"&gt;arXiv:2502.14802&lt;/a&gt;, Table 12).&lt;/p&gt;

&lt;p&gt;Those two figures come from different primaries with different method sets, and no single primary puts index-build cost and query cost for the same method on one axis. Which is itself the lesson: the tidy cost model you want does not exist yet, and assembling one from two papers gives you a useful heuristic, not a controlled comparison.&lt;/p&gt;

&lt;h2&gt;
  
  
  The question that survives
&lt;/h2&gt;

&lt;p&gt;Before accepting any retrieval win, mine included:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Was this judged by a model, or scored against ground truth?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;It takes ten seconds to check and it changes what the number means. A model-judged win says an evaluator preferred that answer. A ground-truth score says the answer overlapped with a known correct one. Quoting the first while implying the second is how a benchmark verdict gets mistaken for a decision framework.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Disclosure: I work on &lt;a href="https://mnemoverse.com" rel="noopener noreferrer"&gt;Mnemoverse&lt;/a&gt;, a memory engine for AI agents. Every number above comes from a linked paper, none of them ours. The longer version, with the full decision matrix, is on the &lt;a href="https://mnemoverse.com/docs/library/graphrag-tax" rel="noopener noreferrer"&gt;original page&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>rag</category>
      <category>llm</category>
      <category>benchmarks</category>
    </item>
    <item>
      <title>Is Agent Memory Just RAG With Extra Steps? We Opened the Source Code to Find Out</title>
      <dc:creator>Edward Izgorodin</dc:creator>
      <pubDate>Thu, 27 Aug 2026 15:14:00 +0000</pubDate>
      <link>https://dev.to/izgorodin/is-agent-memory-just-rag-with-extra-steps-we-opened-the-source-code-to-find-out-349i</link>
      <guid>https://dev.to/izgorodin/is-agent-memory-just-rag-with-extra-steps-we-opened-the-source-code-to-find-out-349i</guid>
      <description>&lt;p&gt;Under every agent memory launch, the same comment appears: "so it's RAG with extra steps." Instead of arguing, we opened the shipping source of mem0, LangGraph, Graphiti and Generative Agents at pinned commits and read the actual read and write paths. The answer is more interesting than either side of the flame war.&lt;/p&gt;

&lt;p&gt;Disclosure up front: I work on Mnemoverse, a memory layer for AI agents, so this is a vendor reading competitors' code, and you should weigh it accordingly. Two rules held throughout: in the full version every code claim cites file, lines and a pinned commit, and this short tour names file and commit wherever it quotes code; and there is not a single performance number, ours or anyone's. The full version with all 40 numbered claims and sources lives in our library; this is the short tour.&lt;/p&gt;

&lt;h2&gt;
  
  
  At read time, the skeptic is right
&lt;/h2&gt;

&lt;p&gt;When a memory layer answers a query, here is mem0's shipping search path (&lt;code&gt;mem0/memory/main.py&lt;/code&gt;, commit &lt;code&gt;001c235&lt;/code&gt;): embed the query, over-fetch from a vector store, run a keyword search alongside, fuse the scores, optionally rerank.&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;# Step 2: Embed query
&lt;/span&gt;&lt;span class="n"&gt;embeddings&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;embedding_model&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;embed&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="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;search&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# Step 3: Semantic search (over-fetch for scoring pool)
&lt;/span&gt;&lt;span class="n"&gt;internal_limit&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;limit&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;60&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;semantic_results&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;vector_store&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;search&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="o"&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;vectors&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;embeddings&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;top_k&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;internal_limit&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;filters&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;filters&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# Step 4: Keyword search (if store supports it)
&lt;/span&gt;&lt;span class="n"&gt;keyword_results&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;vector_store&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;keyword_search&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;query_lemmatized&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;top_k&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;internal_limit&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;filters&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;filters&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That is a textbook hybrid retrieval pipeline. If you have built retrieval, you have built this. LangGraph is even more explicit: long-term memory there is a JSON document under a namespace and a key, and semantic search is opt-in. And Anthropic ships a first-party memory tool that is six file commands with no embeddings and no scoring at all: a filesystem, from the company that makes the model.&lt;/p&gt;

&lt;p&gt;So the concession, said plainly because our category usually does not say it: for mem0, LangGraph and Anthropic's tool, the ranking at read time is retrieval and nothing else. Generative Agents, the fourth repository we opened, is the partial exception: its read path sums cosine relevance with a recency term and an importance score the model assigned at write time, weighted 3, 0.5 and 2 in the shipping code, and that is still a scoring function over a stored index rather than a second kind of read. If somebody drew you two different diagrams for how candidates get ranked, one of them was fiction. What differs is what reading does to the record, and that comes below.&lt;/p&gt;

&lt;h2&gt;
  
  
  The difference lives on the write path
&lt;/h2&gt;

&lt;p&gt;Not every memory layer does more than store. LangGraph's &lt;code&gt;put()&lt;/code&gt; writes your dict as it arrived, with no model in the path, and Anthropic's tool writes a file. In the systems that do more, mem0 with inference on, Graphiti and Generative Agents, up to three things happen on write that do not happen when you index a document. A model judges whether the thing deserves to be stored at all. The new item is reconciled against what is already there, as mem0 and Graphiti do. And the stored unit can carry a validity interval separate from when the system learned it.&lt;/p&gt;

&lt;p&gt;The third one is worth seeing in code. In Graphiti (Zep's engine, a competitor of ours), every entity edge carries five datetime fields; three of them are enough to show the idea (&lt;code&gt;graphiti_core/edges.py&lt;/code&gt;, commit &lt;code&gt;96ef997&lt;/code&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;expired_at&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;datetime&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Field&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;default&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;description&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;datetime of when the node was invalidated&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;valid_at&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;datetime&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Field&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;default&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;description&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;datetime of when the fact became true&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;invalid_at&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;datetime&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Field&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;default&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;description&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;datetime of when the fact stopped being true&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;Two axes: when the system learned something, and when it was true in the world. State "we deploy on Fridays" in March, contradict it in June, and the March record is still there, now saying "this used to be true, and here is when it stopped." Your agent can explain March's decisions after June's migration. On contradiction, nothing is deleted, so nothing has to be re-derived from a stale summary.&lt;/p&gt;

&lt;p&gt;Can you build the same thing with timestamps in your RAG metadata? Yes, and it works. The honest difference is where the reconciliation code lives: with metadata it is query-time logic in your application, maintained by you, growing a branch per conflict type; in a memory layer it happens once at write time in code you do not own. What is amortised, not what is achievable. Anyone selling you a capability gap here is selling something that is not there.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why agents remember the wrong things
&lt;/h2&gt;

&lt;p&gt;Here is the part that made us uncomfortable. A memory layer reads from a corpus it wrote itself. Extraction writes memories, retrieval reads them, and the output feeds the next extraction. A RAG pipeline can retrieve badly, but it cannot corrupt its source: your documents were written by people, elsewhere. A memory store's extraction errors become its own retrieval corpus.&lt;/p&gt;

&lt;p&gt;Now add the reinforcement schemes. In every reinforcement scheme we opened, retrieval is what keeps a memory alive. Generative Agents' scored retrieval rewrites &lt;code&gt;last_accessed&lt;/code&gt; on every node it returns (&lt;code&gt;retrieve.py&lt;/code&gt;, commit &lt;code&gt;fe05a71&lt;/code&gt;). MemoryBank, by its own paper, increments a memory's strength and resets its clock on recall. LangGraph ships with expiry switched off, but once an item has a time-to-live, refreshing it on every read is the default (&lt;code&gt;libs/checkpoint/langgraph/store/base/__init__.py&lt;/code&gt;, commit &lt;code&gt;644815f&lt;/code&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;class&lt;/span&gt; &lt;span class="nc"&gt;TTLConfig&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;TypedDict&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="bp"&gt;False&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;Configuration for TTL (time-to-live) behavior in the store.&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;

    &lt;span class="n"&gt;refresh_on_read&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;bool&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;Default behavior for refreshing TTLs on read operations (`GET` and `SEARCH`).

    If `True`, TTLs will be refreshed on read operations (get/search) by default.
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Put together: a wrong fact that keeps getting retrieved is protected by the exact signal that was supposed to prune it. For a corpus the system did not write, "frequently used means valuable" is reasonable. For a corpus the system wrote itself, it is a feedback loop with the sign pointing the wrong way. That is the mechanism behind the complaint under every memory launch: it remembers the wrong details and applies them in the wrong places.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where our own system fails this test
&lt;/h2&gt;

&lt;p&gt;Our shipped write gate scores novelty against the nearest existing memory in the same domain. It does not judge importance or factuality, which makes the name we gave it, an importance gate, wrong: the API field is called importance, the only refusal the core emits reads "Below importance threshold", and the number behind both is novelty. The consequence, in a personal domain, which is where a write lands by default: a correction is by nature phrased almost exactly like the thing it corrects, so it scores as a near-duplicate, so it is the one input most likely to be rejected. The stale fact survives as the sole record and, having no competitor in the store, looks more authoritative than it should. That is in our 0.8.1 changelog as a user-facing known defect. We have not solved it. Since 22 August the REST write accepts a field that names the atom it corrects, and a write declared that way skips the refusal; but the old atom is only marked, not hidden, and still competes in reads, a correction phrased like the original and not declared as one is still rejected on every surface, and the MCP tools carry no such field yet. In a shared room the gate refuses only an exact duplicate, so the same correction stores there; that is a different rule, not a fix.&lt;/p&gt;

&lt;h2&gt;
  
  
  Three checks you can run this afternoon
&lt;/h2&gt;

&lt;p&gt;On any vendor, including us. None of them is a sales-call question.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Open the read path.&lt;/strong&gt; Find the search function and read it: an embed call, an over-fetch, a keyword branch, a fusion step means retrieval. That is fine. It is only a problem if the pricing claims it is something else.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Store a fact, contradict it, list everything.&lt;/strong&gt; Original still there with a closed validity interval: Graphiti-style honesty. Present but hidden: demotion, not forgetting. Gone or silently rewritten: you lost the audit trail.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Submit a correction phrased like the original, in a personal domain.&lt;/strong&gt; If it is not in the store afterwards, the write gate ate it and the wrong fact is now the only record. This is where we fail today in a personal domain, in public, in our changelog. Run it on us.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The whole argument, animated mechanism by mechanism:&lt;/p&gt;

&lt;p&gt;  &lt;iframe src="https://www.youtube.com/embed/tSV0epuR7SI"&gt;
  &lt;/iframe&gt;
&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Disclosure: I work on &lt;a href="https://mnemoverse.com" rel="noopener noreferrer"&gt;Mnemoverse&lt;/a&gt;, a memory engine for AI agents. This article is the short version of the original in our library, which carries all numbered claims, the paper-vs-code table, and full sources at pinned commits: &lt;a href="https://mnemoverse.com/docs/library/rag-vs-agent-memory" rel="noopener noreferrer"&gt;RAG vs agent memory: what the source code actually shows&lt;/a&gt;. Code excerpts reproduced for commentary under the upstream licenses (mem0, Graphiti, Generative Agents: Apache-2.0; LangGraph: MIT).&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>agents</category>
      <category>rag</category>
      <category>llm</category>
    </item>
    <item>
      <title>"Agent Memory" Means Two Different Things, and Answer Engines Hand You the Wrong One</title>
      <dc:creator>Edward Izgorodin</dc:creator>
      <pubDate>Wed, 26 Aug 2026 12:13:00 +0000</pubDate>
      <link>https://dev.to/izgorodin/one-memory-across-claude-code-cursor-and-chatgpt-what-cross-tool-agent-memory-actually-means-3j64</link>
      <guid>https://dev.to/izgorodin/one-memory-across-claude-code-cursor-and-chatgpt-what-cross-tool-agent-memory-actually-means-3j64</guid>
      <description>&lt;p&gt;Ask an answer engine for "a memory API that works across Claude and ChatGPT" and you will mostly get SDKs designed to live inside one application. They are good tools. They also answer a different question than the one you asked. The person typing that query is not building an app; they are using four AI tools in one workday and are tired of being a stranger in every one of them.&lt;/p&gt;

&lt;p&gt;Disclosure up front: I work on Mnemoverse, which exists precisely for that query, so read this as a practitioner's map with a known bias. The map itself, I think, holds regardless of whose product you pick.&lt;/p&gt;

&lt;h2&gt;
  
  
  Two problems wearing the same word
&lt;/h2&gt;

&lt;p&gt;The category called "agent memory" quietly contains two different problems.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;App-scoped memory&lt;/strong&gt; belongs to software you are building. Your support bot should remember this customer's history; your coding agent should remember this repository's conventions. The memory lives inside one application, keyed by your users, managed by your code. SDKs you embed, stores you run: this is what most of the category ships, and for this problem embedding an SDK is the right architecture.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Person-scoped memory&lt;/strong&gt; belongs to you, the human, across every tool you work in. You explained your stack to Claude Code this morning. At lunch you are in Cursor, and it has no idea who you are. In the evening you ask ChatGPT to draft a doc, and it suggests npm for the project you moved to pnpm in June. Three tools, three goldfish.&lt;/p&gt;

&lt;p&gt;The second problem cannot be solved inside any single application, because the whole point is crossing application boundaries. It needs memory that lives &lt;strong&gt;outside&lt;/strong&gt; the tools and a protocol every tool speaks.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why MCP made person-scoped memory possible
&lt;/h2&gt;

&lt;p&gt;Until recently there was no such protocol. Every assistant had its own plugin system, its own storage, its own idea of context. The Model Context Protocol changed the shape of the problem: one server can now expose the same tools to Claude Code, Claude Desktop, Cursor, VS Code, Windsurf, and a growing list of others.&lt;/p&gt;

&lt;p&gt;That turns cross-tool memory into an architecture instead of a feature request:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;One hosted memory store&lt;/strong&gt;, attached to your account rather than to any app.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;One MCP server&lt;/strong&gt; in front of it, which every client connects to. The same &lt;code&gt;memory_write&lt;/code&gt; and &lt;code&gt;memory_read&lt;/code&gt; tools show up in every editor.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;One identity&lt;/strong&gt;: an API key or an OAuth sign-in, so the tool you happen to open resolves to the same memory.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Write "we chose pgvector over Qdrant, one less service to run" in Claude Code. Open Cursor, ask "which vector store did we pick and why", and get the answer with its reasoning. Nothing was copied. The memory simply is not inside either tool.&lt;/p&gt;

&lt;p&gt;ChatGPT is the awkward guest at this table: its MCP support is narrower, so the practical route is a connector or a Custom GPT action speaking to the same backend. Same memory, one extra hop.&lt;/p&gt;

&lt;h2&gt;
  
  
  What actually breaks in practice, and it is not the plumbing
&lt;/h2&gt;

&lt;p&gt;The architecture above is the easy part. Three things decide whether cross-tool memory works day to day.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The invocation gap.&lt;/strong&gt; Connecting memory tools does not make an agent use them. The model has no standing incentive to check memory before acting. Every tool needs one line of standing instruction: in Cursor a rule file, in Claude Code the project instructions, in ChatGPT the GPT's system prompt. Recall before acting on anything project-specific; save decisions and corrections when they happen. Without this, your perfectly wired memory stays silently empty, in every tool at once.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Scope.&lt;/strong&gt; Person-scoped memory must still respect boundaries. Client work should not leak into a personal side project; a shared team room is not your private store. Whatever backend you choose, look for tenant isolation and explicit shared spaces rather than one undifferentiated pile. A memory that crosses tools is valuable; a memory that crosses clients is a liability.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Authority.&lt;/strong&gt; When the same memory feeds four tools, a wrong fact propagates four times as fast. This is why the write discipline matters more in the cross-tool case than anywhere else: one memory per fact, the reason next to the decision, and closed facts kept with their validity window instead of deleted. The tool that recorded "we use Redux" in March must be able to explain March's code even after June's migration.&lt;/p&gt;

&lt;h2&gt;
  
  
  The honest trade-offs
&lt;/h2&gt;

&lt;p&gt;Person-scoped memory over MCP is a hosted-service architecture, and that has real costs. Your context lives with a vendor, which is exactly the wrong property if your constraint is that nothing leaves your perimeter. Every recall is a network call, slower than a local file read. And the cross-tool property only pays off if you genuinely work across tools: for a single app, an embedded SDK is simpler; for a single repo on one machine, a folder of Markdown notes is honestly hard to beat, and I say that selling the alternative.&lt;/p&gt;

&lt;p&gt;So the decision rule is short. Building an app that needs memory for its users: embed an app-scoped SDK. Privacy-critical, one machine: local files or a local MCP server. Living in several AI tools and tired of re-introducing yourself: that is the person-scoped case, and it is the one this architecture exists for.&lt;/p&gt;

&lt;h2&gt;
  
  
  Try the claim, not the marketing
&lt;/h2&gt;

&lt;p&gt;The nice thing about cross-tool memory is that the core claim takes two minutes to falsify. Connect the same memory server to two tools you already use. Save one real decision in the first. Ask the second about it in a fresh session. Either the continuity is there or it is not; no benchmark table required.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;The comparison hub at &lt;a href="https://mnemoverse.com/compare" rel="noopener noreferrer"&gt;mnemoverse.com/compare&lt;/a&gt; lays out how we sit next to Mem0, Zep, Letta, Cognee, LangMem and Supermemory, each compared honestly, including where they are the better pick. The free tier is 1,000 queries a day, no credit card, if you want to run the two-minute test.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>agents</category>
      <category>mcp</category>
      <category>llm</category>
    </item>
    <item>
      <title>Half the Requests Wearing ChatGPT's Name Were Scanning Us for Secrets</title>
      <dc:creator>Edward Izgorodin</dc:creator>
      <pubDate>Tue, 25 Aug 2026 11:53:00 +0000</pubDate>
      <link>https://dev.to/izgorodin/half-of-chatgpts-requests-to-our-site-were-not-chatgpt-3hj2</link>
      <guid>https://dev.to/izgorodin/half-of-chatgpts-requests-to-our-site-were-not-chatgpt-3hj2</guid>
      <description>&lt;p&gt;We finally opened Cloudflare's AI Crawl Control last week, mostly out of curiosity about which AI bots actually visit us. It had been collecting quietly the whole time. The first 24-hour window we looked at showed 1,890 requests from AI agents, and 483 of them failed. Compared with the previous day, that failure count was up 63 percent.&lt;/p&gt;

&lt;p&gt;The worst record belonged to the agent we were most curious about. ChatGPT-User is the one OpenAI documents as user-initiated: it visits a page when someone asks ChatGPT or a Custom GPT a question, rather than crawling on a schedule. It accounted for 859 requests. Only 412 came back 200.&lt;/p&gt;

&lt;p&gt;So roughly half the requests wearing that name were bouncing. I wrote it up as a redirect problem: we had migrated docs slugs more than once, so stale URLs would explain it, and a redirect map would fix it. Clean story. It was wrong.&lt;/p&gt;

&lt;p&gt;Then I looked at the actual paths.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/id_rsa
/terraform.tfstate
/.env.prod.bak
/elmah.axd
/@fs/proc/self/environ
/.github/workflows/deploy.yml
/.claude/settings.json
/api/config
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That is not a stale sitemap. That is a vulnerability scanner's shopping list: SSH keys, Terraform state, environment backups, CI configuration, framework-specific leak paths. Of the 483 failures, 447 were this shape, and all 447 carried the ChatGPT-User user agent.&lt;/p&gt;

&lt;p&gt;Every probe got a 404. Nothing was exposed. As internet background noise this is unremarkable; any public site gets it hourly. What made it interesting is the channel.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;First lesson: the aggregate lied.&lt;/strong&gt; "Unsuccessful requests, up 63 percent" reads like a site problem, and I very nearly shipped a redirect map to fix a scanner. The rate told me nothing. The paths told me everything.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Second lesson, the one I had to be corrected on: the label lied too.&lt;/strong&gt; I wrote a first draft of this that called the remaining 412 requests genuine fetches, which was a claim I had no basis for. On the free plan, Cloudflare's AI Crawl Control identifies AI agents by their user agent string. Its own documentation says so: "On the free plan, AI Crawl Control identifies AI crawlers based on their user agent strings." A user agent is a string the client chose to send. It is not evidence of who sent it.&lt;/p&gt;

&lt;p&gt;So the honest version of my own finding is narrower than the version I liked: 859 requests claimed to be ChatGPT-User, 447 of them were scanning for secrets, and 412 got 200s. Whether any of them came from OpenAI is a separate question that a user-agent label cannot answer.&lt;/p&gt;

&lt;p&gt;If you want to answer it, two things are available without an enterprise plan. OpenAI publishes per-agent IP ranges, including one specifically for this agent at &lt;code&gt;openai.com/chatgpt-user.json&lt;/code&gt;, so you can check an address against the published list. And Cloudflare exposes &lt;code&gt;cf.client.bot&lt;/code&gt; in WAF custom rules on every plan, which carries the same verified-bot signal as the enterprise field; a rule shaped like &lt;code&gt;http.user_agent contains "ChatGPT-User" and not cf.client.bot&lt;/code&gt; separates verified traffic from traffic that merely claims the name. The stronger &lt;code&gt;cf.bot_management.verified_bot&lt;/code&gt; and detection IDs need Enterprise with Bot Management, which is what I had assumed we were looking at and were not.&lt;/p&gt;

&lt;p&gt;One last correction worth passing on, because I had this backwards too. A ChatGPT-User hit in your logs is not the assistant reading your page for the person currently asking. Research published this month found ChatGPT serves opened pages from a shared cache, keyed on the URL rather than the user, so one account's copy gets served to another account in another country with no request reaching your server at all. What you see in your logs is a refresh for whoever comes next.&lt;/p&gt;

&lt;p&gt;Which leaves a tidier summary than the one I started with. We looked at an alarming AI metric, started fixing AI discoverability, and found that most of the traffic was security scanning wearing a familiar name.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Disclosure: I build &lt;a href="https://mnemoverse.com" rel="noopener noreferrer"&gt;Mnemoverse&lt;/a&gt;, a memory engine for AI agents, so this came out of watching our own traffic rather than a security engagement.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>webdev</category>
      <category>security</category>
      <category>devops</category>
    </item>
    <item>
      <title>Nowhere to Put the Disagreement: What a Memory Store Cannot Tell Your Agent</title>
      <dc:creator>Edward Izgorodin</dc:creator>
      <pubDate>Mon, 24 Aug 2026 12:43:00 +0000</pubDate>
      <link>https://dev.to/izgorodin/nowhere-to-put-the-disagreement-what-a-memory-store-cannot-tell-your-agent-369l</link>
      <guid>https://dev.to/izgorodin/nowhere-to-put-the-disagreement-what-a-memory-store-cannot-tell-your-agent-369l</guid>
      <description>&lt;p&gt;Ask a memory system what database production uses, and it can hand back two records that flatly contradict each other, each with a confident similarity score, and nothing else. Ken Alger opened &lt;a href="https://dev.to/kenwalger/your-memory-api-is-lying-to-your-agent-252h"&gt;his piece on this&lt;/a&gt; with exactly that shape: PostgreSQL at 0.94, MongoDB at 0.91, and a migration four months ago that neither number knows anything about.&lt;/p&gt;

&lt;p&gt;He wrote it from the interface side. This is the same problem from the store side, and the uncomfortable part is that a store can hold everything it needs to see the conflict, both records and both timestamps, and still return it flattened. Disclosure up front: I work on Mnemoverse, a memory engine for AI agents, so read the parts about our own failures as the ones I am most sure of.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why does a memory store hand back a contradiction without saying so?
&lt;/h2&gt;

&lt;p&gt;Because the response has nowhere to put it.&lt;/p&gt;

&lt;p&gt;A memory API returns a list of items with scores. That shape can express "here are five things, sorted by how well they match." It cannot express "these two are in conflict," "this one was superseded by that one," or "this is still true but no longer governs." Those are relations between records, and a flat list has no field for a relation.&lt;/p&gt;

&lt;p&gt;So even a store that tracked the conflict perfectly will flatten it on the way out. The agent sees two ordinary hits, takes the top one, and 0.94 beating 0.91 quietly becomes conflict resolution, performed by a number that was never asked to adjudicate anything.&lt;/p&gt;

&lt;p&gt;This is not a bug in anyone's ranker. It is a type problem. Fixing it means the response carries edges, not just items, and that is a much bigger change than adding a column.&lt;/p&gt;

&lt;h2&gt;
  
  
  What are the three operations hiding inside "update"?
&lt;/h2&gt;

&lt;p&gt;This decomposition is Ken's, from the conversation that produced both pieces, and it is the sharpest thing either of us wrote:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Supersession&lt;/strong&gt;: this was true, now this other thing is. The world changed.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Correction&lt;/strong&gt;: this was never true. Our record was wrong, and it was load-bearing for whatever happened while we believed it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Invalidation&lt;/strong&gt;: this is accepted as true and no longer governs. Not a claim about the world at all.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;At the storage layer all three look identical, because all three end up writing a value. They diverge the moment anyone audits. Supersession keeps the past explicable. Correction says the past was built on something false, which is a different and more expensive fact. And invalidation is not a truth claim: a record can be perfectly accurate and still stop being the thing that decides.&lt;/p&gt;

&lt;p&gt;Most stores have one verb for all three, or none. Ours had none until this week, and what it has now is deliberately less than a verb: the REST write accepts a supersedes link, the old record stays and gains a pointer to its replacement, and the read side does not yet hide it, so for now that link is an audit trail rather than a correction. Over MCP there is still no update verb at all, and our own changelog says it plainly: a correction that is admitted at all lands as a second record beside its target. Two atoms, two timestamps, and unless someone linked them, no relation between them. Which means the store genuinely cannot distinguish "never true" from "no longer true."&lt;/p&gt;

&lt;h2&gt;
  
  
  Why can't you just add relationships to the response?
&lt;/h2&gt;

&lt;p&gt;Because of a bootstrapping problem underneath the interface question.&lt;/p&gt;

&lt;p&gt;To know whether a supersession edge is worth carrying, you have to already be holding the record it supersedes. So edge hydration cannot be a filter applied after the top-k cut. It has to influence which candidates are considered in the first place. The relations have to be visible before the ranking, not after it.&lt;/p&gt;

&lt;p&gt;That turns a ranking problem into an allocation problem. Once a response can carry facts, relationships, authority and prior decisions, something has to decide what gets dropped when they do not all fit in the context budget. As Ken put it in the thread, a lower-ranked authority edge may matter more than the next highly relevant fact, and dropping a supersession relationship can change the meaning of the records that survive. Top-k knows none of this. It knows one number.&lt;/p&gt;

&lt;p&gt;Ranked lists are impoverished. They are also cheap, and whatever replaces them inherits a harder question than the one it solved.&lt;/p&gt;

&lt;h2&gt;
  
  
  What identity does a disagreement need?
&lt;/h2&gt;

&lt;p&gt;If yesterday's decision is going to be findable when the same disagreement comes back, the disagreement needs a durable identity of its own.&lt;/p&gt;

&lt;p&gt;The obvious move is to key it on the pair: A conflicts with B. That breaks. The moment a third record arrives, A-conflicts-with-B is no longer the same object, and yesterday's decision points at a conflict that no longer exists in that shape. Key it on the subject the records argue about instead, and the identity survives however many records pile up under it. Participants change, the disputed thing does not.&lt;/p&gt;

&lt;p&gt;Most stores key on the atom. We have not yet found one that keys on the question the atoms are arguing about.&lt;/p&gt;

&lt;h2&gt;
  
  
  Who is allowed to promote a memory, and who can revoke it?
&lt;/h2&gt;

&lt;p&gt;The thread that produced this article converged on a spec none of us had written down, and it belongs to the people who said it.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://dev.to/max_quimby"&gt;Max Quimby&lt;/a&gt; named the promotion boundary: an episode should not graduate into policy silently, because policy is expensive to change by design and should be expensive to create. &lt;a href="https://dev.to/reidmarlow"&gt;Reid Marlow&lt;/a&gt; named the other end of it: every promoted item needs a revoker, or stale policy survives on sounding official. &lt;a href="https://dev.to/joinwell52"&gt;joinwell52&lt;/a&gt; added the acceptance step in between, with scope and supersession kept separate. &lt;a href="https://dev.to/sunychoudhary"&gt;Suny Choudhary&lt;/a&gt; closed the loop from the security side: ten consistent episodes from untrusted documents should not outweigh one reviewed decision, or memory poisoning becomes a promotion attack rather than a retrieval one. &lt;a href="https://dev.to/anasbuilds997"&gt;anasbuilds997&lt;/a&gt; named why the agent cannot be its own gate: two corroborating tool outputs are not authority, and self-promotion is how hallucinations harden into permanent truths.&lt;/p&gt;

&lt;p&gt;Notice what all five are describing. Not better ranking. A write path with governance in it, and a read path honest enough to say which record is governing and on whose authority.&lt;/p&gt;

&lt;p&gt;One thing worth stating for anyone building this: authority is not a score. Collapsing trust, recency, validity and usefulness into a single number is what produces systems nobody can explain, because once they are one number you cannot ask which of them decided.&lt;/p&gt;

&lt;h2&gt;
  
  
  What happens to a decision that is never recorded?
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://dev.to/jugeni"&gt;Mike Czerwinski&lt;/a&gt; made the point that reframed this for me: handing the contradiction back to the agent only closes the gap if the choice the agent then makes gets logged too. In his words, otherwise "silent resolution just relocates from the store to the inference step, same bug at a different address, and now it's harder to find because the store looks honest."&lt;/p&gt;

&lt;p&gt;&lt;a href="https://dev.to/hannune"&gt;Tae Kim&lt;/a&gt; had already run into it, working on trade data, where the same company resolved to different nodes depending on whether you asked before or after an acquisition. They stamped time ranges on the relationships and started returning both versions to the reasoning layer, which helped. The part that stayed broken was that the agent's choice between them vanished without a trace. They started writing those choices back as events, and the honest reason was not architecture taste: a client asked about a strange output and there was nothing to point at.&lt;/p&gt;

&lt;p&gt;That is the pressure that makes a field real. Not elegance, an audit.&lt;/p&gt;

&lt;p&gt;One caution about where that record lives, and the thread supplied its own evidence for it. &lt;a href="https://dev.to/gde03"&gt;Giulio D'Erme&lt;/a&gt; went and counted his own corpus after reading the previous piece: zero of 152 memos and zero of 59 documents carried a validity window or a supersession edge. The engine could read those fields. Nothing was writing them. Availability is not usage.&lt;/p&gt;

&lt;p&gt;So a decision log that sits beside memory, outside the retrieval path, will end up in exactly that state: readable, unread, technically shipped. If tomorrow's agent cannot get yesterday's decision back at the moment the same conflict returns, the log is, as Ken put it in the thread, forensic evidence for humans rather than operationally useful memory for the system.&lt;/p&gt;

&lt;h2&gt;
  
  
  What would a store that does this actually return?
&lt;/h2&gt;

&lt;p&gt;Not a list. Something closer to: here are the records, here is the conflict they belong to, here is which one governs and under whose authority, and here is what was decided the last time this same conflict came up.&lt;/p&gt;

&lt;p&gt;We do not ship that. In a personal domain, what we ship today decides admission with a novelty check against the nearest existing memory, which is not trust and not importance, and which has a failure mode we document publicly: a correction is phrased almost exactly like the thing it corrects, so it scores as a near duplicate, so it is the input most likely to be rejected. The stale record then survives as the only one on that subject and looks more authoritative than it did before anyone tried to fix it.&lt;/p&gt;

&lt;p&gt;I would rather write that down than describe a nicer engine than the one we have. The three checks I would run against any memory vendor, us included, are still the cheap ones: store a fact, contradict it, and list everything the system holds on that subject; submit a correction phrased like the original and see whether it survives; and ask what the response can express beyond a score.&lt;/p&gt;

&lt;p&gt;Ken's piece takes the same problem from the interface end and is worth reading alongside this one. Between us the argument is roughly complete: the store can know more than the response is able to say, and the part it does not know is what anyone did about it.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Disclosure: I work on &lt;a href="https://mnemoverse.com" rel="noopener noreferrer"&gt;Mnemoverse&lt;/a&gt;, a memory engine for AI agents connected over MCP. The failures described here as ours are documented in our own changelog rather than discovered for this article. Every argument credited above arrived in the comments of &lt;a href="https://dev.to/izgorodin/your-agent-doesnt-need-more-memory-it-needs-to-know-what-its-allowed-to-believe-22j7"&gt;the previous piece&lt;/a&gt;, which is a better advertisement for writing honestly about your own defects than anything I could say here.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>agents</category>
      <category>architecture</category>
      <category>llm</category>
    </item>
  </channel>
</rss>
