Local setup
Get a developer machine ready: install the toolchain, clone the four repos, bring up MongoDB and Redis locally, then do the first-time install for each service.
This page takes a clean machine to the point where every service is installed and
its dependencies are running. It does not start the services — that's the next
page, running the stack. The goal here
is: toolchain in place, all four repos cloned, MongoDB and Redis up, dependencies
synced, and a .env ready for each service.
The platform is four cooperating services — Console, Backend API, Voice fleet, and Dialler — around a shared data layer. If that split is new to you, read the system architecture first; it explains why the runtime services hold no durable state and re-fetch config every call.
You can run the whole control plane and most of the runtime plane on a laptop. What you cannot fully exercise locally is real telephony — LiveKit SIP and the Dialler need carrier trunks and reachable media. Those are flagged as advanced / optional below, and you can build everything else without them.
Prerequisites
Install these once. The two Python services and the Dialler all run on the same toolchain; the Console runs on Node.
| Tool | Used by | Why |
|---|---|---|
| git | everything | Clone the repos from Bitbucket. |
| uv | Backend API, Voice fleet, Dialler | Python package manager and runner. Targets Python 3.12. Never use pip. |
| Python 3.12 | the three Python services | requires-python >=3.12. uv can install it for you. |
| Node (current LTS) + npm | Console | React 19 + Vite 8 build and dev server. |
| Docker | local data layer | Runs MongoDB and Redis without polluting your machine. |
# git ships with Xcode CLT; otherwise:
brew install git
# uv — the Python package manager for all three Python services
brew install uv
# Node (current LTS) — for the Console
brew install node
# Docker Desktop — for local MongoDB + Redis
brew install --cask docker# git
sudo apt-get update && sudo apt-get install -y git
# uv (official installer)
curl -LsSf https://astral.sh/uv/install.sh | sh
# Node via nvm (current LTS)
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.1/install.sh | bash
nvm install --lts
# Docker Engine — follow https://docs.docker.com/engine/install/Tip
uv can manage the Python 3.12 interpreter itself — you don't have to install
Python separately. uv sync will fetch a matching toolchain if your system Python
is older.
Verify the toolchain before you go further:
git --version
uv --version # should resolve Python 3.12 for these projects
node --version # current LTS
docker --versionClone the repositories
All four repos live in the oriserve1 Bitbucket workspace. Make sure your SSH key is
added to your Bitbucket account,
then clone them side by side into one parent directory — they reference each other at
runtime over the network, not the filesystem, but keeping them together makes life
easier.
The prose names map to the real Bitbucket repos like this:
| Service (what we call it) | Bitbucket repo | Stack |
|---|---|---|
| Backend API | vox-backend | Python 3.12 · FastAPI |
| Console | vox-frontend | React 19 · Vite 8 |
| Voice fleet | vox-agents | Python 3.12 · FastAPI · Pipecat |
| Dialler | vox-dialler | Python 3.12 · asyncio worker |
# pick a workspace dir
mkdir -p ~/ori && cd ~/ori
git clone git@bitbucket.org:oriserve1/vox-backend.git # Backend API
git clone git@bitbucket.org:oriserve1/vox-frontend.git # Console
git clone git@bitbucket.org:oriserve1/vox-agents.git # Voice fleet
git clone git@bitbucket.org:oriserve1/vox-dialler.git # DiallerFor the full picture of what each repo owns and the contracts between them, see the repository map. From here on we use the friendly service names (Backend, Console, Voice fleet, Dialler).
Start the local data layer
The Backend stores all durable records in MongoDB and uses Redis for queues and runtime cache. The Dialler shares the same MongoDB database as the Backend. Run both in Docker — it's the quickest way to get the exact ports the services expect.
| Dependency | Local port | Used by |
|---|---|---|
| MongoDB | 27017 | Backend (database voxbridge), Dialler (same database) |
| Redis | 6379 | Backend (queues, bot-config cache) |
Drop this docker-compose.yml into your ~/ori workspace dir and bring both up
with one command. Named volumes keep your data across restarts.
services:
mongo:
image: mongo:7
container_name: ori-mongo
ports:
- "27017:27017"
volumes:
- ori-mongo-data:/data/db
redis:
image: redis:7
container_name: ori-redis
ports:
- "6379:6379"
volumes:
- ori-redis-data:/data
volumes:
ori-mongo-data:
ori-redis-data:docker compose up -d # start both in the background
docker compose ps # confirm both are healthy
docker compose down # stop (data is kept in the volumes)If you'd rather not keep a compose file, start each container directly:
docker run -d --name ori-mongo \
-p 27017:27017 \
-v ori-mongo-data:/data/db \
mongo:7
docker run -d --name ori-redis \
-p 6379:6379 \
-v ori-redis-data:/data \
redis:7These map straight onto the connection defaults the services ship with —
mongodb://localhost:27017 and redis://localhost:6379 — so no extra wiring is
needed for local work.
First-time install per service
Each repo installs independently. The three Python services use uv sync; the
Console uses npm install. Every service also reads a .env, which you copy from the
checked-in .env.example. The variable meanings live on the
configuration page — we point you there rather
than repeat them, so there's a single source of truth.
Backend API (vox-backend)
The control-plane API. Installs with uv sync, runs on port 8080, and needs
MongoDB and Redis (which you started above).
cd ~/ori/vox-backend
uv sync
cp .env.example .envThe defaults in .env.example already point at local MongoDB and Redis. The one
value you'll want to set for yourself is JWT_SECRET. See
configuration for every variable.
Tip
Before you can log in to the Console, you need a first admin user. The Backend
ships a helper for exactly this — uv run python scripts/seed_admin.py — which
you'll run once after the Backend is up. We cover that on the
running the stack page.
Console (vox-frontend)
The React + Vite operator dashboard. Installs with npm install. Its branding
and its API target are configured at build time through VITE_* variables —
most importantly VITE_API_URL, which must point at your local Backend.
cd ~/ori/vox-frontend
npm install
cp .env.example .env # then set VITE_API_URL to http://localhost:8080For Ori's single-brand repo the build is just npm install then the dev server —
there's no brand-selection step to run. The committed brand .env already carries
the Ori theme. See configuration for the
VITE_* reference.
Voice fleet (vox-agents)
The call workers and speech pipeline. Installs with uv sync, runs on port
8000 (4 workers in dev). It needs a reachable Backend config URL — locally
that's your Backend on http://localhost:8080/api/v1/config.
cd ~/ori/vox-agents
uv sync
cp .env.example .envThe .env.example here is the largest — it carries the Backend config URL, the
STT / LLM / TTS provider keys (Soniox, Deepgram, OpenAI, Google, ElevenLabs,
Sarvam), object-storage (MinIO) settings for recordings, and audio / concurrency
knobs. Fill in whichever provider keys you actually want to exercise; the rest can
stay blank for local work. Full reference on the
configuration page.
Recording upload and live telephony are the parts you can't fully reproduce on a laptop. The pipeline uploads call WAVs to object storage (MinIO / S3), and real SIP calls need LiveKit — see telephony is optional below. Without those, the fleet still installs and boots; you just won't drive a real phone call through it.
Dialler (vox-dialler)
The campaign-pacing background worker. Installs with uv sync. It shares the
Backend's MongoDB database (voxbridge) and reaches the fleet over the network.
It is not a typical web server — it runs a tick loop and exposes a small
health server on port 8090.
cd ~/ori/vox-dialler
uv sync
cp .env.example .envIts .env carries the shared MONGODB_URI / MONGODB_DB, the fleet URLs, the
shared fleet secret, and LiveKit credentials. The Dialler is optional for
local — see below.
Telephony and the Dialler are optional for local
Real SIP telephony does not work on a plain laptop. LiveKit SIP needs carrier trunks and reachable media (on cloud it needs an external IP), and the Dialler exists to place real outbound calls through it. You can install both, but you can't fully exercise a live phone call without that telephony plane.
What this means in practice for local development:
Build without telephony
The Backend, Console, and Voice fleet all install and run against local MongoDB + Redis. You can build bots, edit campaigns, drive the Console, and exercise the Backend's APIs end to end without LiveKit or the Dialler running at all.
Telephony is a later step
LiveKit runs as a self-hosted docker-compose stack (livekit + livekit-sip) and
the Dialler runs as a single instance against it. Stand these up only when you
specifically need to test outbound dialing or SIP inbound — covered in the DevOps
deployment guide, not required for first-run local work.
One placement rule carries over even when you do run the Dialler: there must be exactly one Dialler instance per database. Two diallers on the same MongoDB over-dial, because each paces as if it were the only one. Locally that just means: don't start a second copy.
What's next
Everything is installed and the data layer is up. Now bring the services to life.
Running the stack
Start the Backend, seed your first admin, launch the Console, run the Voice fleet in dev mode, and check each service's health endpoint. Picks up exactly where this page leaves off.
Repository map
The four Ori repositories, the control-plane / runtime-plane boundary they sit on, and the contracts that bind them together.
Running the stack
The core local dev loop: bring up MongoDB and Redis, run the Backend, run the Console, and run a single voice-fleet worker — then watch a real call land on your machine.