Skip to main content

Memory Types

Mem0’s Python SDK exposes a memory_type parameter on add(). The underlying MemoryType enum defines three values, but only one of them is wired up. This page states plainly which is which so you don’t build against a type that doesn’t exist yet.

Status

Only procedural_memory is a real, working value. Calling memory.add(messages, memory_type="semantic_memory") (or episodic_memory) is rejected and tells you to pass procedural_memory instead. Sync Memory.add() raises Mem0ValidationError; AsyncMemory.add() raises a plain ValueError.

Procedural memory

Procedural memory stores step-by-step task knowledge (how an agent performs a workflow) rather than facts about a user. It requires agent_id:
Omit memory_type entirely and Mem0 stores the messages as an ordinary memory: there is no semantic/episodic pathway for it to fall into. Any other explicit value is rejected by validation rather than quietly falling back to an ordinary memory.

How every other memory is scoped

Outside of the procedural_memory special case, Mem0 does not sort memories into named types. Every memory is scoped by the identifiers you pass in, and the same identifiers are used to retrieve it later:
  • user_id: ties a memory to a specific person or account.
  • agent_id: ties a memory to a specific agent or assistant persona.
  • run_id: ties a memory to a specific session, task, or conversation thread.
  • app_id (Platform only): ties a memory to a specific application or tenant, in addition to the three above. See Entity-Scoped Memory.
At least one identifier is required on add(). Passing more than one narrows the scope further (for example, user_id + run_id together).
Use run_id when you want a set of memories to stay tied to one session or task; use user_id alone for anything that should persist across every session for that person.

How memories are extracted and updated

When infer=True (the default) on add(), Mem0 runs a single pipeline rather than routing through separate type-specific paths:
  1. Context gathering: pulls the most recent messages already stored for the same user_id/agent_id/run_id scope.
  2. Existing memory retrieval: embeds the new messages and runs a vector search against memories already in that same scope, to find candidates that might need to change.
  3. Extraction: a single LLM call compares the new messages against the retrieved candidates and decides, per fact, whether to ADD, UPDATE, DELETE, or leave a memory alone.
Alongside this, both OSS and Platform extract named entities (people, places, organizations) from memory text and use shared entities between memories to boost related results at search time. On Platform, that entity graph is also queryable directly; see Graph Memory. In OSS, entities only affect ranking, there is no separate graph to query.
Avoid storing secrets or unredacted PII in memories: they are retrievable by design. Encrypt or hash sensitive values before calling add().

Put it into practice

Explore Memory Operations

Advanced Memory Operations

AI Tutor Cookbook

Support Inbox Cookbook