Local-first macOS meeting recorder with on-device transcription and speaker recognition.
- Record mic + system audio -- captures both sides of video calls via ScreenCaptureKit
- On-device transcription -- WhisperKit (CoreML) with model sizes from tiny (75 MB) to large-v3 (2.9 GB)
- Speaker diarization -- FluidAudio identifies who said what, with a learnable voice library that improves over time
- Source-aware speaker matching -- uses retained mic/system stems to reduce close-call speaker mixups
- Obsidian-compatible output -- structured markdown with YAML frontmatter and
[[wikilinks]]for speaker pages - Menu bar app -- lives in the menu bar with a global hotkey (Ctrl+Opt+R) for quick recording
- Crash recovery -- two-phase pipeline checkpoints expensive transcription work so crashes don't lose progress
- Auto-transcribe, auto-save -- configurable automation with retention policies (7-90 days)
- Fully local -- no cloud APIs, no internet required after initial model download
- macOS 14+ (Sonoma)
- Apple Silicon (M1 or later)
- Xcode 15.3+ / Swift 5.10+ (for building from source)
- No Apple Developer account needed (ad-hoc code signing)
git clone https://github.com/tonton-golio/meeting-recorder.git
cd meeting-recorder/swift
./build.sh
open -a "Meeting Recorder"The build script compiles via SPM, bundles a .app, ad-hoc signs it, and installs to /Applications. First build downloads dependencies and may take a few minutes.
On first launch, macOS will prompt for two permissions:
- Microphone -- required for recording
- Screen Recording -- needed to capture system audio (the remote side of video calls). Optional: the app falls back to mic-only if denied.
- Record -- captures microphone audio (and optionally system audio) as a final 16kHz mono WAV, retaining mic/system stems while audio is kept
- Transcribe -- WhisperKit runs Whisper locally via CoreML, producing timestamped text segments
- Diarize -- FluidAudio clusters audio into speakers and extracts WeSpeaker embeddings (256-dim vectors)
- Match -- each speaker embedding is compared against the People voice library using cosine similarity. Known voices are auto-labeled; unknown speakers are presented for identification.
- Save -- the transcript is written as Obsidian-compatible markdown with YAML frontmatter
See docs/SPEC.md for the full product specification. See docs/SPEAKER_IDENTIFICATION_EXPERIMENTS.md for the source-aware matching experiment plan. See docs/SYSTEM_AUDIO_CAPTURE_EXPERIMENTS.md for system-audio capture diagnostics.
All data lives locally under ~/.meeting-recorder/:
~/.meeting-recorder/
recordings/
recordings.json # recording index
*.wav # mixed audio files
*.mic.wav # microphone stems, while retained
*.sys.wav # system-audio stems, while retained
people/
people.json # people index
{uuid}/ # per-person directory
{sample-uuid}.caf # voice samples
meetings/
*.md # saved markdown transcripts
The app is a SwiftUI menu bar application with a central AppState coordinator that owns the recording, transcription, people-matching, and playback subsystems. See CLAUDE.md for a detailed architecture overview and component guide.
- WhisperKit by argmaxinc -- on-device speech-to-text via CoreML
- FluidAudio by FluidInference -- on-device speaker diarization and embeddings
