Skip to main content
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

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

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.
Run it with SYNAP_BASE_URL still set. On some machines the Python command is python, not python3:
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. 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:
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:
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. 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 and the Cloud answers 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.