The usual approach: append everything, every turn
The typical way to give an agent memory is the simplest one: on each new turn, append all of the prior context — the earlier prompts and the model's own intermittent output — back into the next input window, and send it again.
It works, so it ships. But it has two quiet problems.
Most of what you re-send is noise. A lot of that appended history — especially the intermittent output: tool results, logs, stack traces, file dumps — was useful for a single step and then just sits in the window, re-sent every turn, diluting the signal the model actually needs now. You pay for it on every call, and it crowds out the few lines that matter.
And nothing is learned. It's all trapped in one session — there's no cross-session memory, and no long-term profile that gets better as the history deepens. The agent never accumulates what it figured out about the user, the project, or the decisions already made; when the window rolls or the session ends, it starts from zero.
So you pay more (re-sending a growing, noisy transcript) and remember less (nothing survives the session). That's the trap.
The "solution" that becomes its own stack
So you add retrieval. Reasonable instinct. But watch what "agent memory" quietly turns into in production:
- a vector database to store, version, and semantically search the embeddings,
- a summarization / extraction pipeline to compress old turns into something retrievable,
- and a memory service to glue it together, decide scope, and rank — usually a bespoke one.
Three systems, and you're still replaying transcripts on the side. Three things to run, monitor, and keep consistent — all to answer one small question on every turn: what does this agent actually need in front of it right now?
The bet behind TemporalStore is that agent memory is one temporal problem — and deserves one temporal engine, not a stitched-together stack.
It's open source (Apache-2.0), Rust-native, runs from a single Docker command, and ships with reproducible benchmarks instead of adjectives. Here's how it works, and why the numbers land.
The core idea: send a ContextPack, not a transcript
The design draws one clean line. Your model reasons and extracts; the engine remembers and serves.
# the flow — you own the model, TemporalStore owns the memory raw query / event / resource + hints → extract intent, time, filters, entities (your runtime, or MatrixArk) → store compact serving records (TemporalStore) → retrieve a token-budgeted ContextPack (TemporalStore) → final LLM = local context + ContextPack → the answer becomes tomorrow's memory
Notice what TemporalStore doesn't do: it never calls an LLM or an embedding model. Your harness — or a managed runtime like MatrixArk (matrixark.ai) that sits on top — produces the vectors and structured intent. TemporalStore stores them and does the fast, bounded work at serving time.
That work produces the whole point of the system: a compact, source-backed
ContextPack. Not a transcript — the few hundred tokens that actually matter for this
query, each traceable to the event that produced it.
And it denoises. Remember all that re-sent intermittent output? TemporalStore ingests it as compact records — the tool call kept as a short marker, the bulky result head-truncated or summarized — so the pack carries the fact the tool produced, not the noisy blob. Less noise in the window is itself better answers: the model isn't rummaging through stale logs to find the one line that mattered.
What you get, in one line each
The payoff up front — the mechanism behind each one is the rest of this piece:
- Fewer tokens at equal-or-better quality — a bounded ContextPack instead of a transcript that grows every turn.
- Better answers, less hallucination — time-valid memory with replayable, source-backed citations.
- Low serving latency across millions of entities — work bounded by the filtered candidate set, not the corpus.
- Exact recall, no vector DB — a controlled candidate set scored exactly; ANN's lossiness never enters the picture.
- Team-wide memory — cross-session, cross-device, cross-agent, and auditable by construction.
- One engine, self-hosted — Apache-2.0, one Docker command, no LSM write-amp on the append path.
Why a small pack beats "replay the newest N tokens"
This is the counterintuitive part, so let's prove it instead of asserting it.
Take a real working set: a developer's full local coding history, tool calls included — 12,384 events, 97 sessions, ~1.7M tokens. Ask six real questions about it. Run two arms through the same reader model and the same judge:
- Replay — feed the full local history, newest-first, up to the model's window.
- Managed — retrieve a token-budgeted
ContextPack.
| Metric | Full replay | TemporalStore pack | Result |
|---|---|---|---|
| Tokens the model works from | 1,698,940 | ~1,333 | 99.9% fewer |
| Answer quality (judge, 0–10) | 6.59 | 8.30 | +1.71 |
| Questions won or tied | — | 6 / 6 | every one |
Now the why, which is more interesting than the headline.
The pack wins by the widest margin on the questions whose answers live in old history —
q_storage 10.0 vs 6.05, q_parity 8.05 vs 5.25. It wins by the smallest margin
when the newest messages happened to already be on-topic.
That gradient is the mechanism, made visible: recency-truncated replay literally cannot see the old-but-relevant facts that ranked retrieval surfaces. You pay for 1.7M tokens and still get the worse answer.
And it holds up on the standard memory benchmarks. On LoCoMo and
LongMemEval_s — the two public long-term-memory suites the field measures agent recall
against — TemporalStore's tree-plus-index retrieval lands hit@k 0.995–1.00. And in a
head-to-head on one shared open-source stack (a qwen2.5:7b reader, MiniLM embeddings,
Claude-judged), it ties an OpenViking-style baseline — a reimplementation of
VikingMem, the memory system that reported state-of-the-art
in its own paper — on short LoCoMo chats (~83–84%) and
wins long-horizon LongMemEval outright — 98% vs 66% answer accuracy. So the token
savings above aren't bought with worse recall: the pack is small and it finds — and answers —
the right evidence.
Memory that's shared — not stuck in a session
Here's the differentiator that matters most for real teams, and it's easy to miss under the token math.
A transcript is trapped in one session. The moment the window rolls or the tab closes, it's gone. That's the true ceiling on agent memory — not how much you can stuff into one prompt, but whether anything survives between prompts, between agents, between people.
Because TemporalStore keeps memory in the engine — ingested once, indexed by scope
(tenant → user → session → agent → resource) — recall isn't bound to the current thread. An
agent can remember what another agent learned yesterday, what the user decided on a
different device, what the team agreed last month. And because every recalled fact is
timestamped and traceable to its source event, shared memory stays auditable — a citation,
not a rumor.
Cross-session, cross-device, cross-agent, cross-teammate — by construction. That's the memory a single-transcript retriever structurally cannot give you.
The serving innovation: a database's serving path, aimed at memory
Most "agent memory" libraries are a thin wrapper over a vector index. TemporalStore is built like a database — and that shows most in the serving path. Three roles, disaggregated:
- Proxy — the front door: routing, request batching, backpressure.
- Metaserver — placement, leases, the shard map. It decides where data lives; it's off the hot read path.
- Datanodes — the workers: a write-ahead log for durability, the model executors, the in-memory indexes that answer reads.
Retrieval is not a brute-force vector scan. Context is a tree — tenant → user → session → resource → entity. A query walks it layer by layer, using compact secondary indexes to prefilter before reading any timeline. Filters compose by intersecting posting lists — status ∩ project ∩ time-bucket — so a query touches a bounded set of events, not the whole corpus. Only then does it score, apply temporal decay, and pack to budget.
The payoff: latency stays low even across millions of entities, because the work per query scales with the filtered set, not the dataset. ContextPack retrieval runs ~17 ms p95 at a 1.2k-token budget.
The storage innovation: append-structured and temporal
Underneath is a storage engine built around one fact: memory is temporal. Data arrives in time order, is queried by time, and cools with age. That shapes every layer.
Append-structured. Writes append; nothing mutates in place, and the engine reloads crash-safe from its own write-ahead log. When the segmented log once re-parsed itself on every append (an O(n²) trap — append #200 took 100+ ms), a per-node cursor made it O(1): 109 ms → 2.2 ms, with the on-disk format byte-identical so live stores reload with zero migration.
Real tiering — eviction and promotion. Hot data sits in memory; as the working set outgrows the budget it's evicted down through cache to SSD and shared storage. The part most systems get wrong: cold data is promoted back into memory on read. A multi-user harness proves it — a deliberately tiny memory budget to force eviction, then cold reads to force promotion: 256k reads, zero mismatches, partition isolation intact, up to 81 users and 187k writes.
Compute/storage separation. The same code runs three ways — local (one node), Raft-replicated, or shared-storage — so you start on a laptop and scale to a disaggregated cluster where compute and storage grow independently, atop two self-contained Apache-2.0 libraries: MatrixCache (caching) and MatrixRaft (replication). For the shared-storage tier at scale, stateless datanodes read and write one durable object store — MatrixObject, the enterprise object store engineered for extreme-performance shared storage — so compute can scale for traffic spikes without copying every shard to every node.
Why no vector database
RAG usually runs on a vector DB doing approximate nearest-neighbor (ANN) search over a giant flat pile of embeddings — trading recall for speed, because scoring every vector exactly is too expensive. TemporalStore never gets there. Its layered virtual file system and compact secondary indexes filter most candidates out first — by scope, type, entity, and time — so by the time we rank, the set is small and we score it exactly, with no ANN loss (that's the hit@k 0.995–1.00 above). That same scoped tree doubles as a virtual file system for resources, skills, and memory — one time-aware namespace instead of a separate store for each — so it's also one fewer system to run and keep in sync.
Why no RocksDB (no LSM)
Temporal memory is append-heavy — you're constantly writing new timestamp-keyed events — which is exactly what an LSM like RocksDB handles worst: compaction keeps rewriting data it already wrote (write amplification), with tail-latency spikes and stop-the-world pauses. TemporalStore's KV is shaped for it: a key's value is a run of timestamp-keyed values appended in order, so an event is an append onto an existing value — not a flood of new keys to merge and re-sort. The result: far less write amplification than RocksDB, no compaction, no pauses.
Try it in two minutes
No Rust toolchain on your host — it builds inside the image:
git clone https://github.com/matrixarkai/TemporalStore.git cd TemporalStore docker compose -f docker-compose.single-node.yml up --build
You get a metaserver on 127.0.0.1:17101 and a datanode on :17102. Whole
dependency list: Docker and a clone.
Prototyping one session with a few docs? A plain vector index is fine — TemporalStore earns its place when memory has to persist across sessions, agents, and a team, stay sharp at millions of events, and stop you re-sending a growing transcript every turn.
Two invitations
🛠️ If you build on temporal data — come build with us.
Whether you want to serve your own temporal use cases on TemporalStore, layer a context system on top of it, or dig into the innovative Rust core — Raft replication, the multi-layer cache, and the append-structured storage engine — there's real, open work here. Apache-2.0, and small enough to actually get into.
⭐ Star & build on GitHub📉 If you run agents in production — cut this line-item.
A bounded, ranked ContextPack cuts context cost sharply while raising answer quality, and folds a stack of separate memory services into one self-hosted engine. It also gives agents team-wide, cross-session memory — every recalled fact traceable to its source, and no data ever leaves your boundary.
Pilot it on your workload →