Motivation
MemOS has no server-side dedup on the write path. Any client that re-sends identical memory content (retry loops, replayed events, buggy integrations) creates duplicate nodes — duplicates that then pollute search results, graph structure, and reorganization.
We hit this in production via the OpenClaw cloud plugin (see MemTensor/MemOS-Cloud-OpenClaw-Plugin#145): a replay loop wrote 6,076 memories in 24h, ~90% duplicates (583 unique contents × 30-40 copies). Client-side dedup helps that specific client, but the server is the right place for a last-line defense that protects all writers.
Proposal
Content-hash dedup at MemoryManager.add:
- Compute
sha1(memory_text) for each incoming item
- Skip items whose hash already exists for the same
user_name within a configurable window (default 7 days)
- Also dedup within the batch itself
- Persist the hash as a
content_hash node property with a Neo4j index (memory_content_hash_index) for O(1) lookup
- Fail-open: if the dedup check errors, the write proceeds (availability over strictness)
- Toggles:
MOS_DEDUP_ENABLED=0 to disable, MOS_DEDUP_WINDOW_DAYS to adjust the window
Sketch of what we deployed (self-hosted patch, working in production):
def _dedup_by_content_hash(self, memories, user_name):
kept, seen, skipped = [], set(), 0
for m in memories:
h = hashlib.sha1(m.memory.encode("utf-8")).hexdigest()
if h in seen or self.graph_store.exists_recent_by_hash(user_name, h, days=days):
skipped += 1
continue
m.metadata.content_hash = h # extra="allow" → flows to node property
seen.add(h)
kept.append(m)
return kept
with a matching graph-store query:
MATCH (n:Memory {content_hash: $h})
WHERE n.created_at >= datetime() - duration({days: $days})
AND n.user_name = $user_name
RETURN n.id LIMIT 1
Notes
- Window-based (not permanent) dedup intentionally allows re-learning: the same fact re-stated weeks later is a valid new memory
- The hash doubles as a cheap idempotency key for retried writes
- Happy to contribute this as a PR if the approach looks reasonable
Motivation
MemOS has no server-side dedup on the write path. Any client that re-sends identical memory content (retry loops, replayed events, buggy integrations) creates duplicate nodes — duplicates that then pollute search results, graph structure, and reorganization.
We hit this in production via the OpenClaw cloud plugin (see MemTensor/MemOS-Cloud-OpenClaw-Plugin#145): a replay loop wrote 6,076 memories in 24h, ~90% duplicates (583 unique contents × 30-40 copies). Client-side dedup helps that specific client, but the server is the right place for a last-line defense that protects all writers.
Proposal
Content-hash dedup at
MemoryManager.add:sha1(memory_text)for each incoming itemuser_namewithin a configurable window (default 7 days)content_hashnode property with a Neo4j index (memory_content_hash_index) for O(1) lookupMOS_DEDUP_ENABLED=0to disable,MOS_DEDUP_WINDOW_DAYSto adjust the windowSketch of what we deployed (self-hosted patch, working in production):
with a matching graph-store query:
Notes