> ## 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.

> ## Agent Instructions
> Maximem Synap is a managed memory layer for AI agents: it ingests conversations and documents, extracts structured memory, and returns scoped context to the agent at retrieval time.
> The Python and JavaScript/TypeScript SDKs are the supported way to use Synap. Write integration code with SDK calls, not raw HTTP requests.
> Start with the Quickstart: https://docs.maximem.ai/getting-started/quickstart.md. Every SDK method is documented in the SDK reference: https://docs.maximem.ai/sdk-reference/overview.md.
> For requests about adding Vity memory to OpenClaw, Hermes, an MCP client, or a browser, start with the Vity Quickstart: https://docs.maximem.ai/vity/quickstart.md.

# Set up Synap Core

> Run the open-source Synap server on your machine, store a memory and read it back.

Synap Core is the open-source Synap server. It runs on your machine with Docker, keeps its data on your disk, and works with the same SDK as Synap Cloud. The first start takes minutes, not seconds: it downloads about 2.3 GB of models, once. Allow 10 to 25 minutes from `git clone` to a healthy server; once the models are on disk, later starts take a minute or two.

## What you need

* Docker with Compose. Give Docker at least 6 GB of memory.
* A way to run a model: an API key for a model provider, or a model you run yourself with Ollama.
* About 8 GB of free disk, for the server image and the models it downloads on the first start.
* Python 3.11 or later, or Node 20 or later, for the SDK.

## 1. Get the server

```bash theme={null}
git clone https://github.com/maximem-ai/maximem_synap_core
cd maximem_synap_core
```

By default Docker builds the server image from this folder. To run the published image instead, with no build, set these in your shell before every `docker compose` command for this folder: `SYNAP_IMAGE=ghcr.io/maximem-ai/maximem_synap_core:latest` and `SYNAP_PULL_POLICY=always`. Use the tag `0.1.0` instead of `latest` to stay on one release.

## 2. Choose your model

Synap Core does not pick a model for you. Copy the example settings file and fill in the model lines:

```bash theme={null}
cp .env.example .env
chmod 600 .env
```

The second command keeps other users of your machine from reading the file, which will hold your API keys.

Open `.env` and replace the two placeholders:

```text theme={null}
SYNAP_LLM_PROVIDER=<the provider you use>
SYNAP_LLM_MODEL=<the model you want>
```

Write the model name exactly as your provider names it. Then fill in the key line for your provider, which is already in the file:

| Provider | Line to fill in |
| - | - |
| `openai` | `OPENAI_API_KEY` |
| `anthropic` | `ANTHROPIC_API_KEY` |
| `openai-compatible` | `SYNAP_LLM_BASE_URL`, and `SYNAP_LLM_API_KEY` if the server needs one |
| `ollama` | no key: see "Run a model on your machine" below |

If you leave a placeholder in, the `first-start` step stops and its log names the line (`docker compose -f deploy/docker-compose.yml logs first-start`).

Docker reads `.env` when it creates the server container. If you change `.env` later, run `docker compose -f deploy/docker-compose.yml up -d` again so the server picks the change up.

### Run a model on your machine

Synap Core can use a model that runs on your own machine through [Ollama](https://ollama.com). With Ollama, the text Synap sends to a model goes to the Ollama address you configure. Ollama is not part of Synap's Docker setup: you run it yourself.

1. Pull the model: `ollama pull <the model you want>`. Check with `ollama list`.
2. Make sure the container can reach Ollama. The server runs in Docker and reaches Ollama through `host.docker.internal`, which the Compose file maps to your machine on Linux as well as on Docker Desktop. Ollama must listen on an address the container can use, not on `127.0.0.1` alone; see Ollama's own documentation for how to change that, and keep in mind that listening on all addresses exposes Ollama to your network.
3. In `.env`, set `SYNAP_LLM_PROVIDER=ollama` and `SYNAP_LLM_MODEL=<the exact name you pulled>`. You do not need the OpenAI or Anthropic keys.

Optional settings, each with the value Synap uses when you leave it out:

```text theme={null}
# a model that can read images
SYNAP_LLM_MODEL_VISION=<a vision model>
# how much text Ollama may read at once, in tokens (default 16384)
OLLAMA_NUM_CTX=16384
# tell compaction the same size, so it sizes its calls to it (without this it assumes 128000 for a model it does not know)
SYNAP_LLM_CONTEXT_WINDOW=16384
# only if Ollama is not at the default address, as seen from the container
OLLAMA_BASE_URL=http://host.docker.internal:11434
# a slow model may need longer than the default 300 seconds to answer
SYNAP_LLM_READ_TIMEOUT_SECONDS=600
```

Quality follows your model: Synap has not measured how accurate it is on local models, and what a small model extracts is yours to check. A model that is not pulled fails with a message that tells you to run `ollama pull` for it. Embeddings do not use Ollama; they run inside the Synap server.

## 3. Start it

On Linux, first run `export SYNAP_USER=$(id -u):$(id -g)` in the same terminal, so the `originals/` folder belongs to you. Compose reads this from your shell, not from `.env`. Docker Desktop needs nothing. If port 8000 is already in use, run `export SYNAP_PORT=8010` the same way (any free port) and use that port wherever this page says 8000.

```bash theme={null}
docker compose -f deploy/docker-compose.yml up -d
```

The first time, this command does not return until the downloads are finished, because the server waits for them. The download alone is about 3 minutes at 100 Mbit/s and about 12 minutes at 25 Mbit/s, and the command prints very little. To watch the progress, open a second terminal in the same folder and run:

```bash theme={null}
docker compose -f deploy/docker-compose.yml logs -f first-start
```

It says how far each large file is, every ten seconds. If your connection drops and the download fails, run the same `up -d` again: it continues from where it stopped.

The first start does a few things once:

* It builds the server image on your machine (or pulls the published one).
* It generates the passwords for the databases and keeps them in a Docker volume. They are not in any file you edit.
* It downloads the models, about 2.3 GB in all: the embedding model, a small model that matches names, and a small English text model that splits questions into parts. It checks each file against a fixed checksum. After this first start Synap Core makes no download and does not contact Hugging Face again.
* It creates the database tables and a default client and instance.

Three of the services (`secrets`, `schema` and `first-start`) do their job and then exit. Compose shows them as exited. That is expected.

The server is ready when `docker compose -f deploy/docker-compose.yml ps` shows `synap` as healthy. It is on `http://127.0.0.1:8000` (or your `SYNAP_PORT`) and listens on your machine only.

> [!NOTE]
>
> **If something fails.** Read the log of the service that failed: `docker compose -f deploy/docker-compose.yml logs <service>`. To stop everything, run `docker compose -f deploy/docker-compose.yml down`. To start again from nothing, run it with `down -v`, which also deletes your stored memories and the generated passwords. It does not delete the `originals/` folder next to `deploy/`, which holds a copy of the text you stored: remove that folder too for a full reset. The Python SDK also keeps answers it has already fetched for five minutes, in a folder called `.synap` in your home directory, and answers a repeated query from there. So right after you delete or change a memory, or wipe the server, the same query can still show the old answer. Run `sdk.cache.clear()` to see the server's current answer at once.

## 4. Install the SDK and point it at your server

```bash Python theme={null}
pip install maximem-synap
export SYNAP_BASE_URL=http://127.0.0.1:8000
```

```bash JavaScript theme={null}
npm install @maximem/synap-js-sdk
export SYNAP_BASE_URL=http://127.0.0.1:8000
```

You do not need an API key or an instance id for a local server; this needs `maximem-synap` 0.6.11 or later, or `@maximem/synap-js-sdk` 0.6.7 or later, and a fresh install is newer. If you set `SYNAP_API_TOKEN` on the server (see "Protect the server"), set the same variable for the SDK. If your shell still has `SYNAP_API_KEY` from a Synap Cloud project, run `unset SYNAP_API_KEY` first: with a key set, the SDK acts as a Cloud client even when `SYNAP_BASE_URL` points at your server.

## 5. Store a memory and read it back

The sample configuration treats every user as their own customer, so you only send a `user_id`. If your app has customers with users under them, read "Choose how users are scoped" below before you store anything.

```python hello_core.py theme={null}
import asyncio
from maximem_synap import MaximemSynapSDK

async def main():
    sdk = MaximemSynapSDK()
    await sdk.initialize()
    try:
        result = await sdk.memories.create(
            document="User: I prefer dark mode.\nAssistant: Noted!",
            document_type="ai-chat-conversation",
            user_id="user_alice",
        )
        await sdk.memories.wait_for_completion(result.ingestion_id)

        context = await sdk.user.context.fetch(
            user_id="user_alice",
            search_query=["preferences"],
        )
        for p in context.preferences:
            print(p.content)
    finally:
        await sdk.shutdown()

asyncio.run(main())
```

```javascript hello-core.mjs theme={null}
import { SynapClient } from '@maximem/synap-js-sdk';

const sdk = new SynapClient();
await sdk.initialize();
try {
  const result = await sdk.memories.create({
    document: 'User: I prefer dark mode.\nAssistant: Noted!',
    document_type: 'ai-chat-conversation',
    user_id: 'user_alice',
  });
  await sdk.memories.wait_for_completion(result.ingestion_id);

  const context = await sdk.user.context.fetch({
    user_id: 'user_alice',
    search_query: ['preferences'],
  });
  for (const p of context.preferences ?? []) {
    console.log(p.content);
  }
} finally {
  await sdk.shutdown();
}
```

Run it with `SYNAP_BASE_URL` still set. On some machines the Python command is `python`, not `python3`:

```bash Python theme={null}
python3 hello_core.py
```

```bash JavaScript theme={null}
node hello-core.mjs
```

It prints a short statement about the user's preference for dark mode. Synap does not keep your exact words: it rewrites what you said into a short statement about the user, so the sentence differs from the one you sent. The first memory can take up to a minute while the models load.

`wait_for_completion` waits up to five minutes by default. If it times out, check that the server is still healthy with `docker compose -f deploy/docker-compose.yml ps`. A server that cannot process memories reports itself as not ready, and the reason is in `docker compose -f deploy/docker-compose.yml logs synap`.

## 6. See what was stored

Open `http://127.0.0.1:8000/browser` in your browser (use your port if you changed it; it asks for the token if you set one). It lists your memories, the people they belong to, and the config the server is reading. It is read-only.

## Choose how users are scoped

Synap Core stores each memory at the level of the request: the ids you send decide where it lives. There are two ways your users can relate to customers, and you choose once, in the YAML memory config, with `user_context_isolation`.

| Value | For | What every request must carry |
| - | - | - |
| `equals_customer` | Consumer apps: each user is their own customer | A user id only. A customer id is not accepted |
| `strict` | Business apps: users sit under a customer | A customer id, plus a user id for a memory that belongs to one user. A user id alone is an error |

The sample `config/memory.yml` uses `equals_customer`, so one id is enough on the first run. For a business app, copy `config/samples/business-app.yml` over `config/memory.yml` before you store anything.

**You cannot change the mode after memories exist.** Memories are filed under the ids of the mode you started with, so switching would leave them where the new mode does not look. Before the first memory is stored you can still change your mind: edit `user_context_isolation` in the config and restart the server with `docker compose -f deploy/docker-compose.yml restart synap`. Once any memory exists, the server refuses to start with the changed mode and says so. To start over with another mode, run `docker compose -f deploy/docker-compose.yml down -v` and remove the `originals/` folder; this deletes everything you stored.

A request that does not match your mode, for example a customer id on an `equals_customer` install, is rejected with a message that says what it expected. It does not quietly return empty results. A fact is stored at the level of the request: if a user says something that is really about the whole customer, it stays with that user. A fetch for a customer returns only what is stored at the customer level, not the memories of that customer's users. `scope_path` and `maca_suggests` are refused, because Core has no custom levels and cannot choose the mode for you.

## Fit memory to your use case

The server starts on the small sample config at `config/memory.yml`, which is enough to try it. For your own app, the memory config decides what is remembered and how users are kept apart. You can write it by hand, starting from the two samples in `config/` and the comments in `.env.example`. A mistake in the file stops the server at start and names the line.

You can also have Synap Cloud write it from a description of your use case, with the MACA plugin. You describe your use case in a short file, your Core server sends the file to Synap Cloud, and Synap Cloud returns a memory config built for it, saved next to your own as `config/memory.generated.yml`. You decide whether to use it. This needs a Synap Cloud account with credits and a Cloud management key, and a run takes 15 to 20 minutes. The setup skill in the Core repository (`skills/synap-core/`) walks through it without showing the key.

## Remove a memory

To delete one memory when you have its id:

```python delete_memory.py theme={null}
await sdk.memories.delete(memory_id)
```

```javascript deleteMemory.mjs theme={null}
await sdk.memories.delete(memoryId);
```

To forget something from a person's own words ("forget that I live in Pune"), use forget. It finds the matching memories and removes them, with the copies that were derived from them:

```python forget.py theme={null}
result = await sdk.memories.forget(
    description="my old address",
    user_id="user_alice",
    mode="direct",
)
print(result.status, result.deleted_ids)
```

```javascript forget.mjs theme={null}
const result = await sdk.memories.forget({
  description: 'my old address',
  user_id: 'user_alice',
  mode: 'direct',
});
console.log(result.status, result.deleted_ids);
```

Pass `mode: "direct"`. Both SDKs send `preview` when you name no mode, and a preview deletes nothing: in Synap Cloud a person approves it in the dashboard, and the open-source server has no dashboard, so the request would stay pending. Check `status`: `deleted` means everything was removed, `partial` means the memories are hidden but a store named in `still_present_in` may still hold their text, so only tell your user it was removed when `status` is `deleted`. Forget searches one user at a time, so pass `user_id` (and `customer_id` if your users sit under customers).

Forget by description needs your own Jev API key: Jev decides which memories match, and the text of the candidate memories is sent to it. Set `JEV_API_KEY` in `.env` and run `docker compose -f deploy/docker-compose.yml up -d` again. Without a key, a call that finds candidates answers that forget needs a Jev API key, and nothing is deleted. Deleting by id needs no key. Deleting everything for a user, a conversation or a customer in one call is a Synap Cloud feature.

## Images and files

Synap Core reads images in a conversation (up to 10 per message, 10 MB each) and uploaded files: PDF, DOCX, XLSX, PPTX, TXT, MD, JSON, and PNG, JPG and WEBP images, up to 10 MB per upload. An image is read by your configured model, which must be able to read images. Set a model for that step with `SYNAP_LLM_MODEL_VISION`; if you do not, the main model is used. For `ollama` and `openai-compatible`, Synap logs one warning at start when the vision model's name does not look like one that reads images.

## Protect the server

Synap Core is built to sit behind your own backend, not to face the internet. Anyone who can reach the port can read, write and delete every memory and ask for any user's memories, and every request uses your model, so open ingestion runs up your bill. By default the API listens on `127.0.0.1` only, no database port is published, the Postgres, Redis and Neo4j passwords are generated per store and kept in a Docker volume, and each container keeps at most three log files of 10 MB.

Before you expose it:

1. Keep the server off the public network: a private network or a firewall.
2. Set `SYNAP_API_TOKEN` in `.env`, then run `docker compose -f deploy/docker-compose.yml up -d` again. Every request must then carry it as a bearer token, your SDK reads it from `SYNAP_API_TOKEN` in its own environment, and the memory browser asks for it. It is one token for the whole install, not a user identity. When it is not set, the server prints a warning at startup.
3. Use TLS through a reverse proxy on the same machine, and let only the proxy reach the server. The server does not terminate TLS.
4. Back up the Docker volumes for Postgres, Redis, Chroma and Neo4j, the `state` volume that holds the generated passwords (the databases cannot be opened without it), and the `originals/` folder next to `deploy/`. `docker compose down -v` deletes the volumes. Test a restore before you rely on a backup.
5. Call it from your own backend, never from a browser or a mobile app.
6. Keep `SYNAP_CLOUD_API_KEY` out of `.env` when you are not running the MACA plugin, and revoke it afterwards.

## Core and Cloud

The open-source server is the full memory engine, self-hosted: extraction, entity resolution, temporal reasoning, vector and graph retrieval, and compaction. The SDK is the same for both, so moving to Cloud is a new base URL and an API key.

| | Synap Core | Synap Cloud |
| - | - | - |
| Memory architecture | Write the YAML config yourself, or use the MACA plugin | Designed for you from a description of your use case |
| Scoping | User and customer | Each fact placed at the right level automatically, custom levels, multi-agent memory sharing |
| Deleting data | One memory, or by description with your own Jev key | Plus everything for a user, a conversation or a customer |
| Predictive prefetch, PII management | No | Yes |
| Dashboard, usage analytics, alerts | A read-only memory browser | Yes |
| Authentication and multi-tenancy | Single tenant, optional shared token | Yes |
| LongMemEval, all 500 questions | 83.6% (418 / 500) | 95.6% |

When you call something that only exists on Cloud, the open-source server answers "not available in the open-source server", so you know it is not a bug in your code. Both LongMemEval scores use the same answer model and judge; for Core, the answer model is `gemini-3.8-flash`, the judge is `gpt-4o`, and memories were extracted with `gemini-3.1-pro-preview`, on a server started from the Compose file with the sample config as shipped (run on 2 November 2026). One question that errored counts as wrong. Compare numbers only when the answer model, judge and extraction model match. The [Core results](https://github.com/maximem-ai/maximem_synap_core/blob/main/benchmarks/RESULTS.md) and the [Cloud answers](https://github.com/maximem-ai/eval_benchmark_runs_output) are published.

## More

The Core repository has the full list of settings in `.env.example`, the end-to-end tests, and the setup skill for coding agents: [github.com/maximem-ai/maximem\_synap\_core](https://github.com/maximem-ai/maximem_synap_core).


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.