{"id":44812833,"url":"https://github.com/paberr/ownscribe","last_synced_at":"2026-02-24T01:19:16.813Z","repository":{"id":338277271,"uuid":"1156656910","full_name":"paberr/ownscribe","owner":"paberr","description":"Local-first meeting transcription and summarization CLI","archived":false,"fork":false,"pushed_at":"2026-02-16T15:58:01.000Z","size":659,"stargazers_count":1,"open_issues_count":1,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-02-16T22:44:51.548Z","etag":null,"topics":["cli","lmstudio","local-first","macos","meeting-notes","ollama","privacy","transcription","whisper"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/paberr.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":"AGENTS.md","dco":null,"cla":null}},"created_at":"2026-02-12T22:38:05.000Z","updated_at":"2026-02-16T15:57:41.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/paberr/ownscribe","commit_stats":null,"previous_names":["paberr/ownscribe"],"tags_count":8,"template":false,"template_full_name":null,"purl":"pkg:github/paberr/ownscribe","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/paberr%2Fownscribe","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/paberr%2Fownscribe/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/paberr%2Fownscribe/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/paberr%2Fownscribe/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/paberr","download_url":"https://codeload.github.com/paberr/ownscribe/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/paberr%2Fownscribe/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29765748,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-23T21:02:23.375Z","status":"ssl_error","status_checked_at":"2026-02-23T20:58:31.539Z","response_time":90,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["cli","lmstudio","local-first","macos","meeting-notes","ollama","privacy","transcription","whisper"],"created_at":"2026-02-16T17:12:17.605Z","updated_at":"2026-02-24T01:19:16.807Z","avatar_url":"https://github.com/paberr.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# ownscribe\n\n[![PyPI](https://img.shields.io/pypi/v/ownscribe)](https://pypi.org/project/ownscribe/)\n[![CI](https://github.com/paberr/ownscribe/actions/workflows/ci.yml/badge.svg)](https://github.com/paberr/ownscribe/actions/workflows/ci.yml)\n[![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)\n[![Python 3.12+](https://img.shields.io/badge/python-3.12+-blue.svg)](https://www.python.org/downloads/)\n\nLocal-first meeting transcription and summarization CLI.\nRecord, transcribe, and summarize meetings and system audio entirely on your machine – no cloud, no bots, no data leaving your device.\n\n\u003e System audio capture requires **macOS 14.2 or later**. Other platforms can use the sounddevice backend with an external audio source.\n\n## Privacy\n\nownscribe **does not**:\n\n- send audio to external servers\n- upload transcripts\n- require cloud APIs\n- store data outside your machine\n\nAll audio, transcripts, and summaries remain local.\n\n\u003c!-- TODO: Add asciinema demo or terminal screenshot here --\u003e\n\n## Features\n\n- **System audio capture** — records all system audio natively via Core Audio Taps (macOS 14.2+), no virtual audio drivers needed\n- **Microphone capture** — optionally record system + mic audio simultaneously with `--mic`\n- **WhisperX transcription** — fast, accurate speech-to-text with word-level timestamps\n- **Speaker diarization** — optional speaker identification via pyannote (requires HuggingFace token)\n- **Pipeline progress** — live checklist showing transcription, diarization sub-steps, and summarization progress\n- **Local LLM summarization** — structured meeting notes via Ollama, LM Studio, or any OpenAI-compatible server\n- **Summarization templates** — built-in presets for meetings, lectures, and quick briefs; define your own in config\n- **Ask your meetings** — ask natural-language questions across all your meeting notes; uses a two-stage LLM pipeline with keyword fallback\n- **One command** — just run `ownscribe`, press Ctrl+C when done, get transcript + summary\n\n## Requirements\n\n- macOS 14.2+ (for system audio capture)\n- Python 3.12+\n- [uv](https://docs.astral.sh/uv/)\n- [ffmpeg](https://ffmpeg.org/) — `brew install ffmpeg`\n- Xcode Command Line Tools (`xcode-select --install`)\n- One of:\n  - [Ollama](https://ollama.ai) — `brew install ollama`\n  - [LM Studio](https://lmstudio.ai)\n  - Any OpenAI-compatible local server\n\nWorks with any app that outputs audio through Core Audio (Zoom, Teams, Meet, etc.).\n\n\u003e **Tip:** Your terminal app (Terminal, iTerm2, VS Code, etc.) needs **Screen Recording** permission to capture system audio.\n\u003e Open the settings panel directly with:\n\u003e ```bash\n\u003e open \"x-apple.systempreferences:com.apple.preference.security?Privacy_ScreenCapture\"\n\u003e ```\n\u003e Enable your terminal app, then restart it.\n\n## Installation\n\n### Quick start with uvx\n\n```bash\nuvx ownscribe\n```\n\nOn macOS, the Swift audio capture helper is downloaded automatically on first run.\n\n### From source\n\n```bash\n# Clone the repo\ngit clone https://github.com/paberr/ownscribe.git\ncd ownscribe\n\n# Build the Swift audio capture helper (optional — auto-downloads if skipped)\nbash swift/build.sh\n\n# Install with transcription support\nuv sync --extra transcription\n\n# Pull a model for summarization (if using Ollama)\nollama pull mistral\n```\n\n## Usage\n\n### Record, transcribe, and summarize a meeting\n\n```bash\nownscribe                    # records system audio, Ctrl+C to stop\n```\n\nThis will:\n1. Capture system audio until you press Ctrl+C\n2. Transcribe with WhisperX\n3. Summarize with your local LLM\n4. Save everything to `~/ownscribe/YYYY-MM-DD_HHMMSS/`\n\nOn first run, WhisperX / pyannote may download model files. ownscribe shows a `Preparing models` step and best-effort download progress in the TUI while this happens.\n\n### Options\n\n```bash\nownscribe --mic                               # capture system audio + default mic (press 'm' to mute/unmute)\nownscribe --mic-device \"MacBook Pro Microphone\" # capture system audio + specific mic\nownscribe --device \"MacBook Pro Microphone\"   # use mic instead of system audio\nownscribe --no-summarize                      # skip LLM summarization\nownscribe --diarize                           # enable speaker identification\nownscribe --language en                        # set transcription language (default: auto-detect)\nownscribe --model large-v3                    # use a larger Whisper model\nownscribe --format json                       # output as JSON instead of markdown\nownscribe --no-keep-recording                 # auto-delete WAV files after transcription\nownscribe --template lecture                  # use the lecture summarization template\n```\n\n### Subcommands\n\n```bash\nownscribe devices                  # list audio devices (uses native CoreAudio when available)\nownscribe apps                     # list running apps with PIDs for use with --pid\nownscribe warmup                   # prefetch WhisperX/pyannote models before a meeting\nownscribe transcribe recording.wav # transcribe an audio file (saves alongside the input)\nownscribe summarize transcript.md  # summarize a transcript (saves alongside the input)\nownscribe resume ./2026-02-20_1736 # resume a failed/partial pipeline in a directory\nownscribe ask \"question\"           # search your meetings with a natural-language question\nownscribe config                   # open config file in $EDITOR\nownscribe cleanup                  # remove ownscribe data from disk\n```\n\nUse `warmup` ahead of time to avoid first-run model download delays while recording:\n\n```bash\nownscribe warmup                    # prefetch Whisper model (+ diarization if enabled in config)\nownscribe warmup --language en      # also prefetch alignment model for English\nownscribe warmup --with-diarization # force diarization warmup for this run\n```\n\n### Searching Meeting Notes\n\nUse `ask` to search across all your meeting notes with natural-language questions:\n\n```bash\nownscribe ask \"What did Anna say about the deadline?\"\nownscribe ask \"budget decisions\" --since 2026-01-01\nownscribe ask \"action items from last week\" --limit 5\n```\n\nThis runs a two-stage pipeline:\n1. **Find** — sends meeting summaries to the LLM to identify which meetings are relevant\n2. **Answer** — sends the full transcripts of relevant meetings to the LLM to produce an answer with quotes\n\nIf the LLM finds no relevant meetings, a keyword fallback searches summaries and transcripts directly.\n\n## Configuration\n\nConfig is stored at `~/.config/ownscribe/config.toml`. Run `ownscribe config` to create and edit it.\n\n```toml\n[audio]\nbackend = \"coreaudio\"     # \"coreaudio\" or \"sounddevice\"\ndevice = \"\"               # empty = system audio\nmic = false               # also capture microphone input\nmic_device = \"\"           # specific mic device name (empty = default)\n\n[transcription]\nmodel = \"base\"            # tiny, base, small, medium, large-v3\nlanguage = \"\"             # empty = auto-detect\n\n[diarization]\nenabled = false\nhf_token = \"\"             # HuggingFace token for pyannote\ntelemetry = false         # allow HuggingFace Hub + pyannote metrics telemetry\ndevice = \"auto\"           # \"auto\" (mps if available), \"mps\", or \"cpu\"\n\n[summarization]\nenabled = true\nbackend = \"ollama\"        # \"ollama\" or \"openai\"\nmodel = \"mistral\"\nhost = \"http://localhost:11434\"\n# template = \"meeting\"    # \"meeting\", \"lecture\", \"brief\", or a custom name\n# context_size = 0        # 0 = auto-detect from model; set manually for OpenAI-compatible backends\n\n# Custom templates (optional):\n# [templates.my-standup]\n# system_prompt = \"You summarize daily standups.\"\n# prompt = \"List each person's update:\\n{transcript}\"\n\n[output]\ndir = \"~/ownscribe\"\nformat = \"markdown\"       # \"markdown\" or \"json\"\nkeep_recording = true     # false = auto-delete WAV after transcription\n```\n\n**Precedence:** CLI flags \u003e environment variables (`HF_TOKEN`, `OLLAMA_HOST`) \u003e config file \u003e defaults.\n\n## Summarization Templates\n\nBuilt-in templates control how transcripts are summarized:\n\n| Template | Best for | Output style |\n|----------|----------|-------------|\n| `meeting` | Meetings, standups, 1:1s | Summary, Key Points, Action Items, Decisions |\n| `lecture` | Lectures, seminars, talks | Summary, Key Concepts, Key Takeaways |\n| `brief` | Quick overviews | 3-5 bullet points |\n\nUse `--template` on the CLI or set `template` in `[summarization]` config. Default is `meeting`.\n\nDefine custom templates in config:\n\n```toml\n[templates.my-standup]\nsystem_prompt = \"You summarize daily standups.\"\nprompt = \"List each person's update:\\n{transcript}\"\n```\n\nThen use with `--template my-standup` or `template = \"my-standup\"` in config.\n\n## Speaker Diarization\n\nSpeaker identification requires a HuggingFace token with access to the pyannote models:\n\n1. Accept the terms for both models on HuggingFace:\n   - [pyannote/speaker-diarization-3.1](https://huggingface.co/pyannote/speaker-diarization-3.1)\n   - [pyannote/segmentation-3.0](https://huggingface.co/pyannote/segmentation-3.0)\n2. Create a token at https://huggingface.co/settings/tokens\n3. Set `HF_TOKEN` env var or add `hf_token` to config\n4. Run with `--diarize`\n\nOn Apple Silicon Macs, diarization automatically uses the Metal Performance Shaders (MPS) GPU backend for ~10x faster processing. Set `device = \"cpu\"` in the `[diarization]` config section to disable this.\n\n## Acknowledgments\n\nownscribe builds on some excellent open-source projects:\n\n- [WhisperX](https://github.com/m-bain/whisperX) — fast speech recognition with word-level timestamps and speaker diarization\n- [faster-whisper](https://github.com/SYSTRAN/faster-whisper) — CTranslate2-based Whisper inference\n- [pyannote.audio](https://github.com/pyannote/pyannote-audio) — speaker diarization\n- [Ollama](https://ollama.ai) — local LLM serving\n- [Click](https://click.palletsprojects.com) — CLI framework\n\n## Contributing\n\nSee [CONTRIBUTING.md](CONTRIBUTING.md) for development setup, tests, and open contribution areas.\n\n## License\n\nMIT\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpaberr%2Fownscribe","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fpaberr%2Fownscribe","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpaberr%2Fownscribe/lists"}