For LLM backed applications, we were seeking to store durable knowledge as temporal, source-backed claims rather than raw text, making entity relationships, evidence, contradictions, and supersession inspectable and maintainable. Andrej Karpathy’s hyped LLM wiki suggested a compact, editable knowledge base that the model reads and updates over time.1 This may work for notes, preferences, and procedures but starts to fail when facts drift: people change roles, companies merge, claims are disputed, sources are corrected, and old statements remain phrased as current truth. Raw markdown or text is generally a weak substrate for facts that change over time. Text files lack enforced structure for identity, time, provenance, contradiction, and revision. Some agent systems deliberately use curated text files for persistent memory and a separate SQLite FTS index for session search, which is sensible for lightweight continuity but not equivalent to a structured factual memory store.2
For factual memory, we believe a better primitive is an attributed claim. Instead of storing a sentence like:
Company A owns Company B.
the system stores a claim with a subject, predicate, object, status, timestamps, confidence, and evidence:
Claim:
subject: Company A
predicate: owns
object: Company B
status: reported | confirmed | disputed | retracted | superseded
valid_from: when the relationship was true in the world
valid_until: when the relationship stopped being true, if known
observed_at: when the system learned this
confidence: optional confidence score
evidence: Source X, page 4, paragraph 2
This avoids flattening reported, disputed, confirmed, retracted, and superseded statements into the same textual layer. It also lets multiple incompatible claims coexist until they are resolved. Real knowledge often evolves through partial reports, denials, confirmations, corrections, and changes in validity. A memory system should represent that evolution rather than overwrite it with whichever sentence was most recently summarized.
A compact graph model is enough:
Entity = person, organization, place, law, topic, event, object
Alias = alternate name for an entity
Source = article, filing, interview, transcript, document, record
Evidence = exact excerpt, locator, page, paragraph, timestamp, quote
Claim = assertion linking an entity to another entity or value
The graph is then a ledger of assertions with provenance:
Source ──contains──> Evidence
Evidence ──supports──> Claim
Evidence ──contradicts──> Claim
Claim ──subject──> Entity
Claim ──object──> Entity or literal value
Claim ──supersedes──> Claim
Entity ──has_alias──> Alias
A relationship such as ownership is therefore not stored as an unquestioned edge:
Company A ──owns──> Company B
It is stored as a claim object:
Claim #123:
subject = Entity: Company A
predicate = "owns"
object = Entity: Company B
status = "reported"
source = Source: Registry filing
evidence = "Company A holds 62% of ordinary shares..."
valid_from = 2024-03-01
observed_at = 2024-04-10
This structure is interesting because contradictions are common:
Claim #123:
Company A owns Company B.
status = reported
Claim #124:
Company A sold Company B.
status = confirmed
supersedes = Claim #123
Claim #125:
Company A denies current ownership of Company B.
status = disputed
contradicts = Claim #123
In raw text memory, those statements may simply accumulate as prose. The agent later has to infer which one is current, which one was disputed, and which one had evidence. In a claim graph, that distinction is queryable.
Time should be first-class. At minimum, factual memory benefits from separating when something was true in the world from when the system learned it. This is often described as temporal or bi-temporal memory: valid time tracks the world, observation or transaction time tracks the memory system. Graph-based agent-memory research emphasizes graph structure because it can model dependencies, hierarchy, retrieval paths, and memory evolution more naturally than flat text.3
A practical record therefore carries both world-time and memory-time:
valid_from: 2024-03-01
valid_until: 2025-02-14
observed_at: 2025-02-20
This supports questions that text memory handles poorly:
What was believed as of June 1?
Which claims are currently active?
Which relationships existed during 2024?
Which claims changed after a new source appeared?
Which claims are contradicted but not yet resolved?
This approach also makes supersession maintainable. A new claim does not have to overwrite an old one. The older claim can be marked superseded, disputed, or retracted while remaining available for audit.
Operational view:
active, non-retracted claims
Audit view:
all claims, including disputed, superseded, and retracted claims
SQLite is a reasonable implementation substrate for this kind of local memory. It is embedded, single-file, transactional, and widely deployed.4 SQLite FTS5 can support lexical search over entity names, aliases, and source excerpts.5 Recursive common table expressions can support bounded graph traversal without introducing a separate graph database.6 WAL mode improves concurrent read/write behavior for the common case where one agent is writing while another client inspects the graph.7
The storage model can remain small:
entities
aliases
sources
evidence
claims
The maintainability argument is to keep the source of truth singular, typed, and queryable. Use migrations for schema evolution and generated query code where appropriate.
A minimal schema has stable relational columns for the important parts and leaves JSON only as an extension field:
entities:
id
kind
canonical_name
properties_json
claims:
id
subject_id
predicate
object_entity_id
object_value
status
confidence
valid_from
valid_until
observed_at
superseded_by
sources:
id
uri
title
publisher
published_at
retrieved_at
content_hash
evidence:
id
source_id
claim_id
relation: supports | contradicts
locator
excerpt
That avoids memory sprawl because every factual assertion has a constrained place to live:
| Information type | Better storage |
|---|---|
| User preference | Text/procedural memory |
| Project instruction | Text/procedural memory |
| Person, organization, place | Entity |
| Alternate name | Alias |
| Factual assertion | Claim |
| Original material metadata | Source |
| Exact support or contradiction | Evidence |
| Changed fact | New claim plus supersession |
| Conflict between reports | Competing claims or contradicting evidence |
The core invariant is:
Durable factual memory must be structured as a source-backed claim.
That prevents the memory layer from becoming a junk drawer of summaries, notes, and half-remembered statements. Generated summaries can be useful, but they should not become evidence. Evidence should point back to source material. Durable factual knowledge should preserve the claim, the source, the locator, the timestamp, and the current status.
We don’t claim this is a universal replacement for text memory, it is perfectly reasonable for many applications to store preferences, style rules, and procedural habits as compact text. The architecture we’re using is a split:
Text memory:
preferences
procedures
current project context
writing style
lightweight continuity
Claim graph:
entities
relationships
source-backed assertions
evidence
timelines
contradictions
supersession
Our general conclusion is that for for factual, evolving, evidence-backed knowledge, a temporal claim graph is materially more maintainable than raw text memory. It gives the agent a way to remember without silently converting uncertain, time-bound, source-dependent assertions into permanent prose.
Andrej Karpathy, “LLM Knowledge Bases”: https://x.com/karpathy/status/2039805659525644595?lang=en ↩︎
Hermes Agent documents persistent
MEMORY.mdandUSER.mdfiles, plus SQLite FTS5 session search: https://hermes-agent.nousresearch.com/docs/user-guide/features/memory/ ↩︎“Graph-based Agent Memory: Taxonomy, Techniques, and Applications”: https://arxiv.org/abs/2602.05665 ↩︎
SQLite official site: https://sqlite.org/ ↩︎
SQLite FTS5 documentation: https://sqlite.org/fts5.html ↩︎
SQLite recursive CTE documentation: https://sqlite.org/lang_with.html ↩︎
SQLite WAL documentation: https://sqlite.org/wal.html ↩︎