Skip to main content

What compose is

docker-compose.yml is a local stack: Postgres, the backend, the voice worker and the console, on one network, with both published ports bound to 127.0.0.1.
Each service also has its own Dockerfile and deploys on its own. LiveKit is external in every case: the worker connects out to LIVEKIT_URL.

Read this before it faces a network

The backend has no authentication. Every route is open, including the ones that read and write the LiveKit project and the agent’s prompt. That is deliberate for a tool on your own machine and wrong on a public address. Put something in front of it, or do not expose it.
Three more facts that follow from that:
  • CONSOLE_WRITES_ENABLED stays off. It defaults to false in code. Compose turns it on because compose is local. Anywhere else, leave it off and the write routes refuse.
  • Your LiveKit signing secret is stored unencrypted. On first boot the backend copies the LiveKit project from the environment into the livekit_settings table, and the Deployment page edits it there. So the secret is in Postgres, in the pgdata volume, and in any dump you take. Rotating the key in your LiveKit project is the revocation path.
  • CORS_ORIGINS_STR unset means every origin is allowed. Compose sets it to http://localhost:5173, but the code default is empty and BACKEND_CORS_ORIGINS returns ["*"] for empty, so a backend started without it accepts browser calls from anywhere. Set it explicitly on any host that is not your own machine.

The worker

agent/fly.toml is set up for Fly: performance-1x, blue/green, and a kill_timeout of five minutes matching the drain_timeout=300 on AgentServer. That pairing is what makes a deploy mid-call finish the call instead of dropping it. The worker restarts itself when the stored LiveKit project changes, which is why the compose service carries restart: unless-stopped. Whatever you deploy onto needs the same: a process supervisor that brings it back.

The backend

It runs alembic upgrade head on startup, under a Postgres advisory lock so concurrent boots serialise. There is no separate migration step, and a slow database does not stop it booting: it serves tokens from the environment until Postgres catches up.

The console

Static files. The three VITE_ values are compiled in at build time, so the image is environment-specific: build one per environment, and never reuse a local image against a remote backend.

Where secrets live

In .env, which is gitignored, except for the LiveKit project once the backend has copied it into Postgres. Nothing else in this repo persists a credential.