v0.3.0·Apple Silicon macOS·GPL-3.0

yap

pbpaste, but it talks.

yap reads your macOS clipboard aloud using Kokoro TTS. Synthesis streams chunk-by-chunk, so audio starts playing as soon as the first sentence is ready — not after the whole clipboard.

yap — zsh
$ curl -fsSL https://raw.githubusercontent.com/jonstuebe/yap/main/install.sh | sh jonstuebe/yap ↗

$install

One command, one binary, no runtime dependencies. Apple Silicon macOS only.

install
$ curl -fsSL https://raw.githubusercontent.com/jonstuebe/yap/main/install.sh | sh
Installs to /usr/local/bin/yap (falls back to ~/.local/bin if not writable). Override with YAP_INSTALL_DIR=....
On first run, yap downloads the Kokoro model files (~340MB) to ~/Library/Application Support/yap/.
The release binary is unsigned. The installer downloads via curl, which doesn't set the Gatekeeper quarantine bit, so it runs without prompts. If you download the tarball from GitHub Releases in a browser instead, run xattr -c /usr/local/bin/yap to clear the quarantine attribute.

$from source — requires Rust 1.93+ and CMake

build
$ brew install cmake
$ cargo install --git https://github.com/jonstuebe/yap.git

$features

A one-shot CLI that does one thing well: copy text, hear it spoken.

Streaming playback

Synthesis streams chunk-by-chunk — audio starts the moment the first sentence is ready, not after the whole clipboard is processed.

Watch mode

yap --watch speaks whatever you copy. Copy again mid-playback and it cancels instantly, starting on the new selection.

Save to file

--save out.wav or out.mp3 writes the audio to disk instead of playing it. Podcast-ify any text in one command.

Voices, speed & language

Flags for voice, speech rate, and language code. Run --list-voices to browse every voice Kokoro ships with.

Self-contained binary

No Python, no ONNX Runtime, no espeak-ng install. otool -L shows only Apple system frameworks.

Built-in updates

yap update re-runs the installer and swaps the binary in place, wherever it's currently installed.

$usage

Copy some text, then run yap. That's the whole interface.

basic
$ yap
synthesizing first of 3 chunk(s) 1.2s

Hit Ctrl-C to stop playback.

watch mode
$ yap --watch
yap --watch: copy text to speak; Ctrl-C to quit

Monitors the clipboard and speaks whatever you copy. Copying again while it's talking cancels the current playback and starts on the new selection.

options
$ yap --voice af_heart --speed 1.1 --lang en-us
$ yap --list-voices
af_heart
af_nova
am_adam
$ yap --save out.wav # or out.mp3
saved out.wav
flagdefaultdescription
--voiceaf_heartVoice name
--speed1.0Speech rate
--langen-usLanguage code
--watchSpeak on every clipboard change
--save PATHWrite audio to .wav or .mp3 instead of playing
--list-voicesPrint voices and exit
update
$ yap update

Re-runs the installer to fetch the latest release, replacing the binary in the directory it's currently installed in.

$global hotkey

yap is a one-shot CLI, so binding a system-wide hotkey is best handled outside the binary. Two good options:

macOS Shortcutsbuilt-in

Bind yap to a keyboard shortcut with the Shortcuts app.

  1. Open Shortcuts.app and create a new shortcut named Yap Clipboard.
  2. Add the Run Shell Script action with /usr/local/bin/yap (or ~/.local/bin/yap — use the full path, Shortcuts doesn't inherit your shell's PATH).
  3. In the shortcut's info panel (⌘I), set a Keyboard Shortcut — e.g. ⌃⌥⌘Y.

Running the shortcut a second time won't stop playback — it spawns another instance. To stop, focus the terminal and hit Ctrl-C, or wire up a second shortcut that runs killall yap.

Raycastscript command

A ready-to-use script lives at extras/raycast/yap.sh — it auto-detects where yap is installed.

  1. In Raycast settings → ExtensionsScript Commands, note your Script Directories path.
  2. Drop the script into that directory:
$ mkdir -p ~/.raycast-scripts
$ curl -fsSL https://raw.githubusercontent.com/jonstuebe/yap/main/extras/raycast/yap.sh \
-o ~/.raycast-scripts/yap.sh
$ chmod +x ~/.raycast-scripts/yap.sh
  1. Back in Extensions, find Yap Clipboard and assign a Hotkey.

Edit the @raycast.mode line from silent to compact if you want a HUD while it's speaking.

$how it works

Clipboard to audio in three steps, streaming the whole way.

01

read

Grabs the clipboard via arboard, with a pbpaste fallback.

02

split

Splits text on sentence boundaries, hard-cutting any sentence over 400 chars to stay under Kokoro's ~510-token ceiling.

03

speak

A producer thread synthesizes each chunk into f32 samples via Kokoros (ONNX Runtime + espeak-ng, both static-linked) while the main thread plays them in order through rodio. A bounded channel keeps the producer 1–2 chunks ahead.