These are patterns that hold up once a memory system is carrying real traffic, along with the specific failure each one prevents. They apply whether you built your memory layer or adopted one.
The theme, stated once: most problems that present as retrieval problems are write problems. A corpus of vague, overlapping, badly scoped memories cannot be rescued by a better ranker.
Store conclusions, not transcripts
The most common mistake is writing the conversation. It is the easiest thing to do and it produces a corpus that cannot be retrieved from usefully.
A memory should be a single durable fact, stated so it makes sense with no surrounding context.
- Weak: *"User said they were frustrated with the export taking so long and mentioned they usually work with big files."*
- Better: *"Regularly exports datasets over 2 GB."* and *"Reported export latency as a pain point."*
The second form is two atomic facts, each independently retrievable, each individually supersedable. The first is a paragraph that will match a hundred loosely related queries and can never be cleanly updated.
A practical test: read the memory with no context. If you cannot tell what it means, or if updating part of it would require rewriting the whole thing, it is not atomic enough.
Scope with a stable, opaque identifier
Every memory needs an end-user scope, and the choice of key is close to irreversible.
Use an internal identifier that never changes and reveals nothing: usr_7f3a9c2e, not an email address. Emails change, they are personal data, and once they are your memory key both facts become expensive.
Two related habits are worth adopting early:
- Never derive scope from user input. Scope comes from the authenticated session, server-side. A client that can name the scope it wants is a client that can name someone else's.
- Separate project from user. Organization-wide knowledge and per-user preferences want different retrieval treatment. Collapsing them means either leaking one user's preferences into shared context or duplicating shared knowledge per user.
Retrieve few, not many
Retrieval size is the setting most often tuned in the wrong direction. When answers seem to lack context the instinct is to raise the limit, and that usually makes results worse.
Five to ten memories is the range that works for most conversational applications. Beyond that, precision falls and the model spends attention discriminating rather than answering. Irrelevant context is not neutral — it actively degrades output.
If you need thirty memories to answer a question, the problem is rarely the limit. It is usually that extraction produced fragments where it should have produced facts.
Two refinements are worth the effort. Retrieve against the current turn rather than the whole conversation, because whole-conversation queries drift toward an average of every topic discussed. And keep standing conventions separate from relevance-ranked memories: rules that should always apply belong in the prompt unconditionally, not competing for a slot in a ranked set.
Handle contradictions explicitly
People change their minds, and a system that treats every statement as permanently true will contradict itself in front of users.
When a new memory conflicts with an existing one, exactly one of three things should happen, and the application should decide which:
- Supersede. The new fact replaces the old. Correct for preferences, settings, and current state.
- Coexist. Both are true in different contexts — *"prefers email for updates"* and *"prefers phone for outages"* are not in conflict.
- Escalate. The conflict is material and the system should not guess. Surface it rather than silently picking.
What must not happen is both facts being retrieved with equal standing, leaving the model to arbitrate. It will arbitrate differently on different requests, and users experience that inconsistency as the product being unreliable.
Label memory as context, never as instruction
Where you place retrieved memories in the prompt is a security decision, not a formatting one.
Memories contain user-supplied text. If they are injected where the model reads instructions, a user can write a memory that instructs the model. Keep them in a clearly delimited block labelled as background information about the user, separate from your system instructions, and state that they are context rather than commands.
The same reasoning applies to memories from synced sources. A document in a connected drive is untrusted input; it should never be able to redirect the model because it was retrieved.
Degrade instead of failing
Memory improves answers. It should not be able to prevent them.
Wrap retrieval in a timeout and a fallback. If it is slow or unavailable, answer without it — a slightly less personalised response is a far better outcome than an error. Set the timeout against your latency budget rather than the memory layer's ceiling: if retrieval has not returned in a few hundred milliseconds, proceed.
Writes can be deferred. Retrieval blocks the response; writing does not need to. Moving writes off the request path removes them from your latency budget entirely.
Measure retrieval, not just uptime
Memory quality degrades quietly. A corpus that retrieved well at a thousand memories can retrieve poorly at a hundred thousand with no error, no latency change, and no alert.
Three measurements catch it early:
- Precision on a sample. Read the memories returned for a few dozen real requests each week and count how many were relevant. Unglamorous, and more informative than any aggregate.
- Repeat-question rate. How often the assistant asks for something the user already provided. Users notice this first.
- Contradiction rate. How often two returned memories disagree. Rising means supersession is falling behind.
Watch these against corpus growth rather than in isolation. The number that matters is whether precision holds as volume rises.
Getting the defaults right
If you take four things from this: store atomic conclusions rather than transcripts, scope with a stable opaque identifier from the authenticated session, retrieve a small ranked set, and resolve contradictions rather than returning both sides.
Those four decisions determine most of the quality you will get, and three of them are write-side.
MemorySync implements the mechanics these patterns depend on — server-side extraction into atomic facts, deduplication on write, ranked retrieval combining similarity with recency and importance, and supersession so corrected facts stop competing with current ones. The patterns still matter; what changes is that you are applying them rather than building the machinery underneath them. The quickstart is one write and one retrieval.