adlee-was-taken 1164770d98 spec(slice-1): adversarial review fixes
API-surface corrections (verified against str0m 0.21 docs):
- str0m::Live -> str0m::Rtc (no Live type exists)
- needs_input_timeout() -> Rtc::poll_output() returning Output::Timeout(Instant)
- RtcConfig::with_dtls_cert -> RtcConfig::set_dtls_cert (also: str0m auto-gens
  a cert if none passed; slice 1 still passes explicitly for ownership clarity)
- Event::RtpPacket(pkt, rid) -> Event::RtpPacket(RtpPacket) { single struct,
  RID is a field }
- str0m::ice::IceAgent -> no public 'ice' module; ICE types at crate root:
  Candidate, CandidateKind, IceCreds, IceConnectionState
- str0m.write_rtp() on Rtclive -> Frame API path: Rtc::writer(mid) -> Writer::write

New design decision surfaced by API verification:
- Media API path: Frame API (default) vs RTP API (set_rtp_mode(true)).
  Slice 1 uses Frame API — the proof target is the codec-to-PCM boundary,
  not RTP packetization. RTP API is a candidate for step 5.

Design-level fixes from close reading:
- §3.3 AudioSource/AudioSink: clarify who drives the traits (the poll loop
  drives both; sink on inbound MediaData, source on Output::Timeout deadline)
- §3.6: clarify cert/CrossRef — fresh in-memory cert each restart is safe
  because browser fetches fresh SDP each session, no caching layer to go stale
- §4.1: add Content-Type: application/sdp to /offer (browser-side fetch needs
  it)
- §4.5: resolve 5-min-vs-60s idle-timeout contradiction (60s, not 5 min)
- §4.5: add graceful-shutdown story (drop DashMap on SIGINT, browsers see
  dead peer — acceptable for dev loop)
- §6.4: fix 'mocked str0m Rtc' — str0m's Rtc is a concrete struct, not a
  trait; sans-IO means drive real Rtc with synthetic Inputs, not mock it.
  Stronger than mocking: production path exercised exactly.

Resolves 5 load-bearing API errors + 3 design-level ambiguities. Spec is now
implementation-ready pending user review.
2026-06-28 10:41:18 -04:00
2026-06-28 09:34:04 -04:00

Rutster

The open-source engine for building the AI-era contact center — self-hostable, AI-native, memory-safe Rust. A spiritual successor to Asterisk's place in the world, not its protocols or its architecture.

Not a port of Asterisk. rutster inherits the role Asterisk held — the self-hostable engine a technical builder uses to stand up a contact center — and re-aims it at a category AI is actively disrupting, instead of a PBX category UCaaS already ate.

Why it exists

Asterisk won because contact centers were built on it (Vicidial, GOautodial, a thousand integrator builds) — it never tried to be Five9. rutster inherits that position: it is a framework / engine, not a turnkey product.

The white space no incumbent fills:

Competitor What they are rutster's edge
LiveKit Horizontal real-time media infra (Go) rutster owns the contact-center domain (ACD, IVR, queues, recording, CDR, dialer, supervisor) LiveKit will never ship
Cloud CCaaS (Five9, Genesys, NICE, Amazon Connect, Twilio Flex) Proprietary, AI bolted on Self-hostable, AI-native, no per-seat/minute lock-in
Cloud AI-voice (Vapi, Retell, Bland) Cheap managed voice bots You own your calls and training data; it's a contact center (escalation, queues), not a single bot
Dated OSS (Vicidial, FreePBX) Self-hostable, Asterisk-era Modern, AI-native, memory-safe Rust

The wedge is a coherent combination, not a silver bullet:

  1. No-GC real-time determinism — tight turn-taking / barge-in / jitter in a no-GC loop.
  2. One secure auditable boundary — trunk termination + media + spend/abuse control + audit in a single memory-safe trust domain. One thing to certify (strongest for PCI / HIPAA / TCPA).
  3. Operational simplicity — one binary, one bill, one deploy.

Honest caveat: the agent brain (STT/LLM/TTS) is necessarily external — audio leaves the box to reach it, same as LiveKit. The real-time edge therefore lives in the local reflexes that don't need the brain (VAD killing TTS the instant the caller speaks, barge-in, jitter, pacing, DTMF), not the brain round-trip. The moat is the whole.

Who it's for

The modern equivalent of the 2006 Linux-nerd-who-stood-up-Asterisk-for-an-SMB: the CLI/IDE/AI-comfortable self-hosting technical builder — runs Claude Code in a terminal, lives in an editor with an AI pair, versions everything in git, self-hosts on principle. Not the no-code admin clicking a flow-designer canvas. The builder serves the non-technical operator downstream, exactly as integrators did on top of Asterisk.

What it is / isn't

  • Is: a Rust media core owning the per-call vertical (trunk SIP termination + RTP/SRTP media
    • local real-time reflexes + a clean audio tap to an external brain + in-boundary spend/abuse control); a programmable call model exposed as a REST/gRPC API + event stream; WebRTC-first human ingress; a library of contact-center capabilities (ACD, IVR, queues, recording, CDR, dialer, supervisor) delivered as services around the core.
  • Isn't: a TDM/PSTN-hardware PBX. No DAHDI, no Sangoma/Digium cards, no ISDN/SS7, no IAX2/H.323/SCCP/MGCP/Unistim. PSTN reach is via SIP trunks only. Inbound SIP endpoint registration (desk phones) is deferred to an out-of-tree edge adapter — not the browser/SSO UX rutster targets.

Core design pillars

  1. Memory-safe by construction — Rust everywhere on the hot path; fuzzed sans-IO protocol parsers. Hostile bytes hit a fuzzed Rust parser first. Eliminates the buffer-overflow/RCE CVE class — and, with the C SBC edge dropped, this is literally true at the wire.
  2. Security-as-product — the single auditable boundary is the moat. TLS/SRTP mandatory, deny-by-default routing, built-in toll-fraud controls, mTLS gRPC admin (no plaintext AMI), hard multi-tenancy. Compliance is a buying criterion, not a row.
  3. In-boundary spend / abuse control — spend caps and abuse/pacing control live inside the trust boundary, co-located with trunk termination. A runaway brain can't exceed pacing or spend because it doesn't hold the wire — structurally impossible for a 3-vendor stack.
  4. Data ownership — calls and training data never leave the operator's infra. The self-host wedge and the fuel for the ML self-improvement loop.
  5. Degradation, deterministic, observable — no-GC real-time loop; OpenTelemetry traces that follow a single call across the boundary; config-as-data, not .conf files edited on a box.
  6. Operational simplicity — one binary, one bus, one deploy (compose up).

Layout

  • docs/ARCHITECTURE.md — the fused per-call vertical + composable horizontal platform; the agent tap as the central interface.
  • docs/PORT_PLAN.md — the capability checklist (what a telephony system must handle), not an architecture template. Every Asterisk subsystem mapped to a disposition with rationale.
  • docs/adr/ — decisions. Highlights:
    • 0002 — north star + fused vertical
    • 0003 — Rust-native trunk SIP (no SBC shield)
    • 0004 — GPL-3.0-or-later
    • 0005 — Valkey (bus + state store)
    • 0006 — WebRTC-first ingress; SIP endpoint deferred

Status

Scoping. No code yet — the vision revision and ADRs define the architecture; the workspace will be scaffolded from the capability ladder and the thin-slice first proof.

First proof (the spearhead)

The full thin slice, sequenced so each step is its own proof — never a big bang:

  1. WebRTC media loopback (terminate RTP/SRTP, echo audio to a browser) — proves the media core
  2. Add the tap (route audio to an external echo process and back) — proves the tap interface
  3. Swap echo for the brain (ideally a single speech-to-speech API, e.g. OpenAI Realtime, to collapse STT+LLM+TTS into one integration) — proves agent integration
  4. Add barge-in (VAD-driven playout kill) — proves the reflex
  5. Replace WebRTC ingress with a real PSTN trunk call — proves the trunk client
  6. Add the spend cap (hard-stop at threshold) — proves the boundary

Steps 14 are the reflex loop — the hard, most-differentiating part proves itself before trunk integration piles on. "I called my Rust box and an AI answered the phone" is the momentum fuel a solo multi-year build needs.

Capability ladder (the grand vision, incrementally)

Rung Capability Reuses
1 Self-serve — AI answers, contains the call the thin-slice first proof
2 Escalation — human agent barges in / takes over when AI breaks down the audiohook/barge primitive
3 Measurement — containment rate, where/why AI failed CDR + analytics on calls you own
4 Self-improvement — every takeover → auto-labeled training data → loop rungs 13 compounding

License

GPL-3.0-or-later (ADR-0004). Strong copyleft in the Asterisk lineage, modernized one notch. The license is the floor, not the moat — the wedge is.

Description
Terribly-named "spiritual" ancestor to the niche Asterisk PBX filled in 2005, but for AI-first call centers in 2026
Readme 3.8 MiB
Languages
Rust 99.5%
HTML 0.5%