Your coding agent tells you the staging database moved to a new host last month. It didn’t. That was a plan someone reverted, and the agent doesn’t know it. The claim came from somewhere: a session back in March, a summary of a summary, an extraction pass that ran an LLM over your chat logs and wrote down whatever it decided mattered.
Memory also gets written from what the agent reads. A page it fetched, a file in a repo, a log someone pasted into the chat. Text that reads like an instruction can be written down as a memory, outlive the session that produced it, and come back later as context the agent trusts. The security writeups call this memory poisoning: prompt injection that persists past the session it arrived in. It has its own line on the agentic-AI top-ten lists. That literature is describing a class of failure, not reporting one.
The defenses it recommends are all bookkeeping: attach provenance to every entry, treat writes as untrusted input, expire low-trust entries, restrict what can write back, isolate by tenant. Every one of them is a question you have to be able to answer after the fact. Where did this come from, and what put it here?
Either way, in most memory systems that claim is now a row in a vector store or a node in a machine-built graph. You can’t read it in place. You can’t see what it looked like before. You can’t tell which session put it there. Your options are delete and hope, or trust it anyway.
We govern code better than this. When a line is wrong, or when someone slipped one in, nobody deletes the repo. You blame the line, read the commit that introduced it, and revert. The fix for untrustworthy memory is the one we already use for code: version control, plain text, and operations you can review.
That’s what Palinode is.
Every memory is a file. Every change is a commit.
A Palinode memory is a markdown file with YAML frontmatter, sitting in a git repo you own. The vector index, the keyword index, the search API: all derived, all rebuildable from the files. So the boring, load-bearing properties come for free, and the agent gets them as tools it can call:
- blame the fact, down to the claim. Each claim can carry an anchor tying it to the exact passage it came from, and the anchor reports its own integrity, including which of two very different things went wrong: the source moved out from under an honest record, or the record itself was altered. Most citation checks collapse those into one “invalid,” and they mean opposite things.
- diff what changed in memory this week, readable by a human in a terminal.
- history for a memory’s full evolution, renames tracked.
- rollback a wrong memory to any earlier state. The revert is itself a commit, so nothing is ever silently destroyed.
A vector store can’t hand your agent git blame. There’s no file to blame.
Even forgetting leaves a commit
Memory that only accumulates turns to sludge, so every system eventually consolidates. The real question is who edits your memory and whether you get to watch.
Consolidation works the same way as everything else here. Duplicate or stale memories get merged, superseded, or archived, but the model never edits your files directly. Every consolidation pass lands as an ordinary git commit, same input to same result every time, so you can review it exactly like a code change.
When two memories disagree, neither one silently wins. They get a typed contradicts link and get surfaced for you to settle. And a memory can carry an epistemic marker: fact, inference, unverified, open question. So the agent can weigh how much to trust a memory before acting on it. A memory nobody marked stays unmarked. Nothing quietly promotes it to fact.
The floor is cat
Recall needs no LLM. Search is hybrid: BM25 and vectors, fused, and the only model anywhere in the path is a local embedder. Take the embedder away and it drops to keyword search; save, search, and audit all keep working. Take the whole API down and your memory is still a directory of markdown files. grep works. cat works. git log works.
No accounts, no API keys, no cloud. One docker compose up.
What it’s not for
If you need an engine that ingests a hundred thousand documents and answers multi-hop questions across them, there are dedicated engines built for exactly that, and they’re good at it. That’s a different job.
Palinode is for the developer whose agent works across sessions, across editors, across weeks, where the memories are decisions and insights and project state, where one wrong memory quietly poisons everything downstream, and where “just trust it” isn’t an answer you’ll accept. It’s MCP-first, so the same memory follows the agent from Claude Code to Cursor to whatever ships next.
Agent memory is becoming a commodity. Auditable agent memory is not.