Install with Docker Compose
This page takes you from an empty machine to a running RememberStack that
has read its first document. It uses the compose.yaml and .env.example
that ship in the repository. Check Requirements first.
1. Get the files
git clone https://github.com/writeitai/remember-stack.git
cd remember-stack
git checkout v0.17.2
cp .env.example .env
printf 'REMEMBERSTACK_POSTGRES_PASSWORD=%s\nREMEMBERSTACK_MINIO_ACCESS_KEY=%s\nREMEMBERSTACK_MINIO_SECRET_KEY=%s\nREMEMBERSTACK_SELFHOST_DEPLOYMENT_ID=%s\n' \
"$(openssl rand -hex 32)" "$(openssl rand -hex 12)" "$(openssl rand -hex 32)" \
"$(openssl rand -hex 16 | sed -E 's/^(.{8})(.{4}).(.{3}).(.{3})(.{12})$/\1-\2-4\3-8\4-\5/')" >> .envThe last command generates the database password, the object-store
credentials and the deployment id (a random UUID); .env.example ships
none of them, and Compose refuses to start without them.
Checking out a release tag keeps compose.yaml in step with the image tag
it names (ghcr.io/writeitai/remember-stack:0.17.2). Each GitHub release
also attaches compose.yaml and .env.example. GitHub renames the second
one on download, so it appears as default.env.example.
2. Fill in .env
Warning
The API needs no token by default. That is safe only on Docker Engine 28.0.0 or later; on an older engine, set a token first. See Before you expose it.
Docker Compose reads .env from the project directory, substitutes its
values into compose.yaml and passes every variable in it to the engine
containers. These variables have no default in compose.yaml and must be
set:
| Variable | What to put there |
|---|---|
REMEMBERSTACK_OPENROUTER_API_KEY | Your OpenRouter API key. The placeholder lets the stack start, but every model call fails with it. |
REMEMBERSTACK_SELFHOST_DEPLOYMENT_ID | This deployment's id, a random UUID generated in step 1. |
REMEMBERSTACK_SELFHOST_DEPLOYMENT_SLUG | A short name, such as billing-team. |
REMEMBERSTACK_SELFHOST_DEPLOYMENT_NAME | A display name, such as Billing team memory. |
REMEMBERSTACK_SELFHOST_API_PORT | The host port for the API. 8000 in the example. Compose publishes it on 127.0.0.1 only; see Before you expose it. |
REMEMBERSTACK_POSTGRES_USER, REMEMBERSTACK_POSTGRES_PASSWORD, REMEMBERSTACK_POSTGRES_DB | Database credentials; the password is generated in step 1. PostgreSQL creates them on first start. |
REMEMBERSTACK_MINIO_ACCESS_KEY, REMEMBERSTACK_MINIO_SECRET_KEY | Object-store credentials, generated in step 1. The bundled SeaweedFS store uses them as its only S3 identity; Compose refuses to start if either is empty. |
Warning
Decide the slug and name before the first start, and keep the generated
deployment id. The first setup run records all three in the database,
and every later setup refuses to run if they differ. See
Upgrades and migrations.
3. Start the stack
docker compose up -d --waitOn the first run Compose builds the PostgreSQL image (it compiles the
pg_textsearch extension, which takes a few minutes), pulls SeaweedFS and the
RememberStack image, and starts everything in dependency order:
postgresandobject-storestart and report healthy.setupruns the database migrations, creates the three buckets, records the deployment, installs the assured operations and the example saved queries, and exits.apiand the twelve workers start oncesetuphas exited successfully.
--wait returns when the services are running and healthy.
What each service does
| Service | Command | Role |
|---|---|---|
postgres | postgres | PostgreSQL 19 beta with the extensions RememberStack needs. It holds every document, version, claim, fact and entity, and the work queue. |
object-store | server -s3 | SeaweedFS, S3-compatible storage for original files, converted Markdown and snapshots. Reachable only by the other containers; no host port is published. |
setup | setup | One-shot: migrations, buckets, the deployment row, seed data. Runs again, harmlessly, on every up. |
api | api | The HTTP API on port 8000 inside the container, published on 127.0.0.1:REMEMBERSTACK_SELFHOST_API_PORT. |
worker-convert | worker --stage convert | Turns an uploaded file into Markdown using the configured converter. |
worker-structure | worker --stage structure | Finds the document's sections and writes section summaries. |
worker-chunk | worker --stage chunk | Splits the document into chunks. |
worker-embed-chunk | worker --stage embed_chunk | Embeds chunks for semantic search. |
worker-extract-claims | worker --stage extract_claims | Reads each chunk and selects the sentences that state something. |
worker-ground-claims | worker --stage ground_claims | Turns those sentences into claims (what the source said), each tied to its passage. |
worker-normalize-relations | worker --stage normalize_relations | Resolves entities and turns claims into relations and facts. |
worker-adjudicate-observations | worker --stage adjudicate_observations | Decides, entity by entity, whether a new statement confirms, contradicts or replaces a fact the memory holds. |
worker-adjudicate-supersession | worker --stage adjudicate_supersession | Records the follow-up of those decisions for the version and refreshes affected entity profiles. |
worker-embed-claim | worker --stage embed_claim | Embeds claims for semantic search. |
worker-reconcile | worker --stage reconcile | Settles the version's lifecycle once the other stages are done. |
worker-label-relation | worker --stage label_relation | Writes the searchable label of each relation and embeds facts for semantic search. |
projections | project --plane p3 | Profile operations only. Builds a filesystem view snapshot on demand. |
Each worker handles one stage and wakes when new work for that stage is committed. The pipeline and readiness explains what the stages produce.
4. Check that it is healthy
docker compose ps
curl http://localhost:8000/healthz/healthz answers {"status":"ok"} when the API can reach PostgreSQL.
It is the check Compose itself uses, and it never needs a token.
curl http://localhost:8000/deployment/deployment reports the source revision the image was built from
(build_revision, empty for a locally built image) and the model bound to
each pipeline seat (model_bindings).
5. Send a first document
Install the client on the machine you work from. It needs Python 3.12 or later.
pip install remember
export REMEMBER_API_URL=http://localhost:8000Save this as standup.md:
# Stand-up, 17 September 2026
Ravi said the billing migration moves from June to October, because the
invoice exporter needs a rewrite. Dana agreed and will tell finance.
Ravi owns the invoice exporter.Send it and ask about it:
remember ingest standup.md \
--source-kind file --source-ref notes/standup.md \
--source-modified-at 2026-09-17T09:30:00+00:00
remember query "Who owns the invoice exporter?"remember ingest prints the new version_id. Processing takes minutes, so
a query sent straight away may find nothing yet.
Wait until a document is queryable shows
how to wait for a version. To watch the work happen:
docker compose logs -f worker-extract-claims worker-normalize-relationsNote
Set REMEMBER_API_URL explicitly, or run remember setup --self-hosted,
which stores the address. With no address anywhere, the CLI falls back to
http://127.0.0.1:8000.
Stop, start and reset
| To | Run | Data |
|---|---|---|
| Stop the containers | docker compose stop | Kept |
| Start them again | docker compose start or docker compose up -d | Kept |
| Remove the containers | docker compose down | Kept in the volumes |
| Remove everything, including all memory | docker compose down -v | Deleted |
Volumes
Compose names volumes after the project, rememberstack:
| Volume | Mounted at | Holds |
|---|---|---|
rememberstack_postgres-data | /var/lib/postgresql in postgres | The database: every document, version, claim, fact and entity, the work queue and the cost ledger |
rememberstack_object-store-data | /data in object-store | Original files, converted Markdown, derived artifacts and filesystem snapshots |
rememberstack_app-state | /var/lib/rememberstack in the app containers | Working directories; the optional debug capture of invalid model output |
rememberstack_forget-manifests | /var/lib/rememberstack/forget-manifests in the app containers | Hard-forget manifests. Empty in a Compose deployment. |
The first two hold the memory. Back them up together; see Upgrades and migrations.
Before you expose it
By default the API needs no token, so Compose publishes its port on
127.0.0.1 only: only this machine can reach it. That holds on Docker
Engine 28.0.0 or later. On an older engine, other hosts on the same local
network can reach a port published on 127.0.0.1, so set
REMEMBERSTACK_SELFHOST_API_BEARER_TOKEN and
REMEMBERSTACK_SELFHOST_REQUIRE_API_AUTH=true before the first start (see
Requirements). To serve other machines,
set a token and then the address to publish on
(REMEMBERSTACK_SELFHOST_API_PUBLISH_ADDRESS); see
Opening the API to other machines.