The platform is four cooperating services, and each one lives in its own git repository under the oriserve1 Bitbucket workspace. This page maps every repo to its service, shows which plane it sits on, and spells out the handful of contracts that let the four pieces work as one system.
In prose we call the services Console, Backend / Backend API, Voice fleet, and Dialler. Those friendly names are what you use day to day. The git repositories have their own canonical names — vox-frontend, vox-backend, vox-agents, vox-dialler — and those are what you clone, branch, and deploy. The table below is the one place the two namings meet; everywhere else, the friendly names win.

The four repositories

All four live at git@bitbucket.org:oriserve1/<repo>.git.
RepositoryServicePlaneLanguage / runtimePackage managerWhat it owns
vox-backendBackend APIControlPython 3.12 · FastAPIuvAuth, bots, campaigns, system settings, per-call runtime config, durable call records, CRM push, API keys, recordings access, fleet selection
vox-frontendConsoleOperator surfaceReact 19 · Vite 8 (SPA)npmThe operator dashboard: bot builder, campaign builder, call logs, reports, settings, knowledge bases
vox-agentsVoice fleetRuntime / mediaPython 3.12 · FastAPI · Pipecat 1.3.0uvLive call workers, transport adapters, the speech pipeline, recording upload, post-call packaging, result delivery
vox-diallerDiallerRuntime / executionPython 3.12 · asyncio workeruvCampaign leases, predictive pacing, retry scheduling, outbound SIP dialing, answering-machine screening, attaching answered calls to the fleet
Internal development directories do not match the repo names — you may see a checkout sitting in a folder called something else locally. That mismatch is cosmetic and historical. For anything an operator or DevOps engineer touches — cloning, CI configuration, deploy jobs, runbooks — always refer to the repositories by their Bitbucket names (vox-backend, vox-frontend, vox-agents, vox-dialler). Never script against a local directory name.

Repo → service → plane

Control plane vs runtime plane

The defining rule of the platform is a clean split between the control plane, which owns durable business state, and the runtime plane, which runs the actual calls and holds no long-lived state.

Control plane — the source of truth

vox-backend (Backend API) plus its data layer — MongoDB, Redis, the vector database, and object storage — hold everything durable: bots, campaigns, system settings, and every call record. vox-frontend (Console) is the operator’s window onto that truth. If a piece of state must survive a restart, it lives here.

Runtime plane — disposable muscle

vox-agents (Voice fleet) and vox-dialler (Dialler) do the heavy real-time work but keep no durable state. They re-fetch everything they need from the control plane at the start of each call, which is why you can scale them out, restart them, or replace a host freely — and why a crashed fleet worker costs you exactly one call.
This boundary is not just architectural tidiness; it drives the operational model. You scale the runtime plane horizontally (add fleet hosts, add workers) without touching the control plane, and you back up and protect the control plane carefully because it is the only thing that cannot be regenerated.

The contracts between services

Four narrow contracts connect the services. Everything else is internal. If you understand these four, you understand how a call gets configured, run, recorded, and recorded back.
1

Backend serves per-call runtime config — the fleet fetches it

At the start of every call, the Voice fleet calls the Backend’s config endpoint and gets back the complete picture for that bot: prompts, voice settings, tools, and any CRM data for this contact. The fleet stores nothing between calls — this fetch is how a stateless worker becomes “the right bot” for the next 90 seconds.The endpoint is GET /api/v1/config on the Backend. The fleet (vox-agents) knows where to find it via VOXBRIDGE_CONFIG_URL in its environment (for example http://localhost:8080/api/v1/config when the Backend is co-located).
# vox-agents .env
VOXBRIDGE_CONFIG_URL=http://localhost:8080/api/v1/config
2

The fleet posts results back to the Backend

When the call ends, the fleet hands the Backend a complete record — transcript, post-call analysis, quality-control findings, a disposition, and the recording reference. The Backend stores it as the durable call record and can push it onward to a CRM. The fleet’s job is finished the moment the result is delivered.
3

The Dialler shares the SAME MongoDB database as the Backend

The Dialler and the Backend point at the same MongoDB database (MONGODB_DB=voxbridge in both). The Dialler reads running campaigns and leases call records directly from that shared database — there is no separate dialler API. The campaign records the Console writes through the Backend are the same records the Dialler paces and dials.
# both vox-backend and vox-dialler .env
MONGODB_DB=voxbridge
Exactly one Dialler instance may run against a given database. Two diallers on one MongoDB over-dial, because each one paces as if it is the only dialler in the system. Run the single Dialler instance on the SIP/LiveKit host.
4

The Dialler attaches answered calls to the fleet via POST /attach

The Dialler places outbound SIP calls through LiveKit and, on answer, hands the live call to a free fleet worker with POST /attach. From that point the worker drives the conversation exactly as it would an inbound call — same pipeline, same config fetch, same post-call path. The Dialler authenticates the attach with a shared secret (VOXCORE_SECRET) and finds workers from its configured fleet list (FLEET_URLS).
The Console (vox-frontend) has only one upstream: the Backend. It talks to nothing else — not the fleet, not the dialler, not the database. The Backend’s base URL is baked into the build at build time via VITE_API_URL. Every operator action, every list, every save goes through that one address.
# vox-frontend brand .env
VITE_API_URL=https://api-voice-agent.oriserve.com

Contract summary

ContractFrom → ToMechanismNotes
Runtime configVoice fleet → BackendGET /api/v1/config (fleet fetches per call)Located via VOXBRIDGE_CONFIG_URL
Call resultsVoice fleet → BackendFleet posts the finished record backBackend stores it and may push to a CRM
Shared campaign stateDialler ↔ BackendSame MongoDB database (MONGODB_DB=voxbridge)No dialler API; one dialler per database
Attach answered callDialler → Voice fleetPOST /attach (authenticated with VOXCORE_SECRET)Fleet workers found via FLEET_URLS
Operator actionsConsole → BackendHTTPS to VITE_API_URLConsole’s only upstream

Where each repo runs

The repository boundaries line up with the deployment topology. A small deployment co-locates roles; a larger one spreads them across hosts.
vox-backend (Backend, uvicorn on :8080) and the built static output of vox-frontend (Console, served by nginx). Small deployments also co-locate MongoDB and Redis here.

Package managers at a glance

The three Python repos all use uv — never pip. The Console uses npm.
uv sync                 # install dependencies
uv run uvicorn voxbridge.app:app --host 0.0.0.0 --port 8080 --app-dir src
The module paths above (voxbridge.app, voxcore.app, voxdialler.main) are the importable Python package names inside each repo. They are the run targets, not the repo names — clone vox-backend, but launch voxbridge.app.

Where to go next

System architecture

The end-to-end picture: the four services, the data layer, the telephony plane, and the life of a single call.

Run it locally

Prerequisites, cloning the repos, and running the whole stack on your own machine.

Deploy it

The Bitbucket → Jenkins pipeline, host deployment, configuration, and the operations runbook.