docs: initial design baseline for VoiceCat voice/text chat
Establish the design spec in docs/ before implementation:
- README: overview, locked decisions, principles, glossary
- architecture: shared C++ core + C ABI, native UIs (Swift/C#),
threading model, server design (SFU relay)
- protocol: TCP/TLS control plane, protobuf Envelope + message
catalog, connection lifecycle, extensibility rules
- voice: UDP media frame format, per-channel Opus config,
multi-stream model, two-sided noise reduction, VAD/PTT,
jitter buffer, iOS ReplayKit screen-audio
- security: mandatory encryption (TLS 1.3 + exported-key AEAD),
TOFU server identity, admin-provisioned accounts, anti-replay
- tech-stack: permissive-only deps (mbedTLS, libsodium, opus,
miniaudio, webrtc-apm, ...), build tooling, no GPL/LGPL
- deployment: zero-config self-host (Docker / binary / source)
- roadmap: M0-M5 milestones, resolved decisions
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-15 20:47:09 +02:00
|
|
|
# Deployment & Self-Hosting
|
|
|
|
|
|
|
|
|
|
The product goal: someone looks at this and thinks *"oh, I (or my agent) can stand this up
|
|
|
|
|
in a few minutes."* Everything below is in service of that. Three install paths, all
|
|
|
|
|
**zero-config and encrypted by default**.
|
|
|
|
|
|
|
|
|
|
## 1. The three paths
|
|
|
|
|
|
|
|
|
|
### A. Docker (recommended)
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
docker run -d --name voicecat \
|
|
|
|
|
-p 8384:8384/tcp \ # control (TLS 1.3)
|
|
|
|
|
-p 8384:8384/udp \ # media (encrypted)
|
|
|
|
|
-v voicecat-data:/data \
|
|
|
|
|
ghcr.io/<org>/voicecat:latest
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
That's the whole thing. On first start it generates its Ed25519 identity + self-signed
|
|
|
|
|
cert, creates the SQLite database under `/data`, prints the **server fingerprint** (for
|
|
|
|
|
clients to verify), and listens. Control and media share one port number on TCP+UDP to keep
|
|
|
|
|
firewall rules trivial.
|
|
|
|
|
|
|
|
|
|
A `docker-compose.yml` is provided for people who prefer it, but it isn't required.
|
|
|
|
|
|
|
|
|
|
### B. Single static binary
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
# download for your OS, then:
|
|
|
|
|
./voicecat-server # uses ./voicecat-data/ , prints fingerprint, runs
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
The server is a **single statically linked executable** (mbedTLS, libsodium, opus, sqlite,
|
|
|
|
|
etc. linked in — all permissive licenses). No runtime, no shared libraries to install, no
|
|
|
|
|
package manager. Linux (primary), macOS, and Windows builds.
|
|
|
|
|
|
|
|
|
|
### C. From source
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
git clone … && cd voice-cat
|
build(cmake): clean up presets, add release/apple presets, cross-platform triplets
Rationalize the preset set to match the project's actual state (past M5):
- Rename dev->skeleton (no-deps stub smoke), m1-dev->dev (default dev preset)
- Drop m2-dev (cache-identical to m1-dev)
- Add release preset (optimized + tests on, symbols kept)
- Strip server-release binaries (-s linker flag)
- Add apple-dev/apple-ios/apple-ios-sim scaffolding presets for XCFramework
Add cmake/voicecat-toolchain.cmake wrapper that auto-resolves the vcpkg
triplet from the host platform (x64-mingw-static/x64-linux/arm64-osx) so
the main presets work on Windows/Linux/macOS without per-OS variants.
Update all docs (building.md, CLAUDE.md, README.md, AGENTS.md, deployment.md,
tech-stack.md, client READMEs) and stale preset-name references in code
comments. No C++ behavior changes — the core was already portable.
2026-06-18 03:16:01 +02:00
|
|
|
cmake --preset server-release # vcpkg fetches & pins all deps; auto-triplet (Linux/macOS/Windows)
|
docs: initial design baseline for VoiceCat voice/text chat
Establish the design spec in docs/ before implementation:
- README: overview, locked decisions, principles, glossary
- architecture: shared C++ core + C ABI, native UIs (Swift/C#),
threading model, server design (SFU relay)
- protocol: TCP/TLS control plane, protobuf Envelope + message
catalog, connection lifecycle, extensibility rules
- voice: UDP media frame format, per-channel Opus config,
multi-stream model, two-sided noise reduction, VAD/PTT,
jitter buffer, iOS ReplayKit screen-audio
- security: mandatory encryption (TLS 1.3 + exported-key AEAD),
TOFU server identity, admin-provisioned accounts, anti-replay
- tech-stack: permissive-only deps (mbedTLS, libsodium, opus,
miniaudio, webrtc-apm, ...), build tooling, no GPL/LGPL
- deployment: zero-config self-host (Docker / binary / source)
- roadmap: M0-M5 milestones, resolved decisions
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-15 20:47:09 +02:00
|
|
|
cmake --build --preset server-release
|
build(cmake): clean up presets, add release/apple presets, cross-platform triplets
Rationalize the preset set to match the project's actual state (past M5):
- Rename dev->skeleton (no-deps stub smoke), m1-dev->dev (default dev preset)
- Drop m2-dev (cache-identical to m1-dev)
- Add release preset (optimized + tests on, symbols kept)
- Strip server-release binaries (-s linker flag)
- Add apple-dev/apple-ios/apple-ios-sim scaffolding presets for XCFramework
Add cmake/voicecat-toolchain.cmake wrapper that auto-resolves the vcpkg
triplet from the host platform (x64-mingw-static/x64-linux/arm64-osx) so
the main presets work on Windows/Linux/macOS without per-OS variants.
Update all docs (building.md, CLAUDE.md, README.md, AGENTS.md, deployment.md,
tech-stack.md, client READMEs) and stale preset-name references in code
comments. No C++ behavior changes — the core was already portable.
2026-06-18 03:16:01 +02:00
|
|
|
./build/server-release/bin/voicecat-server
|
docs: initial design baseline for VoiceCat voice/text chat
Establish the design spec in docs/ before implementation:
- README: overview, locked decisions, principles, glossary
- architecture: shared C++ core + C ABI, native UIs (Swift/C#),
threading model, server design (SFU relay)
- protocol: TCP/TLS control plane, protobuf Envelope + message
catalog, connection lifecycle, extensibility rules
- voice: UDP media frame format, per-channel Opus config,
multi-stream model, two-sided noise reduction, VAD/PTT,
jitter buffer, iOS ReplayKit screen-audio
- security: mandatory encryption (TLS 1.3 + exported-key AEAD),
TOFU server identity, admin-provisioned accounts, anti-replay
- tech-stack: permissive-only deps (mbedTLS, libsodium, opus,
miniaudio, webrtc-apm, ...), build tooling, no GPL/LGPL
- deployment: zero-config self-host (Docker / binary / source)
- roadmap: M0-M5 milestones, resolved decisions
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-15 20:47:09 +02:00
|
|
|
```
|
|
|
|
|
|
|
|
|
|
One `cmake` invocation; vcpkg (manifest mode) resolves the dependency graph reproducibly.
|
build(cmake): clean up presets, add release/apple presets, cross-platform triplets
Rationalize the preset set to match the project's actual state (past M5):
- Rename dev->skeleton (no-deps stub smoke), m1-dev->dev (default dev preset)
- Drop m2-dev (cache-identical to m1-dev)
- Add release preset (optimized + tests on, symbols kept)
- Strip server-release binaries (-s linker flag)
- Add apple-dev/apple-ios/apple-ios-sim scaffolding presets for XCFramework
Add cmake/voicecat-toolchain.cmake wrapper that auto-resolves the vcpkg
triplet from the host platform (x64-mingw-static/x64-linux/arm64-osx) so
the main presets work on Windows/Linux/macOS without per-OS variants.
Update all docs (building.md, CLAUDE.md, README.md, AGENTS.md, deployment.md,
tech-stack.md, client READMEs) and stale preset-name references in code
comments. No C++ behavior changes — the core was already portable.
2026-06-18 03:16:01 +02:00
|
|
|
The `server-release` preset produces an optimized, **stripped** binary (`-s` linker flag) —
|
|
|
|
|
smaller executables suitable for distribution. Works on Linux (primary), macOS, and Windows;
|
|
|
|
|
the vcpkg triplet is auto-resolved by [`cmake/voicecat-toolchain.cmake`](../cmake/voicecat-toolchain.cmake).
|
docs: initial design baseline for VoiceCat voice/text chat
Establish the design spec in docs/ before implementation:
- README: overview, locked decisions, principles, glossary
- architecture: shared C++ core + C ABI, native UIs (Swift/C#),
threading model, server design (SFU relay)
- protocol: TCP/TLS control plane, protobuf Envelope + message
catalog, connection lifecycle, extensibility rules
- voice: UDP media frame format, per-channel Opus config,
multi-stream model, two-sided noise reduction, VAD/PTT,
jitter buffer, iOS ReplayKit screen-audio
- security: mandatory encryption (TLS 1.3 + exported-key AEAD),
TOFU server identity, admin-provisioned accounts, anti-replay
- tech-stack: permissive-only deps (mbedTLS, libsodium, opus,
miniaudio, webrtc-apm, ...), build tooling, no GPL/LGPL
- deployment: zero-config self-host (Docker / binary / source)
- roadmap: M0-M5 milestones, resolved decisions
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-15 20:47:09 +02:00
|
|
|
No system packages to chase.
|
|
|
|
|
|
|
|
|
|
## 2. Zero-config defaults
|
|
|
|
|
|
|
|
|
|
The server runs with **no config file at all**. Sensible defaults:
|
|
|
|
|
|
|
|
|
|
| Setting | Default |
|
|
|
|
|
|---------|---------|
|
|
|
|
|
| Encryption | On, always (not configurable off) |
|
|
|
|
|
| TLS cert / identity | Auto-generated on first run, persisted to the data dir |
|
|
|
|
|
| Database | Embedded SQLite in the data dir (no external DB) |
|
|
|
|
|
| Guests | Enabled (so the very first connect "just works"); easily disabled |
|
|
|
|
|
| Ports | `8384` TCP + UDP |
|
|
|
|
|
| A default channel | One "Lobby" voice/text channel created on first run |
|
|
|
|
|
| Opus policy | 48 kHz, 20 ms frames, mono/VOIP defaults; per-channel overrides allowed |
|
|
|
|
|
| Argon2id cost | Auto-tuned to the host on first run |
|
|
|
|
|
|
|
|
|
|
Override only what you care about, via env vars or an optional `server.toml`:
|
|
|
|
|
|
|
|
|
|
```toml
|
|
|
|
|
# server.toml — every key is optional
|
|
|
|
|
server_name = "Cats United"
|
|
|
|
|
allow_guests = false
|
|
|
|
|
bind_port = 8384
|
|
|
|
|
data_dir = "/data"
|
|
|
|
|
|
|
|
|
|
[tls] # only if you want a real CA cert; otherwise self-signed
|
|
|
|
|
cert_file = "/data/fullchain.pem"
|
|
|
|
|
key_file = "/data/privkey.pem"
|
|
|
|
|
|
|
|
|
|
[opus.defaults] # default Opus policy for new channels
|
|
|
|
|
mode = "mono"
|
|
|
|
|
bitrate_bps = 24000
|
|
|
|
|
frame_ms = 20
|
|
|
|
|
fec = true
|
|
|
|
|
dtx = true
|
|
|
|
|
|
|
|
|
|
[opus.limits] # server-enforced ceilings (bound bandwidth)
|
|
|
|
|
max_bitrate_bps = 128000 # channels can't be configured above this
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
Every key also has an `VOICECAT_*` env var form, which is what the Docker path uses.
|
|
|
|
|
|
|
|
|
|
## 3. Connecting (client side)
|
|
|
|
|
|
|
|
|
|
- **Pure direct-connect.** Enter `host:port` (and a nickname or account). There is no central
|
|
|
|
|
directory or server browser — you connect to a server you know.
|
|
|
|
|
- **Saved server list.** The client keeps a local list of saved servers (host:port, pinned
|
|
|
|
|
fingerprint, nickname/credentials per server) so you can store several and pick one to
|
|
|
|
|
join. This lives entirely in the client.
|
|
|
|
|
- On first connect the client shows the server's **fingerprint** and pins it (TOFU). No
|
|
|
|
|
accounts or certs needed to try it; if the operator disabled guests, the client prompts for
|
|
|
|
|
the username/password an admin gave you.
|
|
|
|
|
|
|
|
|
|
That's the entire flow: run the server, share `host:port` + fingerprint, friends save it and
|
|
|
|
|
connect.
|
|
|
|
|
|
|
|
|
|
## 3a. Provisioning accounts (admin)
|
|
|
|
|
|
|
|
|
|
Accounts are **admin-provisioned** — there is no self-serve registration. Two equivalent ways,
|
|
|
|
|
both writing the same SQLite store:
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
# CLI against the server's data dir or a running server
|
|
|
|
|
voicecat-admin account add <username> # prompts for / generates a password
|
|
|
|
|
voicecat-admin account reset <username>
|
|
|
|
|
voicecat-admin account del <username>
|
|
|
|
|
voicecat-admin account list
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
…or from the **in-app admin interface** (a user with the admin permission), which sends the
|
|
|
|
|
privileged `CreateAccount`/`ResetPassword`/`DeleteAccount` control messages over TLS
|
|
|
|
|
(protocol.md §3). Guests need no provisioning; they just pick a nickname (if guests are
|
|
|
|
|
enabled).
|
|
|
|
|
|
|
|
|
|
## 4. Why it stays this easy (design constraints that protect the goal)
|
|
|
|
|
|
|
|
|
|
- **No external services.** No separate database, no Redis, no TURN/STUN server, no reverse
|
|
|
|
|
proxy required. SQLite is embedded; media is plain UDP.
|
|
|
|
|
- **No certificate chore.** Self-signed + Ed25519 TOFU means encryption needs zero operator
|
|
|
|
|
action. A domain owner *can* drop in a Let's Encrypt cert, but never *has* to.
|
|
|
|
|
- **One port pair.** TCP+UDP on the same number; one firewall/port-forward rule.
|
|
|
|
|
- **Static linking + permissive licenses.** The binary has no install-time dependencies and
|
|
|
|
|
can be redistributed (including closed-source) without copyleft obligations.
|
|
|
|
|
- **Agent-friendly.** The run command is a single line with no interactive prompts, the
|
|
|
|
|
server logs its fingerprint and listen address in machine-readable form, and `--help` /
|
|
|
|
|
`--print-config` expose everything an automation needs. Health endpoint for liveness checks.
|
|
|
|
|
|
|
|
|
|
## 5. Operational niceties (planned, not blocking v1)
|
|
|
|
|
|
|
|
|
|
- `voicecat-server --print-fingerprint` and a `/healthz` TCP check.
|
|
|
|
|
- Graceful reload of `server.toml` on `SIGHUP`.
|
|
|
|
|
- `voicecat-admin` (see §3a) also handles bans and channel admin, talking to the same SQLite
|
|
|
|
|
file or a running server.
|
|
|
|
|
- Prebuilt images for `linux/amd64` + `linux/arm64` (Raspberry Pi / cheap VPS friendly).
|