Skip to content

jonsch1/capture

Repository files navigation

Quick Capture

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.

Requirements

  • macOS 14+
  • Swift 6 toolchain (Xcode 16+ / command-line tools)

Build & run

# 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 run

The 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.

Default hotkeys

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.

Capture — the living note

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.

Classification (optional, needs an OpenRouter API key)

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.

Architecture

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/

Persistence

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.

Why annotations still exist in memory

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.

The classification pipeline

  1. Heuristics — immediate, offline, synchronous after insert. Regex URLs, domain detection, to-do patterns.
  2. LLM — on-demand OpenRouter chat completion; JSON-only prompt over the user-editable taxonomy; closed label set.

Tests

swift test

Covers 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.

v1 non-goals

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.

About

No description, website, or topics provided.

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

No releases published

Packages

 
 
 

Contributors