What Cactus released

Cactus released Whistle on October 2, 2026: an open speech recognition model in a single 16.9 MB file that runs on the CPU with no dependencies. The announcement positions it for mobiles, wearables, robots, smart home hardware, automotive systems and microcontrollers.

Whistle handles seven languages: English, German, French, Spanish, Italian, Dutch and Polish. It transcribes up to 30 seconds of 16 kHz mono audio in one pass and detects the language unless you name it. It also returns word timestamps with probabilities, and it can output the encoder state as a speech embedding, one row per 80 millisecond frame, without decoding a transcript at all.

The model loads into the same C++ engine as Needle, Cactus's small language model, from the same container and quantisation. One binary can therefore handle speech, text, or both.

What the model does and how it is built

The front end is conventional. Audio is framed into 80 log-mel bins with a 25 ms window and a 10 ms hop, band-limited from 250 to 3500 Hz and normalised per channel. Thirty seconds becomes 3,000 frames, and a convolutional stem halves that count three times to 375 frames, one per 80 ms.

The encoder has eight Simple Attention blocks with four residual lanes and a Monarch Hadamard MLP instead of a feed-forward network, the same blocks Needle uses. Attention is not causal, so a frame at 3 seconds can attend to one at 12 seconds. The decoder is eight Laddered Simple Attention blocks at width 512, with 8 query heads to 2 KV heads, a causal convolution on queries, keys and values, and engram lookups at layers 3 and 7.

Each decoder layer reads the encoder through gated cross attention, and those projections run once per clip. Five beams therefore cost five short transcript caches rather than five passes over the audio. Decoding uses five beams scored by length-normalised log probability, keyword biasing walks an Aho-Corasick automaton over phrases you supply, and the transcript is capped at 320 tokens. The vocabulary is 8,192 text pieces plus seven language tokens, so the detected language comes back as a token rather than a separate field.

Two design choices affect deployment. Every decoder depth from two layers up was trained as a model of its own, and a load-time flag selects one, while the encoder always runs all eight blocks. The engine also measures loudness before decoding and returns an empty transcript below a threshold, which keeps silence out of beam search.

What the benchmarks show, and what they do not

Cactus compared Whistle with Whisper base and Moonshine tiny v2 on an Apple M4 Pro CPU, running each model on its official runtime at default settings.

The size gap is large: 16.9 MB for Whistle, 41.9 MB for Moonshine tiny v2, and 145.3 MB for Whisper base. Time to first token on ten seconds of audio was 11.1 ms for Whistle, 22.8 ms for Moonshine and 73.2 ms for Whisper base, which stays flat across clip lengths because it pads every input to 30 seconds. Decode speed was 1,319 tokens per second for Whistle against 266 for Whisper base and 262 for Moonshine.

Word error rates are more mixed. Whistle leads on LibriSpeech test-clean and test-other, SPGISpeech, Earnings-22 and the FLEURS average. Whisper base leads on TED-LIUM, AMI and the MLS average. Whistle's rates cover 86,174 utterances scored with the Whisper normalisers, while the competitor figures are the numbers their own authors published. This is a comparison of published results rather than a fresh head-to-head test.

Cactus says no test audio appears in Whistle's training or validation data, checked by comparing audio checksums and speaker IDs across every reported test set. No independent reproduction is included in the release.

How to try it

The Python package is cactus-needle, and a 16 kHz WAV or raw samples works with the base install. Other sample rates and microphone capture need an extra that adds soxr and sounddevice.

Every call returns the text, the language, the time to first token and the decoder's tokens per second. word_timestamps=True adds each word with its times and probability, keywords raises the log probability of chosen phrases during the search, and language forces a language instead of detecting one.

Two commands are built for testing rather than production: a terminal playground that transcribes from the microphone, and a compare command that runs one clip through Whistle, Whisper and Moonshine with timings. The compare command is the practical way to check the claims above against your own audio.

The engine ships prebuilt for seventeen targets, including macOS, Linux, Android, iOS, watchOS, Windows on ARM, RISC-V, MIPS, the browser and a WASI component. Each target folder holds a binary, a static library and a header, and loads whichever model file you give it. Weights are on Hugging Face and the source is on GitHub.

Why one binary matters

The combined build is the more interesting one. A single binary can load the speech model and the language model together, take an audio clip, transcribe it, run the transcript against a tool definition, and return one JSON object containing both the function calls and the speech fields.

That pattern sits behind many voice interfaces: speak, receive a structured action. A cloud API streams the audio to a server and bills per request. A local binary keeps the audio on the device, which Cactus demonstrates with a sandbox that runs in the browser tab.

Concept diagram of one unbranded binary module routing a waveform to a transcript sheet and a second path to a tool-call symbol.
The article says the shared engine can load Whistle and Needle together for transcription and tool-call outputs; concept illustration, not a writer-run test.

What is still open

Cactus is the source for every number here, including the word error rates, the latency figures, the target list and the statement that no test audio leaked into training. No third-party evaluation accompanies the release.

The company publishes no accuracy figure for noisy or far-field audio, which is where small speech models generally struggle, and it says nothing about overlapping speakers. Results on read speech and earnings calls say little about a car cabin or a kitchen.

The post also names no licence for the weights, and it does not explain how the seven language tokens were chosen or how far the model generalises beyond them. For a project whose main appeal is local execution, licensing is the question a product team has to settle before embedding it.

The practical position is that Whistle is a small on-device speech model with published commands and vendor benchmarks you can check on your own audio. Bring your own test clip rather than relying on the comparison table.