Docker Compose
One Compose file with profiles for the laptop, demo and evaluation stacks
One Compose file, docker-compose.yml at the repository root, covers every local scenario. Optional services sit behind Compose profiles. The file is a dev, demo and evaluation stack, not a production deployment: it ships dev fallback secrets, publishes service ports on the host and connects as a database superuser. Production uses the Helm chart in helm/epistom/ (see Installation).
Before the first start
cp .env.example .env.local # settings read by the migration and API containers
make retail-seed # builds demo/retail-estate/seed.sql.gz (not tracked in git)demo/retail-estate/fetch-retail-seed.sh downloads the same seed from a release instead of building it. Run one of the two before the first up: if the seed file is missing, Compose creates an empty directory in its place.
Full platform (default)
make upmake up writes the gitignored .env with generated dev secrets (EPISTOM_JWT_SECRET, EPISTOM_ENCRYPTION_KEY, EPISTOM_PRAXOM_SIGNING_KEY, EPISTOM_DEMO_JWT_SECRET) and then runs docker compose up -d. A plain docker compose up -d refuses to start until those secrets exist.
| Service | Image | Host port | Purpose |
|---|---|---|---|
postgres | pgvector/pgvector:pg16 | 5435 | Demo retail estate and platform metadata |
oxigraph | ghcr.io/oxigraph/oxigraph:0.5.9 | 7879 | SPARQL triplestore |
redis | redis:7-alpine | 6380 | Live attestation feed and shared rate-limit, idempotency and budget stores |
migration | built from Dockerfile | — | Runs alembic upgrade head once, then exits |
api | built from Dockerfile | 8001 | REST API, MCP endpoint and Praxom (pramiti.composition.main:app) |
ui | built from pramiti-console/Dockerfile | — | Console, reached through nginx |
nginx | nginx:alpine | 443, 80 | TLS proxy: /api/v1/ and /mcp/v1/ go to api, everything else to ui |
The api service runs in the laptop demo posture: EPISTOM_PROFILE=dev, EPISTOM_AUTH_MODE=demo and auth disabled unless you set EPISTOM_AUTH_DISABLED=false.
Profiles
| Profile | Adds | Host ports |
|---|---|---|
vkg | ontop (ontop/ontop:5.1.2), the virtual knowledge graph over PostgreSQL | 8081 |
trino | trino (trinodb/trino:483), cross-source federation | 8083 |
epistom | epistom-api (epistom_main:app, read plane only) and epistom-nginx | 8011; 8443, 8088 |
praxom | praxom-api (praxom_main:app, write plane only, no Oxigraph) and praxom-nginx | 8012; 8445, 8089 |
flight-recorder | flight-recorder, the standalone Flight Recorder | FR_PORT (8080) |
EPISTOM_ONTOP_ENABLED=true docker compose --profile vkg up -d # the API routes to Ontop only with the flag set
docker compose --profile trino up -d # set EPISTOM_TRINO_ENABLED=true on the API to use it
docker compose --profile epistom up -d
docker compose --profile praxom up -d
docker compose --profile flight-recorder up -d flight-recorderThe product profiles use their own host ports, so they can run beside the default stack. They share its postgres and migration services.
Flight Recorder
The flight-recorder service has no other dependency. It uses SQLite by default and reads these variables:
FR_DATABASE_URL=sqlite:////app/data/flight_recorder.db # or postgresql://...
FR_SIGNING_PRIVATE_KEY=<base64-ed25519-key>
FR_API_KEY=<your-api-key>
FR_PORT=8080Hot reload
The api service always bind-mounts ./src into the container. For hot reload, stop the running api (docker compose stop api) and start it with --reload:
docker compose run --rm --service-ports api uvicorn pramiti.composition.main:app --host 0.0.0.0 --port 8000 --reloadData persistence
| Volume | Service | Path |
|---|---|---|
oxigraph_data | oxigraph | /data |
postgres_data | postgres | /var/lib/postgresql/data |
nginx_certs | nginx, epistom-nginx, praxom-nginx | /etc/nginx/certs |
fr_data | flight-recorder | /app/data |
To stop the stack and delete all data:
docker compose down -vEnvironment variables
See Configuration for all variables.