Private, local text-to-speech. Say It turns copied text into speech with open models running entirely on your machine — your text and generated audio never leave your computer.
This is a Linux-first port of callebtc/sayit (macOS / Apple silicon). It keeps the original architecture and CLI while replacing Apple-specific layers with Tauri, Svelte, and kokoro-js.
Linux (X11 and Wayland) is built and tested. Windows CI builds an experimental MSI (needs Node and mpv on the machine; playback is not a full Windows port).
On macOS, use the original. This is the Linux port. If you want voice on Apple silicon, install callebtc/sayit — the app Calle wrote for it. This repo can compile the shell on macOS, but it is not the macOS voice experience and does not replace it. That is by design, not a gap waiting to be filled.
- Speak from anywhere. Copy text and press the clipboard hotkey
(Ctrl+Alt+V on X11), or bind
sayit-clipboardas a custom shortcut in your desktop environment — the reliable path on Wayland. - A desktop player. Tray window to speak, pause, seek, change playback speed, and revisit history without leaving your current app.
- Open models. Download supported Kokoro-82M weights in the app or CLI
(
kokoro-q8~90 MB, orkokoro-q4). Speak never downloads on its own. - Efficient model loading. Only one model is kept in memory, and it is unloaded after a configurable idle period (ten minutes by default).
- Local by design. Synthesis works offline after model download. There is no analytics, cloud inference, or passive clipboard monitoring.
- Hear your coding agent work. The bundled Say It agent skill provides live, hands-free spoken progress updates while an agent works.
Say It is in review for the Omarchy package repository — omacom/omarchy-pkgs#813. Once it is merged:
omarchy pkg add sayit-binOne package, everything in it: the desktop app (launcher and tray), the
sayit CLI, sayit-clipboard, and the agent skill. Updates come through
pacman. Until it lands, a 👍 on the PR helps it get reviewed. For the
clipboard hotkey, bind sayit-clipboard to a Hyprland shortcut — Wayland
blocks in-app global shortcuts.
CLI (terminal only, no window). Needs Node ≥ 20, npm, and mpv
(aplay is a limited fallback); clipboard tools (wl-paste, xclip, or
xsel) only if you want the hotkey.
curl -fsSL https://raw.githubusercontent.com/ildella/sayit/master/scripts/install.sh | bash -s -- --systemdAdd ~/.local/bin to your PATH. Omit --systemd to start the daemon once
without enabling it, or use bash scripts/install.sh --systemd from a clone.
Desktop. Download from Releases, then:
sudo apt install ./SayIt_*_amd64.deb # Debian/Ubuntu
sudo rpm -Uvh SayIt-*.x86_64.rpm # Fedora/openSUSE
chmod +x SayIt_*.AppImage && ./SayIt_*.AppImage # anywhere, no sudoAll three embed the sidecar, the sayit CLI, sayit-clipboard, the agent
skill and the licence; they need Node ≥ 20 and mpv (the .deb/.rpm
declare both). The window binary is sayit-desktop; installing the package
also puts sayit and sayit-clipboard on your PATH. It does not replace an
existing CLI install — whoever starts first owns port 7878, the other
connects. Tags also publish an experimental Windows MSI (same Node + mpv
requirement; not a full Windows port).
Auto-update (Settings → Check for updates) covers the AppImage and the MSI.
.deb / .rpm belong to your package manager, so Settings points you there
instead of showing a broken update button.
Download a model once (after that the app stays offline) and speak:
sayit models install kokoro-q8 --use
sayit "Hello from Say It"Or copy text and run sayit-clipboard (bind it as a desktop shortcut). Speak
returns an error until a catalog model is installed and selected.
The install includes a sayit CLI for speech, playback, models, and
automation:
sayit "Read this aloud"
printf 'Read standard input' | sayit
sayit status
sayit pause
sayit resume
sayit volume 0 # silence; 1 = normal, 2 = boost
sayit service status
sayit skill pathRun sayit --help for all commands. The CLI talks to the sidecar on
127.0.0.1:7878. If the daemon is down: sayit service start (or
systemctl --user start sayit after --systemd).
After install:
sayit skill installThat copies SKILL.md to ~/.agents/skills/sayit/ (OpenCode and other
agents that read that directory). Then tell the agent:
Load the Say It skill and use it for live spoken updates.
Claude Code (if you use it instead):
mkdir -p ~/.claude/skills/sayit
cp "$(sayit skill path)" ~/.claude/skills/sayit/SKILL.mdRe-run sayit skill install after upgrading Say It. The sidecar must be
running and a model installed before speech works.
In-app global shortcuts (Ctrl+Alt+V) work on X11. Wayland compositors
block them — bind a custom shortcut in your desktop settings to
sayit-clipboard (installed next to the CLI). There is no cross-compositor
API for another app's selection (not clipboard); on X11 you can point
sayit-clipboard at xclip -o (PRIMARY) instead.
NVIDIA on Wayland. WebKitGTK's DMA-BUF renderer crashes there with
"Error 71 (Protocol error) dispatching to Wayland display". Say It detects an
NVIDIA GPU and disables that renderer automatically; if another setup hits the
same error, set WEBKIT_DISABLE_DMABUF_RENDERER=1 yourself.
Contributors: live UI. The end-user GUI package is the AppImage.
You need Rust and Tauri's prerequisites as well as Node ≥ 20 and mpv.
git clone https://github.com/ildella/sayit.git && cd sayit
npm run setup # sidecar + CLI into ~/.local (same as install.sh)
npm install # @tauri-apps/cli
npm --prefix app install # SvelteKit UI
npm run dev # live UI (developer loop, not a distribution)If a daemon is already listening on port 7878, Tauri connects to it instead of spawning a second one.
npm run build:appimage # AppImage with sidecar inside (Linux CI)
npm run build:linux # .deb (optional)
npm run build:msi # MSI with sidecar inside (Windows CI; Windows host)
npm run build:ci # compile the shell, skip installers (on-demand macOS CI)After pulling updates, re-run npm run setup and restart the service so a
CLI install is not talking to a stale sidecar.
The SvelteKit frontend (in a Tauri v2 tray shell) is separate from a
per-user Node sidecar that owns model downloads, synthesis, playback, and
history. The app, CLI, and sayit-clipboard talk to that service over a
token-protected REST + SSE API bound to 127.0.0.1:7878. There is no
Python; synthesis is Kokoro-82M via kokoro-js / onnxruntime-node (CPU).
┌──────────────┐ REST + SSE, Bearer token ┌──────────────────┐
│ Tauri v2 app │ ◄──────────────────────────► │ sidecar (Node) │
│ SvelteKit UI │ │ kokoro-js engine │
│ sayit CLI │ ◄──────────────────────────► │ mpv playback │
│ sayit-clipboard │ history, models │
└──────────────┘ └──────────────────┘
How the port maps onto the original (XPC → loopback HTTP, MLX → kokoro-js, selection → clipboard), filesystem layout, and invariants are in LINUX.md.
Say It was created by callebtc as a privacy-first macOS app. This project exists thanks to his generosity in releasing it under MIT. For the original Apple-silicon experience (MLX Audio, voice cloning, Voice Studio), use callebtc/sayit.
MIT, like the original. Models are distributed under their own licenses. Only synthesize voices you have the right to use.
