95 lines
4.5 KiB
Markdown
95 lines
4.5 KiB
Markdown
|
|
# AGENTS.md — working method
|
|||
|
|
|
|||
|
|
This file is the **working method** for a developer or AI agent picking up VoiceCat. Companion
|
|||
|
|
files:
|
|||
|
|
|
|||
|
|
- [`CLAUDE.md`](CLAUDE.md) — the hub: build/test commands, architecture at a glance, doc map.
|
|||
|
|
- [`PROGRESS.md`](PROGRESS.md) — living tracker: what's done, what's next. **Update it as you work.**
|
|||
|
|
- [`docs/`](docs/) — the **source of truth** for all design.
|
|||
|
|
|
|||
|
|
Read those, then use the method below.
|
|||
|
|
|
|||
|
|
## What this repo is right now
|
|||
|
|
|
|||
|
|
A complete **design** ([`docs/`](docs/)) plus an **M0 skeleton**: it compiles and links, but
|
|||
|
|
`libvoicecat`'s subsystems are stubs that return `VC_ERR_NOT_IMPLEMENTED`. Your job is to turn
|
|||
|
|
the design into working software, one milestone at a time.
|
|||
|
|
|
|||
|
|
## The working method (important)
|
|||
|
|
|
|||
|
|
**A clean compile is the floor, not the goal.** Do not treat "make the compiler errors go
|
|||
|
|
away" as done. Each milestone in [`docs/roadmap.md`](docs/roadmap.md) has an **exit
|
|||
|
|
criterion stated as observable behavior** — that is what "done" means. Examples:
|
|||
|
|
|
|||
|
|
- M1 done = *two `vccli` instances actually chat through a real server over TLS*, not "it builds".
|
|||
|
|
- M2 done = *you can talk between two clients in a channel and hear loss concealment work*.
|
|||
|
|
|
|||
|
|
So the loop is:
|
|||
|
|
|
|||
|
|
1. Pick the current milestone in `docs/roadmap.md`. Read the relevant design doc section.
|
|||
|
|
2. Write the smallest test (CTest, or a `vccli` interaction) that encodes the exit behavior.
|
|||
|
|
3. Implement the subsystem until that test passes — not just until it compiles.
|
|||
|
|
4. Keep the build green and the existing tests passing on every commit.
|
|||
|
|
|
|||
|
|
Every commit must compile and pass `ctest`. Behavior tests are how you know you're actually
|
|||
|
|
making progress.
|
|||
|
|
|
|||
|
|
## Build
|
|||
|
|
|
|||
|
|
Skeleton (no third-party deps — works immediately):
|
|||
|
|
|
|||
|
|
```bash
|
|||
|
|
cmake --preset dev
|
|||
|
|
cmake --build --preset dev
|
|||
|
|
ctest --preset dev
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
When a subsystem needs real libraries, turn on vcpkg deps:
|
|||
|
|
|
|||
|
|
```bash
|
|||
|
|
export VCPKG_ROOT=/path/to/vcpkg # bootstrap vcpkg first; cross-platform
|
|||
|
|
cmake --preset server-release # installs deps pinned in vcpkg.json
|
|||
|
|
cmake --build --preset server-release
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
`vcpkg.json` currently has a placeholder `builtin-baseline` — set it to a real vcpkg commit
|
|||
|
|
SHA the first time you enable `VOICECAT_USE_VCPKG_DEPS`.
|
|||
|
|
|
|||
|
|
## Where each subsystem lives (and its doc)
|
|||
|
|
|
|||
|
|
| Path | Subsystem | Design |
|
|||
|
|
|------|-----------|--------|
|
|||
|
|
| `core/include/voicecat.h` | The C ABI every client/server calls | docs/architecture.md §4 |
|
|||
|
|
| `core/proto/voicecat.proto` | Control-plane wire format | docs/protocol.md |
|
|||
|
|
| `core/src/net/` | Asio TCP/UDP transport, framing | docs/architecture.md, docs/protocol.md §1 |
|
|||
|
|
| `core/src/crypto/` | TLS 1.3 (mbedTLS), media AEAD (libsodium), anti-replay | docs/security.md |
|
|||
|
|
| `core/src/codec/` | Opus encode/decode, FEC/DTX | docs/voice.md §3–4 |
|
|||
|
|
| `core/src/protocol/` | Envelope (de)serialize, state machine, routing | docs/protocol.md |
|
|||
|
|
| `core/src/session/` | Channels, users, streams, permissions, text | docs/protocol.md §5 |
|
|||
|
|
| `core/src/audio/` | Capture/playback (miniaudio), APM DSP, jitter buffer, mixer | docs/voice.md §8–11 |
|
|||
|
|
| `server/` | Connection mgr, session registry, SFU relay, SQLite | docs/architecture.md §5 |
|
|||
|
|
| `tools/vccli/` | Headless client to drive/verify the protocol | — |
|
|||
|
|
|
|||
|
|
## Suggested first steps (M1 spine)
|
|||
|
|
|
|||
|
|
1. **Wire protobuf + framing** (`net/` + `protocol/`): build, then generate C++ from
|
|||
|
|
`voicecat.proto`, implement the `[u32 length][Envelope]` framing over a plain TCP socket
|
|||
|
|
(TLS can come right after). Test: round-trip an `Envelope` through the framer.
|
|||
|
|
2. **TLS 1.3 via mbedTLS** (`crypto/`): wrap the TCP channel. Test: `vccli` completes a TLS
|
|||
|
|
handshake against `voicecat-server` and exchanges a `ClientHello`/`ServerHello`.
|
|||
|
|
3. **Auth + state** (`session/`): guest + admin-provisioned accounts (Argon2id/SQLite),
|
|||
|
|
channel tree snapshot/deltas, ephemeral text relay. Test: two `vccli` chat.
|
|||
|
|
|
|||
|
|
Then proceed to M2 (UDP media) per the roadmap.
|
|||
|
|
|
|||
|
|
## House rules
|
|||
|
|
|
|||
|
|
- **No GPL/LGPL dependencies, ever** (closed-source redistribution is a goal). See
|
|||
|
|
docs/tech-stack.md §5. CI should fail on a copyleft transitive dep.
|
|||
|
|
- **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/` and code in sync. If you change a wire format or the C ABI, update the doc in
|
|||
|
|
the same commit.
|
|||
|
|
- The C ABI is the contract for the Swift/C# clients — treat changes to `voicecat.h` and
|
|||
|
|
`voicecat.proto` as deliberate, versioned events (docs/protocol.md §8).
|