This project was called Murmur until it was renamed to Aparté, to avoid confusion with the unrelated Murmure project. Same repository, same app, new name.
Already running Murmur? Nothing breaks: your config is migrated automatically,
MURMUR_*environment variables still work, and the oldmurmurcommand still launches Aparté — so a global shortcut bound to it keeps working. See Upgrading from Murmur.
Aparté is a local-first dictation app for Linux. It can run as a CLI, as a command bound to a global keyboard shortcut, or as a lightweight local desktop web app.
Nothing leaves your machine: Whisper runs locally, formatting runs locally, and
there is no account, no API key, and no network call. It is also the only
dictation app that takes French typography seriously — non-breaking spaces
before ? ! ; :, real « » quotes, curly apostrophes.
The loop, in four steps:
- Capture speech or accept an audio file.
- Transcribe with a local Whisper backend.
- Polish the raw transcript with punctuation, capitalization, filler cleanup, lists, and optional local LLM formatting.
- Copy or paste the result into the active Linux desktop session.
One screen: a Talk button, a transcript editor, and nothing else in the way. The
transcript is set in a serif face, so the French typography Aparté produces is
actually visible — look at the « », the curly apostrophes, and the spacing
before ; and ?.
Aparté follows your desktop's light or dark theme. While the microphone is open, the button is the only saturated thing on screen — you can tell it is recording from the corner of your eye, and without relying on colour alone (the icon and the label change too).
Grouped settings and built-in setup diagnostics — the diagnostics show what is installed and the exact command to fix anything missing, so any Linux user can get set up without the terminal. The interface is available in English and French.
Aparté is in daily use: dictate with a global shortcut, and the text lands formatted in whichever app is focused. Text polishing and the desktop UI work out of the box; audio transcription activates when one of these local backends is available:
faster-whisperPython package (recommended — the only one that supports the My words vocabulary setting)openai-whisperPython packagewhisper.cppCLI viaAPARTE_WHISPER_CPP
For best formatting quality, run Ollama locally and set APARTE_POLISH_BACKEND=ollama.
For consistent spelling of names, products, and acronyms, use My words and
Corrections in Settings — see Teaching Aparté your vocabulary.
Still to come: a floating window so the live preview is visible when you dictate with the global shortcut rather than only inside the app, and capturing a correction straight from the editor instead of retyping it in Settings.
Two ways to install. The script is the easy path; the manual venv install gives you more control.
git clone https://github.com/collectifweb/aparte.git
cd aparte
./scripts/install-linux.sh # Whisper + recording + default config + desktop launcher (icon/menu)
./scripts/install-linux.sh --with-system-deps # also apt-installs the recording/clipboard/paste toolsThe script auto-adds GPU support (the cuda extra) when it detects an NVIDIA GPU,
and registers the desktop icon/menu entry for you.
git clone https://github.com/collectifweb/aparte.git
cd aparte
python3 -m venv .venv
source .venv/bin/activate
python -m pip install -e ".[whisper,recording]" # add ,cuda for NVIDIA GPUs — see "GPU acceleration" belowThis [whisper,recording] baseline is what makes Aparté an actual dictation app:
whisper enables transcription and recording enables microphone capture. A bare
pip install -e . only gives you text polishing and the desktop UI — it cannot
transcribe or record.
Then verify the setup and install the desktop launcher (the manual path does not
add the icon/menu entry by itself — only install-linux.sh does):
aparte doctor # green/red status for every dependency, with the fix command for each gap
aparte install-desktop # add the app icon + menu entry (use --print to preview the entry first)Open the desktop app, click Setup, and use the Update section at the bottom: it checks the remote when you press Check, shows what is waiting, pulls it, reinstalls, and restarts Aparté. It refuses — and says why — when the folder has uncommitted changes, when the branch tracks no remote, or when Aparté wasn't installed from a clone.
To do it by hand instead, pull the latest code in the folder you already cloned and re-run the script — don't clone a second copy:
cd aparte # the directory you installed into
git pull
./scripts/install-linux.shRe-running is safe: the existing .venv is reused, dependencies are upgraded in
place, and config init is a no-op. Cloning Aparté again into a new folder instead
leaves you with two separate installs (each with its own multi-GB .venv) and a
desktop launcher and autostart entry that can point at different copies.
On a manual venv install (Option B), update with:
cd aparte
git pull
source .venv/bin/activate
python -m pip install -e ".[whisper,recording]" # add ,cuda for NVIDIA GPUsIf
git pullreports "no tracking information for the current branch", you're on a local branch that was never pushed. Switch tomainfirst (git checkout main), then pull.
Pull and re-run the install script as above; the rename is handled for you:
~/.config/murmur/config.jsonis moved to~/.config/aparte/config.jsonon first run, so your settings, replacements, and snippets carry over.MURMUR_*environment variables are still read as a fallback, so existing shell profiles and scripts keep working.- The old
murmurcommand still runs Aparté, so a global shortcut bound to the old binary keeps working. It is deprecated and will be removed later — re-runaparte install-hotkeyto repoint the shortcut at the new command. - The old desktop launcher, icon, and autostart entry are removed when you
re-run
aparte install-desktop/aparte install-autostart, so you don't end up with two menu entries or two servers competing at login.
| Extra | Adds |
|---|---|
whisper |
faster-whisper transcription backend (required for dictation) |
recording |
microphone capture via sounddevice (required for live dictation) |
cuda |
NVIDIA GPU acceleration — see GPU acceleration below |
sudo apt install alsa-utils ffmpeg wl-clipboard wtype xclip xdotoolUse Wayland tools (wl-copy, wtype) on Wayland, or X11 tools (xclip, xdotool) on X11.
python -m pip install -e ".[whisper,recording,cuda]"This installs the CUDA runtime libraries as pip wheels inside the venv — no
system CUDA toolkit and no driver changes, so it will not touch the GPU drivers your
games or other apps rely on. The app preloads the libraries automatically, so GPU
transcription works without setting LD_LIBRARY_PATH, and falls back to CPU
automatically when CUDA is unusable.
Confirm the GPU is actually used (not merely installed):
.venv/bin/python -c "import ctranslate2; print(ctranslate2.get_cuda_device_count())"> 0 means the GPU will be used; 0 means CPU fallback. Note that aparte doctor's
"GPU acceleration (CUDA): ok" only confirms the CUDA libraries are importable — not
that a device is reachable at runtime. Use the command above, or watch nvidia-smi
during a dictation, to be sure. On older cards (Pascal / GTX 10-series), set
APARTE_COMPUTE_TYPE=int8: the auto default picks float16, which is slow on those
GPUs.
Polish raw text:
echo "hey sarah thanks for sending this euh i will review it tomorrow" | aparte polishTranscribe an audio file and polish it:
aparte transcribe meeting.wav --polishRecord from the microphone, transcribe, polish, and copy:
aparte record --seconds 15 --polish --copyDictate directly into the active app:
aparte dictate --seconds 8Use fixed-duration dictation as a global keyboard shortcut command in GNOME/KDE/XFCE:
aparte dictate --seconds 8 --target pasteFor a more Flow-like shortcut, bind the same toggle command to one global hotkey. The first press starts recording; the second press stops, transcribes, polishes, and inserts:
aparte toggle --target pasteCheck whether a toggle recording is already active:
aparte toggle --statusIf direct paste is unavailable on your desktop, copy instead:
aparte toggle --target copyLaunch the Linux desktop app:
aparte desktopInstall a desktop launcher in ~/.local/share/applications:
aparte install-desktopRun the desktop server automatically at login (writes ~/.config/autostart).
It starts in the background without opening a browser, so the editor and the
Settings tab are always available at http://127.0.0.1:8765:
aparte install-autostart
aparte install-autostart --remove # undoThe Flow-like flow is one global shortcut bound to toggle: press once to start,
press again to transcribe and insert into whatever app is focused (Slack, email,
…). The binding is stored by your desktop and survives reboots, so no background
process is required for it.
On Cinnamon and GNOME, Aparté can register the shortcut for you:
aparte install-hotkey # bind Super+Space to toggle dictation
aparte install-hotkey --key '<Control><Alt>d' # pick another accelerator
aparte install-hotkey --print # show what it would bind, without applying
aparte install-hotkey --remove # remove itIt allocates a custom keybinding through gsettings, reusing the same slot on
re-runs so it never piles up duplicates. A bare install-hotkey keeps an
already-chosen key; only --key moves it.
On other desktops, add the shortcut yourself (System Settings → Keyboard → Shortcuts → Custom Shortcuts → Add) with this command — use the full path to the binary inside your venv:
/path/to/aparte/.venv/bin/aparte toggle --target pasteThen assign a key (e.g. a spare key or Super+Space). Direct paste needs
xdotool on X11 or wtype on Wayland; otherwise use --target copy and paste
with Ctrl+V. Desktop notifications show when recording starts and stops.
Open Setup in aparte desktop to check the binding: the Keyboard
shortcut card shows whether the shortcut is bound and to which key, the
one-command auto-bind, and the exact toggle command to bind by hand — each with
a copy button.
Create and inspect your config:
aparte config init # write a default config.json
aparte config path # print its location
aparte config show # print the active (merged) configThere is no config set command. To change settings persistently, edit the JSON
file printed by aparte config path, or use the Settings panel in aparte desktop — it writes to the same file and applies immediately, including to the
global-hotkey flow.
Environment variables:
APARTE_TRANSCRIBER=auto
APARTE_RECORDER=auto
APARTE_MODEL=small
APARTE_DEVICE=auto
APARTE_COMPUTE_TYPE=auto
APARTE_LANGUAGE=
APARTE_POLISH_BACKEND=heuristic
APARTE_PASTE_MODE=clipboard
APARTE_MICROPHONE=
APARTE_RUNTIME_DIR=
APARTE_OLLAMA_URL=http://127.0.0.1:11434
APARTE_OLLAMA_MODEL=llama3.1:8b
APARTE_WHISPER_CPP=
APARTE_CONFIG=APARTE_DEVICE controls the faster-whisper compute device (auto, cpu, or cuda).
When a GPU is detected but its CUDA runtime is missing or unusable
(libcublas/libcudnn not found), transcription automatically falls back to CPU
with int8, so it works out of the box on machines without a CUDA install.
Force CPU with APARTE_DEVICE=cpu to skip the GPU probe entirely.
Polish backends:
heuristic: fully local, no model required, good enough for punctuation and capitalization cleanup.ollama: local LLM rewrite through Ollama, much better for fillers, backtracking, tone, and context.
Running the desktop app puts an Aparté icon in the system tray: three bars at rest, a filled disc while the microphone is open, and a menu to open the app, copy the last dictation, jump to Settings, or quit.
It relies on PyGObject and the AppIndicator typelib, which are system packages rather than pip ones:
sudo apt install python3-gi gir1.2-ayatanaappindicator3-0.1./scripts/install-linux.sh --with-system-deps installs them for you, and the
script creates the virtualenv with --system-site-packages so it can see them.
A virtualenv created before this change cannot see them, but it does not need
rebuilding — flip one line in .venv/pyvenv.cfg, which keeps the multi-gigabyte
Whisper and CUDA packages already installed:
include-system-site-packages = true
Without the bindings, Aparté starts exactly as it did before, and aparte doctor
tells you what is missing.
The last five dictations sit under the action bar in the desktop app; click one
to copy it. From a terminal, aparte last prints the most recent one and
aparte last --target paste re-inserts it into the focused window.
They live in the runtime directory ($XDG_RUNTIME_DIR/aparte, which is tmpfs and
wiped when you log out), because a dictation can carry a password or a private
message. Tick Keep history between sessions in Settings — or set
history_persist in the config — to write them to ~/.local/state/aparte
instead, in a file only you can read.
Every Aparté process shares that one store, so a dictation made through the global hotkey shows up in the app, and vice versa, without either one having to be running for the other.
Insertion modes (paste_mode in the config, or How to insert under
Hardware in the desktop app). Every mode copies the dictation to the
clipboard first, so it is never lost when the insertion lands somewhere
unexpected:
clipboard(default): one atomicCtrl+V. Right nearly everywhere.terminal:Ctrl+Shift+V— terminals ignoreCtrl+Ventirely.direct: types the text out. For apps that refuse a synthetic paste (LibreOffice, some Electron apps). Slower, and a stray click mid-insertion can scatter it.
Input device, under Hardware in Settings, lists what ALSA can capture from — pick one, or leave it on the system default. Refresh rebuilds the list without closing the panel, for a microphone plugged in after opening it. A device that has since been unplugged stays in the list, marked as such, rather than being silently swapped for another one.
It applies to the global shortcut and to the terminal commands (microphone in
the config, an ALSA name such as plughw:CARD=Mini,DEV=0). The desktop app's
Talk button records through the browser, so it follows whichever microphone
the browser is set to.
Tick Beep on start and stop (beep) for two short tones — a high one when
the microphone opens, a lower one when it closes. It is off by default; turn it
on if you dictate with the global shortcut without watching the screen.
Preview while dictating (live_preview, on by default) shows the transcript
building up in the editor instead of leaving you talking into the void. Roughly
once a second, whatever has been recorded so far is transcribed again from the
start and the result replaces the previous pass — which is also why the text
corrects itself as you go: Whisper revises its own guesses once it has heard the
end of the sentence. Preview text is shown in lighter ink and the action buttons
stay off, because it is not the final version yet; auto-polish only runs at the
end, on the final transcript.
Never more than one pass at a time: the next one is scheduled when the previous one comes back. On a slow machine that means fewer previews, never a queue. Even so, without a GPU this keeps one core busy for as long as you speak — untick the setting if the machine struggles. As a side effect, the first preview loads the Whisper model while you are still talking, so the wait after you stop is shorter.
Pressing the global shortcut used to start a fresh process that read the Whisper model off disk on every dictation, while the desktop app already held it in memory. The shortcut now hands its audio to that running app when one answers on the loopback address: 0.26 s instead of 1.53 s for the same ten seconds of audio.
Nothing leaves the machine — it is the same local address the browser talks to.
When the desktop app is not running, the shortcut loads its own model exactly as
before, so dictation never depends on it. Delegation is also skipped when an
APARTE_* transcription override is set in the environment, since the running
app reads the config file and would ignore it.
Whisper was trained on subtitled video. On silence — the tail of a dictation, a
pause, a microphone picking up nothing — it does not return an empty string: it
fills the gap with a subtitling credit seen thousands of times during training.
In French the usual one is Sous-titres réalisés par la communauté d'Amara.org.
Aparté strips the known credits from every transcript, whichever path produced it.
Credits carrying a domain or a broadcaster name are removed wherever they appear;
generic video sign-offs such as Merci d'avoir regardé cette vidéo, which someone
writing a video script may genuinely dictate, are only removed when they make up
the whole transcript. When in doubt nothing moves — a normal dictation comes back
unchanged, and Amara.org on its own is deliberately not in the list.
Aparté is built for dictating in French, so the formatting rules follow French typography rather than the English ones:
- a non-breaking space before
? ! ;and:— but not insidehttps://or14:30 « »instead of straight double quotes, when they pair up- a typographic apostrophe:
l'ami→l’ami - standalone
iis left alone (upper-casing it is the English pronoun rule)
Which set applies follows the Dictation language setting. On Auto, the
language is guessed from the text itself, so French typography works without
setting anything — but pinning the setting to Français is more reliable, and
it also stops Whisper from drifting to another language.
Set "nonbreaking_spaces": false in the config to use ordinary spaces instead of
non-breaking ones, for apps that handle them poorly.
Numbers dictated in words become digits (numbers_from, French only). Whisper
already writes digits about half the time; the point is that the same sentence
dictated twice comes out the same way. The setting is the threshold below which a
number stays in words — 10 by default, which is the French rule:
- "vingt-deux personnes" → "22 personnes", "quatre-vingt-dix-sept" → "97", "l'an deux mille vingt-six" → "l'an 2026" (a year keeps its four digits together; the thousands separator starts at five)
- times and percentages always become digits, whatever the threshold: "quatorze heures trente" → "14 h 30", "vingt pour cent" → "20 %"
- "deux millions" keeps its word — "2 millions", not "2000000"
- septante, huitante, octante and nonante are understood too
- an article is never a number: "un chien" stays put, "vingt et un chiens" becomes "21 chiens", and "des mille et des cents" is left alone
- anything that doesn't parse as a valid number is left exactly as dictated
Out of scope for now: decimals (the spoken "virgule" is turned into a comma before numbers are read), ordinals ("premier" must not become "1er" in "premier ministre"), and English.
Two settings decide how far the formatting goes:
- Very short dictations (
short_text_words, off by default): below this many words the dictation comes out as spoken — no leading capital, no final period. A search field and a one-word answer are not sentences. - Trailing space (
trailing_space, off by default): ends every dictation with a space, so a second one does not land glued to the first.
Filler word removal (cleanup_level) strips the hesitations: "euh" and
"heu" at every level, plus verbal tics such as "ben", "genre" and "tsé" — or
"like", "basically", "actually" in English — at the high level.
Recorder backends:
auto: try Pythonsounddevice, thenarecord.sounddevice: Python recording backend.arecord: ALSA command-line recorder fromalsa-utils.
Persistent config lives at ${XDG_CONFIG_HOME}/aparte/config.json, or ~/.config/aparte/config.json when XDG_CONFIG_HOME is not set. Override it with APARTE_CONFIG=/path/to/config.json.
Example:
{
"default_style": "neutral",
"cleanup_level": "medium",
"language": "en",
"hotwords": ["Playwright", "Wayland", "PipeWire"],
"replacements": {
"whisper flow": "Wispr Flow",
"pipe wire": "PipeWire",
"my project": "MyProject"
},
"snippets": {
"signature": "Best,\nAlexandre"
}
}With that config, dictating slash signature expands the snippet, and dictated terms such as pipe wire are rewritten with the preferred spelling.
Three settings sit under My dictionary, and they act at three different moments:
| Setting | Config key | When it acts |
|---|---|---|
| My words | hotwords |
before transcription — biases Whisper itself |
| Corrections | replacements |
after, on the text |
| Spoken shortcuts | snippets |
after, expanding slash <name> into ready-made text |
hotwords and replacements are two different tools, not two ways of doing the
same thing. My words is a plain list of names — clients, tools, colleagues —
handed to Whisper up front, so it leans toward those spellings when the audio is
ambiguous. You do not need to have seen the mistake first. Corrections is
the safety net for what slips through anyway.
Measured on real speech: without the word list, PipeWire and Mailpoet came
out as pipe wire and mail poète; with it, both were spelled correctly,
casing included. Three names in the same sentence (Playwright, Wayland,
Claude) were already correct without any help — the list is for what actually
fails, not for everything you own.
Two caveats. hotwords only exists in faster-whisper; with openai-whisper
or whisper.cpp the setting is quietly ignored rather than promising what the
backend cannot deliver. And a word list makes Whisper more likely to hear
those words — on silence, a list containing PipeWire produced PipeWire.com
out of nothing. Keep the list to words you actually say.
Corrections takes one entry per line, heard = written. A line without an
= is refused, with its line number, rather than being dropped silently.
Spoken shortcuts takes the same form, except the text may continue on the
following lines — that is how a multi-line signature is written.
aparte desktop starts a local server on 127.0.0.1 and opens the browser. The
interface is a focused, single-screen app:
- a large Talk button (browser microphone recording as WAV PCM, so no hard
dependency on
ffmpeg) that records, transcribes, and auto-polishes - a transcript editor with Polish, Copy, Insert, and audio import
- a live preview: the text appears as you speak and keeps correcting itself until you stop
- a model toggle (
small= accurate,base= fast); each model loads once and is cached, so switching is instant after first use - a Settings panel (gear icon) ordered by how often a setting is actually
touched: Dictation (language, live preview, style, filler-word removal),
My dictionary (my words, corrections, spoken shortcuts) and French typography
are open on arrival; Hardware (input device, beep, how to insert) and Advanced
(default model, compute device, formatting engine, history) are folded into
native
<details>. Saved to the config file and applied immediately, including to the global-hotkey dictation flow - a Configuration & diagnostics panel that shows, with green/red status, what is installed vs missing (Whisper backend, GPU, microphone, paste/clipboard, notifications) and the exact command to fix each gap — copy-paste onboarding for any Linux user
The interface is bilingual (English / French) with a language switch in the top
bar; it defaults to the browser language. It follows your desktop's light or dark
theme automatically, and the whole keyboard path works: Tab reaches every
control with a visible focus ring, Esc closes a panel, and animations are
skipped when your system asks for reduced motion.
The frontend lives in src/aparte/assets/ (index.html, app.css, app.js,
i18n.js, logo.svg) and is served as static files, with no build step and no
library, so it is easy to contribute to. The design system it follows is
documented in DESIGN.md, and the product direction behind it in
PRODUCT.md.
The hotkey dictation flow (toggle and dictate) shows native Linux
notifications via notify-send so you can tell when recording starts, when
transcription is running, and when text was inserted or copied — useful when the
command is bound to a global shortcut and no terminal is visible. Install it with
sudo apt install libnotify-bin if notify-send is missing; it is optional and
dictation works without it.
This approach avoids GTK/Qt packaging friction while staying Linux-compatible.
Contributions are welcome — see CONTRIBUTING.md for the
development setup, how to run the tests, and the code layout. The desktop UI is
plain HTML/CSS/JS in src/aparte/assets/ with no build step.
Aparté is released under the MIT License. It is an independent, open-source project, not affiliated with the commercial Wispr Flow product, nor with the similarly named Murmure project.



