Files
rutster/docs/QUICKSTART.md
adlee-was-taken 4c0898cd49 docs: QUICKSTART + DEVELOPMENT + CONTRIBUTING, polish README index
Builds out the user-facing docs tree alongside the slice-1 build target.
Kept the implementer's planned Task 7 'Slice 1 dev loop' README section
untouched — these docs are the canonical destination for that pointer.

- docs/QUICKSTART.md: 5-min path to 'hear the echo' (libopus install,
  cargo run, browser steps, troubleshooting, what's happening under the
  hood).
- docs/DEVELOPMENT.md: dev loop — workspace layout, per-crate iteration,
  running tests, the 20 ms loop / 'drop + observe' rule, slice-1
  boundaries (what NOT to add yet).
- CONTRIBUTING.md (at repo root, conventional): trunk-based dev,
  CI gates, commit message style, atomic commits, code style +
  learner-facing documentation policy, terminology policy, PR workflow
  + review checklist, GPL-3.0-or-later license.
- README.md: add a Quickstart pointer at the top, a Documentation table
  linking to every doc, and the slice-1 build-target status block.
2026-06-28 12:32:12 -04:00

3.9 KiB

Quickstart

Get Rutster running and hear your own voice echoed back in under 5 minutes.

Status: Slice 1 (WebRTC media loopback) is the active build target. If the workspace isn't on main yet, check the slice-1-webrtc-loopback branch — that's where the implementation is landing task-by-task. See docs/superpowers/specs/2026-06-28-slice-1-webrtc-loopback-design.md for the full design.


Prerequisites

1. Rust toolchain

Install via rustup:

curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh

The repo pins a specific stable channel in rust-toolchain.tomlrustup will pick it up automatically on first cargo invocation. No manual toolchain selection needed.

2. libopus (FFI dependency)

The opus crate links system libopus via FFI (per PORT_PLAN §7's "🦀 Core (FFI)" disposition — Opus is the codec surface Rust doesn't need to re-implement). Install the dev headers:

Platform Command
Debian/Ubuntu sudo apt-get install -y libopus-dev
Fedora sudo dnf install -y opus-devel
Arch sudo pacman -S opus
macOS (Homebrew) brew install opus

Verify: pkg-config --cflags opus should print a path with no error.

That's the only system dependency in slice 1. Everything else is pure Rust from crates.io.


Run the server

cargo run
# listening on http://0.0.0.0:8080

First build takes ~2 minutes (str0m + axum + tokio compile fresh). Subsequent builds are incremental.


Hear the echo

  1. Open a browser to http://localhost:8080/.
  2. Click Start call.
  3. Grant microphone permission when the browser prompts.
  4. Speak — you should hear yourself back within ~200 ms (no perceptible delay).
  5. Click Hang up to tear down. The server logs Closing → Closed for the session.

Verbose tracing for debugging:

RUST_LOG=rutster=debug cargo run

Troubleshooting

Symptom Likely cause / fix
error: linking with cc failed / could not find opus libopus dev headers not installed. Re-run the install command above.
Browser shows no mic prompt Another tab/app holding the mic, or mic permissions disabled for localhost. Check browser settings.
ICE connection failed in the browser Shouldn't happen on loopback (host candidates only). If it does, check the server console for the str0m error.
Click Start call, nothing happens Open the browser console (F12). The page logs ICE state + connection state to a <pre> element. Look for the failure there.
Port 8080 already in use Another process holding the port. Either stop it or edit crates/rutster/src/main.rs to bind a different port.

The browser test page at GET / is a single self-contained HTML file with inline JS — no build step. View source to see exactly what the client side is doing.


What's happening

When you click "Start call":

  1. Browser captures microphone audio via getUserMedia.
  2. Browser creates an RTCPeerConnection and generates an SDP offer (audio-only, Opus codec).
  3. Browser POSTs the offer to POST /v1/sessions/:id/offer.
  4. The Rutster core (built on str0m, a sans-IO WebRTC implementation) accepts the offer, generates an SDP answer with its DTLS fingerprint + ICE credentials.
  5. Browser sets the answer as remote description; ICE + DTLS handshake completes.
  6. RTP starts flowing: browser → core terminates DTLS-SRTP → decodes Opus to 16-bit PCM @ 24 kHz mono → echoes PCM back → re-encodes to Opus → DTLS-SRTP → browser plays it.

The "codec-to-PCM boundary" is the canonical point where, in a future slice, the audio tap for an external AI brain splices in. Slice 1 just echoes; step 2 of the spearhead swaps the echo for a real tap.

For the why, see ARCHITECTURE.md. For the dev loop, see DEVELOPMENT.md.