MemorySync
Getting Started

Migrating from Supermemory

Move from container tags and document ingestion to explicit end-user scopes and durable memory records. The mapping is mostly about splitting one string into a scope and a set of tags.

Key differences

SupermemoryMemorySyncWhat it means for your code
containerTag string carrying scope and labelsX-End-User-ID header plus tagsIsolation stops being a naming convention you have to keep consistent.
Documents, chunked on ingestMemory records, stored as writtenA retrieval result is the record you wrote, not a fragment of one.
queued then doneDurable when add returnsNo polling loop, and no window where a write is not yet retrievable.
search.execute({ q, containerTag })POST /memory/queryScope comes from the header; filters stays yours.
Chunks with scoresWhole records with metadataNothing to stitch back together before you show or use it.
URLs, PDFs, and files ingested directlyYou extract, then store what mattersA deliberate tradeoff — see the note below.

Install the client

python -m pip install memorysync==1.1.1
import os
from memorysync import MemorySyncClient
client = MemorySyncClient(
api_key=os.environ["MEMORYSYNC_API_KEY"],
base_url="https://api.memorysync.io",
project_id=os.environ["MEMORYSYNC_PROJECT_ID"],
end_user_id="user-123",
)

Operation by operation

client.memories.add(
content="User prefers dark mode",
container_tags=["user_alice", "preferences"],
)
results = client.search.execute(
q="user preferences",
container_tag="user_alice",
)

Move your existing data

1
Decide what each container tag meant

This is the only decision that matters. A tag like user_alice is a scope and becomes X-End-User-ID. A tag like preferences is a label and becomes an entry in tags. A tag that mixed both, such as user_alice_preferences, has to be split.

2
Export your documents

Pull your documents out with their container tags and metadata, and keep the export on disk. It is your rollback.

3
Import one scope at a time
import json, os
from memorysync import MemorySyncClient
with open("supermemory_export.json") as handle:
documents = json.load(handle)
# map the tag that identified a user onto the scope header
def split_tags(tags: list[str]) -> tuple[str, list[str]]:
scope = next((t for t in tags if t.startswith("user_")), "unknown")
return scope.removeprefix("user_"), [t for t in tags if t != scope]
batches: dict[str, list[dict]] = {}
for document in documents:
end_user_id, labels = split_tags(document.get("containerTags", []))
if not document.get("content"):
continue
batches.setdefault(end_user_id, []).append({
"text": document["content"],
"source": "import",
"tags": labels,
"metadata": {"supermemory_id": document.get("id")},
})
for end_user_id, items in batches.items():
client = MemorySyncClient(
api_key=os.environ["MEMORYSYNC_API_KEY"],
base_url="https://api.memorysync.io",
project_id=os.environ["MEMORYSYNC_PROJECT_ID"],
end_user_id=end_user_id,
)
result = client.bulk_add(items, deduplicate=True)
print(end_user_id, result.created, "created,", result.skipped, "skipped")
4
Verify the boundary

Query as one migrated end user and confirm only their memories return. If a container tag was ambiguous, this is where you find out, before it matters.

Next steps