Bucky
June 1, 2026 · View on GitHub
Copyright 2025-2026 Ardan Labs
Bucky
This project lets you use Go for hardware accelerated local speech-to-text with whisper.cpp directly integrated into your applications. Bucky provides a high-level API that mirrors whisper.h 1-to-1 plus pure-Go audio decoding so you can hand any WAV/MP3/FLAC file to a model and get a transcript back.
Bucky is the speech-to-text sibling of hybridgroup/yzma (which binds llama.cpp). The end goal is to give Kronk a native, OpenAI-compatible POST /v1/audio/transcriptions endpoint without the CGo toolchain.
Bucky is the squirrel from The Emperor's New Groove — he speaks in squeaks/whispers. Naming a Whisper binding after him is just good taste.
To install bucky, fetch the whisper.cpp shared libraries, and transcribe the bundled JFK sample:
$ go install github.com/ardanlabs/bucky@latest
$ bucky install -lib ./lib
$ export BUCKY_LIB=$(pwd)/lib
$ bucky model get tiny
$ bucky whisper transcribe -m ~/models/ggml-tiny.bin samples/jfk.wav
Read INSTALL.md for per-OS install notes and MODELS.md for the recommended whisper model set.
Project Status
Sometimes there are breaking changes to whisper.cpp that require an update to bucky. Here are the known compatible versions:
| whisper.cpp | bucky |
|---|---|
| v1.8.6 | 0.1.x |
The core FFI binding (model loading, whisper_full, segments + tokens, VAD, state, language, bench helpers), audio decoding (WAV/MP3/FLAC), CLI (install, system, model get|info|list, whisper transcribe), and examples (hello, transcribe, translate, segments, words, streaming) have all landed. Kronk integration (an OpenAI-compatible POST /v1/audio/transcriptions endpoint) lives in the kronk repo.
Owner Information
Name: Bill Kennedy
Company: Ardan Labs
Title: Managing Partner
Email: bill@ardanlabs.com
BlueSky: https://bsky.app/profile/goinggo.net
LinkedIn: www.linkedin.com/in/william-kennedy-5b318778/
Twitter: https://x.com/goinggodotnet
Install Bucky
The fastest way to install on any supported platform is with Go:
$ go install github.com/ardanlabs/bucky@latest
$ bucky --help
Then fetch the whisper.cpp shared library bundle (xcframework on darwin, DLLs on windows, .tar.gz from ardanlabs/bucky-builder on linux):
$ bucky install -lib ./lib
$ export BUCKY_LIB=$(pwd)/lib
$ bucky system
And pull a model from the bundled catalog:
$ bucky model list
$ bucky model get tiny
$ bucky model info -m ~/models/ggml-tiny.bin
Issues/Features
Here is the existing Issues/Features for the project and the things being worked on or things that would be nice to have.
If you are interested in helping in any way, please send an email to Bill Kennedy.
Architecture
The architecture of bucky mirrors yzma file-for-file so anyone who knows yzma can drop straight in. There is no CGo: every C call goes through purego + JupiterRider/ffi.
┌─────────────────────────────────────────────────────────────┐
│ cmd/ bucky CLI (install, system, model, whisper) │
├─────────────────────────────────────────────────────────────┤
│ pkg/whisper 1-to-1 mirror of whisper.h │
│ (model, context, full, segments, tokens, │
│ lang, state, vad, bench, params) │
│ pkg/audio pure-Go decoders (WAV / MP3 / FLAC) + │
│ downmix-to-mono + 16 kHz resampling │
│ pkg/loader BUCKY_LIB-aware purego library loader │
│ pkg/download go-getter-driven release-archive resolver │
│ pkg/utils cross-platform Go ↔ C string helpers │
└─────────────────────────────────────────────────────────────┘
│
▼
libwhisper.{dylib|so|dll}
(whisper.cpp v1.8.6)
Models
Bucky uses GGML-format models supported by whisper.cpp. The official set lives at ggerganov/whisper.cpp on Hugging Face (tiny / base / small / medium / large-v3 / large-v3-turbo, plus -en English-only and quantized -q5_0 / -q8_0 variants). Companion VAD models live at ggml-org/whisper-vad.
Bucky ships a small bundled catalog so you can bucky model get tiny instead of pasting a URL:
$ bucky model list
$ bucky model get tiny
$ bucky model get -u https://example.com/foo.bin -o ~/models # arbitrary URL
$ bucky model get silero-vad
See MODELS.md for the recommended set with size / speed / quality trade-offs.
Support
Bucky uses the prebuilt whisper.cpp release artifacts where they exist; Linux artifacts come from the ardanlabs/bucky-builder companion repo (whisper.cpp upstream publishes no Linux release).
| OS | CPU | GPU | Source |
|---|---|---|---|
| Linux | amd64, arm64 | CUDA 12.9, Vulkan | whisper-vX.Y.Z-bin-ubuntu-{cpu,cuda,vulkan}-{x64,arm64}.tar.gz (bucky-builder) |
| macOS | arm64, amd64 | Metal | whisper-vX.Y.Z-xcframework.zip (upstream) |
| Windows | amd64 | CPU, CUDA 12 | whisper-bin-x64.zip / -cublas-… (upstream) |
Whenever there is a new release of whisper.cpp, the FFI struct mirrors and pkg/download matrix may need a refresh. The pinned version is captured in pkg/download/.
API Examples
There are examples in the examples/ directory. Each one
expects BUCKY_LIB and BUCKY_TEST_MODEL to be set:
$ export BUCKY_LIB=$(pwd)/lib
$ export BUCKY_TEST_MODEL=$HOME/models/ggml-tiny.bin
HELLO — the smallest possible bucky program: load a tiny model, decode an audio file, print the transcript.
$ make hello
TRANSCRIBE — fuller transcription example with -lang, -prompt, -temperature, and -beam flags.
$ go run ./examples/transcribe -lang en samples/jfk.wav
TRANSLATE — sets wparams.Translate = 1 to translate non-English audio to English.
$ go run ./examples/translate -m $HOME/models/ggml-base.bin some-foreign-audio.wav
SEGMENTS — print each generated segment with [mm:ss.mmm -> mm:ss.mmm] text. Pass -tokens for per-token detail.
$ go run ./examples/segments -tokens samples/jfk.wav
WORDS — enable token-level timestamps and print [t0 -> t1] word for every emitted token. Documents the experimental DTW path in a comment.
$ go run ./examples/words samples/jfk.wav
STREAMING — sliding-window pseudo-streaming over the input file. Each window's tail tokens are carried into the next via wparams.PromptTokens.
$ go run ./examples/streaming samples/jfk.wav
Sample API Program — Hello Example
// hello is the smallest possible bucky example: load a tiny whisper model,
// decode an audio file (WAV / MP3 / FLAC), and print the resulting text.
package main
import (
"fmt"
"log"
"os"
"strings"
"github.com/ardanlabs/bucky/pkg/audio"
"github.com/ardanlabs/bucky/pkg/whisper"
)
func main() {
if len(os.Args) < 2 {
log.Fatalf("usage: %s <audio-file>", os.Args[0])
}
audioPath := os.Args[1]
libPath := os.Getenv("BUCKY_LIB")
if libPath == "" {
log.Fatal("BUCKY_LIB must point to the directory containing libwhisper")
}
modelPath := os.Getenv("BUCKY_TEST_MODEL")
if modelPath == "" {
log.Fatal("BUCKY_TEST_MODEL must point to a GGML whisper model (e.g. ggml-tiny.bin)")
}
if err := whisper.Load(libPath); err != nil {
log.Fatalf("whisper.Load: %v", err)
}
if err := whisper.Init(libPath); err != nil {
log.Fatalf("whisper.Init: %v", err)
}
cparams := whisper.ContextDefaultParams()
ctx, err := whisper.InitFromFileWithParams(modelPath, cparams)
if err != nil {
log.Fatalf("InitFromFileWithParams: %v", err)
}
defer whisper.Free(ctx)
f, err := os.Open(audioPath)
if err != nil {
log.Fatalf("open %s: %v", audioPath, err)
}
defer f.Close()
samples, err := audio.Decode(f)
if err != nil {
log.Fatalf("audio.Decode: %v", err)
}
wparams := whisper.FullDefaultParams(whisper.SamplingGreedy)
wparams.PrintProgress = 0
wparams.PrintRealtime = 0
wparams.PrintTimestamps = 0
wparams.NoTimestamps = 1
if err := whisper.Full(ctx, wparams, samples); err != nil {
log.Fatalf("Full: %v", err)
}
var sb strings.Builder
for i := int32(0); i < whisper.FullNSegments(ctx); i++ {
sb.WriteString(whisper.FullGetSegmentText(ctx, i))
}
fmt.Println(strings.TrimSpace(sb.String()))
}
This example produces the following output:
$ make hello
go run ./examples/hello samples/jfk.wav
And so my fellow Americans ask not what your country can do for you ask what you can do for your country.
License
Apache-2.0 — see LICENSE.