MIT · macOS · Linux · Windows

Voice in, text out. A Rust toolkit that's ~19× faster than Whisper on Apple Silicon.

Speech-to-text with word-level timestamps, text-to-speech, live dictation and language ID. Your audio stays on your machine, and models download only when you ask for them. CoreML/ANE on Apple Silicon; ONNX on Linux and Windows. No Python. No ffmpeg. No surprise downloads.

$ bun add -g @drakulavich/kesha-voice-kit
  • 25 STT languages
  • 107 Detection langs
  • ~67-74 MB Published engine binary
  • 19× vs Whisper (M-series)

Capabilities

Everything voice, in a single CLI.

Transcription works after one install. Speech synthesis, VAD and speaker labels are separate installs you add when you need them.

Speech-to-text

25 languages via NVIDIA Parakeet TDT. ~19× faster than Whisper on Apple Silicon, ~10× on an x86 CPU. Auto language detection, optional VAD for long audio, word-level timestamps, plain text, or LLM-friendly TOON output.

  • EN · RU · DE · FR · ES
  • + 20 more
  • word timestamps
  • VAD opt-in
  • JSON / TOON

Speaker diarization

Drop a meeting recording in, get back timestamped segments tagged with a stable speaker ID. Powered by FluidAudio’s Sortformer model on the Apple Neural Engine, running inside the engine process. kesha install --diarize installs it with VAD and warms the compiled model, so the first --speakers run skips the cold compile.

  • --speakers
  • darwin-arm64
  • Sortformer (CoreML)
  • opt-in install
New

MCP server

kesha mcp runs a local Model Context Protocol server over stdio with four tools: transcribe_audio, synthesize_speech, list_voices and list_languages. Add it to Claude Code with claude mcp add kesha -- kesha mcp, or to Claude Desktop, Codex, Gemini CLI or Cursor with one config entry. A missing engine or model fails the tool with a kesha install hint; nothing downloads on its own.

  • kesha mcp
  • stdio
  • Claude · Codex · Gemini · Cursor
New

First-run install offer

Run kesha audio.ogg before installing anything and, in a terminal, Kesha shows the install plan, asks once, and on yes installs and transcribes in the same run. Piped and non-interactive runs keep the error and its install hint.

Text-to-speech

Kokoro runs through CoreML/ANE on Apple Silicon and ONNX on Linux and Windows; Vosk-TTS covers Russian, and macOS system voices need no model download. macOS auto-routes from the text language. On Linux and Windows mostly-Cyrillic text still goes to ru-vosk-m02; other languages use --lang or --voice. Kokoro (ANE or ONNX) and Vosk support SSML <prosody rate> and <break>; <emphasis> is Vosk-only. macOS system voices reject --ssml.

OGG/Opus voice notes

Synthesize straight into a Telegram-ready voice note, ~24× smaller than WAV. The default is 32 kbps; --bitrate takes 6000 to 510000 bits/s and --sample-rate takes 8000, 12000, 16000, 24000 or 48000. The engine handles the OggOpus container, no ffmpeg required.

  • --format ogg-opus
  • 32 kbps default
  • --bitrate

Timestamped transcripts

--json --timestamps adds a words array to each segment, with times counted from the start of the file. Each word's end is predicted on its own, so neighbouring words can overlap.

Language detection

107 languages from audio via SpeechBrain ECAPA-TDNN. JSON and TOON also expose textLanguage separately from spoken audioLanguage: Apple’s recognizer on macOS and bundled tinyld elsewhere. Their confidence scales are not comparable.

Voice activity detection

Silero VAD v5 trims silence on long, sparse recordings. Install it explicitly with kesha install --vad; Kesha uses it automatically past 120 seconds once it is available.

Live dictation with recovery

On darwin-arm64, kesha record --live prints what you say to stdout. With VAD installed, --auto-stop ends the recording after a second of silence. Recording stops at 120 seconds unless you pass --max-seconds. Ctrl-C still prints the transcript, and the audio is kept as a WAV when Ctrl-C or SIGTERM ends the session or the transcript cannot be delivered.

  • darwin-arm64
  • kesha install --vad
  • --auto-stop

Privacy-safe diagnostic logs

Local-only command events with paths and user-supplied text redacted. The default mode, retain-on-failure, writes a log only when a command fails, so passing commands leave no file. kesha doctor surfaces status; kesha logs manages them; kesha support-bundle bundles them for support.

  • kesha doctor
  • kesha logs
  • support-bundle
  • local only

Multilingual TTS

Kokoro speaks English, Spanish, French, Italian and Portuguese; Vosk-TTS speaks Russian. Chinese, Japanese and Hindi are darwin-arm64 only: Chinese accepts Han text, and the Kokoro Hindi and Japanese voices take romanized input. Devanagari or kana/kanji text goes to an installed macOS system voice instead. Text in a script the voice cannot speak is refused with E_SCRIPT_UNSUPPORTED and a hint naming the script to transliterate into. On Linux and Windows, pass --lang.

  • en · es · fr · it · pt
  • ru (Vosk)
  • hi · ja · zh (darwin-arm64)
  • --lang off macOS

One home for every state file

Set KESHA_HOME and the model cache, diagnostic logs, the stats database, and MCP audio all live under one directory with the same layout on every platform: cache/, logs/, stats.sqlite, mcp-audio/. A per-location variable such as KESHA_CACHE_DIR still wins; unset, nothing changes and nothing is migrated. kesha status --json and kesha doctor --json report each path with its source. On darwin-arm64 some FluidAudio files still stay outside KESHA_HOME.

  • KESHA_HOME
  • cache · logs · stats
  • status --json paths

Structured errors and events

Every failure path prints a stable, machine-readable error [CODE]: … line, and every engine progress, warning, or debug line on stderr is one NDJSON event the CLI renders for you. kesha-engine describe publishes the whole contract (flags, feature gates, the error taxonomy), and the CLI checks each argv against it before spawning, so an unknown flag is refused with a did-you-mean and exit 2. A run stopped by Ctrl-C or a signal reports E_INTERRUPTED. Agents and CI can branch on why something failed instead of regexing log soup.

  • stable codes
  • kesha-engine describe
  • NDJSON events
  • E_INTERRUPTED
New

kesha status --check

Readiness by exit code, for scripts. It exits 0 with no output when the engine and the ASR model are installed. Otherwise it exits 1 with E_MODEL_MISSING or E_ENGINE_SPAWN, or with E_ENGINE_PROTOCOL when the engine does not answer within 15 seconds. Plain status and status --json still exit 0.

Rust engine, zero deps

A single Rust binary for macOS arm64, Linux x64, and Windows x64. FluidAudio (CoreML) runs in-process on Apple Silicon; two Swift sidecars cover macOS system voices (say-avspeech) and text-language detection (kesha-textlang); ort (ONNX) elsewhere. Kesha reads ogg, opus, mp3, m4a, aac, wav, flac, aiff and webm. Encoding uses one statically linked libopus and pure-Rust FLAC: royalty-free codecs, no patent exposure. Linux .deb and .rpm packages signed with Sigstore. No ffmpeg. No Python. No native Node addons.

OpenClaw-ready

Kesha ships as an OpenClaw plugin. Point OpenClaw's audio tool at kesha and voice messages reach your agent as text, transcribed locally with no API keys.

Hear it

Four samples, two engines, two languages.

Real output from kesha say: Kokoro-82M for English, Vosk-TTS for Russian. SSML <prosody rate> renders the same text at different speeds. Kokoro and Vosk honor <prosody> and <break>; <emphasis> is Vosk-only.

EN · Kokoro-82M medium (1.0×)

“Kesha turns voice into text in a single command — no Python, no ffmpeg.”

kesha say --voice en-am_michael "…" --out demo.flac
EN · Kokoro-82M <prosody rate="x-fast"> · 1.5×

Same text, x-fast prosody.

kesha say --voice en-am_michael --ssml '<speak><prosody rate="x-fast">…'
RU · Vosk-TTS medium (1.0×)

«Кеша превращает голос в текст одной командой — без зависимостей.»

kesha say --voice ru-vosk-m02 "…" --out demo.flac
RU · Vosk-TTS <prosody rate="slow"> · 0.75×

Same text, slow prosody. Useful for accessibility and dictation.

kesha say --voice ru-vosk-m02 --ssml '<speak><prosody rate="slow">…'

Performance

Faster than Whisper.
On your own hardware.

Compared against Whisper large-v3-turbo across Russian and English clips, with every engine left to auto-detect the language. CoreML on M-series is roughly 19× faster than openai-whisper; the ONNX path on an x86 CPU is ~10× faster than openai-whisper and ~2.5× faster than faster-whisper.

  • ~19× vs openai-whisper · M-series
  • ~10× vs openai-whisper · CPU x86
  • ~30-38× vs faster-whisper · M-series
Read the full benchmark
Bar chart comparing transcription speed: openai-whisper vs faster-whisper vs Kesha Voice Kit
Lower bars = faster. Source: BENCHMARK.md.

Quick start

Three commands to a working transcript.

Requires Bun ≥ 1.4.4 on macOS arm64, Linux x64, or Windows x64. Engine and models download only when you ask them to.

01

Install Bun

Skip if you already have it.

macOS / Linux

$ curl -fsSL https://bun.sh/install | bash

Windows PowerShell

> powershell -c "irm bun.sh/install.ps1 | iex"
02

Install Kesha

Preview the size, then explicitly download the engine and base STT models: about 0.6 GB on Apple Silicon, 2.5 GB on Linux and Windows. kesha init is the guided alternative. Progress and recovery hints go to stderr. Skip this step and the first kesha audio.ogg in a terminal shows the plan and asks once before it downloads; piped runs keep the error. Add --tts or --vad only when those workflows need them.

$ bun add -g @drakulavich/kesha-voice-kit
$ kesha install --plan && kesha install
$ kesha install --vad    # only for live auto-stop / VAD
03

Transcribe

Pipe-friendly: stdout is the transcript; stderr carries progress and errors.

$ kesha audio.ogg
Свободу попугаям! Свободу!
# Plain transcript
$ kesha audio.ogg

# Text + language/confidence
$ kesha --format transcript audio.ogg

# Full JSON with lang fields
$ kesha --format json audio.ogg

# Compact, LLM-friendly TOON
$ kesha --toon audio.ogg

# Long / silence-heavy audio (after: kesha install --vad)
$ kesha --vad lecture.m4a

# Segments plus word-level timestamps
$ kesha --json --timestamps interview.ogg

# Meeting transcript with speaker IDs (darwin-arm64)
$ kesha install --diarize && kesha --json --speakers meeting.m4a

# Warn if detected language differs
$ kesha --lang en interview.wav

# Live dictation: darwin-arm64 + explicit VAD install
$ kesha install --vad && kesha record --live --auto-stop
# Opt-in TTS pack: English; preview sizes first
$ kesha install --tts

# macOS auto-routes from text language
$ kesha say "Hello, world" > hello.wav
$ kesha say "Привет, мир" > privet.wav

# Linux / Windows: state the language explicitly
$ kesha say --lang ru "Привет, мир" > privet.wav

# OGG/Opus voice notes (drop straight into Telegram)
$ kesha say --format ogg-opus "Уже бегу!" --out voice.ogg

# Kokoro / Vosk only: variable-speed playback via SSML <prosody rate>
$ kesha say --voice en-am_michael --ssml \
    '<speak><prosody rate="x-fast">Read this fast.</prosody></speak>' \
    --out fast.wav

# Use a macOS system voice
$ kesha say --voice Milena "Чао!"

Want to hear what these voices sound like? Play the four samples ↗

import { install, transcribe, say, KeshaError } from "@drakulavich/kesha-voice-kit/core";

// The one call that downloads: engine, ASR models, English TTS
await install({ tts: ["en"] });

// Transcribe a file: resolves to a TranscribeResult
const { text, lang } = await transcribe("audio.ogg");

// Speak: resolves to the audio bytes
const wav = await say({ text: "Hello" });

// Every rejection is a KeshaError with a stable code
try {
  await transcribe("note.ogg");
} catch (err) {
  if (err instanceof KeshaError && err.code === "E_ENGINE_SPAWN") console.error(err.hint);
  else throw err;
}
# Multiple files — headers per file, like `head`
$ kesha freedom.ogg tahiti.ogg
=== freedom.ogg ===
Свободу попугаям! Свободу!

=== tahiti.ogg ===
Таити, Таити! Не были мы ни в какой Таити! Нас и тут неплохо кормят.

# Pipe transcripts into your favorite LLM
$ kesha --toon meeting.m4a | llm "Summarize action items"

# Status of installed engine + models
$ kesha status

# Diagnose env, log status, and CoreML caches
$ kesha doctor

# Bundle logs + manifests for a bug report
$ kesha support-bundle

What's inside

Every model, one runtime.

Each model runs through kesha-engine, written in Rust: CoreML in-process on Apple Silicon and ONNX everywhere else. Text-to-speech covers nine languages across Kokoro and Vosk.

Model Task Size Source
NVIDIA Parakeet TDT 0.6B v3 Speech-to-text ~2.5 GB ONNX, ~0.5 GB CoreML HuggingFace ↗
SpeechBrain ECAPA-TDNN Audio language detection ~86 MB HuggingFace ↗
Apple NLLanguageRecognizer Text language detection (macOS) built-in macOS framework
tinyld Text language detection (elsewhere) bundled komodojp/tinyld ↗
Silero VAD v5 (opt-in) Voice activity detection ~2.3 MB snakers4/silero-vad ↗
Kokoro-82M (opt-in) Text-to-speech (ONNX) · en, es, fr, it, pt ~326 MB HuggingFace ↗
CharsiuG2P (opt-in) Phonemes for es, fr, it, pt (ONNX) ~106 MB HuggingFace ↗
Vosk-TTS (opt-in) Text-to-speech · Russian ~937 MB alphacep/vosk-tts ↗
FluidAudio Sortformer v2 (opt-in, darwin-arm64) Speaker diarization ~245 MB FluidInference/FluidAudio ↗
FluidAudio Kokoro, multilingual (opt-in, darwin-arm64) Text-to-speech (CoreML) · en, es, fr, it, pt, hi, ja, zh ~105 MB for en; zh adds ~253 MB FluidInference/FluidAudio ↗

Audio decoding via Symphonia, with a libopus adapter for Opus: ogg, opus, mp3, m4a, aac, wav, flac, aiff and webm.

Languages

25 for transcription. 107 for detection.

English Spanish German French Italian Portuguese Russian Polish Dutch Czech Slovak Slovenian Croatian Bulgarian Romanian Greek Hungarian Finnish Swedish Danish Estonian Latvian Lithuanian Ukrainian Maltese

Need detection only? VoxLingua107 covers 107 languages.

Integrations

Drop in where you already work.

OpenClaw

Voice messages reach your OpenClaw agent as text, transcribed locally. Ships as a plugin.

Setup guide →

Raycast

Dictate to Clipboard on macOS: records with a live meter, auto-stops on silence, transcribes locally, and copies the text.

Raycast Store →
New

Core API v2

Import transcribe(), say(), install() and capabilities() into a Bun program. transcribe() resolves to a TranscribeResult, and every rejection is a KeshaError with a stable code.

API docs →

Air-gapped mirrors

Behind a corporate proxy or fully offline? Point Kesha at your model mirror.

Mirror docs →

Ready to ship voice?

Open source, MIT licensed, and improving every week. Star the repo or jump straight to the install.

Copied