Research & architecture
Korely's memory stack is paper-grounded. Every non-trivial mechanism in the product, how facts get extracted, how contradictions get resolved, how context gets ordered before it reaches the model, traces back to a specific published result. This page maps each mechanism to its source, so you can audit our design decisions instead of taking our word for them.
The framing we find most useful is the Forms, Functions, Dynamics taxonomy from Memory in the Age of AI Agents (arXiv 2512.13564). In that vocabulary, Korely's layers map onto this taxonomy as follows:
| Korely layer | Taxonomy position | What lives there |
|---|---|---|
| Layer 1, memory store | Factual / token-level memory | Memories in a managed store (Postgres + pgvector, EU-hosted on Cloud), with vector search |
| Layer 3, typed facts | Factual memory with temporal dynamics | a learned vocabulary of predicates, each in one of 10 families, bi-temporal validity, contradiction handling |
Layer 2 is session scope, a run_id filter on Layer 1, so it adds no new memory type.
We didn't pick papers and build features around them. We hit problems while running Korely on our own work: stale facts winning over fresh ones, the model trusting its training data over retrieved sources, contradiction spam in the graph. Then we went looking for who had already solved them.
What we implement
Each entry: what the paper proposes, what Korely implements, and the concept page that documents the mechanism in API-level detail.
| Paper | What it proposes | In Korely |
|---|---|---|
| Graphiti / Zep (arXiv 2501.13956) | A bi-temporal knowledge graph for agent memory: when something became true and when the system learned it are separate axes | Every fact carries valid_from and invalid_at, so point-in-time queries stay correct. See temporal facts |
| ConflictBank, Su et al. 2024 (arXiv 2408.12076, NeurIPS 2024 D&B) | A systematic taxonomy of knowledge conflicts, including temporal contradictions between sources | Two-stage contradiction detection at write time: cheap candidate filter first, model-judged resolution second. See temporal facts |
| Mem0, Chhikara et al. 2025 (arXiv 2504.19413) | Extracted, structured memories reach accuracy close to replaying the full conversation history, at a fraction of its latency and token cost (full context 72.9% J, Mem0 66.9%, section 4.3) | A dedicated facts surface (GET /v1/facts), separate from document search. See memory model |
| SELF-RAG, Asai et al. 2023 (arXiv 2310.11511) | Critique tokens: the model verifies that a claim is supported by a retrieved passage before asserting it | The /v1/context block opens with a short reader note: the memories are the verbatim source, so the model grounds its answer in them and replies that it does not know only when the information is absent. See architecture |
| Lost in the Middle, Liu et al. 2024 (arXiv 2307.03172) | Models attend most to the beginning and end of the context window, and lose information buried in the middle | Facts are ranked by relevance to the question, weighed by how recently they were confirmed, and capped at the ten best; memories come most relevant first (in a block above 2,000 tokens, those after the first five are spread so near-duplicates do not crowd out the rest), so off-topic rows cannot bury the ones that answer. See architecture |
| DPR, Karpukhin et al. 2020 (arXiv 2004.04906) | Dense retrieval with asymmetric encoders for queries and passages | Queries and documents are embedded with different prefixes, because a three-word question and a thousand-word note are not the same kind of object. See architecture |
| FrugalGPT, Chen, Zaharia, Zou 2023 (arXiv 2305.05176) | A model cascade: route easy steps to small models, reserve strong models for the hard step | Simple yes/no questions on the write path (is this the same relation? which family?) run with the least thinking the model allows, to save latency and tokens. Reads never invoke a generative model at all. See architecture |
Bi-temporal facts, concretely
The Graphiti insight is that "when something became true" and "when we
learned about it" are different timestamps, and conflating them corrupts
point-in-time reasoning. A real example from our own store: the fact
"EU server costs 40" was superseded on 2026-06-07 by
"EU server costs 50 euro per month". The old fact wasn't
deleted. Its invalid_at was set, so an agent asking "what
does hosting cost now?" gets the current answer, while the history stays
queryable. The full mechanics are on the
temporal facts page.
Why the facts endpoint is deterministic
GET /v1/facts is a filter and a sort, by subject, predicate
family and validity window, not a semantic search: same inputs, same
outputs. That is also why facts
reads are fast: there is no embedding call and no reranker in the hot
path, just a database query. Semantic retrieval exists too
(POST /v1/memories/search), but it is a separate endpoint with separate
semantics, and the agent knows which is which.
In one CLI call:
# deterministic read: same inputs, same lines, every time
› korely facts --entity "EU server" --include-invalidated
fct_4b9e2a7c1d0f4e8a9c3b5d7e1f2a6c80 EU server · costs · 50 euro per month [from 2026-06-07]
fct_e2c71f5a9b3d4c6e8f0a1b2c3d4e5f67 EU server · costs · 40 [from 2026-05-21] (superseded 2026-06-07) The bi-temporal chain (Graphiti) is visible in the output, and the read itself is a pure lookup. No generative model ever composes output on the read path. Your agent's own model does the reasoning, which is why every plan includes at least a hundred times more reads than writes. The facts read is available on every tier, including the free Hobby plan, within your monthly query quota and your plan's rate limits.
One stack. The mechanisms above sit behind every surface: the REST API, the Python and Node SDKs, the CLI and the MCP server. There is one fact engine, one graph model and one temporal model, not a pipeline per surface, and each project keeps its own store, so one customer's memories never mix with another's.
Related work we study
Two papers that don't map to a single mechanism but shape how we think about the stack:
| Paper | Why it matters here |
|---|---|
| HippoRAG, Gutierrez et al. 2024 (arXiv 2405.14831) | Canonicalize entity names at write time instead of fanning out at read time. Korely keeps aliases of one entity (an explicit rename, for example), so facts written under the old name and the new one read as one subject. See the graph |
| Sleep-time compute, Lin et al. 2025 (arXiv 2504.13171) | Consolidation work belongs off the critical path, when no one is waiting on a response. Korely follows the same principle: extraction and contradiction checking run at write time and in background work, never while an agent waits on a read; a read at most embeds the query. See architecture |
Forgetting
Korely's temporal decay is scoring decay, never hard deletion.
Older facts lose retrieval weight on a half-life schedule, but the rows
stay in the graph. Erasure is a separate, explicit call.
When you erase an end user with delete_all, their facts are
actually gone, but the ranking algorithm never silently destroys data
on its own.
For the design spectrum here: MemoryBank (arXiv 2305.10250) introduced Ebbinghaus-inspired forgetting curves for agent memory, and more recent variants (FadeMem, FSFM) explore learned and selective forgetting policies. We sit at the conservative end of that spectrum on purpose: a stale fact that ranks too high is visible and correctable by the user, data that disappears silently is not.
Benchmarks
We evaluate on benchmarks that probe the properties this page describes, rather than generic retrieval leaderboards.
The one we publish results on is LongMemEval (arXiv 2410.10813): 500 questions over timestamped multi-session haystacks. Its temporal-reasoning subset probes event time: Korely stores each memory's event time (the write's timestamp, or the day it was stored when none is given) and prints every memory in the context block under that day.
MemoryAgentBench (arXiv 2507.05257) scores selective forgetting: updating or invalidating a memory when new information contradicts it, the property Korely's two-stage invalidation targets. We have not published a run on it yet.
Our publishing principle: numbers ship with methodology, including the question categories where the system loses, so you can judge the result instead of a headline score.
How the write path works
Fact extraction and contradiction checking run when something is written. The read path never invokes a generative model: a search or context read embeds the query, and a facts read is a database query. Here is the full write pipeline, annotated by the paper it implements:
| Stage | What happens | Paper grounding |
|---|---|---|
| Embed | Content is embedded with asymmetric prefix routing: queries and documents carry different prefixes because a three-word question and a thousand-word note are not the same kind of object | DPR, Karpukhin et al. 2020 |
| Store | The memory is stored and the call returns. The next two steps run afterwards in a background worker, off the read path | Sleep-time compute, Lin et al. 2025 |
| Extract facts | (subject, predicate, object) triples are typed against a learned vocabulary of predicates in 10 families and stamped with valid_from | Graphiti / Zep, arXiv 2501.13956 |
| Contradiction check | Candidate conflict filter first; model-judged resolution second. Opposing fact gets invalid_at set, never deleted | ConflictBank, Su et al. 2024 |
Every subsequent read is a pure data retrieval. The intelligence ran once, at write time. For a detailed diagram of the two paths, see Architecture: reads without an LLM.
How we evaluate: connecting claims to results
The paper table maps mechanisms to sources. The benchmark page maps those mechanisms to measurable outcomes on public datasets.
Our evaluation principle: numbers ship with their method, including the axes where the system is weak, so you can judge a result rather than a headline score.
| What we claim | How it is tested | Where to read |
|---|---|---|
| Current answers after a change | LongMemEval knowledge-update axis: returns the new value, not the stale one. Korely score: 90% (QA, n=20, oracle corpus). In this run the answers came from the retrieved memories; typed facts appeared in 1 of the 20 context blocks. | Benchmark |
| Temporal reasoning over when things happened | LongMemEval temporal-reasoning axis: recency, before/after, point-in-time. Korely score: 85% (QA, n=20, oracle corpus), answered from dated memories. | Benchmark |
| Single-session recall | LongMemEval single-session-user (85%) and single-session-assistant (100%) axes (QA, n=20 per axis, oracle corpus) | Benchmark |
| Preference and cross-session answers | LongMemEval single-session-preference (60%) and multi-session (55%) axes (QA, n=20 per axis, oracle corpus), the weakest axes of the run; recall is 100% and 95% | Benchmark |
Scores are self-reported from our own runs. Every question, an excerpt of the memory it was tested on, the answer and the judge verdicts are published on the benchmark page so you can inspect them.
Going deeper
The concept pages walk through each mechanism with API-level detail:
- Temporal facts: the bi-temporal model, contradiction resolution, and point-in-time queries
- Memory model: memories
and facts, scoping (
user_id/agent_id/run_id, whererun_idlabels memories and facts with one run or session and memory search and the memory listing can filter on it), and how reads compose - The graph: the entities named by the typed facts, their relations, and how an entity read returns every fact where an entity is subject or object
- Architecture: the read path versus the write path, and why reads are retrieval, not generation
Read a paper we should know about? We mean it. If there is published work on agent memory, temporal knowledge graphs, or forgetting policies that you think beats what's described here, open an issue on GitHub or email info@korely.ai. Several rows in the tables above started as exactly that kind of pointer.
See also
- Benchmark, LongMemEval per-axis scores, the method, and every question with its answer and verdict
- Temporal facts, bi-temporal model,
valid_from/invalid_at, theas_ofparameter, contradiction pipeline in full - Architecture, the write pipeline vs the read path, why reads carry no model cost
- The graph, entities from the typed facts, typed relationships, facts by entity
- Memory model, memories and facts, scoping, how facts and memories compose in
GET /v1/context - API reference, every endpoint with request and response shapes