A modern replacement for icalBuddy, built with Swift and EventKit.
make buildmake install # copies to ~/.local/bin/calbuddy
# optional: override install prefix
make install PREFIX=/usr/local# Today's events
calbuddy eventsToday
# Next 7 days
calbuddy eventsToday+7
# Events happening right now
calbuddy eventsNow
# Date range
calbuddy eventsFrom:2026-02-01 to:2026-02-28
# List calendars
calbuddy calendars
# Start a foreground local server for Calendar access
calbuddy serve
# Use a custom client/server socket
calbuddy --socket /tmp/calbuddy.sock serve
calbuddy --socket /tmp/calbuddy.sock eventsToday
# Bypass the server and access Calendar directly
calbuddy --direct eventsToday
# Add, edit, and delete events with reversible action-log entries
calbuddy addEvent --title "Dentist" --calendar Family --start "2026-02-10 14:00" --duration 30
calbuddy editEvent --uid EVENT_UID --title "Dentist moved"
calbuddy deleteEvent --uid EVENT_UID
# Notes decode common backslash escapes for Calendar text; use --literal-notes to preserve them
calbuddy addEvent --title "Planning" --calendar Work --start "2026-02-10 09:00" --notes "Agenda\nRoom\t402"
calbuddy editEvent --uid EVENT_UID --notes 'Use \n literally' --literal-notes
# Inspect and revert calendar mutations
calbuddy actionLog
calbuddy actionLog --actionID ACTION_ID
calbuddy revertAction --actionID ACTION_ID
calbuddy revertAction --actionID ACTION_ID --force
# Agent-friendly JSON output
calbuddy --json eventsToday
calbuddy --json eventsNow
calbuddy --json eventsFrom:today to:today+7
calbuddy --json calendars
calbuddy --json actionLog
# Full JSON payload (verbose)
calbuddy --json=all eventsToday
calbuddy --json --verbose eventsToday
# Generate completion script for your shell
calbuddy completion zshGenerate completion scripts:
calbuddy completion bash
calbuddy completion zsh
calbuddy completion fishGenerate all scripts into ./completions:
make completionsInstall completions locally:
make install-completions-localInstalled paths:
- Bash:
~/.local/share/bash-completion/completions/calbuddy - Zsh:
~/.zsh/completions/_calbuddy - Fish:
~/.config/fish/completions/calbuddy.fish
| Short | Long | Description |
|---|---|---|
-df |
--dateFormat |
strftime date format (default: %Y-%m-%d %A) |
-tf |
--timeFormat |
strftime time format (default: %H:%M) |
-ic |
--includeCals |
Include only these calendars (comma-separated) |
-ec |
--excludeCals |
Exclude these calendars (comma-separated) |
-sc |
--separateByCalendar |
Group by calendar |
-sd |
--separateByDate |
Group by date |
-b |
--bullet |
Bullet string (default: • ) |
-nc |
--noCalendarNames |
Omit calendar names |
-ea |
--excludeAllDayEvents |
Skip all-day events |
-n |
--includeOnlyEventsFromNowOn |
Only future events |
-eep |
--excludeEventProps |
Exclude properties |
-iep |
--includeEventProps |
Include only properties |
-li |
--limitItems |
Max items |
-uid |
--showUIDs |
Show event UIDs |
-eed |
--excludeEndDates |
Don't show end times |
-sed |
--showEmptyDates |
Show empty date sections |
-f |
--formatOutput |
ANSI colors |
--json |
Compact JSON output for eventsToday, eventsNow, eventsFrom:*, and calendars |
|
--direct |
Bypass the local server and access Apple Calendar directly | |
--socket |
Unix socket path for client/server mode | |
-v |
--verbose |
Verbose output (with --json, includes extended fields) |
-V |
--version |
Version |
--actionLogDB |
Override action log SQLite database path | |
--actionID |
Action ID for actionLog show and revertAction |
|
--force |
Force revertAction through conflict checks |
Properties: title, datetime, location, notes, url, attendees
calbuddy serve starts a foreground local server that owns Apple Calendar access through EventKit. Normal calendar commands first try to connect to that server and, if the server socket is unavailable, fall back to direct Calendar access so existing CLI workflows keep working.
# Terminal 1: grant Calendar access to this long-lived process
calbuddy serve
# Terminal 2: uses the server when it is reachable
calbuddy eventsToday
calbuddy addEvent --title "Dentist" --calendar "Family" --start "2026-02-10 14:00"The default Unix socket is /tmp/calbuddy-$UID.sock. Override it with --socket PATH or CALBUDDY_SOCKET:
CALBUDDY_SOCKET=/tmp/calbuddy-agent.sock calbuddy serve
CALBUDDY_SOCKET=/tmp/calbuddy-agent.sock calbuddy eventsTodayUse --direct or CALBUDDY_DIRECT=1 to bypass the server:
calbuddy --direct eventsToday
CALBUDDY_DIRECT=1 calbuddy calendarsConnection-level failures such as a missing, refused, timed-out, or stale socket fall back to direct mode. A reachable server's command errors, Calendar/API failures, malformed responses, and protocol-version mismatches are reported as server errors.
The transport is local Unix-domain socket only. Each message is a 4-byte big-endian payload length followed by UTF-8 JSON. Field names are snake_case.
Request:
{
"protocol_version": 1,
"client_version": "1.0.0",
"request_id": "UUID",
"argv": ["eventsToday"]
}Response:
{
"protocol_version": 1,
"server_version": "1.0.0",
"request_id": "UUID",
"exit_code": 0,
"stdout": "...",
"stderr": "",
"error": null
}argv uses the same command tokens and options as the CLI, and the server returns the rendered stdout/stderr so existing output behavior remains centralized in CalBuddy.
Every mutating calendar command appends an immutable SQLite action-log entry before returning successfully. Existing entries are append-only: corrections and reverts are represented by new entries, never by editing or deleting earlier ones.
Default database path:
~/Library/Application Support/calbuddy/action-log.sqlite3Override precedence:
--actionLogDB PATHCALBUDDY_ACTION_LOG_DB- default path above
Logged mutators:
addEventstoresbefore = null,after = created event, and can be reverted by deleting the created event.editEventstores full before/after event snapshots and can be reverted by restoring the before snapshot.deleteEventstoresbefore = deleted event,after = null, and can be reverted by recreating the event.revertActionis itself logged and linked to the original action.
Conflict behavior:
- Reverts are exact by default. If the current calendar item no longer matches the logged after-state,
revertActionrefuses to run. --forceapplies the stored inverse despite conflicts.- Deleting events with unsupported restorable state, such as recurrence rules, attendees, or absolute alarms, is refused because CalBuddy cannot guarantee a perfect recreate.
uncompletedTasks has been removed from CalBuddy. For Apple Reminders CLI workflows, use remindctl: https://github.com/steipete/remindctl