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. All entity cursors, ID mappings, and snapshots are checkpointed atomically in
~/.config/event-sync/sync-state.json.
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