Dictation at cursor for Linux and macOS. A Rust rewrite based on the original xhisper project.
On Linux, rhisper needs pipewire (for pw-record) and ffmpeg at runtime. On macOS, it needs sox (for rec) and ffmpeg. Everything else (HTTP, JSON, clipboard) is built into the binary.
Arch Linux / Manjaro
sudo pacman -S pipewire ffmpegDebian / Ubuntu / Linux Mint
sudo apt update
sudo apt install pipewire ffmpegFedora / RHEL / AlmaLinux / Rocky
Fedora's base repos don't shipffmpeg (licensing) — enable RPM Fusion first:
sudo dnf install -y https://download1.rpmfusion.org/free/fedora/rpmfusion-free-release-$(rpm -E %fedora).noarch.rpm
sudo dnf install -y pipewire-utils ffmpegmacOS
brew install sox ffmpegrec to capture audio — rhisper --setup checks and prompts for these.
Arch Linux (AUR)
yay -S rhisper
# or
paru -S rhisperpackaging/PKGBUILD:
git clone --depth 1 https://github.com/lv10/rhisper.git
cd rhisper/packaging && makepkg -simakepkg, not bare pacman -S — pacman itself has no native AUR support, which is true of every AUR package, not just this one.
Debian / Ubuntu (APT repository)
curl -1sLf 'https://dl.cloudsmith.io/public/lv10-labs/rhisper/gpg.key' | sudo gpg --dearmor -o /usr/share/keyrings/rhisper-archive-keyring.gpg
echo "deb [signed-by=/usr/share/keyrings/rhisper-archive-keyring.gpg] https://dl.cloudsmith.io/public/lv10-labs/rhisper/deb/ubuntu jammy main" | sudo tee /etc/apt/sources.list.d/rhisper.list
sudo apt update && sudo apt install rhisper.deb directly from the latest release and sudo apt install ./rhisper_*.deb.
Fedora / RHEL / AlmaLinux / Rocky
Download the.rpm from the latest release, then:
sudo dnf install ./rhisper-*.rpmmacOS (Homebrew)
brew tap lv10/rhisper
brew install rhispercargo (any distro with Rust installed)
cargo install rhispercargo install only builds and places the two binaries on your $PATH — it has no post-install hook, so it can't install the udev rule the .deb/.rpm/AUR packages ship. Without it, the daemon can't open /dev/uinput unless you're already in the input group. After installing, either run:
sudo usermod -aG input $USER # then log out and back incurl -sL https://raw.githubusercontent.com/lv10/rhisper/main/packaging/rhisper-uinput.rules | sudo tee /usr/lib/udev/rules.d/60-rhisper-uinput.rules
sudo udevadm control --reload-rules && sudo udevadm trigger --subsystem-match=misc --attr-match=name=uinputrhisper --setup checks and prompts for these).
Build from source (any distro)
Requires the Rust toolchain (rustup.rs) andnasm (a build-time dependency of the TLS stack):
git clone --depth 1 https://github.com/lv10/rhisper.git
cd rhisper
cargo build --release
sudo install -Dm755 target/release/rhisper /usr/local/bin/rhisperrhispertool is a Linux-only stub there, see Usage):
sudo install -Dm755 target/release/rhispertool /usr/local/bin/rhispertool
sudo ln -sf rhispertool /usr/local/bin/rhispertoold
sudo install -Dm644 packaging/rhisper-uinput.rules /usr/lib/udev/rules.d/60-rhisper-uinput.rules
sudo udevadm control --reload-rules && sudo udevadm trigger --subsystem-match=misc --attr-match=name=uinputLinux packages install a udev rule granting access to /dev/uinput automatically — no group membership change or re-login needed. If you built from source without the udev rule (or on a system without udev-tag-aware session management), fall back to:
sudo usermod -aG input $USERthen log out and log back in (restart is safer) for the group change to take effect. Check with groups — you should see input in the output.
- Get a Groq API key from console.groq.com (free tier available) and add to
~/.env:
GROQ_API_KEY=<your_API_key>(Or run rhisper --setup for an interactive prompt plus a platform permission/dependency check — /dev/uinput on Linux, Accessibility on macOS.)
- Bind
rhisperbinary to your favorite key:
keyd
[main]
capslock = layer(dictate)
[dictate:C]
d = macro(rhisper)sxhkd
super + d
rhisper
i3 / sway
bindsym $mod+d exec rhisper
Hyprland
bind = $mainMod, D, exec, rhisper
macOS (skhd)
macOS has no bundled hotkey daemon; skhd is the closest widely-used equivalent (also needs Accessibility permission, granted separately from rhisper's own):
brew install skhd# ~/.config/skhd/skhdrc
cmd + shift - d : rhisper
skhd --start-serviceGnome
# In your terminal:
name="rhisper"
binding="<CTRL><SHIFT>X"
action="/usr/local/bin/rhisper"
media_keys=org.gnome.settings-daemon.plugins.media-keys
custom_kbd=org.gnome.settings-daemon.plugins.media-keys.custom-keybinding
kbd_path=/org/gnome/settings-daemon/plugins/media-keys/custom-keybindings/$name/
new_bindings=`gsettings get $media_keys custom-keybindings | sed -e"s>'\]>','$kbd_path']>"| sed -e"s>@as \[\]>['$kbd_path']>"`
gsettings set $media_keys custom-keybindings "$new_bindings"
gsettings set $custom_kbd:$kbd_path name "$name"
gsettings set $custom_kbd:$kbd_path binding "$binding"
gsettings set $custom_kbd:$kbd_path command "$action"Simply run rhisper twice (via your favorite keybinding):
- First run: Starts recording
- Second run: Stops and transcribes
The transcription will be typed at your cursor position.
View logs:
rhisper --logNon-QWERTY layouts (Linux only):
Linux types by simulating physical key positions, so a non-QWERTY layout (e.g. Dvorak, International) needs an input switch key to QWERTY (e.g. rightalt) set up first. Then instead of binding to rhisper, bind to:
rhisper --<your-input-switch-key>Available input switch keys: --leftalt, --rightalt, --leftctrl, --rightctrl, --leftshift, --rightshift, --super (on macOS, --super wraps with Cmd instead — there's no physical Super/Windows key)
Key chords (like ctrl-space) not available yet. macOS doesn't need any of this: it types via direct Unicode injection regardless of the active keyboard layout, so there's nothing to switch.
Keyboard layout for typed symbols (Linux only):
ASCII letters and digits are typed by physical key position, but punctuation symbols differ between layouts. If you use a Danish or Spanish keyboard layout and get wrong characters (e.g. on Danish, ' comes out as ø; on Spanish, ~ comes out as ª), set the layout in ~/.config/rhisper/rhisperrc:
keyboard-layout : dk
Supported layouts: us, dk, es. The layout is read by the daemon at startup; the daemon is restarted automatically when the setting changes. Ignored on macOS (see above).
Configuration is read from ~/.config/rhisper/rhisperrc. A default one is created automatically the first time you run rhisper — no setup step required.
To view or reset your configuration:
rhisper --config # print current config
cp /usr/share/rhisper/rhisperrc.default \
~/.config/rhisper/rhisperrc # reset to defaults| Option | Default | Description |
|---|---|---|
provider |
groq |
Transcription provider: groq (reads GROQ_API_KEY), openai (reads OPENAI_API_KEY), or custom (reads RHISPER_API_KEY, sends to api-base-url) |
api-base-url |
(empty) | Base URL for provider: custom — any OpenAI-compatible /audio/transcriptions endpoint |
model |
(empty) | Overrides the provider's default model (e.g. whisper-1, gpt-4o-transcribe). Empty = provider default |
long-recording-threshold |
1000 |
Duration in seconds above which Groq's larger whisper-large-v3 model is used instead of whisper-large-v3-turbo |
transcription-prompt |
(empty) | Context hint passed to Whisper to improve accuracy (e.g. common words, names, or domain vocabulary) |
language |
(empty) | ISO-639-1 code (e.g. de, en, fr) to force the transcription language — leave empty to let Whisper auto-detect |
paste-mode |
type |
type (layout-sensitive, keeps clipboard), clipboard (always paste via clipboard, overwrites clipboard), or clipboard-restore (like clipboard, but saves and restores previous clipboard content) |
non-ascii-initial-delay |
0.15 |
Seconds to wait before pasting the first non-ASCII clipboard chunk — increase if the first character is wrong |
non-ascii-default-delay |
0.025 |
Seconds to wait before subsequent non-ASCII clipboard chunks |
keyboard-layout |
us |
Linux only. Keyboard layout used when typing ASCII characters (us, dk, or es) — see Keyboard layout for typed symbols. Ignored on macOS, which types via direct Unicode injection |
silence-threshold |
-50 |
Max volume in dB below which audio counts as quiet (e.g. -50 means anything quieter is discarded) |
min-speech-seconds |
0.3 |
Minimum contiguous stretch of audio above silence-threshold required anywhere in the recording to count as real speech, regardless of how long you pause before/after |
Terminal Applications: Clipboard paste uses Ctrl+V, which doesn't work in terminal emulators (they require Ctrl+Shift+V). Temporary workaround is to remap Ctrl+V to paste in your terminal emulator's settings. Note that this limitation only affects international/Unicode characters. ASCII characters (a-z, A-Z, 0-9, punctuation) are typed directly and are unaffected.
Non-ASCII characters come out wrong: Increase non-ascii-initial-delay (and non-ascii-default-delay) to give the Wayland compositor more time to process the clipboard update before the paste keystroke arrives.
Clipboard content is lost after dictation: This should not happen — rhisper saves and restores your clipboard around any non-ASCII paste operations. If you see this, please open an issue.
Run the test suite:
cargo testThis runs unit tests (keymap tables for every supported layout, the IPC protocol, ASCII/Unicode paste-chunking, silence-detection parsing, config parsing) plus integration tests for the transcription provider against a local mock HTTP server (tests/provider_test.rs).
Every push and pull request against main runs cargo build, cargo test, cargo clippy -- -D warnings, and cargo fmt --check on both Linux and macOS runners in CI (see .github/workflows/ci.yml). Tagged releases (v*) additionally build and publish .deb/.rpm/AUR-source/Homebrew-formula packages via .github/workflows/release.yml.
Low complexity dictation for Linux
