> ## Documentation Index
> Fetch the complete documentation index at: https://docs.maximem.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Migrate from Zep to Synap

> Looking for a Zep alternative? Map Zep's Sessions, Users, and automatic facts onto Synap: concept mapping, SDK call equivalents, and a backfill snippet for a clean cutover.

You're using Zep and want to evaluate or move to Synap. This page covers how Zep stores memory, how its concepts map onto Synap, and how to backfill your existing sessions.

<Note>
  This page is the Zep-specific mapping. For the method every migration shares — scope mapping, configuring your instance, pilot, verify, cut over — see [How migration works](/migrations/how-it-works).
</Note>

## How Zep stores memory

Zep has Sessions (≈ conversations), Users, and an automatic Facts extraction over sessions. Multi-user is `user_id`; multi-tenant is loosely "Project."

<Note>
  Zep API surfaces vary by version: Zep Cloud's v2 renamed Sessions → Threads and restructured the Project surface. Check your installed `zep_python` (or `zep-cloud`) version against the names used below.
</Note>

## The mapping

| Zep concept                          | Synap concept                                                                                                                                 |
| ------------------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------- |
| `Project`                            | Either one Instance per project, or one Instance + `customer_id` per project                                                                  |
| `User` (`zep.user.add`)              | Implicit: Synap creates user records on first ingestion by `user_id`                                                                          |
| `Session` (`zep.memory.add_session`) | `conversation_id` (must be a UUID, use `str(uuid.uuid4())` per session)                                                                       |
| `zep.memory.add`                     | `sdk.conversation.record_message` (incremental) + periodic `sdk.conversation.context.compact`                                                 |
| `zep.memory.get`                     | `sdk.conversation.context.fetch` or `get_context_for_prompt`                                                                                  |
| `zep.memory.search_sessions`         | `sdk.user.context.fetch(user_id=..., search_query=[...])`                                                                                     |
| Automatic facts                      | Native: `ContextResponse.facts` is the equivalent of Zep's automatic facts, with the addition of preferences/episodes/emotions/temporal types |

## Backfill from Zep

```python theme={null}
from zep_python.client import AsyncZep
from maximem_synap import MaximemSynapSDK
import uuid

zep = AsyncZep(api_key="...")
new = MaximemSynapSDK()
await new.initialize()

async def migrate_session(zep_user_id: str, zep_session_id: str, customer_id: str = "default"):
    messages = await zep.memory.get_session_messages(session_id=zep_session_id)
    synap_conv = str(uuid.uuid4())

    # Record each message individually so Synap can compact later
    for m in messages.messages:
        # Zep `role_type` can be "user" / "assistant" / "system" / "function" / "tool".
        # Synap only accepts "user" or "assistant"; filter or coerce other roles.
        if m.role_type not in ("user", "assistant"):
            continue   # or map system/function/tool to "assistant" if you want to preserve them

        await new.conversation.record_message(
            conversation_id=synap_conv,
            role=m.role_type,
            content=m.content,
            user_id=zep_user_id,
            customer_id=customer_id,
            metadata={"zep_session_id": zep_session_id, "zep_uuid": m.uuid},
        )

    # Trigger one compaction so the conversation arrives compacted
    await new.conversation.context.compact(
        conversation_id=synap_conv,
        strategy="adaptive",
    )
```

## Differences worth noting

* Zep stores the literal message log forever; Synap compacts it. If you rely on retrieving raw messages by ID, plan to keep your Zep log around for a transition period.
* Zep has built-in evaluation via fact graphs; Synap does this differently: the entity graph is the equivalent and is queried by both `fast` and `accurate` retrieval. `accurate` additionally adds LLM subquery decomposition + reranking on top of the same vector + graph search.

## Next

Follow the shared [migration method](/migrations/how-it-works) to pilot one user, verify scope isolation, swap your retrieval call sites, and cut over.
