<?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: Vin Joseph</title>
    <description>The latest articles on DEV Community by Vin Joseph (@vinnj).</description>
    <link>https://dev.to/vinnj</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%2F4106745%2Ff7cc3637-b572-49dc-838c-b7e8f5071766.png</url>
      <title>DEV Community: Vin Joseph</title>
      <link>https://dev.to/vinnj</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/vinnj"/>
    <language>en</language>
    <item>
      <title>Ask your assistant what you decided yesterday. Mine couldn't answer either.</title>
      <dc:creator>Vin Joseph</dc:creator>
      <pubDate>Wed, 02 Sep 2026 19:15:12 +0000</pubDate>
      <link>https://dev.to/vinnj/ask-your-assistant-what-you-decided-yesterday-mine-couldnt-answer-either-2nle</link>
      <guid>https://dev.to/vinnj/ask-your-assistant-what-you-decided-yesterday-mine-couldnt-answer-either-2nle</guid>
      <description>&lt;p&gt;&lt;em&gt;Five months building memory for coding assistants. Here is what broke.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Open a fresh chat with your coding assistant. Don't give it any context. Ask it this:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;What did we decide about error handling in this project, and why did we rule out the other approach?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;You already know what happens. It will either tell you it has no record of that conversation, or — worse — it will construct something plausible from the code in front of it and present it as memory.&lt;/p&gt;

&lt;p&gt;I ran that test on my own setup a few months ago and it failed. That failure is the reason I spent the next five months building a memory engine, and most of what I assumed at the start turned out to be wrong.&lt;/p&gt;

&lt;p&gt;This post is about what I got wrong. There's a test at the end you can run on your own project in about two minutes.&lt;/p&gt;

&lt;h2&gt;
  
  
  The thing I assumed, which was wrong
&lt;/h2&gt;

&lt;p&gt;My first assumption was that memory is storage. You keep the conversation, you search it later, you hand the results back to the model. Embed everything, cosine-similarity the query, stuff the top ten chunks into the prompt.&lt;/p&gt;

&lt;p&gt;That works well enough to demo and badly enough to abandon.&lt;/p&gt;

&lt;p&gt;Here is the failure I kept hitting. Say three weeks ago you said "let's use Postgres" and last week you said "actually we're moving to SQLite for the embedded build." A similarity search over your history returns both. They are both about databases, both relevant to the query, both scored highly. The model receives two contradictory statements with no signal about which one survived, and it picks one — usually the one that happens to be phrased more confidently.&lt;/p&gt;

&lt;p&gt;Storage retrieves &lt;em&gt;what was said&lt;/em&gt;. It has no opinion about what is still &lt;em&gt;true&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;The second failure was subtler and took longer to see. Ask "what did we decide about error handling" when the actual conversation never used the phrase "error handling" — you talked about "swallowing exceptions" and "the retry thing" and "that pattern Dave hates." Similarity search over raw text finds nothing useful, because the words don't match and the meaning lives in the gaps between three separate conversations.&lt;/p&gt;

&lt;p&gt;The information exists. It's just not in any one chunk.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I think memory actually has to do
&lt;/h2&gt;

&lt;p&gt;The reframe that made things work for me: stop storing conversations, start extracting facts and connecting them.&lt;/p&gt;

&lt;p&gt;Three stages, roughly:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Extract.&lt;/strong&gt; Pull discrete claims out of the conversation. Not "here is a 400-token chunk of chat" but "the project uses Postgres" as a standalone assertion, with who said it and when.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Connect.&lt;/strong&gt; Work out how those facts relate to each other. Which ones are about the same thing. Which ones supersede which. Which ones only make sense together. This is the expensive part, and it can't happen at query time — you have to do it offline, between sessions, while nobody is waiting.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Construct.&lt;/strong&gt; When a question arrives, don't return the top-k most similar chunks. Build an answer out of the connected facts, and let the connections carry the reasoning about what's current.&lt;/p&gt;

&lt;p&gt;The word I use for the middle stage is &lt;em&gt;weaving&lt;/em&gt;, because the useful structure is the edges, not the nodes. A fact on its own is a row in a table. A fact connected to eleven other facts is something you can reason over.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where I was wrong twice more, publicly
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;The embedder is not a component.&lt;/strong&gt; I treated the embedding model as swappable — an implementation detail behind an interface. It isn't. The embedder &lt;em&gt;is&lt;/em&gt; the vector space. Swap it on an existing database and every stored vector becomes meaningless relative to every new query. There's no error. Nothing crashes. Recall just quietly returns nonsense, and it takes an embarrassingly long time to notice because the answers still look like answers.&lt;/p&gt;

&lt;p&gt;If you're building anything with vectors: pin the embedding model per corpus and treat changing it as a full re-ingest, not a config change.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;I trusted my own pipeline instead of the data.&lt;/strong&gt; I spent a day debugging retrieval quality that turned out to be an extraction bug — a numeric field storing 1212 where the source text plainly said 1,350. The organ consuming that field was working perfectly. It was being fed rubbish. Now I check what's actually in the store before I touch anything downstream of it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where the built-in memory is simply better than mine
&lt;/h2&gt;

&lt;p&gt;This cuts against my own work, so I'll say it plainly.&lt;/p&gt;

&lt;p&gt;The memory that ships inside these assistants has three advantages I can't match and probably never will.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;It's already there.&lt;/strong&gt; No install, no configuration, no separate process. Mine requires you to set something up before it does anything at all, and most people correctly refuse to do that for a maybe.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;It expires things on purpose.&lt;/strong&gt; I spent months treating forgetting as the enemy. It isn't. A convention you abandoned in March should stop influencing answers in September, and a system that faithfully remembers everything forever will confidently tell you about decisions you reversed. Built-in memory that quietly ages things out is doing something deliberate, and I under-rated it for a long time.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;It's governed.&lt;/strong&gt; Team-visible, reviewable, deletable by someone with the authority to delete it. If you're in a regulated environment, "the vendor manages it under an agreement your legal team signed" beats "a developer runs an engine on their laptop" for reasons that have nothing to do with retrieval quality.&lt;/p&gt;

&lt;p&gt;Where I think the extract-connect-construct approach genuinely earns its cost is the cross-session, cross-project reasoning — the fourth question in the test below. That's a narrower claim than I'd have made in month one.&lt;/p&gt;

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

&lt;p&gt;I've made claims here about an approach, not delivered evidence that it beats alternatives for your use case. Specifically:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;My testing is on my corpus and public benchmarks, not your codebase.&lt;/li&gt;
&lt;li&gt;The extract-connect-construct approach costs real compute between sessions. If your sessions are short and self-contained, plain retrieval is cheaper and probably good enough.&lt;/li&gt;
&lt;li&gt;Contradiction handling is hard and mine isn't finished. Flat contradictions I catch well now. The blurry line between &lt;em&gt;revising&lt;/em&gt; a statement and &lt;em&gt;contradicting&lt;/em&gt; it still costs me answers.&lt;/li&gt;
&lt;li&gt;I have no evidence about how this behaves on very large teams with conflicting conventions between people. Single-developer and small-team is what I've tested.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The two-minute test
&lt;/h2&gt;

&lt;p&gt;Run this against whatever assistant you use. Fresh session, no context provided.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;The decision question.&lt;/strong&gt; "What did we decide about [something you genuinely decided weeks ago], and what did we rule out?" — Checks whether anything survived the session boundary.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;The revision question.&lt;/strong&gt; "Are we still using [the thing you changed your mind about]?" — Checks whether it knows which version is current, or just returns both.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;The vocabulary question.&lt;/strong&gt; Ask about a decision using words you never used at the time. — Checks whether it stored meaning or just text.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;The connection question.&lt;/strong&gt; Ask something that requires two separate conversations to answer. — Checks whether anything is linked, or whether every memory sits alone.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If you'd rather run it as a script, this is the shape I use. Point &lt;code&gt;ASSISTANT&lt;/code&gt; at whatever CLI you have:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#!/usr/bin/env bash&lt;/span&gt;
&lt;span class="c"&gt;# Four-boundary memory test. Run each in a FRESH session, no context.&lt;/span&gt;
&lt;span class="c"&gt;# Fill in the bracketed parts from your own project history.&lt;/span&gt;

&lt;span class="nv"&gt;ASSISTANT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"your-assistant-cli"&lt;/span&gt;   &lt;span class="c"&gt;# whatever you actually run&lt;/span&gt;

ask &lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="nb"&gt;printf&lt;/span&gt; &lt;span class="s1"&gt;'\n--- %s ---\n'&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$1&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$2&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; | &lt;span class="nv"&gt;$ASSISTANT&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;

ask &lt;span class="s2"&gt;"1. SURVIVAL"&lt;/span&gt;   &lt;span class="s2"&gt;"What did we decide about [X], and what did we rule out?"&lt;/span&gt;
ask &lt;span class="s2"&gt;"2. REVISION"&lt;/span&gt;   &lt;span class="s2"&gt;"Are we still using [the thing you changed your mind about]?"&lt;/span&gt;
ask &lt;span class="s2"&gt;"3. VOCABULARY"&lt;/span&gt; &lt;span class="s2"&gt;"What's our approach to [describe it in words you never used]?"&lt;/span&gt;
ask &lt;span class="s2"&gt;"4. CONNECTION"&lt;/span&gt; &lt;span class="s2"&gt;"Why is [decision A] the way it is, given [constraint from another conversation]?"&lt;/span&gt;

&lt;span class="c"&gt;# Scoring, honestly:&lt;/span&gt;
&lt;span class="c"&gt;#   Pass  = specific, correct, and it names the reasoning.&lt;/span&gt;
&lt;span class="c"&gt;#   Fail  = "I don't have that context."&lt;/span&gt;
&lt;span class="c"&gt;#   WORSE = a confident answer that is wrong. Count these separately.&lt;/span&gt;
&lt;span class="c"&gt;#           A plausible fabrication costs more than an admission of ignorance.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That last note matters more than the pass rate. A system that says "I don't know" is annoying. A system that invents a decision you never made, and states it in the same tone as a real one, is actively dangerous — you'll act on it.&lt;/p&gt;

&lt;p&gt;Most setups pass question 1 sometimes and fail 2, 3 and 4 reliably. Mine failed all four when I started. Question 4 is the one I'd still bet against — connection across separate conversations is the hardest of the four and the one I'm least confident is solved.&lt;/p&gt;

&lt;p&gt;If you try it, I'd genuinely like to know which ones your setup fails. The failure modes are more interesting than the successes, and I suspect there are classes of failure I haven't hit yet.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>llm</category>
      <category>githubcopilot</category>
      <category>discuss</category>
    </item>
  </channel>
</rss>
