Features, and how far the port has got
OpenMila copies Mila's features rather than inventing new ones, so the
honest way to describe it is Mila's own feature list with a status beside
each entry. The tables below are generated from the port's parity file,
measured against upstream v1.9.5-beta.2. OpenMila's own
version is 1.9.5-beta.2+port.3.
What a machine needs to run any of it - cores, memory, disk, and what a GPU does and does not buy you - is on the download page.
How to read this
The first status column is Mila on macOS, and it says
baseline in every row, because
every row is one of Mila's own features. It is the ruler, not a score.
Linux is the development platform (Ubuntu 26.04, GNOME on Wayland, no
GPU), so its evidence is direct. Windows is built and tested on a
windows-2025 runner in CI, where the core, the CLI, the
MCP helper, the port's tests, the WinUI app and the portable zip all
pass. No Windows row says done, because nobody has run any of
it on a Windows desktop yet.
| Status | Meaning |
|---|---|
| baseline | Not a status. It marks the macOS column, where the feature is Mila's own and is the thing the other two columns are measured against. |
| done | Implemented and exercised on that operating system, by a test, the CI pipeline, the headless self-test, or a run of the app. |
| partial | Works, with a stated limitation. The limitation is in the row. |
| written | Code exists but nothing has run it yet on that operating system. Every Windows row is at best this until the Windows CI job is green. |
| planned | Not started. |
| not applicable | An Apple-only mechanism with no equivalent, or nothing to do. |
A row moves to done only with evidence on that operating system: "it compiles" is not evidence. A feature that lands on one system and not the other stays visible here rather than being quietly dropped. The source of truth is docs/port/PARITY.md.
Where it falls short today
On Linux
- Meeting detection misses browser meetings on a pure Wayland session. Native applications come from
/procon every session, and a meeting in a browser tab is read from the window title, which only X11 and XWayland expose. A Wayland client cannot see another client's windows by design, so there is nothing to read. - The Wayland global-shortcut path has not been confirmed by a human. The XDG
GlobalShortcutsportal is wired and picks itself where no X display answers, and it was exercised withopenmila-cli hotkey, but an actual key press at a Wayland desktop is still unwitnessed. - Vulkan has never been timed. The backend is compiled in and the probe is tested, but the development machine has no GPU, so no transcription has been measured on one.
- The managed Claude install verifies a checksum, and there is no signature to verify. Anthropic notarises the macOS binary through Apple and ships the Linux one unsigned, so the port's verifier fails closed rather than pretending.
- No menu bar on GNOME. GNOME removed the global menu and a Mac-style menu bar is not something a Linux application can have, so every command keeps its keyboard shortcut and Settings lists them.
- Sidebar chrome has no blur. The blur behind a translucent surface is the compositor's to give and GTK 4 cannot ask for it. Layered translucent surfaces get close, and that is where it stops.
- No Neural Engine, so no CoreML encoder. There is no equivalent to ask for.
On Windows
- Nothing has been run on a real desktop. Everything marked written builds and ships, and that is all that can be claimed.
- Compact
.m4arecordings depend on the machine. ffmpeg and GStreamer are both tried, and neither ships in the zip, so whether you get.m4aor WAV depends on what is already installed. - The portable zip has no self-install. The update check works; installing the update is a fresh download.
- Managed Claude sign-in needs a real terminal. Authenticode is verified with the signer's name checked, but browser sign-in waits on a ConPTY path replacing the POSIX pseudo-terminal.
- No file association for
.milaconfig. The app reads a path from its arguments; the installer has no association to register.
Mila on macOS, OpenMila on Linux, OpenMila on Windows
Three columns, one row per Mila feature. The macOS column is the upstream baseline: this project does not build, test or ship Mila for macOS, so it has nothing of its own to report there, and the honest reading of every row is "Mila does this, and here is how far each port has got". The tables are generated from docs/port/PARITY.md, which has the Linux and Windows columns and nothing else.
Recording and capture
| # | Feature | Mila macOS | OpenMila Linux | OpenMila Windows |
|---|---|---|---|---|
| 1 | Microphone recording, device picker, pinned input, live input level | baseline | done miniaudio, openmila-cli devices and record |
written same capture code, WASAPI backend |
| 2 | System audio from one chosen app | baseline | done PipeWire links a capture stream to the chosen application's output ( pw-record --target), with whole-system monitors still offered; verified with openmila-cli app-audio (3.07 s captured from one player, peak 0.78) |
written WASAPI process loopback binds a capture client to the chosen process tree, with the whole-system monitors still offered. It compiles in CI and nothing has run it: no Windows machine has been available to this port |
| 3 | Meeting mode: mic + app audio mixed to one mono 16 kHz WAV | baseline | donePort/Recording/RecordingSession.swift, RecordingTests |
written |
| 4 | Independent mic / app-audio toggles | baseline | done | written |
| 5 | Pause and resume with the paused span absent from audio and timer | baseline | doneRecordingTests |
written |
| 6 | Folder and meeting name chosen at record start | baseline | done | written |
| 7 | Adaptive gain control for quiet mics | baseline | done upstream's AdaptiveGainController, vDSP calls behind the Accelerate shim |
written |
| 8 | Mic stall watchdog and app-audio restart with backoff | baseline | done the session watches the frame count every second and restarts a capture that stops moving, with upstream's timeout and its backoff, and reports it when the device cannot be reopened. Upstream's policy types were not compiled off macOS at all before this ( CaptureWatchdogTests) |
done the same code, one watchdog for both systems |
| 9 | Mic bring-up timeout with an error that names the device | baseline | done | written |
| 10 | Refuse to transcribe an empty capture, duration read from the file | baseline | done | written |
| 11 | AAC .m4a recordings |
baseline | done ffmpeg where it is installed, GStreamer otherwise, which a GNOME or KDE install almost always has. Proven by a round trip: WAV to AAC and back transcribes to the same sentence |
partial the same two routes are tried, but neither ships in the zip, so it depends on what the machine has |
| 12 | Configurable recordings directory | baseline | done plain paths, no security-scoped bookmarks |
written |
| 13 | Storage cap, respected by dictation | baseline | done upstream code, unchanged |
written |
| 14 | Auto-discard accidental clips | baseline | done upstream code, unchanged |
written |
| 15 | Sleep and screen-lock guard while recording | baseline | donegnome-session-inhibit, systemd-inhibit fallback |
writtenSetThreadExecutionState |
| 16 | Crash-recovered WAV header repair | baseline | done upstream WAVHeaderRepair, WAVHeaderRepairTests runs off macOS |
written |
| 17 | Meeting detection (Zoom, Teams, Meet, Proton Meet) with prompts to start and stop | baseline | done native apps come from /proc on every session. A meeting in a browser tab is found by window title, from X11 where a display answers and from the accessibility bus on a Wayland session, where the display protocol refuses by design. Verified live: the accessibility walk reads Wayland-native window titles on GNOME 26.04 with the desktop switch still off. Firefox and Chromium publish their windows only once accessibility is on (gsettings set org.gnome.desktop.interface toolkit-accessibility true), and the app says so rather than finding nothing quietly |
written process names via CreateToolhelp32Snapshot, window captions via EnumWindows; Windows places no Wayland-style restriction on reading them, so a tab meeting is detectable on every session. MeetingTitleTests covers the shared patterns on both systems |
| 18 | Live level meters and elapsed clock without re-rendering the app | baseline | doneRecordingMeters, observed by the leaf view only |
written |
Transcription
| # | Feature | Mila macOS | OpenMila Linux | OpenMila Windows |
|---|---|---|---|---|
| 19 | On-device whisper.cpp, ivrit.ai large-v3 (Hebrew) and large-v3-turbo (English) | baseline | done built with the Vulkan backend; a real GPU is used, a software Vulkan device is refused because it is slower than the CPU backend, and a machine with neither runs on the CPU. openmila-cli gpu reports what was found. Not yet measured on real GPU hardware |
written the same code, and CI installs the Vulkan SDK so the backend is compiled into the release zip. Never run on a Windows machine, with or without a GPU |
| 20 | CoreML / ANE encoder and its banner | baseline | not applicable no ANE; .mlmodelc downloads skipped |
not applicable |
| 21 | First-launch model download with progress and SHA-256 verification | baseline | done verified by downloading both models |
written |
| 22 | Model deletion frees the whole install and keeps the choice sane | baseline | done upstream ModelManager |
written |
| 23 | Recording language Hebrew or English, model routed per language | baseline | done | written |
| 24 | Remote transcription on any OpenAI-compatible endpoint | baseline | done upstream code with the port's SecretStore; exercised against scripts/mock-openai-transcription-server.py |
written |
| 25 | Neural VAD (Silero) and hallucination reduction | baseline | doneTranscriptionCore as-is, weights bundled |
written |
| 26 | Live transcription while recording, mic and app audio | baseline | done | written |
| 27 | Live transcript editing, copy, mid-recording SRT export | baseline | donePort/App/Sources/Views |
written the app builds on Windows with the WinUI backend (CI packages a zip); nothing has run it |
| 28 | Hardware gate for Live AI on weak machines | baseline | doneSystemCapabilities twin reads RAM and activeProcessorCount |
written |
| 29 | Transcription queue with no stuck items after relaunch | baseline | done upstream TranscriptionService |
written |
| 30 | Re-transcribe a recording, speaker names re-attached | baseline | done | written |
| 31 | Import and transcribe existing audio files | baseline | doneFileTranscriber twin; watched-folder import verified word for word |
written |
| 32 | audio_ctx speed-up and beam search 5 |
baseline | doneTranscriptionCore unchanged |
written |
Speakers
| # | Feature | Mila macOS | OpenMila Linux | OpenMila Windows |
|---|---|---|---|---|
| 33 | Speaker diarization with pyannote, bundled Python runtime, torch on first enable | baseline | donediarization/build-bundle-linux.sh, proven by openmila-selftest diarize (torch 2.2.2 installed at runtime, turns returned) |
writtenbuild-bundle-windows.ps1 builds the runtime in CI (run 35546341637, the first time it has ever been run). Nothing has loaded that runtime or diarized with it |
| 34 | Live speaker labels during recording | baseline | done upstream LiveSpeakerDiarizer |
written |
| 35 | A colour per speaker | baseline | done port theme palette |
written the app builds on Windows with the WinUI backend (CI packages a zip); nothing has run it |
| 36 | Speaker directory: name, rename, merge, un-name, naming mid-recording | baseline | done | written the app builds on Windows with the WinUI backend (CI packages a zip); nothing has run it |
| 37 | Cross-recording voice recognition, opt-in, deletable | baseline | done upstream OfflineVoiceEmbedder, SpeakerProfileStore |
written |
| 38 | Diarization toggle mid-recording takes effect immediately | baseline | done | written |
Dictation
| # | Feature | Mila macOS | OpenMila Linux | OpenMila Windows |
|---|---|---|---|---|
| 39 | Global hotkeys for English and Hebrew, configurable, conflict-checked | baseline | doneXGrabKey where an X display answers (including XWayland), the XDG GlobalShortcuts portal on a pure Wayland session. Both paths pick themselves and were exercised with openmila-cli hotkey; a key press through the portal still needs a human at a Wayland desktop to confirm |
writtenRegisterHotKey on a dedicated message thread |
| 40 | Dictation overlay pill with live text, level and busy state | baseline | done app window; no layer-shell, so it is an ordinary always-on-top window |
written the app builds on Windows with the WinUI backend (CI packages a zip); nothing has run it |
| 41 | Paste at the cursor into the previous app, with clipboard fallback | baseline | donexdotool or wtype where they are installed, the RemoteDesktop portal on a Wayland session once the user grants it (openmila-cli grant-typing, or the Settings button), and the clipboard with a notification otherwise. Dictation never waits on the consent dialog: without permission it falls back in 0.1 s |
written clipboard plus SendInput Ctrl+V |
| 42 | Dictations saved under History | baseline | done | written |
AI features
| # | Feature | Mila macOS | OpenMila Linux | OpenMila Windows |
|---|---|---|---|---|
| 43 | Providers: Claude, Cursor, Gemini CLIs and any OpenAI-compatible endpoint | baseline | done real claude CLI produced a summary in 8 s |
written.cmd shims run through cmd /c |
| 44 | Managed Claude install with checksum and signature checks | baseline | done as the platform allows - the linux-x64 manifest key and the published SHA-256 are verified before anything runs. There is no signature to check: Anthropic signs the macOS binary through Apple's notary service and ships the Linux one unsigned, so the port's SignatureVerifier fails closed rather than pretending to verify |
partialwin32-x64 key, Authenticode verified with the signer's name checked; browser sign-in needs a real terminal until a ConPTY path replaces the POSIX pseudo-terminal |
| 45 | Suggested recording names | baseline | done | written |
| 46 | Automatic summary after each recording, backfill, regenerate, .summary.txt |
baseline | done | written |
| 47 | Send to LLM with a custom prompt | baseline | done | written |
| 48 | Live AI rolling summary and action items with a per-recording context box | baseline | done | written the app builds on Windows with the WinUI backend (CI packages a zip); nothing has run it |
| 49 | AI output language, per-feature prompts with an undo stack | baseline | done | written the app builds on Windows with the WinUI backend (CI packages a zip); nothing has run it |
| 50 | Every CLI invocation logged with credentials redacted | baseline | doneOpenMilaLogging redacts unless OPENMILA_LOG_PRIVATE=1 |
written |
Library and UI
| # | Feature | Mila macOS | OpenMila Linux | OpenMila Windows |
|---|---|---|---|---|
| 51 | Sidebar: Home, All Transcriptions, folders with drag-and-drop, Dictations, watched folders, Recently Deleted | baseline | done SwiftCrossUI + GTK4 |
written the app builds on Windows with the WinUI backend (CI packages a zip); nothing has run it |
| 52 | Detail view: playback, click to seek, 0.5x-2x speed, transcript follows playback | baseline | done speed goes through a WSOLA time stretcher, so pitch is preserved ( StretchTests); the stretched audio also transcribes to the same words at 0.75x and 1.5x, which is the intelligibility check a frequency test cannot give |
written the app builds on Windows with the WinUI backend (CI packages a zip); nothing has run it |
| 53 | Post-recording popup and rename sheet with summary and action items | baseline | done | written the app builds on Windows with the WinUI backend (CI packages a zip); nothing has run it |
| 54 | Right-click context menu on recordings | baseline | done GTK GtkPopover via a button-3 gesture |
written the app builds on Windows with the WinUI backend (CI packages a zip); nothing has run it |
| 55 | Copy and share transcript with speaker labels, SRT export, timestamps | baseline | done | written core only |
| 56 | Hebrew RTL rendering per section | baseline | done Pango handles bidi; direction decided per block by upstream's HebrewDetection |
written the app builds on Windows with the WinUI backend (CI packages a zip); nothing has run it |
| 57 | Hide recents toggle | baseline | done | written the app builds on Windows with the WinUI backend (CI packages a zip); nothing has run it |
| 58 | Settings with all nine sections | baseline | done | written the app builds on Windows with the WinUI backend (CI packages a zip); nothing has run it |
| 59 | "What's New" before an update | baseline | done notes from the GitHub release body |
written the app builds on Windows with the WinUI backend (CI packages a zip); nothing has run it |
| 60 | Main menu commands and keyboard shortcuts | baseline | done as the platform allows - every command has its keyboard shortcut in the app. There is no menu bar to put them in: GNOME removed the global menu, and a Mac-style menu bar is not a thing a Linux application can have. The shortcuts are listed in Settings instead |
written the app builds on Windows with the WinUI backend (CI packages a zip); nothing has run it |
| 61 | Diagnostic report export, credentials redacted, logs attached | baseline | doneDiagnosticSnapshotProvider twin over the port's own log files |
written |
| 62 | Sidebar material chrome | baseline | done as the platform allows - layered translucent surfaces stand in for .regularMaterial. The blur behind them is the compositor's to give, and GTK 4 cannot ask for it; the look is close, not identical, and that is where it stops |
written the app builds on Windows with the WinUI backend (CI packages a zip); nothing has run it |
Integrations
| # | Feature | Mila macOS | OpenMila Linux | OpenMila Windows |
|---|---|---|---|---|
| 63 | iPhone Voice Memos sync | baseline | done as watched folders - the same start-date and destination rules over any synced directory (iCloud discovery is macOS-only); inotify watcher, per-folder toggles |
writtenReadDirectoryChangesW |
| 64 | .milaconfig one-click team setup |
baseline | done the packages declare application/x-milaconfig with a *.milaconfig glob and refresh the MIME database on install and removal, so a double-click opens OpenMila; update-mime-database accepts the definition |
partial the app reads a path from argv; the installer has no file association yet |
| 65 | Obsidian export and vault git sync | baseline | donegit from PATH |
written |
| 66 | MCP server with the consent gate | baseline | doneopenmila-mcp through Claude Code: refused with consent off, listed recordings with it on |
written builds and ships in the Windows zip; nothing has run it there |
| 67 | Self-hosted server docs | baseline | donedocs/self-hosted-server, docs/openmila/REMOTE_SERVER.md |
done same docs |
Updates, permissions, system
| # | Feature | Mila macOS | OpenMila Linux | OpenMila Windows |
|---|---|---|---|---|
| 68 | Auto-update with a beta channel and a pre-release guard | baseline | done for the AppImage - the check, the beta channel and the pre-release guard, plus an install step that verifies the published SHA-256 and replaces the running AppImage ( SelfUpdateTests); a .deb install is sent to the release page, since that belongs to the package manager |
partial the check works; the zip has no self-install |
| 69 | Permission prompts for microphone, screen recording, accessibility | baseline | not applicable no per-app permission gates; PipeWire and portal dialogs appear where the session requires them |
not applicable the microphone privacy setting is the OS's own |
| 70 | Keychain storage for API keys | baseline | done the desktop keyring through libsecret (GNOME Keyring, KWallet, KeePassXC), with 0600 files where no Secret Service answers ( SecretServiceStoreTests) |
written DPAPI |
| 71 | Privacy-safe logging | baseline | done | written |
| 72 | Stable code signing so permissions survive updates | baseline | not applicable | not applicable |
Which Mila release this matches
OpenMila is measured against one upstream tag at a time. It currently tracks Mila v1.9.5-beta.2 (2026-09-17), with v1.9.4 (2026-09-10), the latest upstream stable, kept as the archived build used for side-by-side comparison. Earlier releases from v1.8.8 onwards are folded into the tables above.
Each OpenMila version is a port of one Mila version, named
<mila version>+port.<n>. Features, models and
engine pins track upstream: the port adds platform code, not features.
See the changelog.