AI / Desktop
Meeting Assistant
A macOS meeting companion that transcribes live and recorded meetings on the device, tells speakers apart by voice, and tracks which questions were raised and whether anyone answered them.
- Role
- Sole engineer
- When
- 2026
- Source
- Private · walkthrough on request
- Stack
- Rust
- Tauri 2
- whisper-rs (Metal)
- sherpa-onnx
- Swift
- React
- SQLite
- Claude
- Built in 137 commits over 5 days (29 Oct – 2 Nov 2026), with 62 merged pull requests
- All domain behaviour lives in one Rust crate with no Tauri or UI dependency, covered by 288 integration tests
- Meeting audio and voiceprints never leave the Mac; only finalised transcript text goes out for question extraction
Problem
In long meetings, questions get asked and then lost. Nobody remembers which ones were answered, and by the next meeting in a series they’re gone. Cloud meeting bots handle this by recording everyone and sending the audio to a server. That’s expensive for hours-long calls, and hard to justify for people who never agreed to be recorded. I wanted a personal tool that listens to any meeting app, shows a live transcript and keeps a running list of open questions across meetings, while meeting audio stays on the machine.
My role
Sole engineer: domain model, architecture decisions (four ADRs), Rust core, Swift audio sidecar, Tauri shell and React UI. Work ran through GitHub issues with triage labels and a shared glossary, so any issue could go to a coding agent or be picked up by hand.
Architecture
meeting-core(Rust crate) owns the Meeting lifecycle, storage (SQLite viarusqlite), question tracking, speaker recognition and echo handling. With no dependency on Tauri or the UI, it keeps the Tauri layer and React frontend thin.- Swift sidecar (
audio-capture) streams 16 kHz mono Float32 audio over stdout. The source is the echo-cancelled microphone (macOS voice processing), system audio through a Core Audio process tap, or a decoded audio/video file for imports. It never writes audio to disk. - Transcription runs whisper.cpp through
whisper-rswith Metal, with selectable models from base up to large-v3. - Voice analysis uses sherpa-onnx from Rust: pyannote segmentation 3.0 finds speaker turns and a WeSpeaker ResNet34 model produces voice embeddings. Each Speaker keeps an embedding, never audio.
- Question extraction sends finalised transcript text to Claude roughly every 10 seconds, either through the locally installed Claude Code CLI or the Anthropic API with a key held in the macOS Keychain.
Key decisions
- Local transcription, cloud question extraction (ADR-0001). Cost drove this. Per-minute streaming speech-to-text is what makes a long meeting expensive; sending text to an LLM is cheap. I rejected local LLMs because they were weaker at Urdu and mixed Urdu/English speech, and at judging whether a question was actually answered. Transcription keeps working offline; extraction catches up when the connection returns.
- Tauri with a Rust core over native SwiftUI (ADR-0003, superseding ADR-0002). The first plan was SwiftUI with WhisperKit. I reversed it to keep other platforms open. The newer Apple audio APIs stay in a small Swift sidecar, since Rust’s Objective-C bindings for them are less proven.
- Seams around everything platform-specific.
SpeechSource,VoiceAnalyserand the question engine are traits, so the sidecar, models or LLM can be swapped without touching the core. A scriptedSpeechSourcebehind a Cargo feature lets the whole app run without audio. - Speaker recognition stays on-device (ADR-0004). Voiceprints are biometric data about people who never consented to the app, so cloud diarization was out. For an unclear match the app suggests a known Person (“Maybe
?”), and it never relabels an earlier meeting without asking. - Echo dropping in pure logic. Without headphones the microphone picks up remote speakers. A “You” segment that closely matches overlapping “Others” text (similarity 0.85, 1 s timing slack) gets dropped, so remote speech appears once.
Outcomes
- Working macOS app (Apple Silicon, macOS 14.2+) with live and imported meetings, speaker naming, question tracking, search, export and crash recovery.
- 288 integration tests over the core, including contract tests for both Claude adapters.