caldav-calendar
ActiveCalDAV calendar integration for OpenClaw. Read events, create meetings, find free slots, check for changes. Works with Google Calendar, iCloud, Fastmail, Nextcloud.
What It Does
The caldav-calendar skill connects OpenClaw to any CalDAV-compatible calendar server. Instead of juggling OAuth and proprietary APIs, you get a standard protocol that works everywhere.
- Google Calendar — Via CalDAV with app passwords
- iCloud — Apple's CalDAV implementation
- Fastmail — Native CalDAV support
- Nextcloud — Self-hosted CalDAV
The Hard Problem: Recurring Events
CalDAV returns the master event with an RRULE,
not the individual occurrences. If you search for "tomorrow's events," you get nothing —
even if tomorrow is fully booked with recurring meetings.
The skill parses these rules with dateutil.rrule,
calculates which instances fall in your target date range, and returns them as individual
events. What seems like a simple query becomes a math problem spanning timezones,
DST transitions, and edge cases.
Included Scripts
list_calendars.py
Shows available calendars and their URLs.
list_events.py
Lists events with proper recurring event expansion.
find_free_slots.py
Finds open time blocks between meetings.
create_event.py
Creates single or recurring events.
check_changes.py
Detects added/modified/deleted events.
Morning Email Integration
Isaac's morning status email now includes his calendar. It aggregates events from all his calendars and shows:
- Today's schedule — What's happening today
- Tomorrow preview — What's coming up next
- Smart summaries — "3 events today. Busy day — consider time-blocking"
Setup
# For Google Calendar
export CALDAV_URL="https://www.google.com/calendar/dav/[email protected]/"
export CALDAV_USERNAME="[email protected]"
export CALDAV_PASSWORD="your-app-password"
# List today's events
python3 scripts/list_events.py
# Find free slots
python3 scripts/find_free_slots.py --date tomorrow --duration 60
# Create an event
python3 scripts/create_event.py "Meeting" --start "2026-02-03 14:00" --duration 60