Temporal facts
Facts can carry a validity window, [valid_from, valid_to). Nothing changes until you use it:
a fact with no validity data is always current.
Replace a fact and keep history
Section titled “Replace a fact and keep history”// The user moved; the move happened on March 1.const { newId } = await wiki.supersede( 'user-123', seattleFactId, { title: 'Lives in San Francisco', body: 'Moved in March.' }, { validFrom: Date.parse('2026-03-01') },);Ask about the past
Section titled “Ask about the past”await wiki.read('user-123', 'where do I live'); // San Franciscoawait wiki.read('user-123', 'where do I live', { asOf: Date.parse('2026-02-01') }); // Seattleawait wiki.history('user-123', seattleFactId); // [Seattle, San Francisco]- The window is half-open. At the switch instant, only the new fact matches.
asOfanswers “what do we now know was true at time T”. If you learn about a past change late, past queries still come out correct.traverseGraph({ asOf })only walks edges whose two facts were both live at that instant.
To record a new fact that replaces nothing, use remember() with an optional valid_from. It stores the fact directly, with no LLM call. supersede() is still the way to replace one.
supersede() throws WikiSupersedeError (with a reason) when the target:
- is an
immutable_documentfact (re-ingest the document instead), - belongs to another entity,
- is already superseded, or
- would create a cycle.
Record when events really happened
Section titled “Record when events really happened”await wiki.write('user-123', { event_type: 'observation', summary: 'Moved to SF', occurred_at: Date.parse('2026-03-01'), // real-world time; defaults to ingestion time});Pass the client’s timestamp, so a delayed or queued write still reflects when the event happened.
The 'ops' librarian sets valid_from on each fact it extracts. It uses the date the model
gives, if any. Otherwise it uses the source event’s occurred_at, or the time the event was stored
when that is not set. If the model names no source event, it uses the newest such date in the
batch, but never a date later than the time of the pass. A fact taken from an event with a future
occurred_at keeps that future date, so current reads leave it out until then.
Retention
Section titled “Retention”History is kept indefinitely by default. Set config.pruneSupersededAfter (in days) to let
runPrune() retire facts that expired that long ago. getMemoryBundle() and exportDump()
return all non-deleted facts, including history.