Agentero
Connect your own Agent, keep research context in a local Vault. Seamlessly migrate from Zotero, read, understand, link, and reuse your research context.
AI translation
Hold a key, speak, release it — local, free, open-source dictation powered by Whisper.
Translation pending
ProductivityRust · TypeScriptGitHub @arunmiriappalliOnlineOwner unconfirmed
Have you tried it? One tap is enough. No sign-in needed.
Owners of public repositories under a personal GitHub account can sign in to verify ownership and manage the introduction themselves. No administrator approval is needed.
Sign in, generate a verification file, and commit it to this repository’s default branch within 30 minutes. Files on other branches or forks do not count. Then check the file below to manage the project without administrator approval. Keep the file to retain your access.
If needed, you will go to sign-in. After signing in, return here and press your chosen verification button again.
Run /nomorevibe verify in your project folder to verify ownership and manage the introduction yourself.
Verify in one minuteAsk about other verification options
Hold a key, speak, release it — local push-to-talk dictation powered by Whisper. Free, cross-platform (Linux + macOS), no audio ever leaves your machine.
Translation pending
Taken from the repository README
Loading the full README.
Read the full README ↗Hold a key, speak, release it — your words get typed wherever your cursor is, transcribed locally with Whisper. Cross-platform (Linux + macOS), local-only (no audio ever leaves your machine), with a GUI setup wizard for configuring the hotkey, microphone, and model.
This started as a hardcoded personal bash script and was rebuilt as a proper Tauri v2 app so it's installable and reconfigurable without editing shell variables.
Grab the latest build for your OS from Releases:
.deb (Debian/Ubuntu) or .AppImage (portable, any distro).dmg — pick aarch64 for Apple Silicon or x86_64 for IntelmacOS builds are ad-hoc signed (no Apple Developer account behind this project — that costs $99/year, so this stays free) rather than signed with a real Developer ID and notarized. Gatekeeper will still flag the first launch. Try right-click the app → Open first; if macOS instead says the app "is damaged and can't be opened" (a misleading message some macOS versions show for unsigned apps, particularly on Apple Silicon — it's not actually a corrupted download), strip the quarantine flag instead:
xattr -cr /Applications/push2talk.app
On first launch, a setup wizard walks through: picking a microphone, setting your push-to-talk key, choosing and downloading a Whisper model, checking the typing backend, and optionally enabling launch-on-login. After that it lives in the tray/menu bar — reopen the window any time from there to change settings.
Installing the .deb/.rpm via your package manager (apt install ./push2talk_*.deb, etc.) already handles what a package can safely
automate: it pulls in libvulkan1/vulkan-loader (required at launch) and
ydotool (recommended — apt/dnf
installs it by default unless you pass --no-install-recommends) as
dependencies.
Two things are left as manual one-time steps, both because they touch
kernel-level input device permissions — package managers deliberately don't
grant these silently during install, without you explicitly running the
command yourself. This isn't push2talk being lazy: ydotool's own Debian
package documents the exact same two steps, for the exact same reason.
input group — this one group covers both
push2talk reading raw keyboard events and ydotool's daemon writing
synthetic ones via /dev/uinput:
sudo usermod -aG input $USER # log out and back in afterward
ydotool background service once — it ships a systemd
user service, which a package's install script can't reliably enable on
your behalf (it needs your active login session, not available yet during
apt install):
systemctl --user enable --now ydotool
The setup wizard's "Typing backend" step checks both and tells you exactly
what's missing. If you installed the .AppImage instead of .deb/.rpm,
you'll need to install ydotool yourself too — AppImages don't go through a
package manager, so there's no dependency mechanism to lean on there.
push2talk needs three separate permissions granted in System Settings → Privacy & Security, confirmed the hard way across real testing — macOS doesn't always prompt for these automatically on an ad-hoc-signed, unnotarized app the way it would for one signed with a real Developer ID, so check each one manually if something silently doesn't work:
NSMicrophoneUsageDescription, which it does). If you're not on a
build with that Info.plist entry, the OS silently denies access instead of
prompting at all.After granting or changing any of these, fully quit push2talk (tray menu → Quit, not just closing the window) and relaunch it — permission changes often don't take effect for an already-running process.
Linux build dependencies (Ubuntu/Debian):
sudo apt install build-essential curl wget file cmake pkg-config \
libwebkit2gtk-4.1-dev libayatana-appindicator3-dev librsvg2-dev \
libxdo-dev libssl-dev libasound2-dev clang libclang-dev libvulkan-dev glslc
clang/libclang-dev are required by bindgen (used by whisper-rs-sys) —
without them the build silently falls back to a stale bundled bindings file
instead of failing, which is easy to not notice (see
Known limitations for the exact failure mode this
causes if skipped). libvulkan-dev + glslc (package name is literally
glslc on Ubuntu) are for whisper.cpp's Vulkan GPU backend.
macOS build dependencies: Xcode Command Line Tools (xcode-select --install) and cmake (brew install cmake). GPU acceleration there uses
Metal, which needs no extra install — it's part of the OS.
Then:
npm install
npm run tauri dev # run in dev mode
npm run tauri build # produce an installable bundle for this OS
whisper-rs compiles whisper.cpp from source as part of the build (that's
what cmake is for) — no separate whisper.cpp clone or model files are
needed at build time; Whisper models are downloaded on demand by the setup
wizard.
To regenerate the app icon from its source (src-tauri/icons/app-icon-source.svg)
after editing it:
npx tauri icon src-tauri/icons/app-icon-source.svg --output src-tauri/icons
rm -rf src-tauri/icons/android src-tauri/icons/ios # this project is desktop-only
/dev/input/eventN (via the evdev crate), the same approach as the
original script's evtest usage; this works under both X11 and Wayland
since it bypasses the display server entirely. macOS uses a hand-rolled
CGEventTap (via core-graphics/core-foundation) that reads only the raw
keycode integer field from each event — see Known limitations
for why it's hand-rolled instead of using the rdev crate.cpal captures from the selected microphone; audio is
downmixed to mono and resampled to 16kHz for Whisper.whisper-rs (Rust bindings to whisper.cpp) runs
locally against the model you picked in the wizard, GPU-accelerated via
Vulkan (Linux) or Metal (macOS) — falls back to CPU automatically if no
compatible GPU/driver is found at runtime. The setup wizard detects your
CPU/RAM/GPU and recommends a model tier accordingly.llama-server
(from an official llama.cpp release, downloaded once) as a local
subprocess and asks a small LLM to rephrase the transcription for clarity
and concision; the rewrite is typed on a second line right under the
original so you can pick which one to keep (and delete the other). Enable
it in Settings, where you can also point it at any GGUF model you already
have locally (e.g. from LM Studio) instead of downloading the bundled
default. Like Whisper, this stays entirely on-device — it's a separate
process rather than linked into push2talk's own binary, because
statically linking llama.cpp and whisper.cpp together fails at link time
(both vendor their own copy of ggml under the same symbol names).ydotool type (uinput-based, works under
Wayland). macOS uses enigo to simulate keystrokes via CGEvent.~/.config/push2talk/config.json (Linux) or
~/Library/Application Support/push2talk/config.json (macOS); models cache
alongside it in the platform's data directory.Pushing a v* tag runs .github/workflows/release.yml,
which builds Linux and macOS bundles via tauri-action and attaches them to
a draft GitHub release.
Note: the Linux binary dynamically links libvulkan.so.1 (for GPU
acceleration) but Tauri's bundler doesn't auto-detect that as a package
dependency the way it does for webkit2gtk/GTK — without it, a machine
lacking the Vulkan loader would install the .deb/.rpm fine via the
package manager but fail to launch the app. libvulkan1 (deb) /
vulkan-loader (rpm) are declared explicitly in tauri.conf.json's
bundle.linux.deb.depends/bundle.linux.rpm.depends to cover this.
whisper-rs's vulkan feature fails to compile with an error like
no ggml_backend_vk_get_device_count in the root, it's very likely a stale
whisper-rs-sys build cache from an earlier attempt where clang/
libclang-dev weren't installed yet — without them, bindgen silently
falls back to an incomplete bundled bindings file instead of failing
loudly, and Cargo can keep reusing that stale output across later builds
even after the real prerequisites are installed. Fix: cargo clean -p whisper-rs-sys -p whisper-rs and rebuild. (This isn't a hypothetical —
it's exactly what happened building this project; a manual bindgen run
with identical flags produced the correct bindings immediately, which is
what pointed at stale cache rather than an upstream bug.)rdev crate used to crash on real Apple Silicon hardware (confirmed
via an actual crash report on macOS 26.5/M4): its event tap callback
unconditionally resolves a human-readable key name via Carbon/TSM
(Keyboard::string_from_code → TSMGetInputSourceProperty), which asserts
it's running on the main dispatch queue and aborts
(dispatch_assert_queue_fail, EXC_BREAKPOINT) when the tap runs on a
background thread — which is exactly how rdev::listen() is meant to be
used. Replaced with a hand-rolled CGEventTap that only ever reads the raw
keycode integer field (see "How it works" above). Confirmed fixed on
real Apple Silicon hardware once Input Monitoring permission was granted
(see macOS prerequisites above) — no more crash.NSMicrophoneUsageDescription Info.plist entry silently broke
recording on macOS (confirmed on real hardware, not a hypothetical):
without it, macOS never prompts for Microphone access and just denies it,
which doesn't surface as an error — cpal still "records" successfully,
just silence, which Whisper then hallucinates into something like "Thank
you" (a well-known artifact of transcribing near-silent audio, not a bug
in the transcription itself). Fixed by adding src-tauri/Info.plist with
the required usage description string, which Tauri auto-merges into the
bundled Info.plist.exit()ggml_metal_rsets_free_exit()app.exit()exit()_exit()window.hide() and
bring it back with window.show(). On this project that left the
window's titlebar buttons (minimize/maximize/close) permanently
unresponsive after the first hide/show cycle — the window content itself
kept rendering and accepting clicks fine, just not its own chrome.
window.minimize() / window.unminimize() is a far more standard,
better-tested GTK/Wayland window lifecycle and doesn't have this problem;
see lib.rs's window setup code.