4
15 Comments

My AI agent quoted a client a price we killed months ago. So I built Engram.

A few weeks back, one of my AI agents quoted a client a price we had retired months earlier. It wasn't a hallucination. The dead number was sitting right there in my notes, and the agent's search ranked it above the current one, because a retired price list uses the word "price" just as often as a live one.

That was the moment I stopped trusting bolt-on "agent memory" and built my own.

Engram is an open-source, self-hosted memory layer for AI agents. It's an MCP server plus a dashboard over a plain folder of markdown files. Your agents (Claude Code, Cursor, Codex, whatever speaks MCP) read and write notes through one endpoint, the files are the source of truth, and git is the database. No vector store, no black-box "memories" you can't read.

The core idea, and the thing I'd genuinely love feedback on, is what I call authority-aware search. Normal search ranks by how well text matches your query and has no notion of which note is still true. So Engram gives every note an authority from its folder and frontmatter (locked, current, superseded, archived) and ranks by relevance x authority. A superseded note sinks below the live one, and every search result tells the agent how much to trust it. That one change is what stopped my agents from quoting dead data.

A few other things that came out of running it with several agents at once:

  • Every write is committed to git, attributed to the exact agent or human who made it. The dashboard doubles as an audit trail with per-file diffs, so I can see what changed and roll it back.
  • Per-agent tokens are read-only or read-write. A teammate's agent gets a read token and physically cannot touch the vault.
  • It reads any existing Obsidian vault as is, and draws a knowledge graph.

It's MIT, one Docker container, deploys to Railway or Render or any box with a volume.

Repo (deploy buttons in the readme): https://github.com/rwnalds/engram

The closest tools I found are hypermnesic and basic-memory, both git-backed markdown memory. The difference with Engram is the dashboard, the authority ranking, and the per-agent access control, rather than a headless server.

I'm still early and figuring out whether the authority-ranking idea generalizes past my own vault. If you run agents that keep resurfacing stale context, I'd really like to hear where this holds up or breaks for you.

posted to Icon for group Developers
Developers
on July 11, 2026
  1. 1

    I like the idea of treating memory as authority based knowledge instead of just searchable text, cus 'current' and 'relevant' are treated as the same thing a lot when they really aren't.

  2. 2

    Authority-aware search generalizes, but the failure point won't be the ranking, it'll be the discipline of marking things superseded. In any team bigger than one, nobody maintains frontmatter, so the tools that win here will infer authority from signals like recency, supersede links, and contradictions between notes. What does Engram do today when two notes both claim current and disagree?

    1. 1

      Thanks for the question, and fair, that's the real weak spot.

      Today if two notes both say current and disagree, Engram does not pick a winner. Both surface, both tagged current, and the agent gets the authority of each plus the whole documents. The agent loop is told that a single-valued fact with two disagreeing sources is a vault defect, so it flags the conflict instead of quietly quoting one. Loud beats silently confident.

      You're right it leans on someone marking things superseded, and in a team nobody does. My bet: the agents doing the writing maintain the frontmatter, because the write tools enforce it (bad frontmatter is rejected, you archive instead of delete, you read a note before you can overwrite it). The discipline moves from humans to tooling.

      Contradiction detection I do not do yet, that's the real answer. It belongs at write time, not read time: capture already searches before it files, so that is where it can catch "this contradicts an authoritative note" and flag it. That is the next build probably, gathering a bit of feedback around here before I jump to any conclusions.

  3. 2

    the folder/frontmatter authority is a solid heuristic, and "git is the database, files are the truth" is the right call. the part i'd push on is that location-authority still can't see the one thing that actually went wrong in your price story: supersession. a retired price often lives in a perfectly legitimate note, sometimes the same note, so ranking by folder demotes low-authority junk but not a dead value sitting in a high-authority place.

    the failure isn't "this note is untrustworthy," it's "this value was retired and the retirement didn't demote it." so the robust version keys authority to the value, not just the note: when you kill a price, that act has to mark the old number superseded, so a later search can't surface it even if its note still scores high on "price." authority-by-location handles the easy half, the retirement event handles the half that bit you.

    we hit the identical wall building a local-first assistant, and the thing that generalizes is that "still true" can't be recovered from the text at read time, it has to be written on the supersession itself. cosine can't tell a contradiction from a duplicate. love that engram keeps it in readable files though, that's exactly where this belongs.

    1. 1

      Yeah, you've nailed the gap. Today Engram only does note-level supersession (archive or mark the whole note). A dead value inside a high-authority note still surfaces, which is exactly what bit me.

      Value-level is the thing to build. The retirement has to be recorded when it happens, like you said, since you can't recover "still true" from the text later. My plan is to make retiring a value a first-class write, so setting a new price marks the old one in the same act instead of adding a second note that also scores high on "price." Capture already searches before it files, so that's the place to catch the collision and turn an append into a supersession.

      Still open for me is where the marker lives: a struck value in place, a frontmatter edge, or a separate event log. They read and merge pretty differently under git. What did you use?

      1. 1

        We landed on the separate event log, and the deciding factor was exactly your "read and merge differently under git" instinct.

        Quick version of why the other two lost for us:

        Struck-in-place is the most readable and the worst under contention. It's a same-line edit, so the moment two writers (you plus an agent, or two agents) retire near each other you get a real merge conflict on the value itself, and the strike is prose, so retrieval still sees the old number and has to parse the intent back out. You've turned a data question into a text-diff question.

        Frontmatter edge is clean for note-level supersession and awkward for value-level. A dead value inside a live note wants a per-value key, and now the frontmatter is carrying a shadow copy of the body's structure. It also still writes the note file, so the write contention is still there, just moved to the top of the file.

        Separate append-only log: the retirement is an event, appended, keyed to the value. Two retirements append at different offsets so they don't line-conflict, and the note stays a clean human-readable current state. The log is the authority overlay, a value is live unless there's a later retire event for its key.

        The honest cost is the read-time fold: the note file literally still holds the old value, and the log is what tells retrieval it's dead, so you pay a merge-over-notes at read. We took that on purpose, because both "cheaper at read" options put the write back on the same line or file two writers fight over, and I'd rather pay a deterministic fold at read than eat an occasional silent lost retirement.

        The piece that makes "the marker lives elsewhere" actually safe: the retire event and the new value go in the same commit. Add-and-retire can't drift even though they live in different files. If they can land in separate commits the log stops being trustworthy and you're back to bookkeeping.

        Are you leaning log too, or does keeping it all inside the Obsidian file win for you on readability?

  4. 2

    Interesting idea, although I think this is more of an information architecture problem than an AI problem.

    A human could make exactly the same mistake if your notes are scattered everywhere and they happen to open an outdated document first.

    My Obsidian vault has canonical documents that are updated whenever prices or other important information change. If I need to keep something for historical purposes, it gets moved into an Archive folder that's only used when I'm intentionally looking for historical context. Current information has a single source of truth, so there's nothing for Claude or another agent to "choose" between.

    As someone who builds software, I've also built tools to solve pain points., but one thing I've learned is knowing when a problem needs a new system and when it just needs better organisation. To me, this feels like an organisation problem.

    1. 1

      Canonical doc + an archive folder + a single source of truth is exactly what Engram assumes. I built it on the same convention, so I'm not arguing against your setup.

      The difference is who maintains it. Yours works because you keep it clean. When a price changes you update the canonical doc, which is the retirement done by hand. That breaks down when the writer isn't you. Agents read and write too, and an agent won't inherit your filing habits, so it'll drop a new note next to the canonical one instead of updating it, and now there are two.

      So Engram is basically your setup, enforced by the tools so it holds when agents or teammates are writing, not just you. Solo and disciplined, you probably don't need it.

      If you're already running agents against your vault, have they stayed as clean as you keep it by hand?

  5. 2

    the read-side authority ranking is the easy 20% here. the part that decides whether this holds up is the write path: authority only saves you if something reliably flips the old price to superseded the moment you add the new one. if that flip is a human convention or a separate step, it gets skipped, and then authority-aware search confidently ranks a stale note as current again. the durable version is supersession as one atomic operation, the write that adds the new fact demotes its predecessor in the same commit, so add and retire can't drift apart. otherwise you've just moved the bug from retrieval to bookkeeping.

    smaller second point: for facts-of-record like price or contract terms, relevance x authority is still a soft demotion, and soft loses sometimes. a thin one-line live price note can get out-ranked by a verbose retired price list that matches the query better, penalty and all. for that specific class i'd hard-exclude superseded by default and only surface it when history is explicitly asked for, rather than trusting it to sink far enough.

    1. 1

      Both right, and the first is the one that keeps boggling me. Read-side authority is worthless if the flip to superseded is a separate step someone forgets. Atomic is the only version that holds up: the write that adds the new value demotes the old one in the same commit, so they can't drift. Otherwise the bug just moves from retrieval to bookkeeping, exactly like you said. Capture already searches before it files, so that's where add-and-retire becomes one write instead of two.

      On the second point, some of that already exists. Archived notes are hard-excluded from search by default today. Superseded is only soft-demoted, and you're right that soft loses against a verbose retired doc that matches the query better. For facts-of-record I should treat superseded like archived: hidden by default, shown only when history is asked for.

      Did you make the flip atomic in one commit, or reconcile after the fact?

  6. 2

    Treating authority as part of retrieval feels right. I would be careful about using folder location as the default authority signal, because the freshest commercial fact often lives in a working note while the polished doc is already stale. Requiring a current or superseded status, plus an expiry date for things like pricing, could make the failure visible before an agent sends it. The real test is whether an agent can explain which source it rejected and why.

    1. 1

      Good catch, it's actually a hole in what I have. Folder location is one of my two signals, and you're right it can point the wrong way. Worse, a doc marked "locked" keeps its authority even after it goes stale, so a blessed-but-old canonical doc out-ranks a fresh working note. The blessing doesn't expire. That's the bug.

      Expiry is the fix I hadn't considered. A price with a valid-until date flags itself the moment it's past, instead of waiting for someone to remember to mark it superseded. Staleness becomes visible without depending on discipline, which is the part that keeps failing.

      Really like your last line. The agent already gets the authority of every result, so it can say what it used, but I don't make it justify what it rejected. "Skipped the Q1 sheet because it expired" is a stronger guarantee than a silent ranking. Stealing that as the bar.

      Do you put the expiry on the fact or the note?

  7. 2

    I've hit the same failure with coding agents, they'll pull an old README or a doc for an API we changed months ago and treat it as equally true as the current one, because vector similarity has no concept of this used to be true. Ranking by authority instead of just recency or embedding distance is the right fix, recency alone breaks the moment someone re-saves an old doc and resets its timestamp. The part I like most is that changes are git backed, with diffs per file and rollback, because that means you can actually check what the agent's memory write changed instead of trusting a summary of it. That's the same reason I read every diff a coding agent produces rather than the commit message it writes for itself.

    1. 1

      Yeah, that's the exact failure. And you're right recency can't fix it, a re-save resets the timestamp and the dead doc looks newest again. A stated status beats a proxy you can trip by accident :)

      The diff point is the whole intent. An agent writing its own memory is like it writing its own commit message, you want the diff, not its summary. Engram tags each write with which agent made it too, so once several share a vault you see who changed what.

      Running multiple agents against one repo yet, or one at a time?

  8. 2

    What I like here is that you treated the failure as an interpretation problem rather than a retrieval problem.

    The agent already had the right information. It just couldn't distinguish between "historically true" and "currently true." That feels like a more fundamental issue than memory quality, and it's probably going to matter in a lot more agent workflows than pricing.

Trending on Indie Hackers
5 days post-launch: Top 50 on Product Hunt, zero signups, and why I think that's actually fine User Avatar 135 comments The feature you're most sure about is the one you should question first User Avatar 122 comments I built an AI fitness coach, then realized AI was only solving half my funnel User Avatar 73 comments 641 downloads, 2 sales, and I still don't know why User Avatar 51 comments I let 3 LLMs argue on the famous AI "Car wash: Walk or Drive" problem to prove a point. User Avatar 50 comments I built a macOS app to make mobile E2E testing less awful User Avatar 46 comments