scaffold: M0 skeleton + agent onboarding (build, architecture, progress)
Turn the design into a buildable, dependency-free M0 skeleton plus the
onboarding layer so a new agent can pick up instantly.
Build system:
- CMake + CMakePresets (dev = no deps; server-release = vcpkg) + vcpkg.json
- Skeleton builds with just a C++20 compiler; deps stay off until needed
- .gitattributes (LF), .gitignore, .clang-format
Core (libvoicecat):
- core/include/voicecat.h: full C ABI (the client/server contract), stubbed
- core/proto/voicecat.proto: control-plane wire format, matches docs/protocol.md
- src/{net,crypto,codec,protocol,session,audio,core}: subsystem stubs that
return VC_ERR_NOT_IMPLEMENTED, each pointing to its design doc
- server/ (voicecat-server) and tools/vccli/ link the core
- tests/: CTest smoke test asserting the C ABI contract (behavior, not just build)
- clients/{apple,windows}: M4 placeholders
Onboarding for agents:
- CLAUDE.md: hub — build/test commands, architecture at a glance, doc map, rules
- AGENTS.md: working method (behavior-driven; clean compile is the floor not the goal)
- PROGRESS.md: living tracker — M0 done, M1 task checklist, "where we left off"
Verified: cmake --preset dev && cmake --build --preset dev && ctest --preset dev → green.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-15 21:09:09 +02:00
|
|
|
|
# CLAUDE.md — agent hub for VoiceCat
|
|
|
|
|
|
|
|
|
|
|
|
Auto-loaded each session. This is the **map**: build commands, architecture at a glance, and
|
|
|
|
|
|
where everything is. For the *working method* read [`AGENTS.md`](AGENTS.md); for *what's done
|
|
|
|
|
|
and what's next* read [`PROGRESS.md`](PROGRESS.md); for *design* read [`docs/`](docs/).
|
|
|
|
|
|
|
feat(M1): TCP/TLS control plane -- auth, channels, ephemeral text
Implements the full M1 milestone. Two clients authenticate over TLS 1.3
(guest + Argon2id password) and exchange channel + private text messages
through a real server. All five ctest --preset m1-dev tests pass in ~1 s.
Key components added:
- vcpkg baseline + m1-dev preset (protobuf/mbedTLS/libsodium/asio/sqlite3)
- FrameCodec feed+emit, encode/decode_envelope, protobuf codegen
- TcpServerConn with blocking TLS handshake thread + tls_read_loop
- TlsContext (mbedTLS 1.3, ECDSA-P256 self-signed cert, TOFU on client)
- WorkerPool (3 threads, used for Argon2id)
- Database: SQLite + libsodium Argon2id, account lifecycle, bootstrap admin
- ServerIdentityManager: Ed25519 key + cert generate/persist/fingerprint
- ConnSession state machine: WaitingHello -> WaitingAuth -> Authenticated
- SessionRegistry: channel tree, user map, text routing, broadcast
- vc_client full M1 C ABI: connect/TLS/handshake/auth/text/disconnect
- voicecat-admin CLI: account add/reset/del/list
- test_m1_integration: M1 exit criterion, verified green
Bug fixed: double-framing in ConnSession::send_envelope -- encode_envelope
was adding the [4-byte len] prefix, then TcpServerConn::send_frame added
a second one, causing the client to parse [len][proto] as protobuf (silent
failure). Fixed by serializing raw protobuf bytes in send_envelope and
letting send_frame apply the single length prefix.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-15 23:48:44 +02:00
|
|
|
|
> **One-line status:** M1 control plane is complete and verified (`ctest --preset m1-dev`
|
|
|
|
|
|
> green — 5/5 tests including full TLS auth + text relay integration test). Next up is
|
|
|
|
|
|
> **M2** (UDP media, Opus, jitter buffer). See [`PROGRESS.md`](PROGRESS.md).
|
scaffold: M0 skeleton + agent onboarding (build, architecture, progress)
Turn the design into a buildable, dependency-free M0 skeleton plus the
onboarding layer so a new agent can pick up instantly.
Build system:
- CMake + CMakePresets (dev = no deps; server-release = vcpkg) + vcpkg.json
- Skeleton builds with just a C++20 compiler; deps stay off until needed
- .gitattributes (LF), .gitignore, .clang-format
Core (libvoicecat):
- core/include/voicecat.h: full C ABI (the client/server contract), stubbed
- core/proto/voicecat.proto: control-plane wire format, matches docs/protocol.md
- src/{net,crypto,codec,protocol,session,audio,core}: subsystem stubs that
return VC_ERR_NOT_IMPLEMENTED, each pointing to its design doc
- server/ (voicecat-server) and tools/vccli/ link the core
- tests/: CTest smoke test asserting the C ABI contract (behavior, not just build)
- clients/{apple,windows}: M4 placeholders
Onboarding for agents:
- CLAUDE.md: hub — build/test commands, architecture at a glance, doc map, rules
- AGENTS.md: working method (behavior-driven; clean compile is the floor not the goal)
- PROGRESS.md: living tracker — M0 done, M1 task checklist, "where we left off"
Verified: cmake --preset dev && cmake --build --preset dev && ctest --preset dev → green.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-15 21:09:09 +02:00
|
|
|
|
|
|
|
|
|
|
VoiceCat = self-hosted native voice & text chat (TeamSpeak/Mumble-style). Plain TCP (control)
|
|
|
|
|
|
+ UDP (media), no WebRTC, encrypted by default. A shared C++ core (`libvoicecat`) drives
|
|
|
|
|
|
native clients (Swift on macOS/iOS, C# on Windows) and the server.
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
## Build & test commands
|
|
|
|
|
|
|
|
|
|
|
|
The **M0 skeleton builds with no third-party dependencies** — just CMake + Ninja + a C++20
|
|
|
|
|
|
compiler. Deps (vcpkg) are off until a subsystem needs them.
|
|
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
|
# Configure + build the skeleton (default; no vcpkg needed)
|
|
|
|
|
|
cmake --preset dev
|
|
|
|
|
|
cmake --build --preset dev
|
|
|
|
|
|
|
|
|
|
|
|
# Run the tests (behavior smoke test today; grows per milestone)
|
|
|
|
|
|
ctest --preset dev # or: ctest --test-dir build/dev --output-on-failure
|
|
|
|
|
|
|
|
|
|
|
|
# Run the binaries (Windows adds .exe; Linux/macOS no extension)
|
|
|
|
|
|
./build/dev/bin/vccli # headless test client
|
|
|
|
|
|
./build/dev/bin/voicecat-server --help
|
|
|
|
|
|
./build/dev/bin/voicecat-server --name "My Server"
|
|
|
|
|
|
|
|
|
|
|
|
# Build a single target / be verbose
|
|
|
|
|
|
cmake --build --preset dev --target vccli
|
|
|
|
|
|
cmake --build --preset dev --verbose
|
|
|
|
|
|
|
|
|
|
|
|
# Clean
|
|
|
|
|
|
rm -rf build/dev # nuke; or:
|
|
|
|
|
|
cmake --build --preset dev --target clean
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
When you start a subsystem that needs real libraries (mbedTLS, libsodium, opus, protobuf, …),
|
|
|
|
|
|
turn vcpkg deps on:
|
|
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
|
# one-time: git clone https://github.com/microsoft/vcpkg && ./vcpkg/bootstrap-vcpkg.sh (.bat on Windows)
|
|
|
|
|
|
export VCPKG_ROOT=/path/to/vcpkg # works on Linux / macOS / Windows
|
|
|
|
|
|
cmake --preset server-release # auto-installs deps pinned in vcpkg.json
|
|
|
|
|
|
cmake --build --preset server-release
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
Other useful toggles (pass with `-D` at configure time):
|
|
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
|
cmake --preset dev -DVOICECAT_BUILD_SHARED=ON # build libvoicecat as a .dll/.so/.dylib (for the C# client)
|
|
|
|
|
|
cmake --preset dev -DVOICECAT_BUILD_SERVER=OFF # core + tools only
|
|
|
|
|
|
cmake --preset dev -DVOICECAT_BUILD_TESTS=OFF
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
Formatting: `clang-format` config is `.clang-format` (Google base, 100 cols, 4-space).
|
|
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
|
git ls-files '*.cpp' '*.h' | xargs clang-format -i
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
## Architecture at a glance
|
|
|
|
|
|
|
|
|
|
|
|
Full detail: [`docs/architecture.md`](docs/architecture.md). The short version:
|
|
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
Swift (macOS/iOS) ─┐ ┌─ C# (Windows)
|
|
|
|
|
|
├──▶ libvoicecat (C ABI: voicecat.h) ◀──┤
|
|
|
|
|
|
voicecat-server ───┘ net · crypto · codec · protocol · └─ all UIs are thin
|
|
|
|
|
|
(links core) session · audio the core owns audio
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
- **One core, many faces.** Protocol, Opus, crypto, networking, jitter buffer, and mixing
|
|
|
|
|
|
live once in C++. Clients call the **C ABI** (`core/include/voicecat.h`); the server links
|
|
|
|
|
|
the same core, so framing/crypto never drift between ends.
|
|
|
|
|
|
- **Two transports.** TCP + **TLS 1.3** (control, protobuf `Envelope`) and UDP + **exported-key
|
|
|
|
|
|
ChaCha20-Poly1305 AEAD** (media, fixed binary voice frame). Encryption is mandatory.
|
|
|
|
|
|
- **Threading.** Real-time audio threads never allocate/lock/block; they exchange data with
|
|
|
|
|
|
the net thread via lock-free ring buffers; a worker pool absorbs blocking work.
|
|
|
|
|
|
|
|
|
|
|
|
### Subsystem map (code ↔ design doc)
|
|
|
|
|
|
|
|
|
|
|
|
| Path | Subsystem | Design |
|
|
|
|
|
|
|------|-----------|--------|
|
|
|
|
|
|
| `core/include/voicecat.h` | The C ABI (client/server contract) | architecture.md §4 |
|
|
|
|
|
|
| `core/proto/voicecat.proto` | Control-plane wire format (source of truth) | protocol.md |
|
|
|
|
|
|
| `core/src/net/` | Asio TCP/UDP transport, `[u32 len][payload]` framing | protocol.md §1, voice.md §2 |
|
|
|
|
|
|
| `core/src/crypto/` | TLS 1.3 (mbedTLS), media AEAD (libsodium), anti-replay | security.md |
|
|
|
|
|
|
| `core/src/codec/` | Opus encode/decode, FEC/DTX | voice.md §3–4 |
|
|
|
|
|
|
| `core/src/protocol/` | Envelope (de)serialize, request/response, dispatch | protocol.md |
|
|
|
|
|
|
| `core/src/session/` | Channels, users, streams, permissions, ephemeral text | protocol.md §5 |
|
|
|
|
|
|
| `core/src/audio/` | miniaudio I/O, APM DSP, jitter buffer, mixer | voice.md §8–11 |
|
|
|
|
|
|
| `core/src/core/` | `vc_client` — the handle behind the C ABI | architecture.md §4 |
|
|
|
|
|
|
| `server/` | Connection mgr, session registry, SFU relay, SQLite | architecture.md §5 |
|
|
|
|
|
|
| `tools/vccli/` | Headless client that drives/verifies the protocol | — |
|
|
|
|
|
|
| `clients/apple/`, `clients/windows/` | Native GUIs (M4) | architecture.md §4 |
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
## Documentation index (source of truth)
|
|
|
|
|
|
|
|
|
|
|
|
Read [`docs/`](docs/) before changing behavior. Order:
|
|
|
|
|
|
|
|
|
|
|
|
1. [docs/README.md](docs/README.md) — overview, locked decisions, glossary
|
|
|
|
|
|
2. [docs/architecture.md](docs/architecture.md) — core, C ABI, threading, server
|
|
|
|
|
|
3. [docs/protocol.md](docs/protocol.md) — control plane, Envelope, message catalog
|
|
|
|
|
|
4. [docs/voice.md](docs/voice.md) — UDP media, Opus, multi-stream, two-sided NR, VAD/PTT
|
|
|
|
|
|
5. [docs/security.md](docs/security.md) — mandatory encryption, TLS+AEAD, accounts, threat model
|
|
|
|
|
|
6. [docs/tech-stack.md](docs/tech-stack.md) — libraries, permissive-license rule, tooling
|
|
|
|
|
|
7. [docs/deployment.md](docs/deployment.md) — zero-config self-host (Docker / binary / source)
|
|
|
|
|
|
8. [docs/roadmap.md](docs/roadmap.md) — milestones + resolved decisions
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
## Keeping track of progress
|
|
|
|
|
|
|
|
|
|
|
|
**[`PROGRESS.md`](PROGRESS.md) is the living status file.** When you finish a task, check it
|
|
|
|
|
|
off there and note the next step, so the next agent can pick up instantly. Treat it as part of
|
|
|
|
|
|
the work, not an afterthought — update it in the same commit as the code.
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
## House rules (hard constraints)
|
|
|
|
|
|
|
|
|
|
|
|
- **A clean compile is the floor, not the goal.** "Done" = the milestone's observable exit
|
|
|
|
|
|
criterion in [`docs/roadmap.md`](docs/roadmap.md) passes (e.g. M1 = two `vccli` actually chat
|
|
|
|
|
|
over TLS). Encode it as a test. See [`AGENTS.md`](AGENTS.md).
|
|
|
|
|
|
- **No GPL/LGPL dependencies, ever** (closed-source redistribution is a goal). docs/tech-stack.md §5.
|
|
|
|
|
|
- **Encryption is mandatory** — never add a plaintext transport path. docs/security.md.
|
|
|
|
|
|
- **Real-time audio threads** never allocate, lock, or block. docs/architecture.md §3.
|
|
|
|
|
|
- **Keep docs + code in sync.** Changing a wire format (`voicecat.proto`) or the C ABI
|
|
|
|
|
|
(`voicecat.h`) is a deliberate, versioned act — update the doc in the same commit (protocol.md §8).
|
|
|
|
|
|
- Every commit must build (`cmake --build --preset dev`) and pass `ctest --preset dev`.
|