Local-first speech-to-text CLI.
sotto captures microphone audio, streams to a local ASR backend (Riva by default), assembles transcript text, and commits output to the clipboard with optional paste dispatch.
Why this exists
- single-process CLI (no daemon)
- local-first by default (localhost Riva endpoints)
- explicit state machine (
toggle,stop,cancel) - deterministic config + observable runtime logs
Feature summary
- single-instance command coordination via unix socket
- audio capture via PipeWire/Pulse
- streaming ASR via NVIDIA Riva gRPC
- transcript normalization + sentence capitalization + optional trailing space
- output adapters:
- clipboard command (
clipboard_cmd) - optional paste command override (
paste_cmd) - default Hyprland paste path (
hyprctl sendshortcut) whenpaste_cmdis unset
- clipboard command (
- indicator backends:
hyprnotificationsdesktop(freedesktop notifications, e.g. mako)
- embedded cue WAV assets for start/stop/complete/cancel (not user-configurable)
- built-in indicator localization scaffolding (English catalog currently shipped)
- built-in environment diagnostics via
sotto doctor
Platform scope (current)
sotto is currently optimized for Wayland + Hyprland workflows.
- default paste behavior uses
hyprctl doctorcurrently checks for a Hyprland session
You can still reduce Hyprland coupling by using:
indicator.backend = desktoppaste_cmd = "..."(explicit command override)
Install
Nix (recommended)
nix build 'path:.#sotto' nix run 'path:.#sotto' -- --help
From source
just tools
go test ./apps/sotto/...
go build ./apps/sotto/cmd/sottoQuickstart
sotto doctor sotto toggle # start sotto toggle # stop + commit
Core commands:
sotto toggle sotto stop sotto cancel sotto status sotto devices sotto doctor sotto version
Configuration
Config resolution order:
--config <path>$XDG_CONFIG_HOME/sotto/config.jsonc~/.config/sotto/config.jsonc
Compatibility note:
- if the default
.jsoncfile is missing, sotto will fall back to legacyconfig.confautomatically.
See full key reference and examples in:
Verification
Required local gate before hand-off:
just ci-check
nix build 'path:.#sotto'Manual/local runtime checklist: