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.

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 .deb declares these as libgtk-4-1, libadwaita-1-0, libsecret-1-0, libglib2.0-0, libc6 and zlib1g.
Linux, to record one application's audio
PipeWire's own tools, the pipewire-bin package, which provides pw-dump and pw-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. XGrabKey is used wherever an X display answers, including XWayland, and the XDG GlobalShortcuts portal on a pure Wayland session; the two paths pick themselves. See Dictation.
Linux, for dictation that pastes by itself
xdotool or wtype to paste at the cursor, plus wl-clipboard or xclip for the clipboard. On a Wayland session OpenMila can use the RemoteDesktop portal 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 .m4a recordings, 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-bin for 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-turbo for English and other languages, 1.6 GB.
  • ivrit.ai large-v3 for 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

File locations per system
WhatLinuxWindows
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

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

The four tools, and what each returns
ToolWhat 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_transcript with 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.