Skip to content

Docker quickstart

Bring up the SecondBrain Memory API in a single container with docker compose up. This is the shortest path from a clean machine to a running, tokened HTTP API that other agents and integrations can call.

Prerequisites

  • Docker Engine 24+ with the docker compose plugin (Docker Desktop, OrbStack, Colima, or native Linux Docker all work)
  • ~3 GB free disk for the image and the first cold-start model download
  • A free TCP port 8765 on the host

A bearer token is required for any /v1/* Memory API call. The compose file can accept SB_SERVE_TOKEN from the shell. Generate one through the built-in token manager instead of relying on a placeholder:

eval "$(uv run sb serve-token env)"

sb serve-token env creates a local serve_auth.json token if one does not already exist, prints an export SB_SERVE_TOKEN=... line, and keeps the token file at owner-only 0600 permissions.

Quickstart

From the repo root:

make quickstart-docker

That target prints a banner, runs docker compose build, runs docker compose up -d, polls /health until it returns 200, and prints the exact curl you need for your first Memory API call. If SB_SERVE_TOKEN is not set, the target generates a secure local token with sb serve-token.

If you prefer the raw commands:

eval "$(uv run sb serve-token env)"
docker compose build
docker compose up -d
# Wait ~30–60s on first run while the FastAPI app and embedding model warm up.
curl http://localhost:8765/health

/health does not require auth; it returns {"status": "ok", "host": "127.0.0.1"} when the daemon is ready. The host field reflects the in-app default and is harmless — the listener itself binds to 0.0.0.0:8765 inside the container.

State is persisted across restarts via two host bind-mounts that compose creates next to the repo:

Path on host Path in container What lives there
./state /data/state runtime db, vector index, event log, model cache
./vault /data/vault your markdown knowledge base

Drop a .md file into ./vault/00_inbox/ on the host and it is immediately visible to ingest commands inside the container.

First Memory API call

Every /v1/* route requires Authorization: Bearer <SB_SERVE_TOKEN>. A canonical first call is the memory recall route:

TOKEN="${SB_SERVE_TOKEN:-$(uv run sb serve-token show --create)}"

curl -H "Authorization: Bearer ${TOKEN}" \
  "http://localhost:8765/v1/memory/recall?query=hello&top_k=3"

For an audited inspection of recent runtime events:

curl -H "Authorization: Bearer ${TOKEN}" \
  "http://localhost:8765/v1/audit/event_log?limit=5"

The very first recall after a fresh build can take 10–60 seconds while sentence-transformers downloads its default embedding model into ./state/hf_cache. Subsequent calls hit the local cache and return in milliseconds. This warm-up is expected, not a bug.

The full route surface, request/response shapes, and error contract live in contracts/memory_api_v1.yaml (in the repo root). Treat that file as the source of truth — anything documented there is callable against the running container with the same bearer token used above.

Observing the daemon

docker compose ps                  # running container + health status
docker compose logs -f secondbrain # live logs
docker compose exec secondbrain sb doctor   # in-container diagnostics

Stopping and resetting

docker compose down                # stop the container, keep ./state and ./vault
docker compose down -v             # also drop named volumes (bind mounts survive)
rm -rf ./state ./vault             # full local reset (destructive)

Troubleshooting

  • /health never responds. First boot pulls and compiles sentence-transformers wheels; expect up to 90 s. If it still hangs after that, inspect docker compose logs secondbrain.
  • 401 Unauthorized on /v1/*. The Authorization: Bearer … header is missing or does not match SB_SERVE_TOKEN. The token is read from the environment at container start; restart compose after exporting a new value. Use sb serve-token status to inspect the local token state without printing the secret, or eval "$(uv run sb serve-token env)" to export the active token into your current shell.
  • Port 8765 already bound. Either stop the conflicting process or remap in docker-compose.yml: "18765:8765" then call localhost:18765.
  • Permission errors writing to ./state or ./vault. The container runs as UID 1000. On Linux hosts where your shell user is not UID 1000, run sudo chown -R 1000:1000 ./state ./vault once.