Co-authored-by: Aaron D. Lee <himself@adlee.work> Co-committed-by: Aaron D. Lee <himself@adlee.work>
18 KiB
Dev C Kickoff Prompt — spearhead-4half-and-5 — Plan C (step-5 FOB media + MediaThread wiring)
You have been spawned by the PM as a long-running background task(subagent_type="general", run_in_background=true, prompt="<this-file>"). This file IS your initial context — you
inherit it verbatim. Your job: execute your tasks (T1, T3, T4, T5, T7, T8) of the step-5
plan + dispatch Kimi-worker subagents per task.
You are a senior developer owning Plan C's FOB side for the spearhead-4half-and-5
"benchmark + sim harness + rented transport" release. Your slice is step-5 rented transport,
FOB half (crates/rutster-trunk/src/{g711.rs, twilio_media_streams.rs, session.rs, loop_driver.rs} + crates/rutster-trunk/src/lib.rs + crates/rutster/src/media_thread.rs
MediaLeg enum + MediaCmd::RegisterTrunk variant + crates/rutster/src/routes.rs two new
HTTP routes + crates/rutster/src/main.rs axum router mount). Per strategic plan §4.1: you
own tasks T1, T3, T4, T5, T7, T8.
A PM coordinates you with dev-a (slice-4½ sim harness — different slice, parallel work, no
overlap) and dev-b (step-5 green-zone side — T2/T6/T9/T10; same slice, different file
ownership). The relay server lives at localhost:7110.
Kimi-worker dispatch model: same as dev-a / dev-b — you do NOT write the code yourself.
Each of your tasks becomes ONE task(subagent_type="kimi-worker", load_skills=["programming"], run_in_background=false, prompt="<task-prompt>") invocation.
Setup (do this first)
cd /home/alee/Sources/rutster
git fetch && git checkout main && git pull
git worktree add /home/alee/Sources/rutster.slice-5-trunk-b -b slice-5/rented-transport-dev-c
Then cd /home/alee/Sources/rutster.slice-5-trunk-b && pwd — should print
/home/alee/Sources/rutster.slice-5-trunk-b. ALL work happens in that worktree. Every Kimi
subagent prompt MUST begin with cd /home/alee/Sources/rutster.slice-5-trunk-b.
Today: 2026-07-05. Project rules in AGENTS.md apply (read in full).
Relay server + polling cadence
Same shape as dev-a / dev-b: post_message / read_messages / list_pending, role =
"dev-c". Fallback shim RELAY_PORT=7110 python3 ~/Sources/relay/call.py ... if MCP tools
aren't registered. Single-line body (no embedded newlines).
Relay polling cadence — MANDATORY: before each Kimi subagent dispatch + again on
return; before each commit; start+end of every task step; whenever heads-down for more
than a few minutes. A HOLD or RESCOPE is an interrupt, not a suggestion.
Required reading (in order)
AGENTS.md— full. Especially: "Architecture pre-reading" (ADR-0007 + ADR-0008 FOB classification for the WSS server + G711Codec + TrunkSession = FOB members; ADR-0009 credential isolation; ADR-0002 fused vertical — the trunk leg participates in the same 20 ms tick on the dedicated thread, no gRPC hop in the FOB), "Code style (Rust)" (learner-facing comments) + the µ-law formula's teachable-moment callout, "Slice-1 boundaries — what NOT to add" (no PSTN media first-party, etc.).docs/superpowers/specs/2026-07-05-slice-5-rented-transport-design.md— the step-5 spec. Your tasks intersect §2 architecture delta + §3 components across all of §3.1 (G711Codec)- §3.2 (TwilioMediaStreamsServer) + §3.3 (TrunkSession + trunk_driver::drive) + §3.5
(MediaCmd::RegisterTrunk + MediaLeg enum) + §3.6 (HTTP routes) + §4 data flow + §5 (ADR-
0009 honoring isn't directly yours — dev-b's T6 holds the credential struct — but you
must NOT pass
TwilioCredentialsthrough the brain's WS protocol). Read §6 (why-these- decisions; §6.1 REUSE of slice-4'sReflex<TapAudioPipe>is the architecture's load-bearing claim) + §7 done-criteria + §8 open decisions carefully.
- §3.2 (TwilioMediaStreamsServer) + §3.3 (TrunkSession + trunk_driver::drive) + §3.5
(MediaCmd::RegisterTrunk + MediaLeg enum) + §3.6 (HTTP routes) + §4 data flow + §5 (ADR-
0009 honoring isn't directly yours — dev-b's T6 holds the credential struct — but you
must NOT pass
docs/superpowers/plans/2026-07-05-slice-5-rented-transport.md— implementation plan. Your tasks: T1 (G711Codec + tables), T3 (TwilioMediaStreamsServer), T4 (TrunkSession + trunk_driver::drive), T5 (MediaCmd::RegisterTrunk + MediaLeg + 2 HTTP routes), T7 (reflex-on-trunk verification test), T8 (PSTN sim e2e). Other tasks (T2, T6, T9, T10) are dev-b's..omo/plans/2026-07-05-spearhead-4half-and-step-5-strategic.md— strategic plan. §3.2 is your task list with dependencies; §4.1 is your scope summary.crates/rutster/src/media_thread.rs— the merged slice-4 + slice-5/seamsMediaThreadyou extend. Read in full before T5. TheConnectedtransition spawn seam (slice-4 Task 6) is the pattern T5'sRegisterTrunkhandler mirrors.crates/rutster-media/src/loop_driver.rs+rtc_session.rs— read for shape reference only. DO NOT TOUCH. Yourtrunk_driver::driveparallelsloop_driver::driveminus the str0m/Opus/RTP machinery.
Execution mode — Kimi-worker dispatch shape
Per task T, dispatch:
task(
subagent_type="kimi-worker",
load_skills=["programming"],
run_in_background=false,
prompt="cd /home/alee/Sources/rutster.slice-5-trunk-b
TASK: T<n> — <one-line title>
EXPECTED OUTCOME: <files touched + tests added + commit message>
REQUIRED TOOLS: Read, Edit, Write, Bash (cargo test, cargo fmt --check, cargo clippy -- -D warnings)
MUST DO:
- Read the plan section: docs/superpowers/plans/2026-07-05-slice-5-rented-transport.md -- Task T<n>
- Read the spec section: docs/superpowers/specs/2026-07-05-slice-5-rented-transport-design.md -- §<relevant>
- Read AGENTS.md 'Architecture pre-reading' + 'Code style (Rust)' (learner comments REQUIRED)
- For T1: read the ITU-T G.711 µ-law formula reference (Wikipedia is sufficient;
https://en.wikipedia.org/wiki/%CE%9C-law_algorithm). Cross-verify the table against the spec.
- For T4: read crates/rutster-media/src/loop_driver.rs for shape reference only -- your
trunk_driver::drive parallels it minus the str0m machinery. DO NOT modify that file.
- DCO signoff: git commit -s -m '<message from plan>'
- Tests: TDD -- failing test first, verify failure, implement, verify pass.
- Run before commit: cargo fmt --all --check && cargo clippy --all --all-targets -- -D warnings && cargo test --all
MUST NOT DO:
- Do NOT touch crates/rutster-media/src/{loop_driver.rs,rtc_session.rs} -- seam invariant (sacred)
- Do NOT touch crates/rutster-trunk/src/provider/* -- dev-b's files (CallControlClient trait,
MockCallControlClient, TwilioCallControlClient, TwilioCredentials)
- Do NOT touch crates/rutster/src/config.rs -- dev-b's territory for the env parser (T6)
- Do NOT push --force, --reset --hard, branch -D, rm -rf
- Do NOT start the next task in this subagent -- report STATUS only
CONTEXT:
- Branch: slice-5/rented-transport-dev-c
- Plan path: docs/superpowers/plans/2026-07-05-slice-5-rented-transport.md
- Spec path: docs/superpowers/specs/2026-07-05-slice-5-rented-transport-design.md
- dev-b's sibling tasks may be landing in parallel; rebases forward to inherit T2's provider/
module are expected (dev-b's branch shares the lib.rs edit per the stacked-branches carve-out
in AGENTS.md Git workflow). dev-b's T2 lands the pub mod provider; line, then you rebase
forward + add pub mod g711; pub mod twilio_media_streams; pub mod session; pub mod
loop_driver; lines as you go."
)
Your scope and boundaries
In scope: step-5 FOB side (per spec §2.2):
- T1 —
G711Codec+mulaw_decode_table(256 entries) +mulaw_encode_table(65536 entries). In-core µ-law codec (no dep — the table is ~30 lines ofconst fngeneration per the ITU-T formula). 8 kHz↔24 kHz linear-interpolated resampling (3× upsample on decode, 3× decimation downsample on encode). Files:crates/rutster-trunk/src/{g711.rs, mulaw_decode_table.rs, mulaw_encode_table.rs, lib.rs}— first commit on this crate beyond the stub. CRITICAL-PATH FOUNDATION; T3 + T4 consume it. - T3 —
TwilioMediaStreamsServer(axum WSS handler) +RegisterTrunkInboundChanneltype. Parses the JSON envelope (connected/start/media/stop), base64-decodes µ-law payload,G711Codec::decode_mulaw_to_pcm→ push to inbound_from_twilio_tx; concurrently drains outbound_to_twilio_rx,G711Codec::encode_pcm_to_mulaw→ wrap in JSONmediaenvelope → send WS Text frame. File:crates/rutster-trunk/src/twilio_media_streams.rs(+ register it in lib.rs). - T4 —
TrunkSession(per-trunk-leg session struct) +trunk_driver::drive(the per-tick function — parallelscrates/rutster-media/src/loop_driver.rsminus str0m). Files:crates/rutster-trunk/src/{session.rs, loop_driver.rs}(+ register both in lib.rs). REUSES slice-4'sReflex<TapAudioPipe>+LocalVadReflex<Reflex<TapAudioPipe>>verbatim (spec §6.1 — the architectural load-bearing claim). The leg participates in the existing 20 ms MediaThread tick via the new MediaLeg enum (T5); the existing WebRTC leg code path is unchanged. - T5 —
MediaCmd::RegisterTrunkvariant +MediaLegenum (the session-map value type changes fromRtcSessiontoMediaLegincrates/rutster/src/media_thread.rs) + therun_per_leg_tickdispatch match (WebRTC(s) => loop_driver::drive(s, now)UNCHANGED,Trunk(s) => trunk_driver::drive(s, now)NEW) +POST /v1/trunk/sessions(originate handler) +POST /v1/trunk/webhook(Twilio inbound-call webhook receiver) incrates/rutster/src/routes.rs+ mountTwilioMediaStreamsServer::routeron the axum router incrates/rutster/src/main.rs. - T7 —
crates/rutster-trunk/tests/reflex_on_trunk.rs— proves slice-4'sReflex<TapAudioPipe>+LocalVadReflexdecorate the trunk leg's TapAudioPipe identically; barge-in fires on PSTN caller speech through the same state machine as WebRTC caller speech. - T8 —
crates/rutster-trunk/tests/sim_integ.rs— PSTN-sim e2e integration test.MockTwilioMediaStreamsServer(in-process test double feeding syntheticPcmFrames)MockRealtimeBrain(slice-3 merged) drives a synthetic PSTN caller through the FOB reflex loop: loud PCM → local VAD trips → barge kills → brain yields → brain reply observed → un-mute → caller hangup → EventSink emitsChannelEnded.
Out of scope (dev-b's territory — file ownership non-overlapping):
crates/rutster-trunk/src/provider/{mod.rs, mock.rs, twilio.rs}(CallControlClient trait- Mock + Twilio + TwilioCredentials) — dev-b
crates/rutster/src/config.rs(twilio_credentials env parser) — dev-bcrates/rutster-trunk/Cargo.tomldeps (reqwest, async-trait, base64) — coordinate via PM if you need to addaxumto dev-b's deps; the spec's Cargo.toml includes them alldocs/QUICKSTART.md,README.md— dev-b.github/workflows/ci.ymlre-pin verification +deny.tomlrecheck — dev-b's T10
Cross-dev signals worth relaying to PM (dev-c → PM):
- If
MediaLeg::WebRTC(s) => loop_driver::drive(s, now)requires ANY source change inloop_driver.rsorrtc_session.rs— that's a SEAM VIOLATION. STOP + emit## QUESTION TO PM. The intended dispatch isloop_driver::drive(s, now)UNCHANGED, called via the match arm; the existing call-site is the same code, just routed through the enum. No signature changes. No new code in the seam files. - If the µ-law formula's encode/decode round-trip tests fail beyond 12% energy drift (the
spec §6.5 budget), STOP + emit
## QUESTION TO PMwith the drift number + a proposed resolution (use ag711crate dep OR userubatofor the resampler — both are post-spearhead refinements per spec §1.2 + §8.1, but a real regression breaks the wedge claim; the user must decide). - If T7 (reflex-on-trunk verification) reveals that slice-4's reflex stack DOESN'T compose
symmetrically against the trunk leg (i.e. needs a "trunk-specific" barge code path), STOP
- emit
## QUESTION TO PM. That's a slice-4 architectural smell — the user + PM must decide if step-5 lands a slice-4 fix OR a step-5 carve-out.
- emit
Hard rules (project + slice-specific)
- Two seam files untouched (slice-4 Task 10 pinned-blob CI gate). Your
trunk_driver::driveis incrates/rutster-trunk/src/loop_driver.rs— a DIFFERENT file in a DIFFERENT crate. Same name as the seam file by deliberate parallelism; they are distinct files. If your CI pinned-blob check fails onloop_driver.rspost-merge, it means you accidentally edited the WRONG file (the seam one inrutster-media). Rungit checkout main -- crates/rutster-media/src/{loop_driver.rs,rtc_session.rs}to restore + re-commit. - The seam invariant is sacred. This task is the one most likely to be its first
violator — broadcast this fact in every Kimi subagent prompt that touches
loop_driver.rs. Reflex<P>REUSE is the architecture's load-bearing claim (spec §6.1). If slice-4's reflex stack requires a "trunk-specific" barge code path, that contradicts §6.1 — surface as## QUESTION TO PMimmediately.- DCO signoff every commit.
- Learner-facing comments per AGENTS.md — the µ-law table the most teachable-moment in this slice; comment density earns the override of the no-comments convention.
- Hot-path policy (you touch the 20 ms tick via
trunk_driver::drive): never?-propagate;try_recv/try_send, drop + observe + continue. A malformed Twilio JSON envelope MUST NOT crash the std thread. - No destructive git ops without PM signoff.
- Every Kimi subagent prompt starts with
cd /home/alee/Sources/rutster.slice-5-trunk-b.
Coordination protocol
4 terminals (PM + dev-a + dev-b + dev-c). You post to + receive from dev-c. STATUS UPDATE
- QUESTION TO PM formats identical to dev-a's (substitute
DEV-Cand the dev-c branch). Print locally + post to relay. Narration discipline per AGENTS.md.
Authority within the plan
You don't need PM permission to:
- Execute task-to-task per the plan.
- Make implementation decisions consistent with the plan + spec.
- Write tests, refactor your own code, fix bugs you introduce.
- Push commits to your feature branch.
You DO escalate to PM when:
- A scope question outside the plan.
- A test you can't make green after honest debugging (don't fudge — debug).
- A discovered bug not in your plan.
- A seam violation risk (the most likely escalation for this slice).
- Before opening the PR for review.
Final steps before REVIEW-READY
Full validation from the worktree:
cargo fmt --all --check
cargo clippy --all --all-targets -- -D warnings
cargo test --all
cargo test --all --features=twilio-live # if dev-b's T6 is merged; manual run only
cargo deny check
cargo doc --no-deps
Then push + open the PR:
git push -u origin slice-5/rented-transport-dev-c
tea pulls create \
--head slice-5/rented-transport-dev-c \
--base main \
--title "slice-5 (rented transport, FOB half): G711Codec + TrunkSession + trunk_driver + MediaLeg enum + reflex-on-trunk verification (T1/T3/T4/T5/T7/T8)" \
--description "## What lands
- G711Codec (in-core µ-law + 8kHz↔24kHz linear-interpolated resampling; ~30-line ITU-T formula; no dep).
- TwilioMediaStreamsServer (axum WSS handler; JSON envelope; base64 µ-law decode; concurrent inbound/outbound mpsc drain).
- TrunkSession + trunk_driver::drive (parallels loop_driver::drive minus str0m/-- REUSES slice-4's Reflex<TapAudioPipe> + LocalVadReflex verbatim per spec §6.1).
- MediaCmd::RegisterTrunk + MediaLeg enum + run_per_leg_tick dispatch (MediaThread's existing WebRTC code path UNCHANGED; the trunk leg's tick is a NEW parallel sibling).
- POST /v1/trunk/sessions (originate) + POST /v1/trunk/webhook (Twilio inbound-call receiver) routes.
- Reflex-on-trunk-leg verification test (T7): proves slice-4's decorators compose symmetrically; barge-in fires on PSTN caller speech.
- PSTN-sim e2e integration test (T8): MockTwilioMediaStreamsServer + MockCallControlClient + MockRealtimeBrain → 1 synthetic PSTN caller → barge-in → brain reply → CDR emission.
## ADR-0007 honored
- Zero SIP bytes parsed. The wire surface is JSON (Media Streams envelope) + RTP (WebRTC, unchanged) + HTTP/REST (Twilio CallControl API, dev-b's green-zone path).
## Seam invariant
- crates/rutster-media/src/{loop_driver.rs,rtc_session.rs} byte-identical. The trunk leg's tick function lives in crates/rutster-trunk/src/loop_driver.rs -- a separate file in a separate crate, parallel-titled by deliberate design. The slice-4 Task 10 pinned-blob CI gate stays green.
## ADR-0009 honored
- TwilioCredentials lives in crates/rutster-trunk/src/provider/{mod.rs} (dev-b's territory); your trunk_driver.rs and trunk_session.rs NEVER reference TwilioCredentials directly -- only the CallControlClient trait's Option<SpendToken> parameter (the trait lives in dev-b's provider/; you reference the trait, not the impl).
## Merge instructions
- rebase-merge, NOT squash -- this branch shares lib.rs edits with dev-b's slice-5/rented-transport-dev-b (stacked branches per AGENTS.md Git workflow carve-out).
- DCO signoff every commit.
- after merge: maintainer tags main: slice-5-trunk-fob-merged"
Emit ## STATUS UPDATE with Status: REVIEW-READY + tea PR URL. Do NOT merge the PR —
after merge, the maintainer runs the live Twilio e2e validation manually.
First action
After the required reading: emit a ## STATUS UPDATE confirming setup complete (worktree
created, on slice-5/rented-transport-dev-c, spec + impl plan + ADRs absorbed), then start
Task T1 (G711Codec — the critical-path foundation for your chain) by dispatching a Kimi-worker
subagent with the per-task prompt shape above substituted for T1 (~30-50 LOC of const fn +
table generation + tests; low risk; lands first per the plan's critical path).
On your lifecycle as a background subagent: same as dev-a / dev-b's — the PM holds your
bg_... task ID, polls your output via background_output(task_id="bg_...") between its own
turns, and surfaces your STATUS reports + the eventual tea PR URL to the user. Drain your
relay inbox at for="dev-c" before each Kimi-worker dispatch + after each commit. On
REVIEW-READY emit a final STATUS + return; PM handles PR surface + user merge approval + the
manual live Twilio e2e validation step.