scribble
Library Listed
High-level Rust API for audio transcription using Whisper
- Downloads
- 457
- Dependents
- 0
- Stars
- 105
- Forks
- 10
- Contributors
- 6
- Commits
- 391
- Latest release
- 0.5.4 ·
About
Scribble is a fast, lightweight transcription engine written in Rust, with a built-in Whisper backend and a backend trait for custom implementations.

Scribble will demux/decode audio or video containers (MP4, MP3, WAV, FLAC, OGG, WebM, MKV, etc.), downmix to mono, and resample to 16 kHz — no preprocessing required.
Demo

Project goals
- Provide a clean, idiomatic Rust API for audio transcription
- Support multiple output formats (JSON, VTT, plain text, etc.)
- Work equally well as a CLI tool or embedded library
- Be streaming-first: designed to support incremental, chunk-based transcription pipelines (live audio, long-running streams, and low-latency workflows)
- Enable composable pipelines: VAD → transcription → encoding, with clear extension points for streaming and real-time use cases
- Keep the core simple, explicit, and easy to extend
Scribble is built with streaming and real-time transcription in mind, even when operating on static files today.
Installation
Rust toolchain
Scribble targets Rust stable (tracked via rust-toolchain.toml).
Clone the repository and build the binaries:
./scripts/build-all.sh
Or build a single binary to a target directory:
./scripts/build.sh scribble-cli ./dist
Read the full README
This will produce the following binaries:
scribble-cli— transcribe audio/video (decodes + normalizes to mono 16 kHz)scribble-server— HTTP server for transcriptionmodel-downloader— download Whisper and VAD models
GPU acceleration (feature flags)
Scribble exposes whisper-rs GPU backend features as Cargo features. Enable the
backend you want in Cargo.toml or via --features:
[dependencies]
scribble = { version = "0.5", features = ["cuda"] }
cargo run --features "bin-scribble-cli,cuda" --bin scribble-cli -- \
--model ./models/ggml-large-v3-turbo.bin \
--input ./input.wav
Available GPU feature flags:
cuda(NVIDIA CUDA)metal(Apple Metal)hipblas(AMD ROCm)vulkan(Vulkan)coreml(Apple CoreML)
These are passthrough features; you still need the corresponding system dependencies installed for your platform. See the whisper-rs documentation for backend setup details.
model-downloader
model-downloader is a small helper CLI for downloading known-good Whisper and Whisper-VAD models into a local directory.
List available models
cargo run --features bin-model-downloader --bin model-downloader -- --list
Example output:
Whisper models:
- tiny
- base.en
- large-v3-turbo
- large-v3-turbo-q8_0
...
VAD models:
- silero-v5.1.2
- silero-v6.2.0
Download a model
cargo run --features bin-model-downloader --bin model-downloader -- --name large-v3-turbo
By default, models are downloaded into ./models.
Download into a custom directory
cargo run --features bin-model-downloader --bin model-downloader -- \
--name silero-v6.2.0 \
--dir /opt/scribble/models
Downloads are performed safely:
- written to
*.part - fsynced
- atomically renamed into place
scribble-cli
scribble-cli is the main transcription CLI.
It accepts audio or video containers and normalizes them to Whisper’s required mono 16 kHz internally. Provide:
- an input media path (e.g. MP4, MP3, WAV, FLAC, OGG, WebM, MKV) or
-to stream from stdin - a Whisper model
- a Whisper-VAD model (used when
--enable-vadis set)
Basic transcription (VTT output)
cargo run --features bin-scribble-cli --bin scribble-cli -- \
--model ./models/ggml-large-v3-turbo.bin \
--vad-model ./models/ggml-silero-v6.2.0.bin \
--input ./input.mp4
Output is written to stdout in WebVTT format by default.
Stream a live URL into scribble-cli (via ffmpeg)
If you have a live audio stream URL (MP3/AAC/etc.), you can decode it to Whisper-friendly WAV and pipe it into scribble-cli via stdin:
ffmpeg -re -loglevel error -nostats \
-i "https://stream.example.com/live.mp3?session-id=REDACTED" \
-f wav -ac 1 -ar 16000 - \
| scribble-cli \
--model ./models/ggml-tiny.bin \
--vad-model ./models/ggml-silero-v6.2.0.bin \
--enable-vad \
--input -
Stream a Twitch channel into scribble-cli (via streamlink + ffmpeg)
If you have streamlink installed, you can pull a Twitch stream to stdout and feed it through ffmpeg:
streamlink --stdout https://www.twitch.tv/dougdoug best \
| ffmpeg -hide_banner -loglevel error -i pipe:0 -vn -ac 1 -ar 16000 -f wav pipe:1 \
| scribble-cli \
--model ./models/ggml-tiny.bin \
--vad-model ./models/ggml-silero-v6.2.0.bin \
--enable-vad \
--input -
scribble-server
scribble-server is a long-running HTTP server that loads models once and accepts transcription requests over HTTP.
Start the server
cargo run --features bin-scribble-server --bin scribble-server -- \
--model ./models/ggml-large-v3-turbo.bin \
--vad-model ./models/ggml-silero-v6.2.0.bin \
--host 127.0.0.1 \
--port 8080
Transcribe via HTTP (multipart upload)
curl -sS --data-binary @./input.mp4 \
"http://127.0.0.1:8080/transcribe?output=vtt" \
> transcript.vtt
For JSON output:
curl -sS --data-binary @./input.wav \
"http://127.0.0.1:8080/transcribe?output=json" \
> transcript.json
Example using all query params:
curl -sS --data-binary @./input.mp4 \
"http://127.0.0.1:8080/transcribe?output=json&output_type=json&model_key=ggml-large-v3-turbo.bin&enable_vad=true&translate_to_english=true&language=en" \
> transcript.json
Prometheus metrics
scribble-server exposes Prometheus metrics at GET /metrics.
curl -sS "http://127.0.0.1:8080/metrics"
Key metrics:
scribble_http_requests_total(labels:status)scribble_http_request_duration_seconds(labels:status)scribble_http_in_flight_requests
Logging
All binaries emit structured JSON logs to stderr.
- Default level:
error - Override with
SCRIBBLE_LOG(e.g.SCRIBBLE_LOG=info)
JSON output
cargo run --features bin-scribble-cli --bin scribble-cli -- \
--model ./models/ggml-large-v3-turbo.bin \
--vad-model ./models/ggml-silero-v6.2.0.bin \
--input ./input.wav \
--output-type json
Enable voice activity detection (VAD)
cargo run --features bin-scribble-cli --bin scribble-cli -- \
--model ./models/ggml-large-v3-turbo.bin \
--vad-model ./models/ggml-silero-v6.2.0.bin \
--enable-vad \
--input ./input.wav
When VAD is enabled:
- non-speech regions are suppressed
- if no speech is detected, no output is produced
Specify language explicitly
cargo run --features bin-scribble-cli --bin scribble-cli -- \
--model ./models/ggml-large-v3-turbo.bin \
--vad-model ./models/ggml-silero-v6.2.0.bin \
--input ./input.wav \
--language en
If --language is omitted, Whisper will auto-detect.
Write output to a file
cargo run --features bin-scribble-cli --bin scribble-cli -- \
--model ./models/ggml-large-v3-turbo.bin \
--vad-model ./models/ggml-silero-v6.2.0.bin \
--input ./input.wav \
--output-type vtt \
> transcript.vtt
Library usage
Scribble is also designed to be embedded as a library.
High-level usage looks like:
use scribble::{Opts, OutputType, Scribble};
use std::fs::File;
let mut scribble = Scribble::new(
["./models/ggml-large-v3-turbo.bin"],
"./models/ggml-silero-v6.2.0.bin",
)?;
let mut input = File::open("audio.wav")?;
let mut output = Vec::new();
let opts = Opts {
model_key: None,
enable_translate_to_english: false,
enable_voice_activity_detection: true,
language: None,
output_type: OutputType::Json,
incremental_min_window_seconds: 1,
};
scribble.transcribe(&mut input, &mut output, &opts)?;
let json = String::from_utf8(output)?;
println!("{json}");
Goals
- [X] Make VAD streaming-capable
- [X] Support streaming and incremental transcription
- [X] Select the primary audio track in multi-track video containers
- [X] Implement a web server
- [X] Add Prometheus metrics endpoint
- [X] Add structured logs (tracing)
- [X] Expand test coverage to 80%+
Coverage
This project uses cargo-llvm-cov for coverage locally and in CI.
One-time setup:
rustup component add llvm-tools-preview
cargo install cargo-llvm-cov
Run coverage locally:
# Print a summary to stdout
cargo llvm-cov --features bin-scribble-cli,bin-model-downloader,bin-scribble-server --all-targets
# Generate an HTML report (writes to ./target/llvm-cov/html)
cargo llvm-cov --features bin-scribble-cli,bin-model-downloader,bin-scribble-server --all-targets --html
Status
Scribble is under active development. The API is not yet stable, but the foundations are in place and evolving quickly.
Release notes live in CHANGELOG.md (and GitHub Releases).
Contributing
See STYLEGUIDE.md for code style, verification conventions, and repo-level checklists.
License
MIT

Compatibility
- Runs on
- CUDA, Metal, Vulkan
What shows it
- CUDA: scribble feature cuda
- Metal: scribble feature metal
- Vulkan: scribble feature vulkan
- Native code
- Required
- Binds native code: whisper-rs-sys
- Python bindings
- No Python binding crate found
- License
- MIT
Compare with similar projects
Order: strongest tier first, then most downloads, then name, with unmeasured values last. A library counts downloads over 30 days. An app counts binary downloads per release. An app with none counts its crate downloads over 30 days. ML Rust runs this catalogue, so its closest project always gets a row.
| Project | Downloads | Dependents | Stars | Latest release | Runs on (GPU) | Native code | License |
|---|---|---|---|---|---|---|---|
|
High-level Rust API for audio transcription using Whisper |
457 downloads over 30 days | 0 | 105 | 0.5.4 | CUDA, Metal, Vulkan | Binds native code: whisper-rs-sys | MIT |
|
whisper-rs Featured
Rust bindings for whisper.cpp |
466,717 downloads over 30 days | 98 | Not measured | 0.16.0 | CUDA, Metal, Vulkan | Binds native code: piper, piper1-rs-sys, whisper, whisper-rs-sys. Build uses a native toolchain: bindgen, cmake | Unlicense |
|
sherpa-onnx Featured
Safe Rust wrapper for sherpa-onnx speech recognition toolkit |
259,599 downloads over 30 days | 28 | 15,834 | 2.0.1 | GPU support unknown | Binds native code: sherpa-onnx, sherpa-onnx-sys | Apache-2.0 |
|
sonora Listed
Automatic Gain Control 2 (AGC2) with RNN VAD for WebRTC Audio Processing |
551,810 downloads over 30 days | 3 | 99 | 0.3.0 | GPU support unknown | No native code found | BSD-3-Clause |
|
cohere-transcribe-rs Listed
Rust implementation for the CohereLabs/cohere-transcribe-03-2026 speech-to-text model. Includes a CLI and an OpenAI-compatible API server. |
0 downloads over 30 days | 0 | 101 | 0.1.1 | CUDA | Binds native code: torch-sys (feature tch-backend). Build uses a native toolchain: cmake | Apache-2.0 |
|
voxr New
Audio and speech on boostr: compressed-audio decode, resampling, DSP and grapheme to phoneme, with speech synthesis (Kokoro, VITS), voice cloning (VoxCPM2), transcription with word timings (Whisper), voice activity (Silero) and audio-text scoring (CLAP), on CPU or CUDA. |
642 downloads over 30 days | 2 | 2 | 0.9.1 | CUDA | No native code found | Apache-2.0 |
Why ListedNo archive, New or Featured rule places it, so it is Listed.
What it lacks for Featured
- It has 0 active dependents and 0 new dependents in 365 days. Featured needs 11 active dependents or 9 new dependents in 365 days. The repository route reads 105 stars, 10 forks and 6 contributors. It needs 4,539 stars, 434 forks and 79 contributors together.
What else the check found
- The last activity is on 22 Jun 2026, 140 days ago. The rules expect an update within 450 days. Dormancy rule
Exact rules: Listed, Featured library. The check on applied thresholds version 9.
Every rule outcome, as the check records it
expected-interval: version 0.5.4 base 450: E = 450 daysdormancy: last activity 2026-06-22, 140 days ago, E = 450: activefeatured: not featured: active_users 0 < 11 and new_adopters 0 < 9 and repository route stars 105 (needs 4539), forks 10 (needs 434), contributors 6 (needs 79)listed: listed: no archive, new or featured rule applies
Measurements and sources
Each signal row shows the raw value, its source and the fetch date. The Sources list gathers every distinct source on this page. Movement needs more history.
Sources6 sources
- Description: the crates.io description
- crates.io database dump, fetched
- RustSec advisory database, fetched
- GitHub repository, fetched
- crates.io package, fetched
- GitHub contributors, fetched
Adoption0 active dependents, 0 new dependents in 365 days1 not measured
| Signal | Value | Source | Fetched | Counts |
|---|---|---|---|---|
| Active dependents | 0 | crates.io database dump | Yes | |
| New dependents (365 days) | 0 | crates.io database dump | Yes | |
| Peak active dependents | 0 | crates.io database dump | Yes | |
| Active dependents as a share of the peak | 1 | crates.io database dump | Yes | |
| Binary downloads per release | Not measured | Yes |
MaintenanceLatest human commit: 4 months ago3 not measured
| Signal | Value | Source | Fetched | Counts |
|---|---|---|---|---|
| Latest human commit | 2026-06-22 | GitHub repository | Yes | |
| Latest release | 2026-02-27 | crates.io database dump | Yes | |
| First release | 2025-12-19 | crates.io database dump | Yes | |
| Latest version | 0.5.4 | crates.io database dump | Yes | |
| Days the oldest outside issue waits for a reply | 293 | GitHub repository | Yes | |
| Maintainer replies over 365 days | 17 | GitHub repository | Yes | |
| Repository archived | false | GitHub repository | Yes | |
| Repository gone | false | GitHub repository | Yes | |
| Release commit or manifest in the repo | true | crates.io package | Yes | |
| Published docs | true | crates.io database dump | Yes | |
| Latest release fails cargo check | Not measured | Yes | ||
| Build check date | Not measured | Yes | ||
| Build check toolchain | Not measured | Yes |
SecurityUnpatched vulnerabilities: none
| Signal | Value | Source | Fetched | Counts |
|---|---|---|---|---|
| Unpatched vulnerabilities past the grace window | none | RustSec advisory database | Yes | |
| RustSec unmaintained advisory | none | RustSec advisory database | Yes | |
| Deprecation notice | none | crates.io database dump | Yes | |
| Deprecated requirement | none | crates.io database dump | Yes |
Distribution17 releases, 457 downloads over 30 days5 not measured
| Signal | Value | Source | Fetched | Counts |
|---|---|---|---|---|
| Releases | 17 | crates.io database dump | Yes | |
| Downloads over 30 days | 457 | crates.io database dump | Yes | |
| Binary downloads over the last 3 releases | Not measured | Yes | ||
| Homebrew installs on request over 365 days | Not measured | Yes | ||
| Repology repository families | Not measured | Yes | ||
| Docker pull growth over 90 days | Not measured | Yes | ||
| Docker pulls at the growth baseline | Not measured | Yes | ||
| Every version a prerelease | false | crates.io database dump | Yes | |
| Every version 0.0.x | false | crates.io database dump | Yes | |
| Every version yanked | false | crates.io database dump | Yes | |
| Crate deleted from crates.io | false | crates.io database dump | Yes |
Repository105 stars, 10 forks, 6 contributors, 391 commits. Stars alone never qualify a project.
| Signal | Value | Source | Fetched | Counts |
|---|---|---|---|---|
| GitHub stars | 105 | GitHub repository | Yes — one part of the repository route | |
| GitHub forks | 10 | GitHub repository | Yes — one part of the repository route | |
| Contributors with a GitHub account | 6 | GitHub contributors | Yes — one part of the repository route | |
| Commits on the default branch | 391 | GitHub repository | No | |
| Repository's main crate left out of the entry | none | crates.io database dump | Yes |
Facts that never count
| Signal | Value | Source | Fetched | Counts |
|---|---|---|---|---|
| License | MIT | crates.io database dump | No | |
| Runs on, from listed crates and their direct dependencies | CUDA, Metal, Vulkan | crates.io database dump | No | |
| What shows each backend | CUDA: scribble feature cuda; Metal: scribble feature metal; Vulkan: scribble feature vulkan | crates.io database dump | No | |
| Native code, from listed crates and their dependencies | Binds native code: whisper-rs-sys | crates.io database dump | No | |
| Python bindings, from direct dependencies of listed crates | No Python binding crate found | crates.io database dump | No | |
| Crates that depend on a listed crate directly | 0 | crates.io database dump | No |
Corrections and review history
No correction applies to this entry.
Judgments
A judgment enters only through an approved issue and a merged pull request.
No judgment applies to this entry.