Quick multi-modal note capture with LLM-powered titles and tags.
Captures ideas as timestamped markdown notes from text, voice, images, PDFs, or an iOS staging folder. Uses Ollama for smart title generation, auto-tagging, and serendipitous note connections.
# Option 1: symlink (simplest)
ln -s /path/to/capture/capture ~/.local/bin/capture
# Option 2: pipx
pipx install .
# Option 3: pip editable
pip install -e .Required: Python 3.9+
Optional:
- Ollama + a model (e.g.
ollama pull phi3:mini) -- smart titles and tags - Whisper -- voice transcription
- PyObjC -- Apple Vision OCR (macOS only)
- tesseract -- OCR fallback
- fzf -- interactive destination picker
- SoX (
rec) or ffmpeg -- voice recording - PyYAML -- config file support
Without Ollama, titles fall back to first-line truncation and tags are skipped. Without PyYAML, built-in defaults are used. Everything degrades gracefully.
capture # Interactive menu
capture quick "idea" # One-liner capture
capture text # Open editor for longer text
capture photo image.jpg # OCR from image
capture voice # Record and transcribe
capture voice --multi # Record multiple notes with pipelined transcription
capture process # Process staging folder (from iOS Shortcuts)--dest, -d PATH Save notes to a specific directory
--config PATH Use a specific config file
--init-config Generate default config at ~/.config/capture/config.yaml
Capture works out of the box with no config file. To customize:
capture --init-config # Creates ~/.config/capture/config.yamlOr copy config.example.yaml to ~/.config/capture/config.yaml and edit.
Each pipeline stage picks its own backend — local models, cloud APIs, or disabled:
| Stage | Mac default | iOS default (future) |
|---|---|---|
transcription |
whisper_local |
gemini_flash |
ocr |
apple_vision |
apple_vision |
title |
ollama_local |
gemini_flash |
tags |
ollama_local |
gemini_flash |
correction |
ollama_local |
disabled |
connections |
keyword |
keyword |
Available backends per stage:
- transcription:
whisper_local,gemini_flash,disabled - ocr:
apple_vision,tesseract,disabled - title:
ollama_local,gemini_flash,truncate,disabled - tags:
ollama_local,gemini_flash,disabled - correction:
ollama_local,gemini_flash,claude,disabled
API keys use env:VAR_NAME in config (e.g. api_key: env:GOOGLE_API_KEY).
The legacy llm: config block is still honored and merged into provider settings.
- Environment variables (
OLLAMA_MODEL,EDITOR,CAPTURE_METIS) - Config file (
$CAPTURE_CONFIGenv var, or~/.config/capture/config.yaml) - Built-in defaults
See config.example.yaml for the full provider schema. Minimal example:
notes_dir: ~/Notes
capture_dir: ~/Notes/_capture-staging
providers:
transcription:
default: whisper_local
title:
default: ollama_local
correction:
default: claude
claude:
model: claude-sonnet-4-20250514
api_key: env:ANTHROPIC_API_KEY
defaults:
tags:
- "[[kernel]]"
- "[[captured]]"
metis:
serendipity_age_days: 30
max_connections: 3
max_keywords: 10Uses Ollama to generate concise 3-8 word titles. Falls back to first-line truncation for short content or when Ollama is unavailable.
- Auto-tags: LLM-suggested tags added alongside base tags
- Connection finder: Surfaces related notes based on keyword overlap
- Serendipity: Shows a random old note for unexpected inspiration
Disable with export CAPTURE_METIS=false or set llm.enable_metis: false in config.
Custom vocabulary and post-processing corrections for voice transcription. Create a YAML file:
prompt_vocab:
- Diffie-Hellman
- cypherpunk
- Zimmermann
corrections:
"Zimmerman": "Zimmermann"
"cypher punk": "cypherpunk"Point to it with whisper_dictionary in config, or place whisper-dictionary.yaml next to your notes directory.
| Model | Size | Speed | Quality |
|---|---|---|---|
| phi3:mini | 1.9GB | 2-4s | Excellent titles, rich tags |
| gemma2:2b | 1.6GB | 1.6-2s | Concise titles, fewer tags |
| llama3.2:1b | 1.3GB | 40s | Frequent timeouts |
| llama3.1:latest | 4.9GB | 20s+ | Too slow |
The tool warms up Ollama in the background while you type, so the model is ready when needed.
Create iOS Shortcuts that save to the staging folder, then process with capture process.
- Ask for Input (Question: "What's your idea?", Type: Text)
- Save File to
iCloud Drive/Notes/_capture-staging/Text-[Current Date].txt
- Record Audio (Start: Immediately, Finish: On Tap)
- Save File to
iCloud Drive/Notes/_capture-staging/Voice-[Current Date].m4a
- Scan Document (uses VisionKit scanner with edge detection)
- Save File to
iCloud Drive/Notes/_capture-staging/Scan-[Current Date].pdf
capture processTranscribes audio with Whisper, OCRs images and PDFs with Apple Vision, creates notes with smart titles, and sends a macOS notification when complete.
capture/
├── cli.py # CLI entry point
├── core/
│ ├── config.py # Config + provider defaults
│ ├── pipeline.py # Extract → refine → enrich orchestration
│ ├── note.py # Note formatting and Metis display
│ ├── vocabulary.py # Whisper dictionary helpers
│ └── prompts/ # Shared prompt templates
├── providers/
│ ├── registry.py # Per-stage provider resolution
│ ├── transcription/ # whisper_local, gemini_flash
│ ├── ocr/ # apple_vision, tesseract
│ ├── enrich/ # ollama_local, gemini_flash, truncate
│ ├── refine/ # ollama_local, gemini_flash, claude
│ └── connections/ # keyword search
└── platforms/
├── mac.defaults.yaml
└── ios.defaults.yaml
CLI: capture quick/text/voice/photo ──▶ ~/Notes/ (timestamped .md)
iOS:
┌─────────────┐ ┌──────────────────┐ ┌──────────────┐
│ iPhone │ │ _capture-staging/ │ │ ~/Notes/ │
│ Shortcuts │ ──▶ │ (iCloud sync) │ ──▶ │ Kernel notes │
└─────────────┘ └──────────────────┘ └──────────────┘
│
Apple Vision OCR (images, PDFs)
Whisper (voice transcription)
Ollama (title generation, tagging)
MIT