TreeMap
A free, open-source disk-space visualizer. Squarified treemap, duplicate hunting, disk-full forecasting, and cleanup that only ever moves files to the Trash.
Hold a key anywhere on macOS and talk. Kaho types it into whatever app has focus, transcribed on your own Mac. Say how you want it written in the same breath. Free and open source.
ProductivityPython · ShellGitHub @utsavanandOnlineOwner unconfirmed
Have you tried it? One tap is enough. No sign-in needed.
Hold a key, speak, release — your words typed into any Mac app. On-device Whisper, no cloud.
Taken from the repository README
Loading the full README. The saved excerpt is shown below.
Kaho कहो — Hindi for “say it” Hold a key anywhere on macOS, speak, release — your words are typed into whatever app has focus. Everything runs on your Mac via Apple MLX: no cloud, no account, no telemetry.Read the full README ↗
Hold a key anywhere on macOS, speak, release — your words are typed into whatever app has focus. Everything runs on your Mac via Apple MLX: no cloud, no account, no telemetry.
Recent transcripts (click to copy), your hotkey, rewrite mode, history, log, and one-click bug reports:
If your menu bar is full, macOS hides the icon behind the notch. Kaho detects that and adds a Dock icon with the same menu, so Settings and History stay reachable — no alert, no lost settings.
A second on-device model (Qwen3-4B-Instruct, ~2.3 GB on first enable, ~0.5 s per dictation) polishes the transcript before it's pasted. Three modes: Clean up keeps your wording, strips filler and keeps only the fix when you correct yourself ("Thursday, no wait, Friday"), Structured gives the dictation the shape it needs (crisp prose, bullets for parallel items, numbered steps for a sequence), and Caveman compresses hard for pasting into an AI assistant — one line, every instruction kept, the words and formatting around them cut.
In Clean up, Kaho first asks the same model whether the transcript is already clean — one forward pass, ~85 ms, no text generated — and pastes it as-is when the model is at least 90% sure, skipping the rewrite entirely. If a cleanup would drop a "not" or "never", the transcript is pasted instead: resolving a correction means deleting words, and a deleted "not" reverses what you said.
Off by default. If the model isn't loaded yet or a rewrite fails, the raw transcript is pasted — you never lose words.
Requires an Apple Silicon Mac on macOS 14+, and Python 3.13 — that exact minor version, because the lock file pins hash-verified 3.13 wheels.
On a fresh Mac, two one-time steps first:
# 1. Homebrew (also installs git via the Xcode Command Line Tools)
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
# then run the eval line(s) the installer prints, so `brew` is on your PATH
# 2. Python 3.13
brew install [email protected]
Then:
git clone https://github.com/utsavanand/kaho && cd kaho
./install.sh
open /Applications/Kaho.app
install.sh builds Kaho.app locally (hash-verified Python environment +
ad-hoc-signed bundle), so there are no Gatekeeper warnings. On first launch
Kaho asks for two permissions:
| Permission | Why |
|---|---|
| Microphone | recording while the hotkey is held |
| Accessibility | observing the global hotkey, sending the paste, and (if Words on Screen is on) reading the focused window's text |
Until Accessibility is granted the menu bar shows ⚠️ and the first menu item opens the right Settings pane. Kaho notices the grant and restarts itself, so there's no need to quit and reopen it. The downloaded app also offers to move itself into Applications if it's opened from the disk image or Downloads, since permissions granted there don't follow the app.
First launch downloads the speech model (~2.3 GB). The menu bar shows the percentage, and "Ready to dictate" appears when it's done. To run at login: System Settings → General → Login Items.
Put your cursor where the text should go, hold ⌥ right Option, speak, release. Double-tap instead to record hands-free; tap once to stop. Everything else lives in the 🎙 menu.
🎙 → History…, or — if the menu bar icon is hidden behind the notch — just
launch Kaho again (Launchpad, Finder, or open /Applications/Kaho.app)
while it's running: the History window opens. Only one Kaho ever runs; a
second launch brings the running one forward and quits.
If the menu bar shows ⚠️, Accessibility isn't granted yet: click the first
menu item and switch Kaho on. If it's already switched on and Kaho still
can't paste, Kaho says so after a short wait and walks you through removing
the old entry and adding Kaho again. Re-running install.sh rebuilds the
bundle and can reset the grant. Also make sure you're pressing the key shown
in 🎙 → Hotkey — it's the right-side key.
Some app is holding macOS secure input (password fields, sudo prompts,
and Keychain dialogs block global key observation by design — usually it's a
terminal that never released it). Close that app or its window.
Fixed by design: Kaho always records from the built-in microphone. Bluetooth mics switch to a low-quality codec when recording starts and lose ~1 s of audio during the switch, garbling the start of every dictation.
Speech models hallucinate on silence. Holds under 0.3 s and audio below a loudness floor are dropped, but a longer silent hold can still produce one of these.
It changes for about a second and a half, then changes back. Kaho pastes by writing the transcript to the clipboard and sending ⌘V, then puts your previous clipboard back — unless you copied something else in the meantime, in which case yours wins and the transcript is left alone. The transcript is marked transient, so clipboard managers that honour that flag (Maccy, Paste, Raycast) will not archive your dictations.
The speech and rewrite models are constants at the top of kaho.py; re-run
./install.sh after editing. mlx-community/Qwen3-ASR-0.6B-8bit is about
twice as fast again (0.94 GB), a little worse on names and jargon.
flowchart LR
K["hotkey (hold or double-tap)"] --> M["NSEvent global monitor (main run loop)"]
M --> R["Recorder — sounddevice, 16 kHz"]
M -.-> O["Overlay pill — live mic level"]
M -.-> S["Words on screen — focused window via Accessibility (own thread)"]
S -.-> T
R --> Q[["audio queue"]]
Q --> W["Worker thread"]
W --> T["mlx-audio — Qwen3-ASR 1.7B on the Apple GPU"]
T --> RW["optional rewrite — Qwen3-4B via mlx-lm"]
RW --> P["Clipboard + synthetic Cmd+V"]
P --> A["Focused app"]
T --> H[("history.jsonl")]
H --> V["History window"]
The hotkey handler and UI live on the main run loop; recording and inference run off it, so a slow transcription can never stall key handling. The full trade-off discussion: DESIGN.md.
Audio is captured only while the hotkey is held, processed in memory, never
written to disk or sent anywhere. Transcripts go to the clipboard, the local
log, and the local history file (~/Library/Application Support/Kaho/) —
delete them any time. Rewriting runs entirely on-device too. The models are
fetched once from Hugging Face. Once a day Kaho asks GitHub for the latest
version number, and sends nothing about you or your dictation; untick
Check for new versions in Settings to stop it. Nothing else touches the
network.
Words on Screen reads only the window you're dictating into, only when you press the hotkey, and only its visible text. The names and jargon it picks out stay in memory for that one dictation and are then discarded — they are never written to the log, the history, or disk, and never sent anywhere. Kaho's own windows are never read. Untick Use Words on Screen in the menu or Settings to turn it off.
python3.13 -m venv .venv && .venv/bin/pip install -r requirements.txt
./run.sh # runs from the repo, logs to the terminal
Design rationale: DESIGN.md · Contributing: CONTRIBUTING.md
rm -rf /Applications/Kaho.app ~/Library/Logs/Kaho.log
rm -rf "$HOME/Library/Application Support/Kaho"
The cached models live in ~/.cache/huggingface if you want those gone too.
Built on mlx-audio, mlx-lm, sounddevice, and PyObjC. Interaction model inspired by Wispr Flow.