Agent memory that
never lies.
When an agent learns something, the JSON row, its embedding and the lineage edge back to the session that produced it commit in one atomic write. The next turn reads exactly that state — never a vector without its row, never a fact without its source.
> POST /v1/tenants/:t/rows/agent_memory
> { "note": "user prefers weekly digests",
> "embedding": […], "session": "s_84" }
committed atomically
row agent_memory/m_812 ✓
vector hnsw entry ✓
edge session ↔ memory (both) ✓
the next turn reads all three — or none Under-informed agents fail in production.
The model is rarely the problem — the context is. When an agent's memory is scattered across a vector store, a graph store and a database that drift out of step, even a great model gives confident, wrong answers. Four ways scattered memory rots:
Memory rows in one store, embeddings in another, relationships in a third. The agent stitches them at request time — and the stitching is where the bugs live.
The vector index lags the row it points at. The agent retrieves an embedding of a fact that has since changed, and reasons over yesterday's truth.
Every hop to a separate system adds latency — and agents fail when retrieval misses the window a tool call gives it.
Without durable, queryable memory, agents relearn the same context every session instead of compounding it.
The fact, its embedding, its lineage. One transaction.
An agent observes something, embeds it, and links it to the entities it touches. With separate stores that is three writes and a consistency problem. On one substrate it is one write: the row, the HNSW entry, the full-text postings and the graph edges land on the same write-ahead log in a single append.
Read-your-writes holds the moment the commit returns. There is no window where the embedding exists but the row it describes doesn't — the agent's view is internally consistent at every instant, by construction, not by best-effort reconciliation.
> the turn after the commit, every path agrees
memory row agent_memory/m_812 present
vector index hnsw entry present
lineage edge session ↔ memory present, both directions
structurally impossible: a vector pointing at
a row that no longer matches Four ways back to the same memory.
Because every shape sits on one store, the agent retrieves by whichever path fits the question — semantic nearness, exact keywords, both fused, or a walk along lineage — and every path resolves to the same committed row. Fresh operational state stays queryable in full SQL beside it.
Embed the situation, retrieve the memories nearest to it — recall that compounds across sessions.
VectorExact identifiers, error codes and names the embedding model never saw. Full-text catches what geometry misses.
Full-textVector and BM25 run in parallel and fuse by Reciprocal Rank Fusion — each catches the other's misses.
How fusion worksWalk from a memory back to the session, tool call or entity that produced it. Both directions are first-class.
Graph
Give the agent /ask and stop hand-writing four queries.
A tool-style question becomes a plan across SQL, vector, graph and full-text — planned by the cost model, executed by the engine, bounded by the bearer's entitlements. One tool definition covers every shape of retrieval.
The agent POSTs a plain-English question to /ask as a tool call — no query language embedded in the prompt, no per-shape client code.
"q": "what does this user prefer?" A foundation model drafts a structured plan from the question and your schema. The plan passes through the same cost model and the same security boundary as any other query — an /ask call cannot read data its bearer wasn't entitled to see.
same cost model · same boundary The engine executes the plan and streams rows grounded in your actual data. Add ?explain=true and the exact query the plan ran comes back with it — auditable, turn after turn.
?explain=true → the query > POST /v1/tenants/:t/ask
> { "q": "what does this user prefer for notifications?" }
plan compiled → same cost model, same security boundary
rows [{ "note": "user prefers weekly digests", … }]
> add ?explain=true → the exact query the plan ran The full flow — compilation, security boundary, bring-your-own LLM key — is on the /ask page.
Half-updated context is the bug you can't reproduce.
When memory spans separate stores, there is always a window where one is ahead of another — and an agent that retrieves inside that window acts on a state that never existed. Those runs are the "sometimes it hallucinates" reports a postmortem struggles to explain, because the inconsistent state is gone by the time anyone looks.
On one substrate that window does not exist. And because /watch streams every committed write the instant it lands — the new vector included — a supervising process observes the same consistent state the agent reads. Memory, retrieval and audit all describe one truth.
- 3+ systems behind one agent
- Sync pipeline + glue code
- Windows of cross-store drift
- Unreproducible bad turns
- 1 engine
- No pipeline to build
- Atomic — no drift window
- Every turn reads one truth