voxora
Model-agnostic Speech-to-Text for Rust.
A candle-native bridge that unifies Whisper, Qwen3-ASR, and future Hugging Face audio models behind one trait, so any Rust application can swap engines without touching inference code.
Status: pre-alpha / engine adapters shipped. The CLI is in
voxora-cli/. The investigation recap and the phased roadmap are indocs/.
Why voxora?
The name is a Latin portmanteau, in the same construction style as Telora:
| Root | Language | Meaning |
|---|---|---|
| vox | Latin | voice |
| ora | Latin | mouth, speech, utterance |
vox + ora = voxora — "voice by mouth" — a name that describes what a
speech-to-text engine does (turn voice into uttered text) and that sounds
right when spoken, because it ends in the open vowel ah, the sound
produced by opening the mouth to speak.
It was chosen from a curated list of ~60 candidates across Latin, Greek, and modern coinages; the criteria were:
- Free on both crates.io and GitHub (
airvzxf/voxora). - Phonetically pronounceable in Spanish and English.
- Mirrors the construction of Telora (tele + ora), so the brand family reads.
- No hyphens (ergonomics in
use voxora::...), no-rssuffix (convention for native Rust crates), no domain suffix like-asr(the name describes the brand, not the function).
Why this project exists
Telora is a local Speech-to-Text assistant for Linux, written in Rust and
originally bound to whisper-rs. As the maintainer explored alternative
models (specifically Qwen3-ASR, via
huggingface/candle#3509
and the qwen3-asr-rs fork),
two problems surfaced:
- candle's maintainers prioritize NVIDIA-native optimization over new model architectures. The Qwen3-ASR PR has been waiting for review for months despite CPU/GPU benchmarks that match or beat PyTorch on RTX 3090.
- The Rust ASR ecosystem is split between ONNX Runtime and whisper.cpp.
transcribe-rs (233⭐)
already provides a
SpeechModeltrait that unifies nine engines, but every engine except whisper.cpp goes through ORT — never candle.
voxora is the candle-native sibling: one trait that wraps candle-native inference engines (Qwen3-ASR today, Voxtral/Granite-Speech tomorrow), with auto-resolution from Hugging Face and a hardware dispatcher (CUDA → Metal → CPU) that lets downstream apps pick the best available accelerator at runtime.
Telora will eventually depend on voxora instead of whisper-rs
directly, becoming model-agnostic the way the maintainer originally
envisioned.
How it fits in the stack
┌─────────────────────────────────────────────────────────────┐
│ Applications: Telora today, any future Rust STT consumer │
└────────────────────────┬────────────────────────────────────┘
│ depends on
▼
┌─────────────────────────────────────────────────────────────┐
│ **voxora** — the candle-native ASR bridge │
│ • AsrEngine trait, TranscribeOptions, TranscriptionResult │
│ • Hugging Face model resolution + quantization selection │
│ • Per-engine adapters (whisper-rs, qwen3-asr-rs, …) │
│ • Hardware dispatcher: CUDA → Metal → CPU │
└────────────────────────┬────────────────────────────────────┘
│ depends on
┌────────────────┼────────────────┐
▼ ▼ ▼
whisper-rs qwen3-asr-rs future engines
(whisper.cpp (candle, via (Voxtral, Granite-
bindings) airvzxf fork) Speech, Parakeet…)
Status and roadmap
The phased plan is in docs/ROADMAP.md. The short
version:
| Phase | Goal | State |
|---|---|---|
| 0 | Repo scaffolding, docs | done |
| 1 | voxora-traits trait + types (originally voxora-core; split out in 0.3.0) |
done |
| 2 | voxora-hf HF model resolver |
done |
| 3 | voxora-whisper engine adapter |
done |
| 4 | voxora-qwen3asr engine adapter |
done |
| 5 | voxora-cli (list / download / run) |
done |
| 6 | Telora integration | pending |
Coordinated releases
voxora publishes a unified version across every workspace crate
that participates in a release. When voxora X.Y.0 ships, all
participating crates ship at X.Y.0 — you can depend on them with
matching versions and trust they stay in lockstep:
= "X.Y.0"
= "X.Y.0"
= "X.Y.0"
= "X.Y.0"
Picking a single version X.Y.0 and using it across the voxora-*
crates in your Cargo.toml is the supported way to consume voxora.
If you depend on, say, voxora-traits = "X.Y.0" and
voxora-engine = "X.Y.0", you can be confident they were released
together and that their public surfaces are wire-compatible. No need
to read per-crate changelogs to figure out which combinations of
minor versions are compatible — the workspace version is the
compatibility promise.
Upgrade guide — 0.3.x → 0.4.0. The voxora-core compatibility
shim that existed in 0.3.0 / 0.3.1 is removed in 0.4.0. The trait
surface has lived in voxora-traits since 0.3.0. To upgrade:
// 0.3.x
use AsrEngine;
use TranscribeOptions;
// 0.4.0
use AsrEngine;
use TranscribeOptions;
In your Cargo.toml, swap voxora-core = "0.3" for
voxora-traits = "0.4". If you used the voxora-core/serde Cargo
feature, switch to voxora-traits/serde. The voxora-bridge
umbrella crate is unaffected and continues to re-export
voxora-traits for one-stop consumption.
The full invariant (including the additive-change exception) is
documented in AGENTS.md → Version coordination.
Quickstart
# Build:
cargo build --release -p voxora-cli
# Download a model:
./target/release/voxora download Qwen/Qwen3-ASR-0.6B
# Transcribe a WAV (engine auto-detected from config.json):
./target/release/voxora run Qwen/Qwen3-ASR-0.6B samples/jfk.wav
# Or pin a specific engine:
./target/release/voxora run ggerganov/whisper.cpp samples/jfk.wav \
--engine whisper --language en
See voxora --help for the full surface. Engine selection falls
back to a --engine <whisper|qwen3-asr> override when config.json
doesn't disambiguate. Hardware flags mirror the engines
(--features cpu (default), metal, cuda).
Investigation
Why this repo exists, the gap it fills, and the options we considered
are documented in docs/INVESTIGATION.md.
Read it before opening an issue — most "why not just X?" questions are
answered there.
License
Apache License, Version 2.0. See LICENSE.
Contributing
See CONTRIBUTING.md and our
Code of Conduct.