Files
youlu-openclaw-workspace/skills/calendar/SKILL.md
Yanxin Lu b2ff8effd4 calendar: fix stale docs and remove unnecessary METHOD from todo add
- Remove duplicate email rule in TOOLS.md
- Add todo mutations to sync description in TOOLS.md
- Remove METHOD:REQUEST from todo add ICS (no longer emailed)
- Update todo check description in SKILL.md
2026-03-23 14:48:05 -07:00

11 KiB

name, description, metadata
name description metadata
calendar Calendar invites and VTODO task management via CalDAV. Send/reply to invites, create/list/complete/delete todos. Syncs to Migadu CalDAV via vdirsyncer.
clawdbot
emoji requires
📅
bins skills
himalaya
vdirsyncer
todo
himalaya

Calendar

Send, accept, and decline calendar invitations via email. Create and manage VTODO tasks with CalDAV sync. Events and tasks sync to Migadu CalDAV via vdirsyncer.

Testing

See TESTING.md for dry-run and live test steps, verification checklists, and troubleshooting.

Prerequisites

  • himalaya configured and working (see the himalaya skill)
  • vdirsyncer configured and syncing to ~/.openclaw/workspace/calendars/
  • todoman (todo) for VTODO management (list, complete, delete)
  • khal for reading calendar (optional but recommended)
  • Runs via uv run (dependencies managed in pyproject.toml)

Important: Email Sending Rules

Calendar invites are outbound emails. Follow the workspace email rules:

Usage

All commands go through the wrapper script:

SKILL_DIR=~/.openclaw/workspace/skills/calendar

# Send an invite
$SKILL_DIR/scripts/calendar.sh send [options]

# Reply to an invite
$SKILL_DIR/scripts/calendar.sh reply [options]

# Manage todos
$SKILL_DIR/scripts/calendar.sh todo add [options]
$SKILL_DIR/scripts/calendar.sh todo list [options]
$SKILL_DIR/scripts/calendar.sh todo complete [options]
$SKILL_DIR/scripts/calendar.sh todo delete [options]
$SKILL_DIR/scripts/calendar.sh todo check

Sending Invites

$SKILL_DIR/scripts/calendar.sh send \
  --to "friend@example.com" \
  --subject "Lunch on Friday" \
  --summary "Lunch at Tartine" \
  --start "2026-03-20T12:00:00" \
  --end "2026-03-20T13:00:00" \
  --location "Tartine Bakery, SF"

Send Options

Flag Required Description
--to Yes Recipient(s), comma-separated
--subject Yes Email subject line
--summary Yes Event title (shown on calendar)
--start Yes Start time, ISO 8601 (2026-03-20T14:00:00)
--end Yes End time, ISO 8601 (2026-03-20T15:00:00)
--from No Sender email (default: youlu@luyanxin.com)
--timezone No IANA timezone (default: America/Los_Angeles)
--location No Event location
--description No Event description / notes
--organizer No Organizer display name (defaults to --from)
--uid No Custom event UID (auto-generated if omitted)
--account No Himalaya account name (if not default)
--dry-run No Print ICS + MIME without sending

Send Examples

# Simple invite (--from and --timezone default to youlu@luyanxin.com / LA)
$SKILL_DIR/scripts/calendar.sh send \
  --to "alice@example.com" \
  --subject "Coffee Chat" \
  --summary "Coffee Chat" \
  --start "2026-03-25T10:00:00" \
  --end "2026-03-25T10:30:00"

# Multiple attendees with details
$SKILL_DIR/scripts/calendar.sh send \
  --to "alice@example.com, bob@example.com" \
  --subject "Team Sync" \
  --summary "Weekly Team Sync" \
  --start "2026-03-23T09:00:00" \
  --end "2026-03-23T09:30:00" \
  --location "Zoom - https://zoom.us/j/123456" \
  --description "Weekly check-in. Agenda: updates, blockers, action items."

# Dry run
$SKILL_DIR/scripts/calendar.sh send \
  --to "test@example.com" \
  --subject "Test" \
  --summary "Test Event" \
  --start "2026-04-01T15:00:00" \
  --end "2026-04-01T16:00:00" \
  --dry-run

Replying to Invites

# Accept by himalaya envelope ID
$SKILL_DIR/scripts/calendar.sh reply \
  --envelope-id 42 \
  --action accept

# Decline with a comment
$SKILL_DIR/scripts/calendar.sh reply \
  --envelope-id 42 \
  --action decline \
  --comment "Sorry, I have a conflict."

# From an .ics file
$SKILL_DIR/scripts/calendar.sh reply \
  --ics-file ~/Downloads/meeting.ics \
  --action tentative

Reply Options

Flag Required Description
--action Yes accept, decline, or tentative
--envelope-id * Himalaya envelope ID containing the .ics attachment
--ics-file * Path to an .ics file (alternative to --envelope-id)
--from No Your email (default: youlu@luyanxin.com)
--account No Himalaya account name
--folder No Himalaya folder (default: INBOX)
--comment No Optional message to include in reply
--dry-run No Preview without sending

* One of --envelope-id or --ics-file is required.

Typical Workflow

  1. List emails: himalaya envelope list
  2. Read the invite: himalaya message read 57
  3. Reply: $SKILL_DIR/scripts/calendar.sh reply --envelope-id 57 --action accept

VTODO Tasks

Manage tasks as RFC 5545 VTODO components, stored in ~/.openclaw/workspace/calendars/tasks/ and synced to CalDAV.

Sync Model

The agent's local CalDAV is the source of truth. When a todo is created, it's saved locally and synced to Migadu CalDAV via vdirsyncer — all connected devices (DAVx5, etc.) pick it up automatically. When the user completes a task, they tell the agent, and the agent runs todo complete. The daily todo check cron reads from local files.

Priority Mapping (RFC 5545)

Label --priority RFC 5545 value
高 (high) high 1
中 (medium) medium 5 (default)
低 (low) low 9

todo add — Create a Todo

$SKILL_DIR/scripts/calendar.sh todo add \
  --summary "跟进iui保险报销" \
  --due "2026-03-25" \
  --priority high \
  --description "确认iui费用保险报销进度" \
  --alarm 1d
Flag Required Description
--summary Yes Todo title
--due No Due date, YYYY-MM-DD (default: tomorrow)
--priority No high, medium, or low (default: medium)
--description No Notes / description
--alarm No Reminder trigger: 1d, 2h, 30m (default: 1d)
--dry-run No Preview ICS without saving

todo list — List Todos

$SKILL_DIR/scripts/calendar.sh todo list           # pending only
$SKILL_DIR/scripts/calendar.sh todo list --all      # include completed

todo complete — Mark as Done

$SKILL_DIR/scripts/calendar.sh todo complete --uid "abc123@openclaw"
$SKILL_DIR/scripts/calendar.sh todo complete --match "保险报销"

todo delete — Remove a Todo

$SKILL_DIR/scripts/calendar.sh todo delete --uid "abc123@openclaw"
$SKILL_DIR/scripts/calendar.sh todo delete --match "保险报销"

todo check — Daily Digest (Cron)

$SKILL_DIR/scripts/calendar.sh todo check

Same as todo list but only pending items. Exits silently when nothing is pending.


How It Works

Sending invites:

  1. Generates an RFC 5545 ICS file with METHOD:REQUEST (via icalendar library)
  2. Builds a MIME email with a text/calendar attachment (via Python email.mime)
  3. Sends via himalaya message send (piped through stdin)
  4. Saves the event to ~/.openclaw/workspace/calendars/home/
  5. Runs vdirsyncer sync to push to Migadu CalDAV

Replying to invites:

  1. Extracts the .ics attachment from the email (via himalaya attachment download)
  2. Parses the original event with the icalendar library
  3. Generates a reply ICS with METHOD:REPLY and the correct PARTSTAT
  4. Sends the reply to the organizer via himalaya message send (stdin)
  5. On accept/tentative: saves event to local calendar. On decline: removes it
  6. Runs vdirsyncer sync to push changes to Migadu CalDAV

Managing todos:

  1. todo add: Creates a VTODO ICS file (via icalendar library), saves to calendars/tasks/, syncs to CalDAV
  2. todo list/complete/delete/check: Delegates to todoman CLI for robust RFC 5545 VTODO parsing
  3. Runs vdirsyncer sync after mutations to push changes to Migadu CalDAV

CalDAV sync:

  • Events and tasks sync to Migadu and appear on all connected devices (DAVx5, etc.)
  • Heartbeat runs vdirsyncer sync periodically as a fallback
  • If sync fails, it warns but doesn't block — next heartbeat catches up

Integration with Email Processor

The email processor (scripts/email_processor/) may classify incoming calendar invites as reminder or confirmation. When reviewing pending emails:

  1. Check if the email contains a calendar invite (look for .ics attachment or "calendar" in subject)
  2. If it does, use reply instead of the email processor's delete/archive/keep actions
  3. The email processor handles the email lifecycle; this skill handles the calendar response

Checking the Calendar

# List upcoming events (next 7 days)
khal list today 7d

# List events for a specific date
khal list 2026-03-25

# Check for conflicts before sending an invite
khal list 2026-03-25 2026-03-26

Timezone Reference

Common IANA timezones:

  • America/Los_Angeles — Pacific (default)
  • America/Denver — Mountain
  • America/Chicago — Central
  • America/New_York — Eastern
  • Asia/Shanghai — China
  • Asia/Tokyo — Japan
  • Europe/London — UK
  • UTC — Coordinated Universal Time

Troubleshooting

Invite shows as attachment instead of calendar event?

  • Ensure the MIME part has Content-Type: text/calendar; method=REQUEST
  • Some clients require the METHOD:REQUEST line in the ICS body

Times are wrong?

  • Double-check --timezone matches the intended timezone
  • Use ISO 8601 format: YYYY-MM-DDTHH:MM:SS (no timezone offset in the value)

Event not showing on phone/other devices?

  • Run vdirsyncer sync manually to force sync
  • Check ~/.openclaw/workspace/logs/vdirsyncer.log for errors
  • Verify the .ics file exists in ~/.openclaw/workspace/calendars/home/

Todos not syncing?

  • Check that ~/.openclaw/workspace/calendars/tasks/ exists
  • Verify vdirsyncer has a cal/tasks pair configured
  • Run vdirsyncer sync manually

Recipient doesn't see Accept/Decline?

  • Gmail, Outlook, Apple Mail all support text/calendar method=REQUEST
  • Some webmail clients may vary