Why no separate vector database
Filter-first, not vector-first. Agent-memory retrieval is filter-first over a temporal tree. Scope hashes, time windows, and typed filters narrow the candidate set before any similarity math runs, which inverts the usual vector-database pipeline where an approximate-nearest-neighbor (ANN) index is the primary lookup and metadata filtering is a post-filter applied to whatever the index happened to return. That ordering matters: the questions agents actually ask — “what happened in this session,” “which tool calls in the last hour,” “what did I decide and when” — are answered exactly by scope and time, not by embedding proximity. Because the candidate set is already small and correct by construction, similarity ranking, when you want it, runs over tens of rows rather than the whole corpus.
Time-validity and supersession are things ANN cannot express. A fact carries a valid-time window, and a later write can supersede an earlier one, so retrieval returns what was true at the asked-about time and drops what has been overwritten. A pure ANN index has no notion of this — it returns whatever is geometrically nearest, which routinely means stale, superseded, or out-of-scope chunks that are merely “near” in embedding space. That is the failure mode behind wrong answers on knowledge-update and temporal-reasoning questions: the nearest chunk is often the outdated one, and a similarity index has no way to know it was replaced.
What skipping the vector DB actually saves. No standalone vector service to deploy, shard, back up, and pay for; no re-embedding and index-rebuild churn every time memory changes; no dual-write consistency problem to keep the store and the index in sync; and no cross-session leakage from chunks that are “near” in embedding space but belong to another session or another point in time. Semantic vector recall stays available as an optional add-on layered on top of the temporal filter — the right tool for genuinely fuzzy “find me something like this” recall — but it is not the primary index, so you run it only where it earns its cost, over an already-narrowed candidate set.
Why not RocksDB — much lower write amplification, not zero
What an LSM tree costs. RocksDB-style LSM trees rewrite SSTables during compaction: each logical write is physically re-written several times as data is merged down the levels — a write-amplification factor of many× — and background compaction periodically competes with foreground traffic for I/O, producing compaction stalls that surface as tail-latency spikes. High-write temporal workloads — event streams, tool traces, velocity counters, session logs — are exactly the access pattern that punishes that design.
What append-structured storage does instead. Values are packed into blocks, blocks are appended into bands, and bands are written into slab files; live data is never rewritten in place, and obsolete data is reclaimed by background garbage collection that drops whole regions once they fall below a liveness ratio — not by merging and re-sorting live rows. That removes the biggest LSM cost: the repeated re-write of data that has not changed, and the multi-level re-sort on the write path.
The honest bound: reduced a lot, not to zero. Append-structured storage greatly reduces write amplification — it does not eliminate it. Each write still pays for the WAL record, the packed block, and index updates, and background GC rewrites the surviving data when it reclaims a sparse region. The win is structural rather than absolute: there is no multiplicative LSM re-write of unchanged live data, and reclamation runs off the hot path — so you avoid both the many× write cost and the compaction-stall tail latency, while writes stay sequential and the WAL remains the single durable path. If you want the exact durability/throughput trade, that is the sync vs async storage dial above.
Model-aware, not opaque blobs
Because the executors run next to the data, callers do not re-implement temporal math on top of a KV value, and the store does not ship whole histories over the wire just to have the client throw most of it away. Windows, filters, distinct, and sequence logic run at the shard, so a read carries temporal semantics rather than returning an opaque blob for the client to re-process — one serving path replaces the usual stack of a stream job, a bespoke cache layout, and a repair pipeline per feature. See the data models — Context, Long Sequence Features, Aggregated Features, and Control State — for what each executor computes at read time.