Local-first macOS meeting transcription and notes. Blaise records your system audio and microphone, transcribes the conversation on-device (Portuguese/English code-switching is a first-class case, not an afterthought), and writes structured notes with your action items pulled out and made impossible to miss. Audio never leaves the app unless you explicitly enable audio delivery to a destination you choose, which is off by default.
- On-device transcription. Speech-to-text runs locally with Whisper
(
large-v3-turbo) by default, or FluidAudio's Parakeet engine — switchable in Settings. No audio is uploaded to transcribe. - Action items are the point. Every meeting produces a dedicated action-items section. This is the load-bearing output: the thing you came for, surfaced first and stated plainly, never buried in a wall of summary.
- Bring your own agentic system. Notes are written to a content-addressed JSON payload with a documented schema, and (optionally) a Markdown sidecar that Obsidian and most note systems ingest natively. Deliver into any local, iCloud, or synced folder you point Blaise at. The format is built to be consumed by external tools and AI agents, not just read in the app.
- Two-track, crash-safe capture. A CoreAudio process tap records meeting audio and your microphone as two separate tracks in one drift-compensated device. No bot joins your call; nothing is automated in the meeting UI. Compressed audio is always retained so a transcript can be regenerated, and a crash mid-recording never loses what was already captured.
- Code-switching, handled. Portuguese and English mid-sentence is the case Blaise is built around. Notes follow the dominant language of the meeting and preserve quoted phrases in their original language.
- Your glossary, filled by your agent. A self-describing
Glossary.mdteaches Blaise the people, companies, products, and project names it will hear — and its header is a prompt you can point your own AI agent at to fill it in from your context. (See First-run setup below.) - Structured notes, your action items. Notes are written for humans; transcripts are kept verbatim for machines. The notes carry an explicit decisions section and a personal action-items section rendered with your name.
- Optional Google Meet participant names. A passive Chrome extension reads the Meet participant roster and active-speaker timing from the page and feeds them to Blaise for speaker naming. It captures display names and speaking times only — no audio, no captions, no chat — and delivers them encrypted to the app on localhost. It is entirely optional; Blaise works without it.
- Optional direct Google Calendar. If macOS Calendar is not a reliable view of your Google calendars, Blaise can connect to Google Calendar directly using a read-only OAuth grant. Upcoming meetings feed the menu bar, the top of the meeting list, one-click recording, and calendar-aware end detection.
- Optional Slack Huddles roster. While you're in a Slack huddle, Blaise learns
the participants and call lifecycle natively over Slack's Socket Mode API and
feeds them into the same speaker-naming and auto-record flow as Meet. It reads
presence metadata only — who is in the huddle and when — never messages, never
audio; the two tokens stay in your Keychain. It is entirely optional (see
docs/slack_huddles_contract.mdfor setup). - Confirm who was in the meeting (optional, off by default). When Blaise cannot work out the participants from your calendar or a roster, it can ask you as the meeting stops. The names land before the notes are written, so speaker labels and action-item owners come out right instead of needing correction afterwards. Transcription and audio retention never wait on your answer — only the notes do — and a meeting waiting on you stays marked in the library until you answer it.
- Transcript as its own Markdown file (optional, off by default). Alongside the
delivered payload, Blaise can write the full transcript as a separate
.mdfile so it is readable in any notes app. It follows whichever delivery destination you have configured. - Keep one current file per meeting, or keep every version. By default every delivered version of a meeting is kept at your destination, so anything referencing an older payload can still find it. An optional setting instead removes the superseded payload when a correction or regeneration is delivered, leaving exactly one current file per meeting.
- Search and library. Full-text search across every transcript and note, with accent-insensitive matching.
- Export notes as a PDF. Three styles (Atlas, Ledger, Clean), A4 or Letter, Save… or Share; rendered offline from the stored notes with no external resources.
- Updates itself. Release builds check the release feed once a day and offer a new version in place (Sparkle); nothing installs without a click. Local builds never check.
Blaise is local-first by design, and the privacy boundary is stated honestly:
- Audio never leaves the app by default — it stays on this machine unless you explicitly enable audio delivery to a destination. Recording, retention, and transcription are all on-device: there is no upload path for audio unless you explicitly enable audio delivery to a destination. The toggle ("Include audio recordings", Settings → Identity & Handoff → Evidence Store) is off by default, and what turning it on means depends on the destination you picked right above it. With a Local Folder destination the recordings are copied into that folder on this Mac and stay here — they leave only if the folder itself syncs (iCloud, Dropbox, a network share). With an Evidence Store (SSH) destination they are uploaded to the remote host you configured, which does take them off this machine. That is the whole exception, stated plainly so you can decide it deliberately.
- Voice identification is local and deletable. Blaise builds a small voice print of you — numeric voice embeddings drawn from a few of your own meetings — so it can tell your speech apart from other people sharing your mic and attribute lines correctly. It is not the audio itself, it is stored only on this machine, and it is never sent anywhere. The toggle (Settings → Voice Print, "Voice identification", on by default) deletes the voice print entirely when turned off.
- One optional cloud call: notes synthesis. By default, notes are written by
Claude (Anthropic's Sonnet model) under your own API key, which means the
meeting transcript — not the audio — is sent to Anthropic for that one step.
This is the only network call that carries meeting content, and it is opt-in by
configuring a key. There are two other ways to run that step, switchable in
Settings: an account engine that uses your existing Claude subscription
through the
claudeCLI's OAuth token instead of a metered API key (same transcript, same destination — only the billing and the credential differ, and no API key is exposed to it), or a local engine that runs on-device and makes no network call at all. - Spend tracking and a ceiling are built in. Blaise tracks what the notes step costs and enforces a configurable monthly ceiling, so the cloud step can never run away.
- Integration tokens stay local. The optional Google Calendar and Slack Huddles integrations read metadata only (event times and attendees; huddle presence — never huddle messages or audio). Their credentials live in the macOS Keychain and never leave the machine except as Blaise's own API calls to the respective service.
- Fully offline mode. Select the local MLX notes engine and Blaise synthesises notes entirely on-device. If neither a cloud key nor a local model is available, the meeting is transcribed and stored with notes marked pending — nothing is lost, and notes can be generated later.
- Download
Blaise.appfrom the Releases page. - Release builds are unsigned. macOS Gatekeeper will refuse a plain double-click. To open it the first time: right-click (or Control-click) the app → Open, then confirm in the dialog. After that first launch it opens normally.
Requirements: macOS 15.6.1 (Sequoia) or later to run, an Xcode installation with a macOS 26 or newer SDK to build (the scripts prefer macOS 26 when it is installed). On Sequoia itself, use Xcode 26.3 — the last Xcode release that runs on macOS 15; later versions require macOS 26. A release build takes a few minutes.
On macOS 15 every feature works; only the macOS 26 Liquid Glass styling degrades — the recording/warning capsules render as translucent material instead of glass, and list edges scroll without the soft fade. See the changelog for the details.
scripts/build_app.sh # release build → dist/Blaise.app, prints the app path
open dist/Blaise.appThe build is pure Swift Package Manager — there is no .xcodeproj. The scripts
invoke the Xcode toolchain's swift directly with an explicit SDK root, so the
Xcode licence does not need to be accepted on a developer machine. The first
build fetches the pinned Swift package dependencies; the first launch provisions
the on-device transcription runtime (a managed Python environment and the model
weights) into the app's own data folder.
Blaise records fine on its own. To also pull Google Meet participant names and active-speaker timing (for better speaker labelling), install the companion Chrome extension:
- Download
blaise-meet-extension.zipfrom the Releases page and unzip it (or use the repo'sextension/folder if you cloned it). - Open
chrome://extensionsand toggle Developer mode (top right). - Click Load unpacked and select the unzipped folder (the one containing
manifest.json).
It reads only participant display names and speaking times from the Meet page and
delivers them encrypted to Blaise on 127.0.0.1 — no audio, captions, or chat,
and nothing leaves your machine. Entirely optional.
Apple Calendar access remains the zero-network path. For a direct Google Calendar
connection, create a Google OAuth Desktop app client ID, paste it in Settings
→ Automation → Calendars, and press Connect. Blaise requests
https://www.googleapis.com/auth/calendar.readonly, stores the refresh token in
the macOS Keychain, and reads calendar events only.
On first launch Blaise walks you through:
-
Permissions. macOS prompts for Microphone, System Audio Recording, Calendar (for one-click recording suggestions from upcoming events), and Notifications. Grant them once. Direct Google Calendar can be connected later from Settings and does not replace the local Calendar permission.
-
Identity. Your name, the nicknames people call you in meetings, and your email (used to match you against calendar attendees). Your name is what the action-items section is rendered with.
-
Glossary — point your agent at it. This is the novel bit. Blaise keeps a
Glossary.mdin its data folder that teaches it the names it will hear: people, companies, products, projects. The file is self-describing — its header is a set of instructions addressed to an AI agent:You are filling in a speech-recognition glossary for your user. Add one line per name under the
## Entriesheading, in the formatCanonical Name | misheard1 | misheard2…Open Settings → Glossary, press Copy agent prompt, and hand that prompt to Claude, ChatGPT, or your Obsidian agent pointed at the file. The agent fills in your contacts, org chart, and project vocabulary from your own context, and Blaise uses it to fix misheard words in transcripts and spell names correctly in notes. You can also edit entries directly in the Settings table. The shipped glossary is empty (instruction header plus commented examples) — it never corrects anyone's transcript until you fill it in.
┌──────────────────────┐ ┌────────────────────┐
audio ──▶ │ Live capture │ │ Chrome extension │
(system │ (CoreAudio tap+mic, │ │ (Meet roster + │
+ mic) │ two crash-safe │ │ speaking times, │
│ tracks) │ │ localhost, AEAD) │
└──────────┬───────────┘ └─────────┬──────────┘
│ │
▼ ▼
┌──────────────────────────────────────────────────────┐
│ Processing pipeline (BlaiseCore) │
│ ASR → diarization → speaker merge/resolve → │
│ vocabulary correction → dominant language → │
│ notes synthesis → finalize + enqueue handoff │
└──────────┬───────────────────────────────┬───────────┘
│ │
▼ ▼
┌────────────────────┐ ┌────────────────────────┐
│ Local store │ │ Handoff queue │
│ (SQLite/GRDB, │ │ (content-addressed │
│ FTS5 search, │ │ JSON payload → │
│ per-meeting │ │ local folder or SSH, │
│ files) │ │ queue-and-retry) │
└────────────────────┘ └────────────────────────┘
│
▼
┌────────────────────┐
│ App UI (SwiftUI): │
│ library, detail, │
│ search, settings │
└────────────────────┘
Each subsystem has a spec under specs/ — they document current
behaviour and are the best entry point for contributors:
specs/c1_scaffold_storage.md— storage, schema, file layoutspecs/c2_engine_interfaces.md— the swappable ASR/summarization engine seamsspecs/c3_asr_engines.md— Whisper and Parakeet transcription enginesspecs/c4_diarization.md— speaker diarizationspecs/c5_vocab_correction.md— glossary-driven vocabulary correctionspecs/c6_notes_synthesis.md— notes synthesis (cloud and local engines)specs/c7_pipeline.md— the end-to-end processing pipelinespecs/c8_handoff_queue.md— the queue-and-retry handoffspecs/c10_app_shell.md— the SwiftUI app shellspecs/c11_live_capture.md— two-track live capturespecs/c12_meet_extension.md— the Google Meet extensionspecs/c14_recording_automation.md— start/stop recording automationspecs/g1_user_glossary.md— the agent-fillable glossary
Contributions are welcome. See CONTRIBUTING.md for how to build, run the tests, and open a pull request. One thing to know up front, because it is the project's bar: tests must pass by their exit code, and they are never weakened or gamed to go green. Environment-gated tests (real audio hardware, API keys, heavyweight models) skip cleanly and record their reason rather than silently passing.
MIT.
Blaise's own code is MIT. The one exception is the test audio fixture
under fixtures/icsi_sample/ (and the speech-recognition and diarization JSON
derived from it): that is third-party material from the ICSI Meeting Corpus,
licensed under Creative Commons Attribution 4.0 (CC BY 4.0), not under the
project's MIT licence. See fixtures/icsi_sample/ATTRIBUTION.md
for the attribution that must be preserved on redistribution.
- FluidAudio (Apache-2.0) — Parakeet TDT v3 CoreML ASR runtime.
- GRDB.swift (MIT) — SQLite persistence.
- swift-markdown (Apache-2.0) — Markdown parsing for the PDF export.
- Pow (MIT) — UI micro-interactions.
- uv (MIT/Apache-2.0) — vendored binary that provisions the app-managed Python environment for the Whisper engine (mlx-whisper, MIT).

0 comments
log in to comment.