A local-first Rust application for converting reviewed technical lessons into long-form audio study guides with natural speech, stable voices, resumable generation, and auditable quality controls.
Rust
0
292 commits
updated Sep 12, 2026
study-tts is a local-first Rust application under active development for converting reviewed technical lessons into long-form audio study guides with natural speech, stable voices, resumable generation, and auditable quality controls.
The project targets software-engineering education, technical interview preparation, and repeated listening. It uses Rust for every durable decision, Chatterbox for speech synthesis, an in-process Whisper verifier for post-render text-integrity triage, and FFmpeg for final audio processing.
[!IMPORTANT] This repository contains the tested E0-S0 walking skeleton and the E1-S1 contract baseline. The E0-S0 walking-skeleton tests use a deterministic tone synthesizer, not Chatterbox, to exercise lesson loading, planning, validated WAV caching, Rust PCM assembly, real FFmpeg M4A and MP3 export, and a private-preview package manifest. On top of that E1-S1 added the published versioned schemas, the synthesis and verification identities, the worker-bundle identity, and the locked Python worker environment, E1-S3 shipped the worker that loads Chatterbox, and E1-S4 completed the minimal package: both lossy exports derived independently from the master, a transcript, WebVTT captions and FFMETADATA chapters derived from the written sample boundaries, and a checksum for every artifact. E1-S5 then added the two authoring commands —
study-tts lesson newandstudy-tts lesson validate— which are the whole of the product CLI that exists. Hardened recovery, loudness normalization, and every other command are not implemented. Planned commands and behavior remain architectural intent rather than completed functionality.
The priority order is technical correctness, comfortable listening, retention value, stable voices, recoverability, local privacy, generation speed, and implementation simplicity.
| Area | Status |
|---|---|
| Architecture | Accepted in ADR-0001, as amended by ADR-0001-D001, ADR-0001-D002, ADR-0001-D003, ADR-0001-D006, which supersedes historical ADR-0001-D004, and approved ADR-0001-D007 |
| Delivery backlog | Approved in DELIVERY-PLAN.md |
| Rust workspace | Four-crate workspace with a tested end-to-end skeleton and the E1-S1 contract baseline |
| Model and voice qualification | E0-S2 rights prerequisites and E0-S3 qualification complete; full-box performance qualification remains required before G3 |
| Chatterbox worker | Single-worker synthesis lands in E1-S3: the shipped worker loads Chatterbox once per lifetime, renders offline into an assigned staging root, and reports its four identities. Five reference-machine criteria pass and a human listening review is recorded; the story record was accepted 2026-09-02 |
| ASR verifier | Not started |
| CLI | Two authoring commands implemented at E1-S5: study-tts lesson new scaffolds a lesson that already validates, and study-tts lesson validate checks one through the same load_lesson a render uses. Every other command below remains architectural intent. See docs/operations/AUTHORING.md |
| Schemas and fixtures | Seven published versioned schemas under schemas/, generated from the Rust types and checked against the checked-in files; skeleton, contract, and deterministic-audio fixtures present |
| Identities | Canonical serialization and the BLAKE3 synthesis and verification identities implemented; the worker-bundle identity is derived mechanically, with the environment precondition ADR-0001-D006 carries forward from D004 |
| Continuous integration | Fast offline pull-request checks with tier-duration reporting, separated from a dispatch-only reference-machine qualification workflow |
| Production qualification | Not started |
The first delivery target is a private, human-reviewed MVP. It will accept canonical lesson JSON with hand-authored spoken text, use a single persistent Chatterbox worker, produce the complete audio package and run report, and record immutable human approval. It will remain mechanically marked as private_preview; ASR integration follows M2, and production publication stays disabled until the production verification, loudness, licensing, recovery, and long-form qualification gates pass.
The workspace declares these crates:
study-tts-clistudy-tts-corestudy-tts-runtimestudy-tts-testkitThe T4 walking skeleton loads reviewed provisional JSON fixtures, derives deterministic cache keys, proves both cache hits and speech-affecting misses, synthesizes deterministic tone WAVs through a fake boundary, assembles exact PCM and silence in Rust, and writes outputs beneath a contained previews/<lesson-id>/ directory. It validates lesson content before subprocess startup, preflights FFmpeg, ffprobe, and the libmp3lame encoder before synthesis, encodes mono AAC/M4A and MP3 independently from the master, validates all three with ffprobe, derives the transcript, captions, and chapters from the frame boundaries the assembly wrote, records every resolved tool identity and effective argument list, and writes a manifest checksumming all six artifacts. CI executes prebuilt tests as the normal runner user with runtime network egress denied, and the production publication entry point returns a typed refusal.
The boundary order and deliberate G1 deferrals are recorded in E0-S0 Walking Skeleton.
flowchart LR
Source["Reviewed lesson JSON or Markdown"] --> Core["Rust lesson compiler and planner"]
Core --> TTS["Chatterbox worker pool"]
TTS --> Cache["Validated segment cache"]
Cache --> ASR["In-process Whisper verification"]
ASR --> Review{"Review required?"}
Review -->|Yes| Human["Human adjudication or retake"]
Human --> ASR
Review -->|No| Audio["Rust PCM assembly"]
Audio --> FFmpeg["FFmpeg loudness and encoding"]
FFmpeg --> Package["WAV, M4A, MP3, transcript, captions, manifest"]
The architecture has five runtime elements:
whisper-rs 0.16.0 performs non-authoritative post-render text-integrity triage after the Chatterbox pool unloads.Rust owns every durable decision. Model-specific code remains behind a versioned newline-delimited JSON protocol so the inference runtime cannot leak into the lesson domain.
validate reviewed lesson
-> plan deterministic segments and pauses
-> render and cache every valid segment
-> drain and unload Chatterbox workers
-> verify selected cached segments with ASR
-> adjudicate findings or request retakes
-> assemble verified selections in Rust
-> normalize and encode from one lossless master
-> inspect, checksum, and publish the package
Synthesis validity and verification status are separate. A structurally valid segment can remain cached while verification is missing, stale, or under review; changing ASR settings must not invoke Chatterbox again.
The private MVP stops before ASR and uses recorded human review as its correctness authority. This removes the native ASR toolchain from the MVP critical path without changing the production architecture.
The planned lesson format separates readable text from exact synthesis input:
display_text preserves the reviewed transcript.spoken_text contains the deterministic, reviewed TTS rendering.The lesson domain retains two pedagogical roles:
Version 1 uses the approved owner-recorded single-instructor configuration selected by ADR-0001-D003. Learner questions become instructor-voiced rhetorical prompts. Nadia and Tom remain conceptual authoring roles, not approved voice identities, and the owner profile must not be relabeled as either role or as multiple speakers. A future two-speaker format requires a new accepted decision and two separately approved profiles.
Each completed package will contain:
| Artifact | Purpose |
|---|---|
lesson.wav | Normalized lossless master |
lesson.m4a | Default listening file |
lesson.mp3 | Compatibility listening file |
transcript.txt | Readable speaker-labelled transcript |
transcript.vtt | Segment-level captions derived from exact PCM boundaries |
chapters.ffmetadata | Chapter source metadata |
manifest.json | Inputs, identities, tools, selections, artifacts, and checksums |
quality-report.json | Automated checks, ASR evidence, and review status |
Both lossy outputs are encoded independently from the lossless master. One lossy format is never used as the source for another.
The initial development and runtime target is Ubuntu 24.04 under WSL2. Keep the repository, Rust build output, Python environment, model files, caches, fixtures, and generated jobs on the WSL2 Linux filesystem rather than under /mnt/c.
Required system capabilities include:
venv support;libmp3lame encoder;pkg-config, Clang, and OpenSSL development headers.The baseline environment check is:
gcc --version
cmake --version
python3 --version
ffmpeg -version
ffprobe -version
ffmpeg -hide_banner -encoders | grep libmp3lame
The exact supported system versions, model installation procedure, and Python worker lockfile will become authoritative during the G0 feasibility work.
Run these commands from the repository root inside WSL2:
cargo check --workspace
cargo test --workspace
cargo fmt --all -- --check
cargo clippy --workspace --all-targets --all-features -- -D warnings
cargo test --offline -p study-tts-testkit --test walking_skeleton --locked
These commands validate the Rust boundaries and the fake-worker audio path. They do not install Chatterbox, download model weights, or qualify natural speech.
Implemented today, and nothing else:
study-tts lesson new <lesson-id> --out lesson.json
study-tts lesson validate lesson.json
docs/operations/AUTHORING.md documents the scaffold, edit,
review, validate, preview loop they open, including how to hear a lesson while no product render
command exists.
The following interface is architectural intent and is not implemented yet:
study-tts doctor
study-tts lesson compile source.md --out lesson.json
study-tts render lesson.json --format m4a
study-tts resume <job-id>
study-tts inspect <job-id>
study-tts retake <job-id> --segment seg-0042
study-tts takes accept <job-id> --segment seg-0042 --out lesson.takes.json
study-tts invalidate <job-id> --segment seg-0042
study-tts export <job-id> --format wav,m4a,mp3
study-tts cache verify
study-tts cache prune --older-than 90d --dry-run
Every command is planned to support human-readable and structured output. Destructive pruning will remain dry-run by default.
technical-tts/
├── Cargo.toml
├── crates/
│ ├── study-tts-cli/
│ ├── study-tts-core/
│ ├── study-tts-runtime/
│ └── study-tts-testkit/
├── worker/
│ ├── bundle-manifest.json
│ ├── launcher.json
│ ├── pyproject.toml
│ ├── requirements.lock
│ └── study_tts_worker/
├── schemas/
├── fixtures/
├── docs/
│ ├── adr/
│ └── operations/
└── data/
study-tts-core will own lesson types, normalization, planning, and cache identities without depending on Python, FFmpeg, or a model SDK.study-tts-runtime will own filesystem state, worker processes, ASR, PCM handling, recovery, and FFmpeg adapters.study-tts-testkit will provide the fake worker, deterministic audio, fixtures, and fault injection.worker contains the persistent NDJSON worker package, its locked Python environment, and the
bundle manifest that declares which of its files are synthesis-key inputs. The Chatterbox backend
landed in E1-S3: the worker loads the model once per lifetime and renders through it, behind the
bundle-identity, model-artifact, and voice-root gates WorkerConfiguration::for_bundle runs
before a child is spawned.schemas contains the seven versioned JSON Schemas, generated from the Rust types that define
each format by cargo run --package study-tts-runtime --example generate-schemas.data will contain local runtime artifacts and will not be committed.| Gate | Target | Result |
|---|---|---|
| G0a — Skeleton | Day 2 | Minimal fake-worker WAV-to-M4A pipeline and manifest stay green in CI |
| G0 — Feasibility | End week 1 | Real Chatterbox smoke render, lawful voice/content path, reference machine, WAV compatibility, performance and determinism evidence, and provisional contracts |
| G1 — Vertical slice | End week 2 | Three real segments become a complete private-preview package |
| M2 candidate | End week 3 | Feature-complete private preview enters correction and acceptance |
| M2 — Private MVP | End week 4 | Five-minute lesson with cache, resume, retake, run report, full outputs, and immutable human approval |
| G3 — Production candidate | Weeks 8–9 | Markdown authoring, integrated ASR with calibration result or amendment path, frozen loudness references, and production state transitions |
| M3 — Version 1.0 | Weeks 10–12 | Long-form qualification, recovery, rights, operations, and every ADR release gate |
The schedule assumes one engineer and one project owner. G0 measurements control the forecast because model performance, voice availability, and media compatibility can reopen a fundamental decision.
Deterministic implementation uses test-driven development. Fast unit, property, schema, golden, fake-worker, filesystem, and fixture-audio tests run on every change. Real Chatterbox, ASR calibration, performance, listening, and long-form soak checks run separately on the named reference machine.
The test plan covers:
Evidence work uses documented protocols and immutable results. Listening panels, legal review, performance qualification, and human adjudication are not presented as automated tests.
These capabilities require measured evidence and a separate decision record. They are not placeholders in the current backlog.
ADR-0002 was accepted on 2026-08-26 with a constrained-development performance waiver. ADR-0003 through ADR-0005 remain proposed and unaccepted until their required measurements and approvals are complete.
The Cargo workspace declares MIT OR Apache-2.0, although the corresponding license text files are not yet present in the repository. Add them before distributing a release. Chatterbox code, model weights, voice references, Whisper models, FFmpeg, and generated audio may have separate terms; the project will record and validate each applicable license before production release or distribution.
290 commits
2 commits
Rust
89.8%
Python
10.2%
A local-first Rust application for converting reviewed technical lessons into long-form audio study guides with natural speech, stable voices, resumable generation, and auditable quality controls.
Rust
0
292 commits
updated Sep 12, 2026
study-tts is a local-first Rust application under active development for converting reviewed technical lessons into long-form audio study guides with natural speech, stable voices, resumable generation, and auditable quality controls.
The project targets software-engineering education, technical interview preparation, and repeated listening. It uses Rust for every durable decision, Chatterbox for speech synthesis, an in-process Whisper verifier for post-render text-integrity triage, and FFmpeg for final audio processing.
[!IMPORTANT] This repository contains the tested E0-S0 walking skeleton and the E1-S1 contract baseline. The E0-S0 walking-skeleton tests use a deterministic tone synthesizer, not Chatterbox, to exercise lesson loading, planning, validated WAV caching, Rust PCM assembly, real FFmpeg M4A and MP3 export, and a private-preview package manifest. On top of that E1-S1 added the published versioned schemas, the synthesis and verification identities, the worker-bundle identity, and the locked Python worker environment, E1-S3 shipped the worker that loads Chatterbox, and E1-S4 completed the minimal package: both lossy exports derived independently from the master, a transcript, WebVTT captions and FFMETADATA chapters derived from the written sample boundaries, and a checksum for every artifact. E1-S5 then added the two authoring commands —
study-tts lesson newandstudy-tts lesson validate— which are the whole of the product CLI that exists. Hardened recovery, loudness normalization, and every other command are not implemented. Planned commands and behavior remain architectural intent rather than completed functionality.
The priority order is technical correctness, comfortable listening, retention value, stable voices, recoverability, local privacy, generation speed, and implementation simplicity.
| Area | Status |
|---|---|
| Architecture | Accepted in ADR-0001, as amended by ADR-0001-D001, ADR-0001-D002, ADR-0001-D003, ADR-0001-D006, which supersedes historical ADR-0001-D004, and approved ADR-0001-D007 |
| Delivery backlog | Approved in DELIVERY-PLAN.md |
| Rust workspace | Four-crate workspace with a tested end-to-end skeleton and the E1-S1 contract baseline |
| Model and voice qualification | E0-S2 rights prerequisites and E0-S3 qualification complete; full-box performance qualification remains required before G3 |
| Chatterbox worker | Single-worker synthesis lands in E1-S3: the shipped worker loads Chatterbox once per lifetime, renders offline into an assigned staging root, and reports its four identities. Five reference-machine criteria pass and a human listening review is recorded; the story record was accepted 2026-09-02 |
| ASR verifier | Not started |
| CLI | Two authoring commands implemented at E1-S5: study-tts lesson new scaffolds a lesson that already validates, and study-tts lesson validate checks one through the same load_lesson a render uses. Every other command below remains architectural intent. See docs/operations/AUTHORING.md |
| Schemas and fixtures | Seven published versioned schemas under schemas/, generated from the Rust types and checked against the checked-in files; skeleton, contract, and deterministic-audio fixtures present |
| Identities | Canonical serialization and the BLAKE3 synthesis and verification identities implemented; the worker-bundle identity is derived mechanically, with the environment precondition ADR-0001-D006 carries forward from D004 |
| Continuous integration | Fast offline pull-request checks with tier-duration reporting, separated from a dispatch-only reference-machine qualification workflow |
| Production qualification | Not started |
The first delivery target is a private, human-reviewed MVP. It will accept canonical lesson JSON with hand-authored spoken text, use a single persistent Chatterbox worker, produce the complete audio package and run report, and record immutable human approval. It will remain mechanically marked as private_preview; ASR integration follows M2, and production publication stays disabled until the production verification, loudness, licensing, recovery, and long-form qualification gates pass.
The workspace declares these crates:
study-tts-clistudy-tts-corestudy-tts-runtimestudy-tts-testkitThe T4 walking skeleton loads reviewed provisional JSON fixtures, derives deterministic cache keys, proves both cache hits and speech-affecting misses, synthesizes deterministic tone WAVs through a fake boundary, assembles exact PCM and silence in Rust, and writes outputs beneath a contained previews/<lesson-id>/ directory. It validates lesson content before subprocess startup, preflights FFmpeg, ffprobe, and the libmp3lame encoder before synthesis, encodes mono AAC/M4A and MP3 independently from the master, validates all three with ffprobe, derives the transcript, captions, and chapters from the frame boundaries the assembly wrote, records every resolved tool identity and effective argument list, and writes a manifest checksumming all six artifacts. CI executes prebuilt tests as the normal runner user with runtime network egress denied, and the production publication entry point returns a typed refusal.
The boundary order and deliberate G1 deferrals are recorded in E0-S0 Walking Skeleton.
flowchart LR
Source["Reviewed lesson JSON or Markdown"] --> Core["Rust lesson compiler and planner"]
Core --> TTS["Chatterbox worker pool"]
TTS --> Cache["Validated segment cache"]
Cache --> ASR["In-process Whisper verification"]
ASR --> Review{"Review required?"}
Review -->|Yes| Human["Human adjudication or retake"]
Human --> ASR
Review -->|No| Audio["Rust PCM assembly"]
Audio --> FFmpeg["FFmpeg loudness and encoding"]
FFmpeg --> Package["WAV, M4A, MP3, transcript, captions, manifest"]
The architecture has five runtime elements:
whisper-rs 0.16.0 performs non-authoritative post-render text-integrity triage after the Chatterbox pool unloads.Rust owns every durable decision. Model-specific code remains behind a versioned newline-delimited JSON protocol so the inference runtime cannot leak into the lesson domain.
validate reviewed lesson
-> plan deterministic segments and pauses
-> render and cache every valid segment
-> drain and unload Chatterbox workers
-> verify selected cached segments with ASR
-> adjudicate findings or request retakes
-> assemble verified selections in Rust
-> normalize and encode from one lossless master
-> inspect, checksum, and publish the package
Synthesis validity and verification status are separate. A structurally valid segment can remain cached while verification is missing, stale, or under review; changing ASR settings must not invoke Chatterbox again.
The private MVP stops before ASR and uses recorded human review as its correctness authority. This removes the native ASR toolchain from the MVP critical path without changing the production architecture.
The planned lesson format separates readable text from exact synthesis input:
display_text preserves the reviewed transcript.spoken_text contains the deterministic, reviewed TTS rendering.The lesson domain retains two pedagogical roles:
Version 1 uses the approved owner-recorded single-instructor configuration selected by ADR-0001-D003. Learner questions become instructor-voiced rhetorical prompts. Nadia and Tom remain conceptual authoring roles, not approved voice identities, and the owner profile must not be relabeled as either role or as multiple speakers. A future two-speaker format requires a new accepted decision and two separately approved profiles.
Each completed package will contain:
| Artifact | Purpose |
|---|---|
lesson.wav | Normalized lossless master |
lesson.m4a | Default listening file |
lesson.mp3 | Compatibility listening file |
transcript.txt | Readable speaker-labelled transcript |
transcript.vtt | Segment-level captions derived from exact PCM boundaries |
chapters.ffmetadata | Chapter source metadata |
manifest.json | Inputs, identities, tools, selections, artifacts, and checksums |
quality-report.json | Automated checks, ASR evidence, and review status |
Both lossy outputs are encoded independently from the lossless master. One lossy format is never used as the source for another.
The initial development and runtime target is Ubuntu 24.04 under WSL2. Keep the repository, Rust build output, Python environment, model files, caches, fixtures, and generated jobs on the WSL2 Linux filesystem rather than under /mnt/c.
Required system capabilities include:
venv support;libmp3lame encoder;pkg-config, Clang, and OpenSSL development headers.The baseline environment check is:
gcc --version
cmake --version
python3 --version
ffmpeg -version
ffprobe -version
ffmpeg -hide_banner -encoders | grep libmp3lame
The exact supported system versions, model installation procedure, and Python worker lockfile will become authoritative during the G0 feasibility work.
Run these commands from the repository root inside WSL2:
cargo check --workspace
cargo test --workspace
cargo fmt --all -- --check
cargo clippy --workspace --all-targets --all-features -- -D warnings
cargo test --offline -p study-tts-testkit --test walking_skeleton --locked
These commands validate the Rust boundaries and the fake-worker audio path. They do not install Chatterbox, download model weights, or qualify natural speech.
Implemented today, and nothing else:
study-tts lesson new <lesson-id> --out lesson.json
study-tts lesson validate lesson.json
docs/operations/AUTHORING.md documents the scaffold, edit,
review, validate, preview loop they open, including how to hear a lesson while no product render
command exists.
The following interface is architectural intent and is not implemented yet:
study-tts doctor
study-tts lesson compile source.md --out lesson.json
study-tts render lesson.json --format m4a
study-tts resume <job-id>
study-tts inspect <job-id>
study-tts retake <job-id> --segment seg-0042
study-tts takes accept <job-id> --segment seg-0042 --out lesson.takes.json
study-tts invalidate <job-id> --segment seg-0042
study-tts export <job-id> --format wav,m4a,mp3
study-tts cache verify
study-tts cache prune --older-than 90d --dry-run
Every command is planned to support human-readable and structured output. Destructive pruning will remain dry-run by default.
technical-tts/
├── Cargo.toml
├── crates/
│ ├── study-tts-cli/
│ ├── study-tts-core/
│ ├── study-tts-runtime/
│ └── study-tts-testkit/
├── worker/
│ ├── bundle-manifest.json
│ ├── launcher.json
│ ├── pyproject.toml
│ ├── requirements.lock
│ └── study_tts_worker/
├── schemas/
├── fixtures/
├── docs/
│ ├── adr/
│ └── operations/
└── data/
study-tts-core will own lesson types, normalization, planning, and cache identities without depending on Python, FFmpeg, or a model SDK.study-tts-runtime will own filesystem state, worker processes, ASR, PCM handling, recovery, and FFmpeg adapters.study-tts-testkit will provide the fake worker, deterministic audio, fixtures, and fault injection.worker contains the persistent NDJSON worker package, its locked Python environment, and the
bundle manifest that declares which of its files are synthesis-key inputs. The Chatterbox backend
landed in E1-S3: the worker loads the model once per lifetime and renders through it, behind the
bundle-identity, model-artifact, and voice-root gates WorkerConfiguration::for_bundle runs
before a child is spawned.schemas contains the seven versioned JSON Schemas, generated from the Rust types that define
each format by cargo run --package study-tts-runtime --example generate-schemas.data will contain local runtime artifacts and will not be committed.| Gate | Target | Result |
|---|---|---|
| G0a — Skeleton | Day 2 | Minimal fake-worker WAV-to-M4A pipeline and manifest stay green in CI |
| G0 — Feasibility | End week 1 | Real Chatterbox smoke render, lawful voice/content path, reference machine, WAV compatibility, performance and determinism evidence, and provisional contracts |
| G1 — Vertical slice | End week 2 | Three real segments become a complete private-preview package |
| M2 candidate | End week 3 | Feature-complete private preview enters correction and acceptance |
| M2 — Private MVP | End week 4 | Five-minute lesson with cache, resume, retake, run report, full outputs, and immutable human approval |
| G3 — Production candidate | Weeks 8–9 | Markdown authoring, integrated ASR with calibration result or amendment path, frozen loudness references, and production state transitions |
| M3 — Version 1.0 | Weeks 10–12 | Long-form qualification, recovery, rights, operations, and every ADR release gate |
The schedule assumes one engineer and one project owner. G0 measurements control the forecast because model performance, voice availability, and media compatibility can reopen a fundamental decision.
Deterministic implementation uses test-driven development. Fast unit, property, schema, golden, fake-worker, filesystem, and fixture-audio tests run on every change. Real Chatterbox, ASR calibration, performance, listening, and long-form soak checks run separately on the named reference machine.
The test plan covers:
Evidence work uses documented protocols and immutable results. Listening panels, legal review, performance qualification, and human adjudication are not presented as automated tests.
These capabilities require measured evidence and a separate decision record. They are not placeholders in the current backlog.
ADR-0002 was accepted on 2026-08-26 with a constrained-development performance waiver. ADR-0003 through ADR-0005 remain proposed and unaccepted until their required measurements and approvals are complete.
The Cargo workspace declares MIT OR Apache-2.0, although the corresponding license text files are not yet present in the repository. Add them before distributing a release. Chatterbox code, model weights, voice references, Whisper models, FFmpeg, and generated audio may have separate terms; the project will record and validate each applicable license before production release or distribution.
290 commits
2 commits
Rust
89.8%
Python
10.2%