English | 简体中文
A pure Swift CLI tool for managing Apple Reminders and Calendar. On macOS it reads and writes Apple data directly through EventKit; on Linux it works against a local SQLite store kept in sync with a Cloudflare D1 backend.
- Create, read, update, and delete reminders
- Full CRUD for calendar events
- Organize reminders into lists
- Add and manage subtasks within reminders
- Tag reminders for organization
- Markdown (default) and JSON output
- Cloud sync across devices with Cloudflare D1 via
event sync - Runs on macOS (EventKit) and Linux (local SQLite + sync)
- Swift 5.9 or later
- macOS 14.0 or later — reads and writes Apple Reminders and Calendar directly via EventKit
- Linux — no EventKit, so
eventworks against a local SQLite database at~/.local/share/event-sync/local.db. Runevent syncto populate it from Cloudflare D1, then use the same commands on that data
# Add tap
brew tap FradSer/brew
# Install
brew install event# Clone the repository
git clone https://github.com/FradSer/event.git
cd event
# Build and install
swift build -c release
cp .build/release/event /usr/local/bin/On first run, the tool requests access to Reminders and Calendar. If the system permission dialog doesn't appear, manually grant access:
Recommended: Use AdvancedReminderEdit Shortcut
- Download AdvancedReminderEdit
- Open Shortcuts and run the shortcut once
- This enables advanced reminder features: native tags, URL, and parent reminder support
- Also triggers the system permission dialogs for Reminders and Calendar
Alternatively, enable permissions in System Settings:
- System Settings > Privacy & Security > Reminders > Enable Terminal
- System Settings > Privacy & Security > Calendars > Enable Terminal
When run headless (SSH, launchd agent/daemon) the prompt cannot be displayed, so event returns a permission error immediately. If the prompt is pending but unanswerable (some launchd contexts), the request gives up after 15 s and reports Permission denied: Timed out waiting for .... Tune the wait with EVENT_PERMISSION_TIMEOUT_MS (must stay below the MCP server's EVENTKIT_CLI_TIMEOUT_MS kill timeout of 30 s so the CLI answers with a readable error first).
# List reminders
event reminders list
# Create a reminder
event reminders create --title "Buy groceries"
# Create with tags
event reminders create --title "Buy groceries" --tags "shopping,urgent"
# Mark reminder complete
event reminders update --id <REMINDER_ID> --completed
# Delete a reminder
event reminders delete --id <REMINDER_ID># List calendar events
event calendar list
# List events in date range
event calendar list --start "2026-03-01" --end "2026-03-31"
# Create an event
event calendar create --title "Meeting" --start "2026-03-10 14:00:00" --end "2026-03-10 15:00:00"
# Create a timed event in an explicit IANA timezone
event calendar create --title "New York meeting" --start "2026-03-10 14:00:00" --end "2026-03-10 15:00:00" --timezone America/New_York
# On macOS, change a timed event's timezone without changing its start or end instant
event calendar update --id EVENT_ID --timezone America/Los_Angeles--timezone accepts an IANA timezone identifier and applies only to timed events. On macOS, create and update parse timed input in the supplied timezone; updates without a new date preserve the event's start and end instants. On Linux and through sync backends, the identifier is retained as event metadata.
Calendar sync payloads include a date-format version so newer clients can distinguish timezone-aware dates from records written by older clients. Legacy records without this marker keep their previous machine-local interpretation until they are reserialized by an authoritative macOS device; the original source machine timezone cannot be recovered from the legacy payload alone. Re-sync older calendar records from that device before relying on their per-event timezone across machines.
# List all reminder lists
event reminders lists list
# Create a list
event reminders lists create --name "Work"event sync keeps reminders, calendar events, and lists in sync across devices
through a Cloudflare Worker backed by D1.
The Worker source is a snapshot of the canonical
apple-sync-kit/worker,
pre-configured for event (ENTITIES="reminders,calendar_events,reminder_lists").
cd skills/apple-events/references/worker
pnpm install
pnpm exec wrangler login
pnpm exec wrangler d1 create event-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 # auto-generate and set a strong shared token
pnpm run deploy # prints https://<worker>.workers.devUpgrading an existing deployment: the pull cursor is keyed on a monotonic
seqcolumn added by migration0002_events_seq_cursor. Re-runpnpm run db:migrate:remoteand thenpnpm run deployafter pulling these changes. Devices stored with an older timestamp cursor self-heal on their next pull (they restart from the beginning once and re-converge), so no client action is needed.
Set two environment variables — add them to ~/.zshrc (or ~/.bashrc) so they
persist across shells:
export EVENT_SYNC_API_URL=https://<your-worker>.workers.dev
export EVENT_SYNC_API_TOKEN=<the API_TOKEN from step 1>
# EVENT_SYNC_DEVICE_ID is optional; defaults to the machine hostname
event sync status # verify the configurationEnvironment variables take precedence. If they are unset, event falls back to
a config file written by event sync config --api-url <URL> --api-token <TOKEN>
(--device-id is optional and defaults to the machine hostname).
Note: the config file at
~/.config/event-sync/config.jsonstores the API token in plain text (mode0600, owner-only). Do not commit it to version control or copy it to shared storage.
event sync # full bidirectional sync: pull, then pushRun it on each device. The device id (hostname by default) keeps devices
distinct, and a device never pulls back its own writes. On Linux this is the
first step on a fresh machine — it fills the local SQLite store before the other
event commands have anything to show.
Advanced one-directional / selective sync:
event sync push --type all # push only
event sync pull --type calendar # pull only, one entity typeNote: Calendar sync covers events from one year in the past to two years ahead; events outside this window are not synced. Conflicts resolve by last-write-wins: a pull never overwrites a local copy that was modified more recently than the server's version, and that copy is pushed on the next sync.
For more commands, run event --help.
The apple-events skill lets AI agents manage your Apple Reminders and Calendar through event.
- Ensure
eventCLI is installed and in your system PATH. - Install the skill:
npx skills add https://github.com/FradSer/event --skill apple-events
- apple-sync-kit — shared sync
library and canonical D1 Worker (
worker/) that powersevent sync - note — companion CLI for Apple Notes; same architecture, separate backend
MIT License
Frad Lee - frad.me