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, the 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.
ToolUsed byWhy
giteverythingClone the repos from Bitbucket.
uvBackend API, Voice fleet, DiallerPython package manager and runner. Targets Python 3.12. Never use pip.
Python 3.12the three Python servicesrequires-python >=3.12. uv can install it for you.
Node (current LTS) + npmConsoleReact 19 + Vite 8 build and dev server.
Dockerlocal data layerRuns 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
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 --version

Clone the repositories

The Pelocal repos live in the pelocal-techservice 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 repoStack
Backend APIvb-corePython 3.12 · FastAPI
Consolevb-dashboardReact 19 · Vite 8
Voice fleetvb-agentsPython 3.12 · FastAPI · Pipecat
Dialler(no separate Pelocal repo)Python 3.12 · asyncio worker
# pick a workspace dir
mkdir -p ~/pelocal && cd ~/pelocal

git clone bitbucket-pelocal:pelocal-techservice/vb-core.git       # Backend API
git clone bitbucket-pelocal:pelocal-techservice/vb-dashboard.git  # Console
git clone bitbucket-pelocal:pelocal-techservice/vb-agents.git     # Voice fleet
The Dialler is not cloned here. It is deployed and operated for Pelocal (it runs on the SIP/LiveKit host), but its source is managed with the platform rather than as a separate Pelocal Bitbucket repo, so there is no Dialler clone URL. Developers rarely run it locally in any case — it needs real SIP to do anything useful. See the telephony note below.
For 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.
DependencyLocal portUsed by
MongoDB27017Backend (database voxbridge), Dialler (same database)
Redis6379Backend (queues, bot-config cache)
These 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.
1

Backend API (vb-core)

The control-plane API. Installs with uv sync, runs on port 8080, and needs MongoDB and Redis (which you started above).
cd ~/pelocal/vb-core
uv sync
cp .env.example .env
The 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.
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.
2

Console (vb-dashboard)

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 ~/pelocal/vb-dashboard
npm install
cp .env.example .env     # then set VITE_API_URL to http://localhost:8080
For Pelocal’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 Pelocal theme. See configuration for the VITE_* reference.
3

Voice fleet (vb-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 ~/pelocal/vb-agents
uv sync
cp .env.example .env
The .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.
4

Dialler

The campaign-pacing background worker. It is not a typical web server — it runs a tick loop and exposes a small health server on port 8090. It shares the Backend’s MongoDB database (voxbridge) and reaches the fleet over the network.The Dialler is deployed and operated for Pelocal (it runs on the SIP/LiveKit host as the voxdialler systemd service), but its source is managed with the platform rather than as a separate Pelocal Bitbucket repo — there is nothing to clone here. Where its source is present it installs the same way as the Python services (uv sync, then a .env from .env.example) and runs with uv run python -m voxdialler.main. Its .env carries the shared MONGODB_URI / MONGODB_DB, the fleet URLs, the shared fleet secret, and LiveKit credentials.In practice you rarely run the Dialler locally — it needs real SIP to do anything useful. It 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.

Configuration reference

Every .env variable for all four services, with defaults and meanings.

Repository map

What each repo owns and the contracts between them.