OpenMila documentation
Everything you need to install OpenMila on Linux or Windows and use it day to day, followed by a quickstart for an AI agent that wants to read your transcripts over MCP. Every claim here is drawn from the port's own repository, and nothing on this page goes further than the parity table does.
Your browser would not let this page write to the clipboard. Here is the same Markdown: select it all and copy it by hand, or open /docs.md directly.
No release has been published yet. OpenMila is in early
development. The first Linux beta will appear on the
releases page.
Everything below describes the files that release will contain and how to
use the app, so you can read it before you need it. Linux is the
development platform. Windows is built and tested on a
windows-2025 runner in CI, where the core, the CLI, the MCP
helper, the tests, the WinUI app and the portable zip all pass, but nobody
has run any of it on a Windows desktop yet.
Install OpenMila
Three packages: an AppImage and a .deb for Linux, and a
portable zip for Windows. On a Mac, use the original,
Mila. OpenMila does not build
for macOS and does not try to.
Linux: the AppImage
One file, no installation. Tested on Ubuntu 26.04 (GNOME, on both Wayland
and X11); other current desktops with GTK 4 should work. Download
OpenMila-<version>-x86_64.AppImage and the
.sha256 file next to it, then check it:
sha256sum -c OpenMila-<version>-x86_64.AppImage.sha256
Make it executable and run it:
chmod +x OpenMila-<version>-x86_64.AppImage
./OpenMila-<version>-x86_64.AppImage
If it complains about FUSE, run it with
--appimage-extract-and-run, or install libfuse2t64.
The AppImage updates itself: it checks the published SHA-256 and replaces the
running file, and it has a beta channel with a pre-release guard.
Linux: the Debian package
openmila_<version>_amd64.deb is built from the same
payload as the AppImage and ships its own .sha256 file. Check
it, then install it with the package manager so the dependencies come with
it:
sha256sum -c openmila_<version>_amd64.deb.sha256
sudo apt install ./openmila_<version>_amd64.deb
The package puts its payload in /opt/openmila/ and three
launchers on your PATH: openmila for the app,
openmila-cli for the headless harness, and
openmila-mcp for the
MCP server. A .deb install does not update
itself: updating belongs to the package manager, so the app points you back
at the releases page.
Windows: the portable zip
Windows 11, and Windows 10 22H2, on x64. Download
OpenMila-<version>-win64.zip and check it against the
.sha256 file beside it:
(Get-FileHash OpenMila-<version>-win64.zip -Algorithm SHA256).Hash
Unblock and extract it anywhere, then run openmila.exe. Nothing
else needs installing: the Swift runtime and the transcription engine travel
with the app. openmila-cli.exe and
openmila-mcp.exe sit beside it in the same folder. The zip has
no self-install, so an update is a fresh download.
What each system needs present
- Linux, required
-
GTK 4 and libadwaita, libsecret, GLib, zlib, and PipeWire or PulseAudio for
audio. The
.debdeclares these aslibgtk-4-1,libadwaita-1-0,libsecret-1-0,libglib2.0-0,libc6andzlib1g. - Linux, to record one application's audio
-
PipeWire's own tools, the
pipewire-binpackage, which providespw-dumpandpw-record. Most PipeWire installs already have them. Without them the source picker still offers the whole-system monitors, so you can record everything the machine plays but not one application on its own. - Linux, for global dictation hotkeys
-
Nothing extra.
XGrabKeyis used wherever an X display answers, including XWayland, and the XDGGlobalShortcutsportal on a pure Wayland session; the two paths pick themselves. See Dictation. - Linux, for dictation that pastes by itself
-
xdotoolorwtypeto paste at the cursor, pluswl-clipboardorxclipfor the clipboard. On a Wayland session OpenMila can use theRemoteDesktopportal instead, once you grant it. With none of that the dictated text still lands on the clipboard and a notification tells you to press Ctrl+V. - Linux, optional
-
ffmpeg, for compact.m4arecordings, the remote transcription backend, and importing audio that is not WAV. GStreamer is used where ffmpeg is absent, which a GNOME or KDE install almost always has.libnotify-binfor desktop notifications. - Windows
- Nothing. Everything the app needs travels in the zip.
Verify what you downloaded
Every release publishes a single SHA256SUMS file covering all of
its files, alongside the per-file .sha256 files. Download it
from the release and check the files you have:
sha256sum --ignore-missing -c SHA256SUMS
The release pipeline also attests what it built, so you can confirm a file came from this repository's workflow and not from somewhere else. With the GitHub CLI installed:
gh attestation verify OpenMila-<version>-x86_64.AppImage --repo NX1X/OpenMila
The same command works for the other files, on Windows too:
gh attestation verify .\OpenMila-<version>-win64.zip --repo NX1X/OpenMila
If a hash or an attestation does not check out, do not run the file, and please report it privately.
First launch
Download a model
The Whisper models are large and are not bundled, so the first thing to do is fetch one. Open Settings > Models and download the one you need:
- OpenAI
large-v3-turbofor English and other languages, 1.6 GB. - ivrit.ai
large-v3for Hebrew, 3.0 GB.
Each download shows a percentage while it runs and is checked against a pinned SHA-256 before it is used. How long it takes is your connection's business rather than the app's: no timing figure is published, because none has been measured. Budget for a 1.6 GB or a 3.0 GB transfer and leave it running. Deleting a model later frees the whole install and keeps the remaining choice sane. A recording's language decides which model is used, so you only need the one you record in.
Where transcription runs: GPU when there is one, CPU otherwise
Mila on a Mac has two accelerators it can count on, the GPU through Metal and the Neural Engine through a CoreML encoder, because Apple ships them in every machine it supports. Linux and Windows have no equivalent that is always present, so the port's rule is to always work on the CPU and use a GPU when the machine turns out to have a usable one.
The release packages for both systems carry whisper.cpp's Vulkan backend,
which covers NVIDIA, AMD and Intel through one driver-level API. A discrete,
integrated or virtual GPU gets the model. A software Vulkan device (llvmpipe,
lavapipe, SwiftShader) is refused, because running the model through a CPU
pretending to be a GPU is slower than whisper.cpp's own CPU backend. No
Vulkan at all is not an error: the CPU path is the fallback and the common
case. openmila-cli gpu prints what the probe found,
Settings > Models shows it, and a switch there forces the
CPU for a driver that misbehaves, as does
OPENMILA_DISABLE_GPU=1.
No speed has been measured. The decision logic is tested and the backend is compiled in, but no transcription has been timed on a real GPU on either system, so "Vulkan works" means built, probed and wired, and no figure is claimed. There is no CoreML or Neural Engine path off macOS at all. The reasoning and what is still unmeasured are in docs/port/HARDWARE.md.
If your machine is slow at this, the way out today is a server of your own: Settings > Models > Backend can point at any OpenAI-compatible transcription endpoint. Audio leaves the machine while a remote backend is active, and the app says so in that screen.
Recording
The Home screen has a source picker, a language picker and a Record button. There are three sources:
- Microphone
- Your input device, with a live level meter and an elapsed clock. Pick a device in Settings > Audio, or leave it on the system default. Adaptive gain for quiet microphones is a toggle in the same place.
- System audio
- On Linux, choosing this reveals a second picker listing what is currently playing: OpenMila asks PipeWire to link that one application's output to a capture stream, so you record the meeting and not your music. The whole-system monitors are offered in the same list. Windows has the same two choices, through WASAPI process loopback bound to the chosen process tree; that code compiles in CI and has never been run on a Windows machine.
- Meeting (mic + system)
- Both, mixed into one mono 16 kHz WAV file. If OpenMila notices a meeting application starting, it offers to start a meeting recording for you, and offers to stop when the application ends. Native applications are found by process name on every session. A meeting in a browser tab is found in the window title, which X11 and XWayland expose and a pure Wayland session does not, by design: there, a tab meeting is missed. Windows places no such restriction, so a tab meeting is detectable on every Windows session.
Live transcription runs while you record, in the Live transcript pane, and you can edit and copy it there.
Pause and resume
While a recording is running the Record button becomes Pause, and Stop sits beside it. A paused span is absent from the audio and from the timer, so pausing for a side conversation leaves no gap of silence to sit through later.
Where the file goes
Stopping saves the recording, queues it for transcription, and shows a
post-recording sheet where you can accept a suggested name and see the
summary and action items if AI features are on. The audio and its transcript
land in the recordings directory, which is
~/.local/share/Mila/ on Linux and %APPDATA%\Mila\
on Windows, and is configurable in Settings > Storage
along with a storage cap. See
Where everything lives on disk.
Dictation
Dictation transcribes a short burst of speech and pastes it where you were typing. Two hotkeys, one per language: Ctrl+Alt+2 for English and Ctrl+Alt+3 for Hebrew by default. Change them in Settings > General, where you type a combination as modifiers plus a key (Ctrl, Alt, Shift, Super, and a letter, digit, F-key, Space, Return, Escape or Tab). The app tells you if another application has already taken the combination you asked for.
On X11, and in XWayland windows, the hotkey works anywhere: press it, speak, press it again, and the text is pasted into whichever window had focus.
On a pure Wayland session, the desktop owns global
shortcuts, so OpenMila asks for them through the XDG
GlobalShortcuts portal instead of grabbing them. Your desktop
will ask you to confirm the binding once. The two paths choose themselves;
you do not configure which. A key press through the portal has not yet been
confirmed by a human at a Wayland desktop, so if it does not fire, the
Dictate buttons on the Home screen do the same job.
Getting the text back to the cursor has three routes, tried in that order:
xdotool or wtype where they are installed, the
RemoteDesktop portal on a Wayland session once you grant it
(openmila-cli grant-typing, or the button in Settings), and the
clipboard with a notification otherwise. Dictation never waits on the consent
dialog: without permission it falls back in a tenth of a second.
On Windows, hotkeys are registered with the operating system and dictated text is pasted into whichever window has focus. That code is written and passes in CI, but like everything else on Windows it has not been run on a real desktop yet.
Dictations are saved under Dictations in the sidebar, and they respect the storage cap like any other recording.
Speakers
Speaker diarization names who said what, live during a recording and afterwards, with a colour per speaker. It is off by default, as it is in Mila.
The first time you turn it on, the app downloads PyTorch for the CPU, about 200 MB, into the Python runtime the packages ship. That download happens once. Turning diarization on or off mid-recording takes effect immediately.
Naming a speaker is a click on the speaker label in a transcript: a sheet
opens with a text field, suggestions from the names you have used before, a
Save button and an Un-name button.
Giving two labels the same name merges them, which is how
you fix diarization splitting one person into
SPEAKER_01 and SPEAKER_04. The names you have used
are listed in Settings > Speakers, where you can remove
any of them. Speakers you have not named stay as
SPEAKER_NN.
Recognising the same person across recordings is separate and opt-in. The toggle is Recognise the same speaker across recordings in Settings > Speakers. With it on, a voice you have named once is labelled automatically in later recordings. Beside it is a Delete everything learned about voices button, which does what it says.
AI features
Nothing is sent anywhere until you configure a provider. OpenMila ships no API keys and has no provider of its own, and every AI feature is inert until Settings > AI Provider names something to talk to. Transcription itself never needs any of this.
Choose a provider
In Settings > AI Provider, pick one of the command-line
tools OpenMila can shell out to, the Claude, Cursor or Gemini CLI, or an
OpenAI-compatible endpoint. A CLI can be found on your PATH or
given an explicit executable path. An OpenAI-compatible endpoint takes a base
URL, a model name and an API key, and the key is kept the way this system
keeps secrets rather than in a settings file (see Secrets).
Every invocation is logged with credentials redacted.
Ollama (local): the option where nothing leaves the machine
The OpenAI-compatible endpoint has presets, and one of them is
Ollama (local). It points at
http://localhost:11434/v1, the default address of
Ollama running on your own computer, and it
is the one preset that asks for no API key, because there is nobody to
authenticate to. Install Ollama, pull a model
(ollama pull llama3.1 matches the preset's default model name),
pick the preset, and every AI feature on this page - suggested names,
summaries, action items, Live AI, Send to LLM - runs without a single
outbound request.
This has not been exercised end to end on OpenMila: the parity table marks the provider list done on Linux on the strength of a run through the Claude CLI, and written on Windows. The preset itself is upstream code that the port compiles unchanged. If it misbehaves, please say so.
Summaries and action items
Settings > AI Features turns on suggested recording names
and an automatic summary after each recording, and holds the prompt each
feature uses, which you can edit. A summary can be regenerated from a
recording's Actions menu, and recordings from before you
turned the feature on can be backfilled. Action items carry where they came
from: a voice_command item is one somebody dictated out loud,
and an inferred item is one Live AI derived from the
conversation. Those are not the same claim.
Live AI
Live AI keeps a rolling summary and a list of action items while the meeting is still going, next to the live transcript, with a context box you fill in per recording so the model knows what the meeting is about. Running transcription and an AI pass concurrently is the heaviest thing the app does, so it is gated on what the machine can actually manage: OpenMila reads the memory and processor count and turns Live AI off on hardware that cannot keep up.
Send to LLM
Send to LLM takes one recording's transcript and a prompt of your own to the provider you configured, for the questions a fixed summary prompt does not answer.
Folders, exports and team setup
Watched folders
Mila watches the folder iCloud syncs iPhone Voice Memos into. OpenMila watches any folder you sync recordings into, a Syncthing or Nextcloud directory or a mounted phone, and imports new audio files automatically. Point it at a folder in Settings > Watched Folders, then choose which subfolders to include and whether to take files sitting directly in the folder. Only files newer than the start date are imported, and they land in a Voice Memos folder in the library.
Obsidian export
With an Obsidian vault configured, every finished recording is also written
into it as a Markdown note carrying the title, date, duration, summary,
action items and transcript. It is off until you choose a vault, and the
vault can be committed and pushed for you using git from your
PATH. The parity table marks this done on Linux.
Team setup with .milaconfig
A .milaconfig file carries a ready-made configuration, the
transcription server, model, language and more, so one person can set a team
up in a step. OpenMila shows you exactly what will change before applying it,
and settings the file does not name are left alone. Import one from
Settings > General > Import a .milaconfig file, or
open it from a terminal:
openmila team.milaconfig
Double-clicking such a file does not work yet, on either system: the desktop
file association is not installed on Linux and there is no file association
on Windows. A .milaconfig written for Mila works in OpenMila and
the other way round. Note that the file holds its API key in plain text, so
hand it to your team over a channel you trust.
SRT export
Actions > Export SRT on a recording writes a subtitle file with the per-segment timestamps. It can also be exported mid-recording, from the live transcript, without waiting for the recording to finish. The same menu copies the transcript with its speaker labels.
Playback speed
A recording plays back between 0.5x and 2x, in steps, and the transcript follows along; clicking a line seeks to it. The speed change goes through a WSOLA time stretcher, so voices keep their natural pitch rather than turning into chipmunks. The stretched audio was checked by transcribing it again at 0.75x and 1.5x and getting the same words, which is the intelligibility test a frequency measurement cannot give.
Where everything lives on disk
| What | Linux | Windows |
|---|---|---|
| Recordings, transcripts, models, settings sidecars | ~/.local/share/Mila/ |
%APPDATA%\Mila\ |
| Logs | ~/.local/state/openmila/logs/openmila.log |
%LOCALAPPDATA%\OpenMila\logs\openmila.log |
| Settings | ~/.config/, managed by the app |
managed by the app |
| MCP consent flag | ~/.local/share/Mila/mcp-access.json |
%APPDATA%\Mila\mcp-access.json |
The data folder is named Mila on purpose: the MCP helper and
other shared code look for it by that name.
Secrets
API keys and tokens are never written into the settings file. On
Linux they go to your desktop keyring through the Secret
Service, which is GNOME Keyring, KWallet or KeePassXC depending on your
desktop. Where no keyring answers, they fall back to files under
~/.local/share/Mila/secrets/ with owner-only permissions. On
Windows they live in
%APPDATA%\Mila\secrets\, encrypted with DPAPI for your Windows
account.
Troubleshooting
No microphone in the picker
Check that PipeWire or PulseAudio is running and that the device appears to the rest of the desktop. The command-line harness lists exactly what the app can see, which separates an OpenMila problem from an audio-stack problem:
openmila-cli devices
If the device is listed there but recording fails, the error names the device and the log file has the detail. On Windows, the microphone privacy setting is the operating system's own; there is no per-application permission gate on either system.
No sound from the application you chose
Recording one application's audio on Linux needs PipeWire's tools, the
pipewire-bin package, which provides pw-dump and
pw-record. Without them the picker offers only the whole-system
monitors. Install the package, then check that the application is actually
playing when you start: the link is made to the output stream that exists at
that moment.
openmila-cli app-audio
On Windows the same picker is drawn from WASAPI process loopback. Nothing there has been run on a real machine, so if it does not offer what you expect, choose the whole-system loopback and mute what you do not want recorded, and please report it.
Hotkeys do not fire on Wayland
On a pure Wayland session the hotkeys go through the XDG
GlobalShortcuts portal, which your desktop has to grant. Confirm
the binding when the desktop asks; if you dismissed that prompt, check your
desktop's own shortcut settings for OpenMila. This path has not yet been
confirmed by a human at a Wayland desktop, so if it stays silent, use the
Dictate buttons on the Home screen and
tell us. If the dictated
text is not typed at the cursor, install xdotool or
wtype, or grant the RemoteDesktop portal with
openmila-cli grant-typing; without either, the text is put on the
clipboard and you paste it yourself.
The model download fails
The error is shown beside the model in Settings > Models. A download is verified against a pinned SHA-256 and a failed check is refused, so a truncated or tampered file is thrown away rather than used. Retry the download; a fresh attempt starts cleanly. If it keeps failing, check that you can reach the network at all and that the disk has room for the 1.6 GB or 3.0 GB file. A network that filters where the weights are served from will show up as a download that never starts, so it is worth trying the connection you would normally install software over. If it still fails, attach a diagnostic report to an issue.
Diarization cannot install torch
Enabling speaker diarization downloads PyTorch for the CPU, about 200 MB, into the Python runtime the packages ship. Two things make this fail: the runtime not being in the package, which happens on Windows today because the Windows diarization bundle has never been built, and the network refusing the download. Leave diarization off in the first case; it is off by default and everything else works without it. In the second case, retry with the network that would normally let you install Python packages. The log file records what the attempt did.
Export a diagnostic report
Settings > General > Export diagnostic report writes a zip and tells you where it saved it. Inside are system information, your settings with credentials redacted and prompts reduced to their length, the shape of your recordings with no titles or paths, and the log files. It is built to be safe to attach in public, and it is the single most useful thing you can put on a bug report.
Where to report a bug
- Bugs and feature requests: the repository's issues, with a diagnostic report attached. If something is marked done in the parity table and does not work for you, that is a bug worth reporting.
- Questions rather than bugs: Discussions.
- Security problems: do not open a public issue. Use private vulnerability reporting on the repository.
- Anything else: the contact form and social links at nx1xlab.dev/contact.
For AI agents: the MCP server
This section is for an AI agent, and for the person configuring one. OpenMila
ships the same MCP server Mila has, built from the same source, as a helper
called openmila-mcp. It speaks MCP over stdio and lets a session
search and read your transcripts, including the live transcript of a meeting
in progress. It reads OpenMila's own on-disk store; nothing leaves the
machine unless the agent is asked to do something with it.
On Linux this has been exercised end to end through Claude Code, refused with consent off and listing recordings with it on. On Windows the helper builds and ships in the zip, and nothing has run it there.
What the server exposes
| Tool | What it returns |
|---|---|
list_recordings |
A list of recordings, filtered by speaker display name, by text in the title, application or folder, by source, or by date range, and sorted by date, duration or title. Trashed recordings are not included. |
get_transcript |
One recording's full transcript with speaker names resolved, plus its
summary and action items. Omit the id and you get the latest
completed recording. Each action item carries a source,
either voice_command (somebody dictated it out loud) or
inferred (Live AI derived it from the conversation);
those are not the same claim, so do not present the second as the
first. Trashed recordings are not reachable, by id or otherwise.
|
search_transcripts |
Full-text matches over titles and transcripts, with context snippets,
sorted by relevance or by date. Relevance is the default and scores
every recording, so it always finds the best match and costs more as
the library grows. Sorting by created_at stops at the
limit, which is cheaper and usually the better question when you want
recent mentions.
|
get_live_transcript |
The in-progress recording's transcript, with a polling cursor for
cheap deltas: nothing new gives a tiny unchanged reply, new content
gives only the new segments. A status field says whether to keep
polling, and hands off to get_transcript when the
recording completes.
|
Nothing is cached. Every call reads the store as it is at that moment, which is what makes the answers trustworthy while a recording is still running.
The consent gate
Access is off by default. Turn it on in Settings > Storage > Allow MCP access to transcriptions. While it is off every tool call is refused, and the refusal explains itself by pointing back at that toggle, so an agent that hits it can tell the person what to do rather than guessing that the transcripts do not exist. The setting takes effect immediately: turning it off cuts an already-running session without restarting anything.
The flag lives in mcp-access.json in the data folder,
~/.local/share/Mila/mcp-access.json on Linux and
%APPDATA%\Mila\mcp-access.json on Windows. Every call re-reads
it. Missing, unreadable or malformed all mean denied: the gate fails closed
on anything it does not positively understand, and a failed attempt to revoke
access escalates to deleting the file so that revocation cannot fail open.
It is a consent control, not a privilege boundary. The helper runs as your user and reads the same files you can, so anything already running as you could read the store directly whatever this setting says. What the toggle prevents is the realistic accident: an MCP client that happens to be configured quietly reading meeting transcripts and sending them to a cloud model because the tools were simply there. It does not, and cannot, defend against a hostile program already running as you.
Register it with Claude Code
One command, once. Use the line that matches how you installed OpenMila.
From the AppImage, which carries the helper inside it:
claude mcp add openmila -- /path/to/OpenMila-<version>-x86_64.AppImage --mcp
From the Debian package, which puts the helper on your PATH:
claude mcp add openmila -- /usr/bin/openmila-mcp
From the Windows zip, using the folder you extracted it into:
claude mcp add openmila -- C:\path\to\OpenMila\openmila-mcp.exe
From a source build:
claude mcp add openmila -- /path/to/OpenMila/.build/debug/openmila-mcp
The same thing as JSON
Other MCP clients take a configuration file instead. The shape is the same everywhere: a named server with a command to run. Replace the path with the one for your install from the section above.
{
"mcpServers": {
"openmila": {
"command": "/usr/bin/openmila-mcp"
}
}
}
The helper takes no arguments of its own and needs no environment. It finds the store through a pointer file the app rewrites on every launch, so it follows the recordings folder if you move it.
What to ask it
- Read my last transcription with a named person and summarise it.
- Search my transcripts for a decision I half remember, and show me the lines around each match.
- List everything I recorded last week, longest first.
- Pull the action items out of yesterday's meeting, and say which ones somebody asked for out loud rather than the ones that were inferred.
-
Follow my current meeting: poll
get_live_transcriptwith the cursor every fifteen to twenty seconds, and when something new lands, suggest in a sentence or two what I should say next. When the status becomes completed, fetch the final transcript and summarise it.
Reading the whole site
An agent that wants the rest of the site, not just this page, should read /llms.txt, which summarises what OpenMila is, where the port stands, what it does, its privacy properties and its known limits, with links to every page. This page itself is available as Markdown at /docs.md, generated from this HTML on every build so the two cannot disagree.