Quick Start
Use this page to run Voxos locally and reach the frontend console.
Prerequisites
Section titled “Prerequisites”- Python 3.12.4 or newer.
uvfor Python dependency management.- Docker and Docker Compose for Postgres/pgvector, LiveKit, and containerized services.
- Node.js and npm for the React frontend.
- A Firebase project and web app configuration for browser sign-in.
- Provider API keys only for the providers you want to test.
Install uv if it is missing:
python -m pip install --upgrade uvDocker Compose Stack
Section titled “Docker Compose Stack”The root docker-compose.yml is the preferred local stack. It starts:
- FastAPI on
http://localhost:7100. - An Alembic migration job.
- LiveKit dev server on
ws://localhost:7880. - Postgres 16 with pgvector and a non-superuser Voxos app role.
- The durable
agent-run-workerused by queued runs and inbound SMS/WhatsApp replies. - A demand-driven voice supervisor under the
voiceprofile. - A multi-tenant WhatsApp linked-device worker under the
whatsappprofile.
Raw Compose commands keep those profiles opt-in. The canonical make up
command enables both so local development has one complete stack.
Create local settings:
cp .env.example .envGenerate a stable local encryption key and store it as
LOCAL_SECRET_ENCRYPTION_KEY in .env:
python -c 'import base64, os; print(base64.b64encode(os.urandom(32)).decode())'Generate a separate persistent signing secret for browser-based MCP OAuth and
store it as MCP_OAUTH_STATE_SIGNING_SECRET in .env:
python -c 'import secrets; print(secrets.token_urlsafe(32))'Keep this value stable and private. It signs short-lived OAuth state so the callback can be returned to the correct Voxos user and MCP server. Do not reuse a provider API key or the local vault-encryption key. All API replicas in one environment must use the same value.
Generate two separate local browser service credentials and append them to the
ignored .env file:
printf 'BROWSER_AGENT_SERVICE_TOKEN=%s\n' "$(openssl rand -hex 32)" >> .envprintf 'STEEL_SERVICE_TOKEN=%s\n' "$(openssl rand -hex 32)" >> .envKeep these values stable and private. Compose shares the browser-agent token
with its API and worker callers and uses the Steel token for the private
browser proxy. Host-mode API or workers also need
BROWSER_ACCOUNTS_STAGEHAND_SERVICE_TOKEN set to the browser-agent token.
See Developer Setup
for sandbox and queue configuration.
Start the stack:
make upThis rebuilds changed images, recreates services when their image changes,
runs migrations, removes obsolete containers, and waits for health checks.
make restart performs the same full reconciliation.
Check the API:
curl http://localhost:7100/healthUseful local commands:
docker compose logs -f api agent-run-worker scheduler whatsapp-worker voice-worker frontendmake db-enable-vectordocker compose downdocker compose down -vmake db-enable-vector creates the pgvector extension in the configured local
database with POSTGRES_ADMIN_USER and POSTGRES_ADMIN_PASSWORD from .env.
Compose explicitly keeps DATABASE_TLS_MODE=driver-default; remote production
databases should use certificate and hostname verification.
make up starts the containerized voice supervisor. You can instead install
the Python dependencies and run make worker on the host. A saved LiveKit URL
must resolve from both the caller and supervisor; container-only livekit and
container-local localhost hostnames are not interchangeable.
The minimal docker-compose.livekit.yml helper is not RLS-safe and does not
support current pgvector migrations.
The WhatsApp service started by make up contains the pinned Node/Baileys
bridge and uses the same database and secret-encryption configuration as the
API. The Phone page can temporarily
capture a registration SMS received by the selected Twilio/Telnyx resource or
answer a Telnyx verification call, respond to WhatsApp’s varying press-a-digit
prompt, and show the spoken code. Arm the selected capture method in Voxos
before requesting the code in WhatsApp Business. For a Telnyx UK mobile, use
the call fallback because ordinary SMS capability does not imply international
OTP reception. Enter the displayed code in WhatsApp Business manually, then
link Voxos from Linked devices with the QR or pairing code.
Local Python Development
Section titled “Local Python Development”Use this mode for hot reload, direct tests, and local worker processes.
uv sync --all-extras --devdocker compose up -d pgvector livekituv run alembic upgrade headmake runIf Alembic reports that the vector extension is missing in the target database, run
make db-enable-vector once and retry uv run alembic upgrade head.
The helper reads DB_HOST, DB_PORT, DB_NAME, POSTGRES_ADMIN_USER, and
POSTGRES_ADMIN_PASSWORD from .env or the shell environment.
Run the host-mode workers you need in separate terminals:
make workermake worker-runsmake worker-whatsappmake schedulermake worker runs the demand-driven LiveKit supervisor. It stays unregistered
until a browser or phone call creates tenant-scoped demand, then starts or reuses
an isolated child for that exact LiveKit project. Project credentials are saved
through Connection and stored in Postgres plus the user secret vault, not in
.env.
make worker-runs is required for durable runs, including an agent reply to an
inbound SMS or WhatsApp message. It is already a default service when using the
root Compose stack. make worker-whatsapp builds the locked Node bridge and
runs the shared linked-device worker. make scheduler is required only when
due schedules should enqueue runs.
make run reads .env, disables New Relic locally, and serves the API on
PORT, defaulting to 7100.
Frontend Console
Section titled “Frontend Console”The selected API provides Firebase client settings at /api/client-config,
including FIREBASE_WEB_APP_ID. Create frontend/.env.local for local API access:
VITE_API_BASE_URL=http://localhost:7100Start the frontend:
make frontendThe console runs at http://localhost:5173. Sign in with Firebase, then use the
console to save provider keys, approve tools, open text chats, test voice
sessions, add phone integrations, link WhatsApp Business, and register MCP
servers.
For Kubernetes, copy the values and environment templates from helm/examples/
into the ignored private/ directory, then use the root helm/ chart. Install its database
release before the application release and supply settings through private
Secrets, including the browser service credentials. Configure network policies
for the cluster and host sandbox profiles for Steel. The production web
frontend calls its current origin. See the repository’s helm/README.md
deployment guide.
MCP OAuth
Section titled “MCP OAuth”Hosted MCP services such as OpenBnB use the callback derived from
VITE_API_BASE_URL, which defaults locally to:
http://localhost:7100/api/mcp/auth/callbackOpenBnB does not require an OpenBnB OAuth client ID or client secret. Choose it from the MCP catalog and select Start sign-in. Voxos discovers the provider OAuth metadata, registers a client dynamically, and uses PKCE. Complete the provider page, return to Voxos, and let the page discover the tools. If the browser does not finalize automatically after focus returns, select Finalize connection once.
After adding or changing MCP_OAUTH_STATE_SIGNING_SECRET, recreate the Compose
API container so it receives the new environment:
docker compose up -d --no-deps --force-recreate apiRestart make run instead when the API is running directly on the host. Start
a fresh provider sign-in after any signing-secret change because previously
issued OAuth state will no longer verify.
Local Flightradar24 MCP
Section titled “Local Flightradar24 MCP”The Flightradar24 MCP requires a provider API key. Add it to the ignored root
.env file:
FR24_API_KEY=replace-with-your-flightradar24-keyStart the root Voxos Compose stack first, then start the separate MCP Compose file:
make mcp-stack-configmake mcp-stack-upOpen MCP, refresh the catalog, search for Flightradar24, and choose
Local Compose. The catalog choice uses the internal endpoint
http://flightradar24-mcp:8000/mcp; do not add the host port as a custom
server. Use make mcp-stack-logs to inspect it and make mcp-stack-down to
stop it.
For an independently hosted instance, choose Deployed HTTPS endpoint and enter its complete public HTTPS MCP URL. Custom public hostnames and paths are supported. Private, loopback, credential-bearing, and non-HTTPS deployment URLs are rejected.
Local Monzo MCP
Section titled “Local Monzo MCP”The Monzo integration builds the stateless ../monzo-mcp container. Create one
separate local MCP endpoint bearer:
install -d -m 700 "$HOME/.config/monzo-mcp"umask 077openssl rand -hex 32 \ > "$HOME/.config/monzo-mcp/monzo-mcp-endpoint-token"Set MONZO_MCP_HOST_ENDPOINT_TOKEN_FILE only when overriding that path. Set a
long random MCP_CREDENTIAL_DELEGATION_SIGNING_SECRET in .env; local setups
fall back to MCP_OAUTH_STATE_SIGNING_SECRET when it is absent. Then run:
make upmake mcp-stack-upOpen MCP, choose Monzo and Local Compose, then enter the contents of the endpoint-bearer file and your Monzo OAuth client ID and secret. Register the displayed callback URI in the Monzo developer portal, open the authorization URL, and approve the connection in the Monzo mobile app.
Voxos stores and refreshes the Monzo tokens. The container validates its own
bearer and exchanges a short-lived X-MCP-Credential-Delegation assertion at
the private Voxos broker for a request-lived access token. Test discovery and
grant only required read tools. The preset grants nothing automatically and
the Compose service disables financial writes.
Public Webhooks
Section titled “Public Webhooks”Phone webhooks, agent webhooks called from outside the local machine, and OAuth providers that reject loopback callbacks need a public HTTPS API base URL. For local development, use:
make ngrokSet API_PUBLIC_BASE_URL to the same https:// ngrok URL before configuring
Twilio, Telnyx, or an external agent-webhook caller. The Operations Webhooks
tab otherwise shows a relative delivery path that can still be used by callers
on the same origin. When an MCP OAuth provider requires a public callback, also
set the frontend’s VITE_API_BASE_URL to that public API origin because the
frontend constructs the MCP redirect URI from that value. Websocket media
stream routes use the same public host with wss://.
Before a Telnyx smoke test, open Phone, expand the connected number, and use Verify. It checks provider number/profile assignments, current public webhooks, outbound destination configuration, text-run prerequisites, and LiveKit routing without changing Telnyx. Use Repair only after reviewing the failed checks and confirming a provider-side update. Test inbound SMS, outbound SMS, inbound calls, and outbound calls separately with approved endpoints; the recent activity panel shows full numbers and safe final/failure states.