Meeting Scribe is a desktop app for turning meetings, calls, interviews, and spoken sessions into a live transcript that can immediately be reused by an assistant.
It is built for the moments where taking notes gets in the way of listening. You start a session, capture microphone and system audio, watch the transcript appear, and ask an assistant to summarize, extract decisions, find risks, or answer questions from the current conversation context.
The app runs as an Electron desktop shell with a React UI and a local Python backend. Audio capture, speech recognition, diarization support, transcript storage, and assistant orchestration happen on the user's machine.
Meeting Scribe is meant to make spoken work easier to review and act on:
- keep a readable live transcript while a conversation is still happening;
- capture microphone, system audio, or selected app/process audio;
- use faster local ASR profiles for real-time work or heavier profiles for quality;
- preserve transcript artifacts for later review;
- ask an assistant for summaries, action items, follow-up drafts, or checks against the transcript;
- support local-first workflows where audio and transcript data should not have to leave the machine by default.
Typical use cases include product calls, support sessions, interviews, demos, research conversations, planning meetings, and long technical discussions where details matter after the call ends.
flowchart TD
User[User starts a session]
UI[React desktop UI]
IPC[Electron IPC bridge]
Backend[Python backend<br/>session controller]
subgraph Capture["Audio capture"]
Mic[Microphone]
System[System loopback]
Process[Selected app / process audio]
Engine[Audio engine<br/>mixing, meters, optional recording tap]
VAD[Voice activity detection<br/>speech windows and silence trimming]
end
subgraph ASR["Transcription"]
Profile[ASR profile<br/>Ultra Fast / Realtime / Balanced / Quality]
Decoder[faster-whisper / streaming backend]
Segment[Timestamped ASR segments<br/>text, start, end, source]
end
subgraph Speakers["Speaker labeling"]
Diar[Diarization runtime<br/>speaker embeddings and assignments]
Match[Overlap-aware speaker matcher<br/>keeps quality chunk tails from rewriting old lines]
Identity[Speaker identity store<br/>known profiles and display names]
end
subgraph Transcript["Working transcript"]
Lines[Transcript timeline<br/>stable line ids, timestamps, sources, speaker labels]
Store[Session artifacts<br/>human log, jsonl, srt, wav when enabled]
Context[Assistant context<br/>current transcript snapshot]
end
User --> UI --> IPC --> Backend
Backend --> Engine
Mic --> Engine
System --> Engine
Process --> Engine
Engine --> VAD --> Profile --> Decoder --> Segment --> Lines
Segment --> Diar --> Match --> Lines
Identity --> Match
Lines --> UI
Lines --> Store
Lines --> Context
The main idea is that transcription and speaker labeling are related but separate. ASR produces timestamped text lines first. Diarization then updates speaker labels by matching speaker events back onto the transcript timeline, instead of owning the transcript text itself. The assistant reads the current transcript snapshot as context; it does not sit in the audio path.
The project is split into a desktop shell, renderer UI, and Python backend:
frontend/electron/- Electron main process, preload bridge, IPC handlers, dev runner, and renderer URL helpers.frontend/renderer/- React application, settings UI, transcript view, assistant panel, and frontend tests.backend/main_electron_backend.py- backend entrypoint used by Electron.backend/src/- audio capture, ASR orchestration, diarization, transcript domain logic, assistant providers, model management, and runtime configuration.tests/- Python backend tests.tools/- release helpers, coverage script, and standalone utilities such as batch transcription.docs/PROJECT_MAP.md- compact map for agents and contributors.docs/TESTING.md- testing commands, coverage notes, and test layout.
Electron owns the desktop lifecycle and user-facing IPC surface. The React renderer owns interaction state and presentation. The Python backend owns the actual work: audio, models, transcripts, assistant calls, and persistence.
Assistant profiles can target several provider types:
codex- Codex CLI with the configured command, model, reasoning effort, and optional proxy.ollama- Ollama HTTP API, defaulting tohttp://127.0.0.1:11434.openai_local- OpenAI-compatible local HTTP API, defaulting tohttp://127.0.0.1:1234/v1for tools such as LM Studio or llama.cpp server.local- in-process GGUF model runner throughllama-cpp-python.
Each profile can keep its own model settings. The assistant uses the current transcript as context, so the same transcript can be summarized, questioned, checked for action items, or transformed into follow-up text without manually copying it out of the app.
Install Node dependencies:
npm installInstall Python dependencies for the backend according to your environment, then add development-only test tooling when needed:
pip install -r requirements/requirements-dev.txtStart the full desktop app:
npm run devThe dev runner chooses a free renderer port when the default one is busy and passes the selected URL to Electron. You can still run parts separately:
npm run dev:renderer # React renderer only
npm run dev:electron # Electron shell when Vite is already runningRuntime files are stored in .local/. Local model and cache files live under models/.
Run the full test suite:
npm testRun frontend or coverage checks separately:
npm run test:frontend
npm run test:coverage:frontend
npm run test:coverage:backendMore detail lives in docs/TESTING.md.
Build the renderer:
npm run buildBuild a local Windows package:
npm run package:winRelease archives are built by GitHub Actions when a v* tag is pushed. The current release targets are:
- Windows x64
- Linux x64
- macOS x64