Handy Speech-to-Text to Tmux

I installed Handy, a local speech-to-text app, on Kubuntu. It uses ONNX models (parakeet-tdt) to transcribe speech locally. Getting it to work required fixing a couple of issues, and then I built a small watcher script to pipe transcriptions into a tmux session.

Fixing the Crash

Handy was crashing silently every time I pressed the shortcut to start recording. The log at ~/.local/share/com.pais.handy/logs/handy.log would just stop dead mid-recording with no error. No segfault in dmesg, no coredump, nothing.

The root cause was that pipewire-alsa wasn't installed. Handy uses CPAL (a Rust audio library) which goes through ALSA, but without the PipeWire-ALSA bridge, it couldn't route audio and would silently die. Running Handy from a terminal showed the errors:

ALSA lib pcm.c:2722:(snd_pcm_open_noupdate) Unknown PCM pipewire
ALSA lib pcm_dmix.c:1000:(snd_pcm_dmix_open) unable to open slave

Fix:

sudo apt install pipewire-alsa

After that, the ALSA errors went away and recording worked.

Push-to-Talk Doesn't Work on KDE Wayland

Push-to-talk mode (hold key to record, release to stop) doesn't work properly on KDE Wayland. The key release event fires immediately, so the recording stops before any speech is captured. The log shows TranscribeAction::start and TranscribeAction::stop in the same second.

This is because Handy falls back to a regular window on KDE Wayland (Skipping GTK layer shell init on KDE Wayland) and global shortcut key-release detection is unreliable under Wayland's security model.

Workaround: use toggle mode instead (push_to_talk: false). Press once to start recording, press again to stop.

Handy Settings

In Handy's settings I changed:

The settings file lives at ~/.local/share/com.pais.handy/settings_store.json.

Sending Transcriptions to a Tmux Session

I wanted to be able to dictate into a specific terminal without switching focus to it. The idea: keep working in whatever window I'm in, press Ctrl+Space, speak, and have the text appear in a tmux session called "handy".

Handy saves every transcription to a SQLite database at ~/.local/share/com.pais.handy/history.db. The schema is simple:

CREATE TABLE transcription_history (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    file_name TEXT NOT NULL,
    timestamp INTEGER NOT NULL,
    saved BOOLEAN NOT NULL DEFAULT 0,
    title TEXT NOT NULL,
    transcription_text TEXT NOT NULL,
    post_processed_text TEXT,
    post_process_prompt TEXT
);

I wrote a watcher script at ~/.local/bin/handy-to-tmux that polls this database for new entries and sends them to the tmux session via tmux send-keys. It debounces rapid writes (Handy sometimes writes partial results) so only the final transcription gets sent.

Usage:

handy-to-tmux start    # start watcher in background
handy-to-tmux stop     # stop it
handy-to-tmux status   # check if running
handy-to-tmux run      # run in foreground for debugging

It uses a pidfile at ~/.local/state/handy-to-tmux.pid to ensure only one instance runs at a time. Logs go to ~/.local/state/handy-to-tmux.log.

The tmux session just needs to exist first:

tmux new-session -d -s handy

Then whatever shell is running in that session receives the transcribed text as if it were typed in.

Targeting Different Tmux Sessions

I added the ability to route transcriptions to different tmux sessions using separate keyboard shortcuts. The target subcommand sets which session to send to and triggers Handy's recording in one step:

handy-to-tmux target code    # sets target to "code" and starts recording
handy-to-tmux target chat    # sets target to "chat" and starts recording

The target persists in ~/.local/state/handy-to-tmux.target until changed, so subsequent Ctrl+Space presses (without setting a new target) continue going to the same session. Defaults to "handy" if no target is set.

To set up per-session shortcuts, bind KDE global shortcuts to:

Each shortcut starts recording and routes the result to its session. Press Ctrl+Space to stop recording.

Repo

Source is at https://github.com/ThomasBurgess2000/handy-to-tmux. Install with ./install.sh which copies the script to ~/.local/bin/.

2.16.2026