Local development
The docker-compose matrix, envctl, and the INTERNAL vs BROWSER URL rule.
Local dev runs the whole stack via docker-compose, from the shape-rotator-all monorepo root.
Environment switching
- Single source of truth per world:
environments/matrix.local.envandmatrix.prod.env(gitignored;.exampletemplates versioned). - The
envctlscript (render / show / check / gen-tokens) reads the matrix and upserts derived keys into the three backend.envfiles (conclave-shape-rotator/.env,capture/.env,FPM/.env), preserving each product's own keys.
The #1 local-stack footgun. There are two URL classes:
INTERNAL_* resolves on the docker network (http://fpm-backend:8085);
BROWSER_* must resolve from the host browser (http://localhost:8085).
Conflating them is the most common breakage.
Bringing up the stack
# from shape-rotator-all/
docker compose -f docker-compose.local.yml up
# migrated / authoritative-finalizer topology:
docker compose -f docker-compose.local.yml -f docker-compose.migrated.yml upServices in the local stack:
| Service | Port | Notes |
|---|---|---|
conclave-api | 8000 | FastAPI + SQLite |
conclave-web | 3001 | next dev |
capture-runtime-api / redis / bot | 8090 / 6379 | online-bot path |
fpm-backend | 8085 | identity |
fpm-web | 3002 | consent dashboard |
capture-diarize-diart | 8087 | in-person live diart |
fpm-diarizen | — | profile-gated |
Cloud endpoints — Supabase auth, NEAR Whisper ASR, RedPill LLM — are the same in both worlds. Local isolation comes from a separate workspace (
local-wsvsdemo-ws) + separate DB volumes, not separate cloud services. In the migrated topology DiariZen runs on a remote GPU box reached by SSH tunnel (scripts/diarize-tunnel.sh,localhost:8086).
compose files
docker-compose.local.yml (full stack) · .migrated.yml (authoritative finalizer override) ·
.diarize-e2e.yml / .identify-e2e.yml (E2E harnesses) · .audio-upload*.yml (upload onboarding).
Source: ENVIRONMENTS.md, DEPLOY-LOCAL.md.