What is a memory?
A memory is the atomic unit of remembered information in OMP. It is always scoped to a specific user (user_id), optionally grouped into a hierarchical namespace (scope), and identified by a provider-assigned id. Because OMP is provider-agnostic, the same schema works whether the backing store is Postgres, Mem0, Supermemory, or any other OMP-compatible backend.
Memory schema
The full JSON representation of a memory looks like this:Field reference
Required fields:
id, content, user_id, and created_at are the only fields a provider must return. All other fields are optional but normalized when present.Extension fields
OMP supports provider-specific data viax-<provider>-prefixed extension fields. Providers use these to expose proprietary metadata — such as graph node IDs or internal embedding versions — without breaking OMP compliance.
- Extension fields must use the
x-<provider>prefix (e.g.x-mem0,x-supermemory). - They must not override or conflict with standard field semantics.
- Any application that does not recognize an extension field must ignore it — forward-compatibility is required.
- Extensions must not be required for an OMP-compliant client to read or use the memory.
Memory lifecycle
A memory follows a straightforward lifecycle from creation to eventual removal:1
Add
Call
mem.add() with at minimum content and user_id. The provider assigns an id and returns the stored record. Async providers may return status: "queued" while indexing is pending.2
Search or list
Retrieve memories with
mem.search() for semantic queries or mem.list() for filtered enumeration. Both support scope filtering to narrow results to a specific namespace.3
Update or supersede
Call
mem.update() to modify a memory in place. Pass supersedes=[old_id] on a new mem.add() call to create a replacement record while preserving the history chain.4
Delete
Call
mem.delete(id) to permanently remove a memory. This is a hard delete — use supersedes instead when you want to retain a history trail.Code example
Here is a completeadd() call using multiple optional fields:
source as a plain dictionary — the SDK converts it automatically: