A native macOS menu bar app for frictionless note capture. A global hotkey summons the capture window; everything you type or paste lands in one append-only, never-ending note — the single source of truth. Lightweight heuristics plus on-demand LLM classification organize entries into smart views without ever moving them out of their chronological context.
Guiding principle: the stream is the source of truth. "Folders" are derived queries. All derived data is recomputable from raw text; only your manual corrections are sacred.
- macOS 14+
- Swift 6 toolchain (Xcode 16+ / command-line tools)
# Build a proper LSUIElement menu-bar .app bundle (release)
./Scripts/make_app.sh release
open ./QuickCapture.app
# Or run straight from SwiftPM during development
swift runThe app has no Dock icon — look for the ✏️ icon in the menu bar. Its menu has Capture, Settings, and Quit.
Everything happens in one capture window with three fixed footer sections: Stream, Todo, and Tags. Stream is the editable note itself; a footer toggle swaps it for a read-only two-column table (entry | labels). Todo has Open/Done tabs above the list. Tags has Ideas, Plans, and Other tabs above editable filtered streams.
| Hotkey | Action |
|---|---|
⌥Space |
Toggle the capture window, landing on the editable stream |
⌥⇧Space |
Toggle the capture window in whatever view it was left |
Each hotkey strictly toggles the window (show ↔ hide). It closes only via hotkey or the close button — not on focus loss, not on Escape. Rebind in Settings → Hotkeys.
The stream is one editable text box that holds your whole running note. Type freely; it behaves like a normal text editor (Return just inserts a newline, nothing is ever cleared or locked).
- A blank line is the soft boundary between entries.
- Lists auto-continue: start a line with
-(or*, or- [ ]) and Return starts the next item; Return on an empty item ends the list. A list (consecutive lines, no blank line in between) stays one entry, so it's labelled as a whole — usually a to-do. - Everything stays editable forever. Fixing a typo in an old block updates that entry and clears stale LLM labels; your manual label fixes are preserved.
- The buffer is auto-saved to disk continuously (crash-safe) and reconciled into entries when you pause (~1.5 s), switch views, or hide the window — applying edits, inserts, and deletions while keeping each entry's identity and stream position stable. Reconciliation never invokes an LLM.
In Settings → General, paste an OpenRouter API key (stored in
the macOS Keychain, never on disk). The default provider is groq and the default model is
openai/gpt-oss-120b. Click Classify unclassified entries to classify entries that do
not yet have LLM labels. Classification never runs automatically.
Edit labels and their descriptions in Settings → Taxonomy (descriptions are sent to the model verbatim). After changing the taxonomy, clear prior LLM labels and run classification again.
App (menu bar, always resident, LSUIElement)
├── CaptureWindow — the one window: editable stream / labels table, Todo, Tags, search
├── SettingsWindow — OpenRouter key/model, classification button, taxonomy editor, hotkeys
├── Store — file-backed daily Markdown + TAGS.md
└── ClassifierActor — on-demand OpenRouter classification
| Layer | Files |
|---|---|
| Data model & store | Sources/QuickCapture/Store/ |
| Classification pipeline | Sources/QuickCapture/Classify/ |
| Capture window | Sources/QuickCapture/Capture/ |
| Settings | Sources/QuickCapture/Settings/ |
| App shell & hotkeys | Sources/QuickCapture/App/ |
| Settings / support utilities | Sources/QuickCapture/Support/ |
Files are the source of truth at ~/Documents/capture by default. Change the folder in
Settings → General → Capture folder.
YYYY-MM-DD.md— the readable stream text for that local calendar day. Each entry starts with<!-- id: YYYY-MM-DD-001 tags: todo -->.TAGS.md— the editable label set and descriptions._draft.md— crash-safety mirror of the combined editor buffer.
Blank lines separate entries inside each daily Markdown file. IDs and tags live directly in the Markdown comments, so manual corrections stay visible and editable.
The capture document is split into entries on blank-line boundaries by
Store/Reconciler.swift (a pure, unit-tested LCS diff) and applied by Store.reconcileDraft,
which maps document edits to entry edits/inserts/deletes — preserving entry identity, user
corrections, and stream order.
Annotations are reconstructed from the daily Markdown tags and entry text so existing views can
work with one in-memory shape. The durable state is the tags: comment in each entry.
- Heuristics — immediate, offline, synchronous after insert. Regex URLs, domain detection, to-do patterns.
- LLM — on-demand OpenRouter chat completion; JSON-only prompt over the user-editable taxonomy; closed label set.
swift testCovers heuristics, substring search, label views, user-correction precedence, OpenRouter response parsing (code-fence stripping + closed label set), and the reclassify invariant — deleting LLM annotations and reclassifying reproduces an equivalent organized state from raw text alone.
Sync, multiple devices, and the web client are out of scope. The daily files are intended to be easy to back up and inspect. No rich text; plain text only.