note
June 23, 2026 · View on GitHub
English | 简体中文
A pure Swift CLI for managing Apple Notes. On macOS it reads and writes Apple Notes directly through AppleScript; on Linux it works against a local SQLite store kept in sync with a Cloudflare D1 backend. Note bodies are end-to-end encrypted before they leave your device.
note is the notes-focused companion to event
(Apple Reminders & Calendar) — same architecture, separate backend, designed to be
used side by side.
Features
- Create, read, edit, move, delete, and search notes
- Organize notes into folders
- Markdown bodies (Apple Notes' HTML is converted to/from Markdown)
- End-to-end encrypted bodies — Cloudflare only ever sees ciphertext
- Markdown (default) and JSON output
- Cloud sync across devices with Cloudflare D1 via
note sync - Runs on macOS (AppleScript) and Linux (local SQLite + sync)
Requirements
- Swift 6.2 or later (built with the Swift 6 language mode)
- macOS 14.0 or later — reads and writes Apple Notes directly via AppleScript
- Linux — no Apple Notes, so
noteworks against a local SQLite database at~/.local/share/note-sync/local.db. Runnote syncto populate it from Cloudflare D1, then use the same commands on that data.
Installation
Homebrew (recommended)
brew tap FradSer/brew
brew install note
Build from source
git clone https://github.com/FradSer/note.git
cd note
swift build -c release
cp .build/release/note /usr/local/bin/
Tagged releases are built and published automatically by GitHub Actions
(.github/workflows/release.yml): pushing a v* tag cross-builds macOS
(arm64/amd64) and Linux (amd64/arm64) binaries, attaches them to the GitHub
release, and updates the Homebrew formula.
First Run — Grant Permission (macOS)
On first run the tool asks for Automation access to Notes. If the prompt does not appear, enable it manually:
- System Settings > Privacy & Security > Automation > your terminal > Notes
Usage
Notes
# List notes (optionally within a folder)
note notes list
note notes list --folder "Ideas"
# Show a single note with its body
note notes show --id <NOTE_ID>
# Create a note (body is Markdown; title becomes the first line)
note notes create --title "Shopping" --body $'- milk\n- eggs' --folder "Ideas"
note notes create --title "Meeting" --body-file ./notes.md
# Edit a note's title and/or body (--body replaces the whole body)
note notes edit --id <NOTE_ID> --title "New title"
note notes edit --id <NOTE_ID> --body-file ./updated.md
# Move a note to another folder (created if missing)
note notes move --id <NOTE_ID> --folder "Archive"
# Search notes by keyword (title + body)
note notes search --keyword "invoice"
# Delete a note
note notes delete --id <NOTE_ID>
Tip: a Markdown body that begins with
-(a bullet) must be passed as--body=- milkor via--body-file, because argument parsers treat a leading-as an option.
Folders
note folders list
note folders create --name "Work"
note folders delete --name "Work" # also deletes the folder's notes
Sync (Cloudflare D1)
note sync keeps notes and folders in sync across devices through a Cloudflare
Worker backed by D1. Note bodies are encrypted with a key only your devices hold.
1. Deploy the Worker (one-time)
The Worker source is a snapshot of the canonical
apple-sync-kit/worker,
pre-configured for note (ENTITIES="notes,note_folders").
cd skills/apple-notes/references/worker
pnpm install
pnpm exec wrangler login
pnpm exec wrangler d1 create note-sync # copy the database_id into wrangler.toml
pnpm run db:migrate:remote # create the D1 tables
openssl rand -hex 32 | pnpm exec wrangler secret put API_TOKEN # set the shared API token
pnpm run deploy # prints https://<worker>.workers.dev
2. Configure each device
export NOTE_SYNC_API_URL=https://<your-worker>.workers.dev
export NOTE_SYNC_API_TOKEN=<the API_TOKEN from step 1>
# NOTE_SYNC_DEVICE_ID is optional; defaults to the machine hostname
# Generate the encryption key ONCE, then set the SAME value on every device:
openssl rand -base64 32
export NOTE_ENCRYPTION_KEY=<that base64 value>
note sync status # verify configuration (shows whether the key is set)
Environment variables take precedence. If unset, note falls back to a config
file written by note sync config --api-url <URL> --api-token <TOKEN>
(--device-id optional). The config file at ~/.config/note-sync/config.json
stores the API token at mode 0o600. The encryption key is never written to
disk by note — it lives only in NOTE_ENCRYPTION_KEY. Lose it and encrypted
bodies are unrecoverable.
3. Sync
note sync # full bidirectional sync (pull, then push)
note sync push # one-directional
note sync pull
note sync --type folders # restrict to one entity type
Conflicts resolve by last-write-wins: a pull never overwrites a local copy modified more recently than the server's version, and that copy is pushed on the next sync.
Direct D1 access (advanced)
Read or write the cloud copy without a local store (e.g. from a throwaway device):
note sync notes list
note sync notes show --id <ID>
note sync folders list
Agent Skill
The apple-notes skill lets AI agents manage your Apple
Notes through note.
- Ensure
noteCLI is installed and in your system PATH. - Install the skill:
npx skills add https://github.com/FradSer/note --skill apple-notes
Architecture
NoteModels ─ domain models, formatters, sync models, HTML<->Markdown converter
NoteSync ─ D1 HTTP client, AES-GCM encryption, SQLite store, Linux sync
NoteCommands─ shared sync subcommands
note ─ CLI: AppleScript NotesService/FolderService, macOS SyncService
skills/apple-notes/ ─ ready-to-use agent skill (SKILL.md) bundling the Worker
See CLAUDE.md for the full architecture, sync algorithm, and known limitations.
Related Projects
- apple-sync-kit — shared sync
library and canonical D1 Worker (
worker/) that powersnote sync - event — companion CLI for Apple Reminders & Calendar; same architecture, separate backend
License
MIT