Skip to content
Back to skills

Calendar

ASecurity

Calendar operations with CalDAV

  • 13 stars
  • 0 votes
  • 0 copies
  • 2 views
  • Added September 3, 2026
ai-agentspythonrustphpbashapi

Works with

  • cli
  • api

Security analysis

A100/100

Pro scans all 3 files and shows the line behind each finding

Scanned October 7, 2026

npx -y skills add istota-project/istota --skill calendar --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Calendar?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Calendar
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/istota-project-calendar/badge)](https://www.skillsdirectory.com/skills/istota-project-calendar)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
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 of your 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"
```

**`--calendar` takes one of the user's own calendars**, as listed in the prompt. A calendar another user shared with the bot is refused as `Calendar not found`, the same answer as one that does not exist.

**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 every calendar the account can see, other users' shared ones included | `list[(name, url)]` |
| `get_calendars_for_user(client, username)` | Get calendars owned by a user | `list[(name, url, writable)]` |
| `owned_calendars(client, username)` | The same, as `(name, url)` | `list[(name, url)]` |
| `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}")
```

Files in this skill

  • __init__.py26.1 KB
  • __main__.py87 B
  • skill.md6.6 KB

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.