11 KiB
Hyprvoice - Voice-Powered Typing for Hyprland / Wayland
Press a toggle key, speak, and get instant text input. Built natively for Wayland/Hyprland - no X11 hacks or workarounds, just clean integration with modern Linux desktops.
Features
- Toggle workflow: Press once to start recording, press again to stop and inject text
- Wayland native: Purpose-built for Wayland compositors - no legacy X11 dependencies or hacky workarounds
- Real-time feedback: Desktop notifications for recording states and transcription status
- Multiple transcription backends: OpenAI Whisper (planned: whisper.cpp for local processing)
- Smart text injection: Clipboard save/restore with direct typing fallback
- Daemon architecture: Lightweight control plane with efficient pipeline management
Status: Early development - core functionality working, transcription integration in progress
Installation
From AUR (Arch Linux)
# Using your preferred AUR helper
yay -S hyprvoice-bin
# or
paru -S hyprvoice-bin
# Enable user service
systemctl --user enable --now hyprvoice.service
Download Binary
- Download from GitHub Releases
- Install:
wget https://github.com/leonardotrapani/hyprvoice/releases/latest/download/hyprvoice-linux-x86_64
mkdir -p ~/.local/bin
mv hyprvoice-linux-x86_64 ~/.local/bin/hyprvoice
chmod +x ~/.local/bin/hyprvoice
# Add to PATH (add to ~/.bashrc or ~/.zshrc)
export PATH="$HOME/.local/bin:$PATH"
Build from Source
git clone https://github.com/leonardotrapani/hyprvoice.git
cd hyprvoice
# Build the binary
CGO_ENABLED=1 go build -o hyprvoice ./cmd/hyprvoice
# Install locally
sudo cp hyprvoice /usr/local/bin/
Requirements
- Wayland desktop (Hyprland, Niri, GNOME, KDE, etc.)
- PipeWire audio system with tools
- System packages:
# Arch Linux
sudo pacman -S pipewire pipewire-pulse pw-record wl-clipboard
# Ubuntu/Debian
sudo apt install pipewire-pulse pipewire-bin wl-clipboard
# Fedora
sudo dnf install pipewire-utils wl-clipboard
For text injection (recommended):
# Arch Linux
sudo pacman -S wtype
# Ubuntu/Debian
sudo apt install wtype
# Alternative: ydotool (if wtype unavailable)
# Follow ydotool setup for user permissions
Optional:
notify-send(desktop notifications)systemd --user(daemon service)
Quick Start
- Setup daemon service:
# Enable and start the user service (reccomended)
systemctl --user enable --now hyprvoice.service
# Or run manually in background
hyprvoice serve &
- Configure Hyprland keybind:
# Add to ~/.config/hypr/hyprland.conf
bind = SUPER, R, exec, hyprvoice toggle
- Test voice input:
# Check daemon status
hyprvoice status
# Toggle recording (or use Super+R)
hyprvoice toggle
# Speak something...
hyprvoice toggle # Stop and transcribe
Quick Reference
Common Commands
# Start the daemon
hyprvoice serve
# Toggle recording on/off
hyprvoice toggle
# Check current status
hyprvoice status
# Get protocol version
hyprvoice version
# Stop the daemon (if not using systemd service)
hyprvoice stop
Keybinding Pattern
Most setups use this toggle pattern in window manager config:
bind = SUPER, R, exec, hyprvoice toggle
Keyboard Shortcuts Setup
Hyprland
Add to your ~/.config/hypr/hyprland.conf:
# Hyprvoice - Voice to Text (toggle recording)
bind = SUPER, R, exec, hyprvoice toggle
# Optional: Status check
bind = SUPER SHIFT, R, exec, hyprvoice status && notify-send "Hyprvoice" "$(hyprvoice status)"
Usage Examples
Basic Toggle Workflow
- Press keybind → Recording starts (notification appears)
- Speak your text → Audio captured in real-time
- Press keybind again → Recording stops, transcription begins
- Text appears → Injected at cursor position or clipboard
CLI Usage
# Start daemon manually (if not using systemd service)
hyprvoice serve
# In another terminal: toggle recording
hyprvoice toggle
# ... speak ...
hyprvoice toggle
# Check what's happening
hyprvoice status
Configuration
Configuration will be read from ~/.config/hyprvoice/config.toml (planned). Currently, the daemon uses default settings.
Transcription Providers
Hyprvoice will support multiple transcription backends:
OpenAI Whisper API (Planned)
Fast, accurate cloud-based transcription:
[transcription]
provider = "openai"
api_key = "your_openai_api_key"
model = "whisper-1"
language = "auto" # or "en", "es", etc.
whisper.cpp Local (Planned)
Private, offline transcription using local models:
[transcription]
provider = "whisper_cpp"
model_path = "~/models/ggml-base.en.bin"
threads = 4
Service Configuration
Systemd Service
The daemon runs as a user service:
# Create service file
mkdir -p ~/.config/systemd/user
cat > ~/.config/systemd/user/hyprvoice.service << 'EOF'
[Unit]
Description=Hyprvoice voice-to-text daemon
After=pipewire.service
[Service]
Type=simple
ExecStart=/usr/local/bin/hyprvoice serve
Restart=on-failure
RestartSec=5
[Install]
WantedBy=default.target
EOF
# Enable and start
systemctl --user daemon-reload
systemctl --user enable --now hyprvoice.service
File Locations
- Socket:
~/.cache/hyprvoice/control.sock- IPC communication - PID file:
~/.cache/hyprvoice/hyprvoice.pid- Process tracking - Config:
~/.config/hyprvoice/config.toml- User settings (planned)
Development Status
| Component | Status | Notes |
|---|---|---|
| Core daemon & IPC | ✅ | Unix socket control plane |
| Recording workflow | ✅ | Toggle recording via PipeWire |
| Audio capture | ✅ | Efficient PipeWire integration |
| Desktop notifications | ✅ | Status feedback via notify-send |
| OpenAI transcription | ✅ | HTTP API integration |
| Text injection | ⏳ | Clipboard + typing implementation |
| Configuration system | ⏳ | TOML-based user settings |
| Comprehensive tests | ⏳ | Pipeline and integration testing |
| whisper.cpp support | ⏳ | Local model inference |
Legend: ✅ Complete · ⏳ Planned
Architecture Overview
Hyprvoice uses a daemon + pipeline architecture for efficient resource management:
- Control Daemon: Lightweight IPC server managing lifecycle
- Pipeline: Stateful audio processing (recording → transcribing → injecting)
- State Machine:
idle → recording → transcribing → injecting → idle
System Architecture
flowchart LR
subgraph Client
CLI["CLI/Tool"]
end
subgraph Daemon
D["Control Daemon (lifecycle + IPC)"]
end
subgraph Pipeline
A["Audio Capture"]
T["Transcribing (ASR TBD)"]
I["Injecting (stub)"]
end
N["notify-send/log"]
CLI -- unix socket --> D
D -- start/stop --> A
A -- frames --> T
T -- status --> D
D -- events --> N
D -- inject action --> T
T --> I
I -->|done| D
stateDiagram-v2
[*] --> idle
idle --> recording: toggle
recording --> transcribing: first_frame
transcribing --> injecting: inject_action
injecting --> idle: done
recording --> idle: abort
injecting --> idle: abort
How It Works
- Toggle recording → Pipeline starts, audio capture begins
- Audio streaming → PipeWire frames buffered for transcription
- Toggle stop → Recording ends, transcription starts
- Text injection → Result typed or copied to clipboard
- Return to idle → Pipeline cleaned up, ready for next session
Data Flow
toggle(daemon) → create pipeline → recording- First frame arrives → transcribing (daemon may notify
Transcribinglater) - Audio frames → audio buffer (collect all audio during session)
- Second
toggleduring transcribing → sendinjectaction → transcribe collected audio → injecting (simulated) - Complete → idle; pipeline stops; daemon clears reference
- Notifications at key transitions
Troubleshooting
Common Issues
Daemon Issues
Daemon won't start:
# Check if already running
hyprvoice status
# Check for stale files
ls -la ~/.cache/hyprvoice/
# Clean up and restart
rm -f ~/.cache/hyprvoice/hyprvoice.pid
rm -f ~/.cache/hyprvoice/control.sock
hyprvoice serve
Command not found:
# Check installation
which hyprvoice
# Add to PATH if using ~/.local/bin
echo 'export PATH="$HOME/.local/bin:$PATH"' >> ~/.bashrc
source ~/.bashrc
Audio Issues
No audio recording:
# Check PipeWire is running
systemctl --user status pipewire
# Test microphone
pw-record --help
pw-record test.wav
# Check microphone permissions and levels
Audio device issues:
# List available audio devices
pw-cli list-objects | grep -A5 -B5 Audio
# Check microphone is not muted in system settings
Notification Issues
No desktop notifications:
# Test notify-send directly
notify-send "Test" "This is a test notification"
# Install if missing
sudo pacman -S libnotify # Arch
sudo apt install libnotify-bin # Ubuntu/Debian
Text Injection Issues
Text not appearing (when implemented):
- Ensure cursor is in a text field when toggling off recording
- Check that
wtypeor clipboard tools are installed - Verify window manager supports the text injection method used
Debug Mode
# Run daemon with verbose output
hyprvoice serve
# Check logs from systemd service (or just see results from hyprvoice serve)
journalctl --user -u hyprvoice.service -f
# Test individual commands
hyprvoice toggle
hyprvoice status
Development
Building from Source
git clone https://github.com/leonardotrapani/hyprvoice.git
cd hyprvoice
# Install Go dependencies
go mod download
# Build
CGO_ENABLED=1 go build -o hyprvoice ./cmd/hyprvoice
# Run tests
go test ./...
# Install locally
sudo cp hyprvoice /usr/local/bin/
Project Structure
hyprvoice/
├── cmd/hyprvoice/ # CLI application entry point
├── internal/
│ ├── bus/ # IPC (Unix socket) + PID management
│ ├── daemon/ # Control daemon (lifecycle management)
│ ├── notify/ # Desktop notification integration
│ ├── pipeline/ # Audio processing pipeline + state machine
│ ├── recording/ # PipeWire audio capture
│ └── transcriber/ # Transcription adapters (OpenAI, whisper.cpp)
├── go.mod # Go module definition
└── README.md
Development Workflow
# Terminal 1: Run daemon with logs
go run ./cmd/hyprvoice serve
# Terminal 2: Test commands
go run ./cmd/hyprvoice toggle
go run ./cmd/hyprvoice status
go run ./cmd/hyprvoice stop
IPC Protocol
Simple single-character commands over Unix socket:
t- Toggle recording on/offs- Get current statusv- Get protocol versionq- Quit daemon gracefully
Contributing
Contributions welcome! Please:
- Follow existing code conventions and patterns
- Add tests for new functionality when available
- Update documentation for user-facing changes
- Test on Hyprland/Wayland before submitting PRs
License
MIT License - see LICENSE.md for details.