mcowger/olive2

Python

1

77 commits

updated Oct 14, 2026

See the code

README

Olive

Self-hosted meeting transcription, speaker diarization, and audio archive

Ingests audio from Plaud hardware recorders, iOS Voice Memos, and browser uploads. Runs local or cloud transcription, matches speakers across meetings with neural voiceprints, and generates Markdown summaries from prompt templates.

Python FastAPI TypeScript React TailwindCSS SQLite pyannote.audio WeSpeaker Cohere Transcribe Docker


Olive Meeting Detail View

Features

FeatureDescription
Multi-source audio ingestionUpload .m4a, .mp3, .wav, .aac, .ogg, .flac, .webm with SHA-256 deduplication and optional auto-transcription.
Plaud Note integrationOAuth 2.0 PKCE sync with Plaud Cloud. Polls in the background for recordings, transcripts, and AI notes.
Apple Voice Memos shortcutOne-tap iOS Share-Sheet shortcut to upload recordings directly from iPhone or iPad.
Dual transcription pipelineLocal neural STT (Cohere Transcribe 03-2026 INT8 ONNX + CTC forced alignment) or cloud Speechmatics.
Speaker diarization & voiceprintsLocal pyannote.audio (speaker-diarization-community-1) + WeSpeaker ResNet293-LM 256-dim embeddings for cross-meeting speaker recognition.
Multi-provider LLM summariesPowered by any-llm and the models.dev catalog. Works with Gemini, Claude, OpenAI, Groq, OpenRouter, Ollama, or custom OpenAI-compatible proxies.
Summary templatesPrompt templates (Executive Summary, 1-on-1 Catchup, Technical Architecture & Design Review, Action Items & Decisions) with {{title}}, {{date}}, {{speakers}}, and {{transcript}} variables.
System & job logsStreaming log viewer with category filters, severity levels (DEBUG to ERROR), and JSON detail inspection.
Backup & restoreSingle-click .tar.gz export and restore containing the SQLite snapshot, settings, speaker clips, transcripts, summaries, and raw audio files.

Screenshots

Meeting archive & detail view

Olive Meetings Dashboard

Meetings dashboard with full-text search across titles, tags, transcripts, and summaries.


Meeting Detail with Audio and Summary

Meeting detail view with seekable audio player, speaker assignment pills, and Markdown summaries.


LLM provider & local ASR settings

LLM Provider and ASR Settings

Model catalog, reasoning/thinking level config, Hugging Face token, and diarization/voiceprint thresholds.


Ingestion & Plaud sync

Upload Audio Recording
Direct audio upload with auto-transcribe toggle and engine selector.
Plaud Device Sync
Plaud Cloud OAuth 2.0 PKCE login and background sync.

Summary templates, logs & backups

Summary Prompt Templates

System and Job Logs

Backup and Restore

Architecture

SOURCES                           PIPELINE & ARTIFACT STORE                       INTELLIGENCE & EXPORT
───────                           ─────────────────────────                       ─────────────────────

 [ Plaud Note AI ] ──(OAuth/PCS)─┐
                                 │      ┌─────────────────────────────┐
 [ iOS Shortcut ]  ──(Ingest)───┼────► │   Meeting Aggregate Root    │
                                 │      │  ─────────────────────────  │
 [ Web UI Upload ] ──(Upload)───┘      │  • sha256 deduplicated      │
                                        │  • audio/<id>.<ext>         │
                                        │  • SQLite metadata + WAL    │
                                        └──────────────┬──────────────┘
                                                       │
                                 ┌─────────────────────┴─────────────────────┐
                                 ▼                                           ▼
                    ┌─────────────────────────┐                 ┌─────────────────────────┐
                    │     Transcription &     │                 │   LLM Summarization &   │
                    │   Speaker Diarization   │                 │      Meeting Chat       │
                    │ ─────────────────────── │                 │ ─────────────────────── │
                    │ • Cohere Transcribe INT8│                 │ • any-llm + models.dev  │
                    │ • MMS CTC Forced Aligner│                 │ • Gemini / Claude / GPT │
                    │ • pyannote community-1  │                 │ • Local Ollama / vLLM   │
                    │ • WeSpeaker ResNet293   │                 │ • Structured Templates  │
                    │ • Cloud: Speechmatics   │                 │ • Read-only /mcp Server │
                    └─────────────────────────┘                 └─────────────────────────┘
                                 │                                           │
                                 └─────────────────────┬─────────────────────┘
                                                       │
                                                       ▼
                                        ┌─────────────────────────────┐
                                        │     React 19 + Vite SPA     │
                                        │  Markdown • Audio • Backup  │
                                        └─────────────────────────────┘

The multi-arch image (linux/amd64, linux/arm64) is the primary way to run Olive. On first start it downloads ~4.5 GB of local speech models (WeSpeaker, MMS aligner, pyannote diarization, Cohere Transcribe INT8) into a persistent models volume, then starts the server. Model downloads survive upgrades because they live on the volume, not in the image.

# Pull and start (mounts required: olive_data for meetings/DB, olive_models for ML models)
HF_TOKEN=hf_... OLIVE_MCP_TOKEN=... docker compose up -d

# Or with plain docker run:
docker run -d \
  --name olive \
  -p 4471:4470 \
  -e HF_TOKEN=hf_... \
  -e OLIVE_MCP_TOKEN=... \
  -v olive_data:/app/data \
  -v olive_models:/app/models \
  --restart unless-stopped \
  ghcr.io/mcowger/olive:latest

Open http://localhost:4471. Follow the logs on first start (docker logs -f olive) — model downloads take several minutes.

The server refuses to start if /app/models is not a mounted, writable volume, or if a model cannot be downloaded — the error message says why. Do not skip the olive_models mount: without it, every upgrade would re-download gigabytes of models.

Local installation (advanced)

Requires uv (Python 3.12+), pnpm (Node.js 22+), ffmpeg, and libsndfile1.

# 1. Clone the repository
git clone https://github.com/mcowger/olive.git
cd olive

# 2. Install Python backend dependencies
cd backend && uv sync && cd ..

# 3. Pre-download local speech, diarization, alignment & voiceprint models
cd backend && uv run olive models download && cd ..

# 4. Install and build the React frontend
cd frontend && pnpm install && pnpm run build && cd ..

# 5. Start the server
cd backend && uv run olive serve

Open http://localhost:4471.


Configuration & environment variables

Olive stores runtime settings in <configDir>/settings.json and accepts environment variables for bootstrap and secrets:

VariableDefaultDescription
PORT / OLIVE_BIND_PORT4471HTTP server port
OLIVE_BIND_HOST127.0.0.1Bind address (0.0.0.0 in Docker)
OLIVE_CONFIG_DIR~/.config/oliveDirectory for olive.sqlite, settings.json, and speaker clips (~/Library/Application Support/olive on macOS)
OLIVE_MEETINGS_DIR<configDir>/meetingsStorage directory for meeting folders (audio/, transcripts/, summaries/)
OLIVE_MODELS_DIR<configDir>/models (/app/models in Docker)Cache directory for local Hugging Face and ONNX models. In Docker this must be a mounted persistent volume — the server exits if it isn't mounted or writable
HF_TOKEN(optional)Hugging Face token for gated pyannote models (overrides hfToken in Settings UI)
OLIVE_INGEST_TOKEN(optional)Bearer token required for POST /api/ingest
OLIVE_MCP_TOKEN(optional)Bearer token for /mcp; falls back to OLIVE_INGEST_TOKEN and is required for non-loopback binds
PLAUD_TOKEN_PATH<configDir>/plaud-tokens.jsonOAuth token file for Plaud Cloud (migrates ~/.plaud/tokens.json automatically if present)
SPEECHMATICS_API_KEY(optional)API key for Speechmatics cloud batch transcription
SPEECHMATICS_WEBHOOK_SECRET(optional)Shared secret for POST /api/webhooks/speechmatics

MCP endpoint

Olive exposes a read-only Model Context Protocol server at /mcp on the main HTTP port (list_meetings, get_meeting, search_transcripts, get_action_items, list_speakers, get_speaker_profile).

Loopback clients can connect without a token. Set OLIVE_MCP_TOKEN (or OLIVE_INGEST_TOKEN) when binding to a non-loopback interface.

{
  "mcpServers": {
    "olive": {
      "url": "http://127.0.0.1:4471/mcp",
      "headers": {
        "Authorization": "Bearer ${OLIVE_MCP_TOKEN}"
      }
    }
  }
}

Integrations

1. Apple Voice Memos (iOS Shortcut)

  1. Open Shortcuts on iOS and create a new shortcut.
  2. Set Receive: Audio and Files from the Share Sheet.
  3. Add Get Contents of URL:
    • URL: https://<your-olive-host>/api/ingest
    • Method: POST
    • Headers: Authorization: Bearer <YOUR_OLIVE_INGEST_TOKEN>
    • Request Body: Form (file = Shortcut Input, autoTranscribe = true, source = ios-shortcut)

2. Plaud Note & Plaud Cloud

  1. Click Plaud in the top navigation bar.
  2. Click Start Login, authorize in your browser, and paste the callback URL.
  3. Olive polls Plaud Cloud in the background and imports recordings, transcripts, and AI notes.

Backup & restore

  • Web UI: Open the Backup tab to download a .tar.gz archive, save a snapshot on the server, or upload an archive to restore.
  • CLI:
    cd backend && uv run olive backup ./my-backup.tar.gz
    cd backend && uv run olive restore ./my-backup.tar.gz
    

Development

# Start backend with live reload
cd backend && uv run uvicorn olive.main:app --reload --port 4471

# Start Vite dev server (proxies /api and /mcp to http://127.0.0.1:4471)
cd frontend && pnpm run dev

# Lint, typecheck, and run backend tests
cd backend && uv run ruff check src tests eval && uv run basedpyright && uv run pytest

# Export OpenAPI schema, regenerate frontend TS types, typecheck, and build
cd backend && uv run python -c "import json; from olive.app import export_openapi_schema; open('openapi.json', 'w').write(json.dumps(export_openapi_schema(), indent=2) + '\n')"
cd ../frontend && pnpm run generate:api && pnpm run typecheck && pnpm run build

License

MIT © Matt Cowger

mcowger/olive2

Python

1

77 commits

updated Oct 14, 2026

See the code

README

Olive

Self-hosted meeting transcription, speaker diarization, and audio archive

Ingests audio from Plaud hardware recorders, iOS Voice Memos, and browser uploads. Runs local or cloud transcription, matches speakers across meetings with neural voiceprints, and generates Markdown summaries from prompt templates.

Python FastAPI TypeScript React TailwindCSS SQLite pyannote.audio WeSpeaker Cohere Transcribe Docker


Olive Meeting Detail View

Features

FeatureDescription
Multi-source audio ingestionUpload .m4a, .mp3, .wav, .aac, .ogg, .flac, .webm with SHA-256 deduplication and optional auto-transcription.
Plaud Note integrationOAuth 2.0 PKCE sync with Plaud Cloud. Polls in the background for recordings, transcripts, and AI notes.
Apple Voice Memos shortcutOne-tap iOS Share-Sheet shortcut to upload recordings directly from iPhone or iPad.
Dual transcription pipelineLocal neural STT (Cohere Transcribe 03-2026 INT8 ONNX + CTC forced alignment) or cloud Speechmatics.
Speaker diarization & voiceprintsLocal pyannote.audio (speaker-diarization-community-1) + WeSpeaker ResNet293-LM 256-dim embeddings for cross-meeting speaker recognition.
Multi-provider LLM summariesPowered by any-llm and the models.dev catalog. Works with Gemini, Claude, OpenAI, Groq, OpenRouter, Ollama, or custom OpenAI-compatible proxies.
Summary templatesPrompt templates (Executive Summary, 1-on-1 Catchup, Technical Architecture & Design Review, Action Items & Decisions) with {{title}}, {{date}}, {{speakers}}, and {{transcript}} variables.
System & job logsStreaming log viewer with category filters, severity levels (DEBUG to ERROR), and JSON detail inspection.
Backup & restoreSingle-click .tar.gz export and restore containing the SQLite snapshot, settings, speaker clips, transcripts, summaries, and raw audio files.

Screenshots

Meeting archive & detail view

Olive Meetings Dashboard

Meetings dashboard with full-text search across titles, tags, transcripts, and summaries.


Meeting Detail with Audio and Summary

Meeting detail view with seekable audio player, speaker assignment pills, and Markdown summaries.


LLM provider & local ASR settings

LLM Provider and ASR Settings

Model catalog, reasoning/thinking level config, Hugging Face token, and diarization/voiceprint thresholds.


Ingestion & Plaud sync

Upload Audio Recording
Direct audio upload with auto-transcribe toggle and engine selector.
Plaud Device Sync
Plaud Cloud OAuth 2.0 PKCE login and background sync.

Summary templates, logs & backups

Summary Prompt Templates

System and Job Logs

Backup and Restore

Architecture

SOURCES                           PIPELINE & ARTIFACT STORE                       INTELLIGENCE & EXPORT
───────                           ─────────────────────────                       ─────────────────────

 [ Plaud Note AI ] ──(OAuth/PCS)─┐
                                 │      ┌─────────────────────────────┐
 [ iOS Shortcut ]  ──(Ingest)───┼────► │   Meeting Aggregate Root    │
                                 │      │  ─────────────────────────  │
 [ Web UI Upload ] ──(Upload)───┘      │  • sha256 deduplicated      │
                                        │  • audio/<id>.<ext>         │
                                        │  • SQLite metadata + WAL    │
                                        └──────────────┬──────────────┘
                                                       │
                                 ┌─────────────────────┴─────────────────────┐
                                 ▼                                           ▼
                    ┌─────────────────────────┐                 ┌─────────────────────────┐
                    │     Transcription &     │                 │   LLM Summarization &   │
                    │   Speaker Diarization   │                 │      Meeting Chat       │
                    │ ─────────────────────── │                 │ ─────────────────────── │
                    │ • Cohere Transcribe INT8│                 │ • any-llm + models.dev  │
                    │ • MMS CTC Forced Aligner│                 │ • Gemini / Claude / GPT │
                    │ • pyannote community-1  │                 │ • Local Ollama / vLLM   │
                    │ • WeSpeaker ResNet293   │                 │ • Structured Templates  │
                    │ • Cloud: Speechmatics   │                 │ • Read-only /mcp Server │
                    └─────────────────────────┘                 └─────────────────────────┘
                                 │                                           │
                                 └─────────────────────┬─────────────────────┘
                                                       │
                                                       ▼
                                        ┌─────────────────────────────┐
                                        │     React 19 + Vite SPA     │
                                        │  Markdown • Audio • Backup  │
                                        └─────────────────────────────┘

The multi-arch image (linux/amd64, linux/arm64) is the primary way to run Olive. On first start it downloads ~4.5 GB of local speech models (WeSpeaker, MMS aligner, pyannote diarization, Cohere Transcribe INT8) into a persistent models volume, then starts the server. Model downloads survive upgrades because they live on the volume, not in the image.

# Pull and start (mounts required: olive_data for meetings/DB, olive_models for ML models)
HF_TOKEN=hf_... OLIVE_MCP_TOKEN=... docker compose up -d

# Or with plain docker run:
docker run -d \
  --name olive \
  -p 4471:4470 \
  -e HF_TOKEN=hf_... \
  -e OLIVE_MCP_TOKEN=... \
  -v olive_data:/app/data \
  -v olive_models:/app/models \
  --restart unless-stopped \
  ghcr.io/mcowger/olive:latest

Open http://localhost:4471. Follow the logs on first start (docker logs -f olive) — model downloads take several minutes.

The server refuses to start if /app/models is not a mounted, writable volume, or if a model cannot be downloaded — the error message says why. Do not skip the olive_models mount: without it, every upgrade would re-download gigabytes of models.

Local installation (advanced)

Requires uv (Python 3.12+), pnpm (Node.js 22+), ffmpeg, and libsndfile1.

# 1. Clone the repository
git clone https://github.com/mcowger/olive.git
cd olive

# 2. Install Python backend dependencies
cd backend && uv sync && cd ..

# 3. Pre-download local speech, diarization, alignment & voiceprint models
cd backend && uv run olive models download && cd ..

# 4. Install and build the React frontend
cd frontend && pnpm install && pnpm run build && cd ..

# 5. Start the server
cd backend && uv run olive serve

Open http://localhost:4471.


Configuration & environment variables

Olive stores runtime settings in <configDir>/settings.json and accepts environment variables for bootstrap and secrets:

VariableDefaultDescription
PORT / OLIVE_BIND_PORT4471HTTP server port
OLIVE_BIND_HOST127.0.0.1Bind address (0.0.0.0 in Docker)
OLIVE_CONFIG_DIR~/.config/oliveDirectory for olive.sqlite, settings.json, and speaker clips (~/Library/Application Support/olive on macOS)
OLIVE_MEETINGS_DIR<configDir>/meetingsStorage directory for meeting folders (audio/, transcripts/, summaries/)
OLIVE_MODELS_DIR<configDir>/models (/app/models in Docker)Cache directory for local Hugging Face and ONNX models. In Docker this must be a mounted persistent volume — the server exits if it isn't mounted or writable
HF_TOKEN(optional)Hugging Face token for gated pyannote models (overrides hfToken in Settings UI)
OLIVE_INGEST_TOKEN(optional)Bearer token required for POST /api/ingest
OLIVE_MCP_TOKEN(optional)Bearer token for /mcp; falls back to OLIVE_INGEST_TOKEN and is required for non-loopback binds
PLAUD_TOKEN_PATH<configDir>/plaud-tokens.jsonOAuth token file for Plaud Cloud (migrates ~/.plaud/tokens.json automatically if present)
SPEECHMATICS_API_KEY(optional)API key for Speechmatics cloud batch transcription
SPEECHMATICS_WEBHOOK_SECRET(optional)Shared secret for POST /api/webhooks/speechmatics

MCP endpoint

Olive exposes a read-only Model Context Protocol server at /mcp on the main HTTP port (list_meetings, get_meeting, search_transcripts, get_action_items, list_speakers, get_speaker_profile).

Loopback clients can connect without a token. Set OLIVE_MCP_TOKEN (or OLIVE_INGEST_TOKEN) when binding to a non-loopback interface.

{
  "mcpServers": {
    "olive": {
      "url": "http://127.0.0.1:4471/mcp",
      "headers": {
        "Authorization": "Bearer ${OLIVE_MCP_TOKEN}"
      }
    }
  }
}

Integrations

1. Apple Voice Memos (iOS Shortcut)

  1. Open Shortcuts on iOS and create a new shortcut.
  2. Set Receive: Audio and Files from the Share Sheet.
  3. Add Get Contents of URL:
    • URL: https://<your-olive-host>/api/ingest
    • Method: POST
    • Headers: Authorization: Bearer <YOUR_OLIVE_INGEST_TOKEN>
    • Request Body: Form (file = Shortcut Input, autoTranscribe = true, source = ios-shortcut)

2. Plaud Note & Plaud Cloud

  1. Click Plaud in the top navigation bar.
  2. Click Start Login, authorize in your browser, and paste the callback URL.
  3. Olive polls Plaud Cloud in the background and imports recordings, transcripts, and AI notes.

Backup & restore

  • Web UI: Open the Backup tab to download a .tar.gz archive, save a snapshot on the server, or upload an archive to restore.
  • CLI:
    cd backend && uv run olive backup ./my-backup.tar.gz
    cd backend && uv run olive restore ./my-backup.tar.gz
    

Development

# Start backend with live reload
cd backend && uv run uvicorn olive.main:app --reload --port 4471

# Start Vite dev server (proxies /api and /mcp to http://127.0.0.1:4471)
cd frontend && pnpm run dev

# Lint, typecheck, and run backend tests
cd backend && uv run ruff check src tests eval && uv run basedpyright && uv run pytest

# Export OpenAPI schema, regenerate frontend TS types, typecheck, and build
cd backend && uv run python -c "import json; from olive.app import export_openapi_schema; open('openapi.json', 'w').write(json.dumps(export_openapi_schema(), indent=2) + '\n')"
cd ../frontend && pnpm run generate:api && pnpm run typecheck && pnpm run build

License

MIT © Matt Cowger