War Room's boardroom has a voice + video call surface and an optional meeting transcriber. Both are opt-in. A fresh clone runs fully without either, the boardroom just shows seats and an amber "voice not configured" note until you wire up LiveKit.
This guide covers the two pieces, in order:
- Self-hosted LiveKit, the realtime server that carries the audio/video. Required for the boardroom call to work.
- WhisperX transcriber, records a call and saves a transcript. Optional on top of (1).
Nothing here touches the default app build. If you skip this page, War Room behaves exactly as before.
The boardroom uses LiveKit for voice/video. You run your own server, there is no shared War Room infrastructure.
tools/install-livekit.sh is a one-shot installer. On the server, as
root:
# optional: a real hostname gets you WSS/TLS instead of plain ws://
LIVEKIT_DOMAIN=livekit.example.com bash install-livekit.shIt installs the LiveKit binary, generates an API key + secret, writes
/etc/livekit.yaml, opens the firewall (UDP 50000-50100 for WebRTC
media, TCP 7880/7881), adds an nginx vhost, and registers LiveKit under
PM2. At the end it prints three values:
LIVEKIT_URL=...
LIVEKIT_API_KEY=...
LIVEKIT_API_SECRET=...
Re-run bash install-livekit.sh --print-creds any time to print them
again (e.g. for a teammate joining later).
Add the three values to your local War Room env file
(~/.war-room/.env, or .env.local in the repo):
LIVEKIT_URL=wss://livekit.example.com
LIVEKIT_API_KEY=APIwr...
LIVEKIT_API_SECRET=...
Restart War Room. The boardroom's amber warning disappears and the mute / camera / screen-share controls go live. Every teammate uses the same three values.
LIVEKIT_API_SECRETsigns room-join tokens. Keep it server-side only, it must never reach a client bundle. War Room mints tokens inapp/api/livekit/token/route.ts(a server route) and the transcriber uses the secret directly. Don't paste it anywhere a browser sees.- Without
LIVEKIT_DOMAINthe installer falls back to plainws://on the bare IP. Fine for a quick trial; use a domain +certbotfor anything real so media negotiation runs over TLS. - The open UDP range is a real network surface. Keep the VPS firewall otherwise tight.
Once LiveKit works, you can optionally run the transcriber. It joins a boardroom call as a hidden listener, records each participant, and after the call saves a speaker-labelled transcript into the boardroom Meeting transcripts panel.
It lives in tools/whisperx-transcriber/. It's a separate Python
process, it does not ship in the War Room app build.
cd tools/whisperx-transcriber
python -m venv .venv
# Windows: .venv\Scripts\activate
# macOS/Linux: source .venv/bin/activate
pip install -r requirements.txt
cp .env.example .envWhisperX pulls in PyTorch. For CPU that's all you need. For real speed
on long meetings, install a CUDA-enabled torch build and set
WHISPER_DEVICE=cuda.
Edit .env:
LIVEKIT_URL,LIVEKIT_API_KEY,LIVEKIT_API_SECRET, the same three values from step 1.WAR_ROOM_URL, where War Room is running (http://127.0.0.1:3000if the worker is on the same machine).ROOM_NAME, leave aswarroom-main(the boardroom's room).WHISPER_MODEL/WHISPER_DEVICE, accuracy vs speed.
python main.pyStart it before or during a boardroom call and leave it running. When the last person leaves the call, or you press Ctrl+C, it transcribes every track and POSTs the result. A minute or two later the transcript shows up in the boardroom panel.
To keep it always-on, run it under PM2 or a systemd service the same way you'd run any worker. It idles cheaply between meetings; the heavy WhisperX/torch load only happens when a call actually ends.
LiveKit gives each participant their own audio track. The transcriber records one WAV per track, so the speaker label is just the participant's name, no diarization guesswork. WhisperX handles the transcription and word-level timing.
The transcriber's POST to War Room is authenticated with
LIVEKIT_API_SECRET as a bearer token. Only a process that already
holds the LiveKit credentials can write transcripts, so there's no
extra secret to manage.
| Symptom | Fix |
|---|---|
| Boardroom still shows the amber "voice not enabled" note | The three LIVEKIT_* vars aren't set, or War Room wasn't restarted after setting them. |
| Call connects but no audio across the network | You're on plain ws://. Set LIVEKIT_DOMAIN + run certbot for WSS. |
Transcriber prints missing env |
Copy .env.example to .env and fill it in. |
POST failed / server replied 401 |
LIVEKIT_API_SECRET in the transcriber's .env doesn't match War Room's. |
POST failed / server replied 503 |
War Room itself has no LIVEKIT_API_SECRET set, finish step 1 first. |
| Transcription is very slow | Use a smaller WHISPER_MODEL, or WHISPER_DEVICE=cuda with a GPU. |