Calendar operations with CalDAV
Scanned 9/3/2026
Install to Claude Code
npx -y skills add istota-project/istota --skill calendar --agent claude-codeInstalls into .claude/skills of the current project.
Are you the author of Calendar?
Add the live security badge to your README — it updates automatically with every re-scan.
[](https://www.skillsdirectory.com/skills/istota-project-calendar)More formats (shields.io, HTML) on the badges page.
---
name: calendar
triggers: [calendar, cal , event, meeting, schedule, appointment, caldav]
description: Calendar operations with CalDAV
cli: true
source_types: [briefing]
companion_skills: [untrusted_input]
dependencies: [caldav, icalendar]
env: [{"var":"CALDAV_URL","from":"config","config_path":"caldav_url","when":"caldav_url","gate_has_discovered_calendars":true},{"var":"CALDAV_USERNAME","from":"config","config_path":"caldav_username","when":"caldav_url","gate_has_discovered_calendars":true},{"var":"CALDAV_PASSWORD","from":"config","config_path":"caldav_password","when":"caldav_url","gate_has_discovered_calendars":true,"sensitive":true}]
---
# Calendar Operations
Calendar operations use CalDAV. Credentials are available via environment variables:
- `CALDAV_URL`: CalDAV server URL (e.g., `https://nextcloud.example.com/remote.php/dav`)
- `CALDAV_USERNAME`: Username for CalDAV authentication
- `CALDAV_PASSWORD`: Password/app token for CalDAV authentication
## CLI Commands
The simplest way to interact with calendars is via the CLI:
```bash
# List today's events from all calendars (`agenda` is an alias for `list`)
istota-skill calendar list --tz "America/Los_Angeles"
# List tomorrow's events
istota-skill calendar list --date tomorrow --tz "America/Los_Angeles"
# List events for a specific date
istota-skill calendar list --date 2026-02-15 --tz "America/Los_Angeles"
# List from a specific calendar
istota-skill calendar list --calendar "https://..." --date today
# List events for the next 7 days
istota-skill calendar list --week --tz "America/Los_Angeles"
# Create an event (floating time — use when the time is local regardless of timezone)
istota-skill calendar create \
--calendar "https://..." \
--summary "Team Meeting" \
--start "2026-02-15 14:00" \
--end "2026-02-15 15:00" \
--location "Conference Room A"
# Create an event with explicit timezone (use for travel/flights)
istota-skill calendar create \
--calendar "https://..." \
--summary "Flight JFK→LHR" \
--start "2026-04-26 19:10" \
--end "2026-04-27 19:05" \
--tz "America/Los_Angeles" \
--description "SAS SK932"
# Create a one-day all-day event
istota-skill calendar create \
--calendar "https://..." \
--summary "Holiday" \
--start "2026-08-29" \
--all-day
# Update an event
istota-skill calendar update \
--calendar "https://..." \
--uid "event-uid-here" \
--summary "Updated Title" \
--start "2026-02-15 15:00" \
--end "2026-02-15 16:00"
# Move an all-day event. The end date is inclusive.
istota-skill calendar update \
--calendar "https://..." \
--uid "event-uid-here" \
--start "2026-08-29" \
--end "2026-08-30" \
--all-day
# Update: clear optional fields
istota-skill calendar update \
--calendar "https://..." \
--uid "event-uid-here" \
--clear-location --clear-description
# Delete an event
istota-skill calendar delete --calendar "https://..." --uid "event-uid-here"
```
**Always pass `--tz` with the user's timezone** (from prompt metadata) to ensure correct date boundaries.
**Always pass `--tz` when creating timed events with specific timezone semantics** (flights, meetings across timezones). Omit `--tz` for local timed events where the wall-clock time is what matters. All-day events are DATE values and never carry a timezone. Their end date is inclusive; create may omit it for a one-day event, while update requires both dates to keep the event boundaries the same type.
Output is JSON:
```json
{
"status": "ok",
"date": "today",
"event_count": 2,
"events": [
{
"calendar": "Work",
"uid": "abc123",
"summary": "Team Meeting",
"start": "2026-02-15T14:00:00",
"end": "2026-02-15T15:00:00",
"location": "Conference Room A",
"description": null,
"all_day": false,
"timezone": "America/Los_Angeles"
}
]
}
```
The `timezone` field shows the original TZID from the iCalendar data. `"floating"` means the event has no timezone — the time is interpreted as-is regardless of the viewer's timezone.
## Python API
The `istota.skills.calendar` module also provides functions for programmatic access:
| Function | Description | Returns |
|----------|-------------|---------|
| `get_caldav_client(url, username, password)` | Create CalDAV client | `caldav.DAVClient` |
| `list_calendars(client)` | List all accessible calendars | `list[(name, url)]` |
| `get_calendars_for_user(client, username)` | Get calendars owned by a user | `list[(name, url, writable)]` |
| `get_events(client, calendar_url, start, end)` | Get events in date range | `list[CalendarEvent]` |
| `get_today_events(client, calendar_url, tz)` | Get today's events | `list[CalendarEvent]` |
| `get_tomorrow_events(client, calendar_url, tz)` | Get tomorrow's events | `list[CalendarEvent]` |
| `get_week_events(client, calendar_url, tz)` | Get next 7 days' events | `list[CalendarEvent]` |
| `get_event_by_uid(client, calendar_url, uid)` | Get single event by UID | `CalendarEvent \| None` |
| `create_event(client, calendar_url, ...)` | Create new event | `str` (event UID) |
| `update_event(client, calendar_url, uid, ...)` | Update existing event | `bool` |
| `delete_event(client, calendar_url, uid)` | Delete event by UID | `bool` |
| `format_event_for_display(event)` | Format event for human display | `str` |
| `format_day_schedule(events, date_label)` | Format day's events | `str` |
### CalendarEvent Dataclass
```python
@dataclass
class CalendarEvent:
uid: str # Unique identifier
summary: str # Event title
start: datetime # Start time; midnight when an all-day event is read
end: datetime # End time; exclusive midnight for an all-day event
location: str | None
description: str | None
all_day: bool
timezone: str | None # Original TZID, None = floating
```
### Permissions
Calendars can be shared with read-only or edit permissions:
- **Read-only**: Can view events but not modify them
- **Edit**: Can create, update, and delete events
When attempting to modify a read-only calendar, `update_event()` and `create_event()` will raise `caldav.error.AuthorizationError`.
### Python Example
```python
from istota.skills.calendar import get_caldav_client, get_today_events
import os
client = get_caldav_client(
url=os.environ["CALDAV_URL"],
username=os.environ["CALDAV_USERNAME"],
password=os.environ["CALDAV_PASSWORD"],
)
# Get today's events (always pass user's timezone)
calendar_url = "https://nextcloud.example.com/remote.php/dav/calendars/alice/personal/"
for event in get_today_events(client, calendar_url, tz="America/Los_Angeles"):
print(f"{event.start.strftime('%H:%M')} - {event.summary}")
```
Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.
No comments yet. Be the first to comment!