Concepts

Reconciliation

How MemHQ resolves contradictions and updates memory over time.

Reconciliation

Memory has to change. People move, change jobs, update preferences. A useful memory system has to be able to take "I now drink decaf" and turn the older "Prefers dark roast coffee, no sugar" into something that doesn't keep firing on future queries.

MemHQ's reconciler runs during Phase 5 of ingestion and makes one of four decisions per extracted candidate.

The four outcomes

OutcomeWhen it firesEffect on the graph
AcceptThe candidate is novel; no existing memory addresses the same fact.New memory inserted, status = active.
SupersedeThe candidate directly contradicts an existing memory on the same entity.New memory inserted, status = active. The old memory is set superseded, with a forward link to the new one.
ReinforceThe candidate restates an existing memory in different words.Existing memory's confidence and last-seen timestamp are bumped; no new row.
RejectThe candidate is too low-confidence, or an exact duplicate of recent input.Discarded; not added to the graph.

What "active" vs "superseded" means at read time

The default retriever returns only active memories. That's the behavior you want when the agent needs current ground truth.

For historical or temporal questions — "what coffee did they used to drink?" — pass include_superseded: true on search or ask. The retriever will then surface the superseded chain too, with timestamps attached so the synthesizer can answer "they used to prefer dark roast, but switched to decaf in March."

The retriever auto-enables historical mode for questions whose phrasing signals a temporal arc: used to, originally, started, since, back when, and similar patterns. You usually don't need to pass the flag explicitly.

Source linking

Every memory — active or superseded — keeps a back-pointer to the episode(s) it was extracted from. This is what powers citations in ask responses: the synthesizer can quote the exact source span that produced a fact, and the dashboard can show the full provenance chain for any memory.

What the reconciler does not do

  • It does not rewrite raw episodes. Episodes are immutable; only the derived memory graph is updated.
  • It does not merge entities across users without explicit shared graph membership. Two users can both have a memory mentioning "Acme", but those references are scoped to each user's own graph unless they're members of a shared group graph that owns the entity.
  • It does not delete memories on a "forget" request. Use the dashboard's Erase memory flow, which writes a tombstone — this is important for audit and compliance.

Tuning

The reconciler exposes two knobs at the project level:

  • reconciliation.contradiction_threshold (default 0.72) — how confident the model has to be that two memories contradict before it supersedes. Lower = more aggressive supersession, higher = more active rows.
  • reconciliation.reinforce_threshold (default 0.85) — semantic similarity above which a candidate reinforces rather than inserts.

Both are tuned to sensible defaults; only adjust them after profiling.