Skip to main content

Susurro

Local voice dictation for macOS. Fully offline. MIT licensed.

Hold a hotkey, talk, release. The transcript is polished into structured text — ordinals become numbered lists, fillers get stripped, self-corrections get applied — and pasted at the cursor in any app. Everything runs on your Mac through Apple's MLX framework. No accounts, no API keys, no network.

License: MIT macOS Apple Silicon Python Version PyPI Landing

Install (one line)

curl -fsSL https://raw.githubusercontent.com/danilobrando/susurro/main/install.sh | bash

Or with pipx:

pipx install susurro
susurro

After install, hold the right Option key (⌥) to dictate. The first launch downloads Whisper + Llama weights (~5 GB total, one-time) and triggers three macOS permission prompts (Microphone, Accessibility, Input Monitoring).

Why Susurro

  • Fully offline. Audio never leaves your machine. No telemetry, no analytics, no cloud calls during normal use.
  • WisprFlow-grade smart formatting. An LLM polishes the raw transcript: ordinals become numbered lists, fillers like "um/eh/o sea" get removed, self-corrections ("Pedro, eh, Pablo digo") collapse to the final intent.
  • Auditable. Every (raw → polished) edit is logged locally to ~/.susurro/polish.jsonl. Nothing is hidden.
  • MIT licensed. Read the code, fork it, redistribute it.

If you want zero local RAM + lower latency at the cost of cloud transcription, Susurro Pro is a paid hosted variant that extends this package.

Requirements

  • Apple Silicon Mac (M1 or later). MLX doesn't support Intel.
  • macOS 13+ recommended (tested on 26).
  • Python 3.10+.
  • ~5 GB free disk (one-time model download).
  • ~3 GB free RAM while running.

Usage

  1. Click into any text field.
  2. Hold the right Option key (⌥) and speak.
  3. Release. After ~1.5 s, the polished transcript pastes at the cursor via Cmd+V.

While recording, a small dark waveform pill appears near the bottom of the active screen, with 16 white bars rippling to your voice. Toggle off via the Show waveform indicator menu item.

Menu bar icon reflects state:

Icon Meaning
🎙 idle Ready. Hold the hotkey to record.
🔴 recording Listening. Release to transcribe.
⏳ processing Transcribing + polishing on-device.

Smart formatting

The polish step turns raw dictation into structured text. Three modes (switchable from the menu):

  • Off — paste raw STT output unchanged.
  • Rules only — regex cleanup: filler removal (eh, mmm, o sea sí, um, uh), whitespace normalization. <5 ms.
  • Smart (LLM) — rules + local Llama 3.2 3B polish, but only when triggers fire (ordinal markers, backtrack phrases, long-form input). Otherwise stays rules-only to keep latency low.

Example (smart mode):

Raw:   "Vamos a seguir tres pasos. Primero, reinicia. Segundo, vuelve a registrarte. Tercero, envía un correo."

Polished:
Vamos a seguir tres pasos.

1. Reinicia
2. Vuelve a registrarte
3. Envía un correo

Configuration

Edit susurro/config.py:

  • STT_BACKEND — local (default). Extension packages can register more.
  • POLISH_MODE — smart (default), rules, or off.
  • LOCAL_STT_MODEL — whisper-large-v3-turbo (default), or whisper-large-v3-mlx for max accuracy.
  • LOCAL_POLISH_MODEL — Llama-3.2-3B-Instruct-4bit (default), or any mlx-community 3B-class model.
  • HOTKEY — alt_r (default). Any pynput Key name: alt_l, ctrl_r, f19, etc.
  • LANGUAGE — None for auto-detect, or pin to "es" / "en" to save ~100 ms per request.
  • INPUT_DEVICE — pick a specific mic. Run python -m sounddevice to list devices.

Permissions

macOS will prompt for three permissions the first time you run Susurro:

  1. Microphone — to capture your voice.
  2. Accessibility — to paste the transcript into the focused app.
  3. Input Monitoring — to listen for the global hotkey.

After granting any of these, fully quit and relaunch your terminal for the new permission to take effect. The menu bar has direct links to each pane.

Architecture

audio (sounddevice → 16kHz mono float32)
    → MLX Whisper (whisper-large-v3-turbo, on-device)
    → raw text
    → Polisher
        ├ Tier 1: regex rules (filler removal, whitespace)
        ├ Tier 2: trigger check (ordinals / backtrack / long-form)
        └ Tier 3: MLX-LM polish (Llama 3.2 3B Instruct, on-device)
    → polished text
    → clipboard write + Cmd+V into focused app

Source layout — under ~1500 lines of Python total:

susurro/
  config.py            # all tunables
  audio.py             # mic capture + peak_level for indicator
  hotkey.py            # pynput global hotkey
  typer.py             # clipboard / keystroke insertion
  indicator.py         # floating waveform pill (PyObjC)
  permissions.py       # System Settings deep links
  app.py               # rumps menu bar + main loop (subclassable)
  backends/
    base.py            # protocols (Transcriber, PolishLLM)
    local_mlx.py       # local Whisper via MLX
    local_mlx_lm.py    # local polish LLM via mlx-lm
    __init__.py        # factories + extension registration
  polish/
    __init__.py        # Polisher orchestrator
    rules.py           # regex cleanup
    triggers.py        # decides if LLM should fire
    prompt.py          # system prompt + few-shot examples
  icons/               # template PNGs for menu bar

Extending Susurro

External packages can register additional backends without modifying this code:

# in your_extension/__init__.py
from susurro.backends import register_transcriber, register_polish_llm

class MyCloudSTT:
    name = "mycloud"
    def warmup(self): ...
    def transcribe(self, audio): ...

register_transcriber("mycloud", lambda: MyCloudSTT())

Then set STT_BACKEND = "mycloud" in susurro/config.py or via environment.

Troubleshooting

  • Menu bar icon invisible — emoji-only menu bar items can be hidden on MacBooks with a notch. This release ships a real template PNG, which fixes it for most users.
  • "This process is not trusted" — Accessibility permission isn't granted. Use the Open Accessibility Settings… menu item, then fully restart the terminal.
  • Hotkey doesn't trigger — Input Monitoring permission is missing.
  • Silent recordings / empty transcript — Microphone permission is missing, or INPUT_DEVICE is pointing at the wrong device.
  • First transcription is slow — the model is still warming up. Wait until the menu shows Status: idle before the first real dictation.

Logs land in ~/.susurro/susurro.log; polish events in ~/.susurro/polish.jsonl.

Contributing

See CONTRIBUTING.md. PRs welcome; please keep the package under ~1500 lines.

Security

See SECURITY.md. Report vulnerabilities privately to the maintainer.

Maintainer

Built and maintained by Danny Bravo (dannybravo@gmail.com). Product strategist, AI ecosystem builder, educator — based in Bogotá.

License

MIT © 2026 Danny Bravo.

Credits

Metadata

Release files for susurro 0.4.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for susurro 0.4.1
File Size Uploaded
susurro-0.4.1.tar.gz 34.0 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for susurro 0.4.1
File Interpreter ABI Platform
susurro-0.4.1-py3-none-any.whl Python 3 none any Details

Total release size: 65.4 kB

Release files / susurro-0.4.1.tar.gz

Download URL susurro-0.4.1.tar.gz
Size 34.0 kB
Tags Source
SHA-256 checksum
How to use checksums
f7d8cbd72728efbfd1ddd6d02b6fbecc2c389c4d915824217cff9ca54ba0af93
BLAKE2b-256 checksum
How to use checksums
a4d8ee9fc4237fec8ada64c00ebfa990f517dcb1cf8eb8dc717051976bad5379
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.12.9

Release files / susurro-0.4.1-py3-none-any.whl

Download URL susurro-0.4.1-py3-none-any.whl
Size 31.5 kB
Tags Python 3
SHA-256 checksum
How to use checksums
7e090dab90f97d35031501084b2d223e0b54e8ad09ba94d70b2ba76814facf98
BLAKE2b-256 checksum
How to use checksums
0d88a7687574c4ae6d0ac871416af04f45140164fd88ae3397ca707dfc4fe92a
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.12.9

Release history Release notifications | RSS feed

This release

0.4.1 This release

2 release files

0.4.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page