The repository ships four Compose files. Only one of them is meant for a laptop. Running docker compose up with the root file on a laptop does not work: it expects host networking, a public TURN domain and an external certificate volume. Use the dev file.

Local development

Open http://localhost:3000. The dev file publishes the media server on 7880 (WebSocket) and 7881, plus a small UDP range for media; set the app’s media server address to ws://localhost:7880. To test phone calls locally, start the optional SIP bridge as well:
Stop everything with Ctrl + C and then:
Linux: the app on the host writes published-agent snapshots with group-only read permission. Set HOST_GID to the output of id -g in .env so the worker container can read them.

What the containers run

app (hosted only)

  • Built from infra/docker/Dockerfile.app.
  • Starts with pnpm voice-session:check && pnpm start -p <port>: the admission limits are validated against the worker’s capacity before the server listens.
  • Serves GET /api/health (liveness) and GET /api/ready (readiness). The container healthcheck uses /api/health; the production deploy waits on /api/ready. See Environment variables.

agent

  • Built from infra/docker/Dockerfile.agent.
  • Runs python src/main.py start: the LiveKit Agents worker. It registers with the media server and accepts jobs; it publishes no HTTP port except the optional Prometheus metrics endpoint.
  • Mounts ./data read-only to read the published-agent snapshots the app writes.

livekit, redis, egress, sip

Shared infrastructure. On the hosted box they are started once by hand and never recreated by a code deploy; deploys recreate only app and agent with --no-deps.

Environment variables

Every service reads .env at startup, but only the variables listed under that service’s environment: block in the Compose file reach the container. A variable in .env that the Compose file does not pass through is silently ignored. Provider keys set here apply to every user and to published agents; see Environment variables for the full list. After adding or changing a key, recreate the affected services:
Keys a user types in the builder’s Settings panel are used for that browser session only and are never written to .env. If the user publishes while a key is typed, that key is stored in the published version’s snapshot on the host so the published agent can use it.

Orchestration mode on publish

An agent’s first publish uses ORCHESTRATION_MODE_DEFAULT (skill_orchestrator unless set). Publishing an agent again keeps the mode of its live version, so a republish never switches how a live agent routes between Skills; versions published before modes were recorded count as linear. The Playground tests on the same mode a publish would use. The Publish panel describes the mode in one sentence, with its name in a tooltip (skill_orchestrator is Smart routing, linear is Step by step). To keep every first publish on linear, set ORCHESTRATION_MODE_DEFAULT=linear in .env and restart the app service.

Logs

Hosted deploys

The hosted environments are never deployed with these commands by hand. Code reaches DEV on a push to develop, STAGING through scripts/promote.sh staging, and PROD through scripts/promote.sh main --deploy plus the Deploy PROD workflow approval. The runbooks are docs/DEPLOYMENT-RUNBOOK.md and VPS-OPERATIONS.md in the repository.