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.
- 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)
- 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.
brew tap FradSer/brew
brew install notegit 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.
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
# 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.
note folders list
note folders create --name "Work"
note folders delete --name "Work" # also deletes the folder's notesnote 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.
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.devexport 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.
note sync # full bidirectional sync (pull, then push)
note sync push # one-directional
note sync pull
note sync --type folders # restrict to one entity typeConflicts 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. A full sync holds one lock for the complete folders -> notes ->
preferences pull, followed by the same-order push. Checkpoints are stored
atomically in ~/.config/note-sync/sync-state.json.
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 listThe 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
NoteModels ─ domain models, formatters, HTML<->Markdown converter
NoteSync ─ AppleSyncKit local-source adapters, 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.
- 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
MIT