Introduction

In DSH agent scenarios, models often need to query “what events are scheduled for today” or “is there any availability tomorrow morning,” or convert a todo item into a calendar event. If they have to manually export calendar text, take screenshots, or write custom sync scripts every time, it becomes difficult for the model to participate directly in scheduling.

dsh-calendar is a DSH community plugin that reads and writes calendar events via CalDAV, supporting Google, iCloud, Nextcloud, and any custom CalDAV server. The DSH ecosystem emphasizes “everything is a plugin”; here we introduce a community plugin, not an official app store built-in capability.

Plugin Overview

dsh-calendar addresses a clear problem: encapsulating calendar event capabilities into model tools that DSH can invoke.

It provides five tools oriented towards the model:

  • calendar_list: List events within a time range
  • calendar_create: Create new events
  • calendar_update: Update events by uid
  • calendar_delete: Delete events by uid
  • calendar_search: Search events by keywords

Several key facts are as follows:

  • GitHub Repository: https://github.com/STARDUSTLC666/dsh-calendar
  • License: MIT
  • Runtime Requirements: Node >=22
  • Authentication Method: Basic Auth using app-specific passwords
  • Does not support Google / iCloud OAuth login flow
  • No settings page UI; configuration is handled via the cordis.patch.yml in the profile
  • The stable event identifier uid uses the CalDAV href

Installation and Enablement

First, install the plugin in the target profile:

dsh plugin --profile web add dsh-calendar

After installation, restart dsh.

The default configuration usually does not contain any credentials. At this point, the plugin can load normally, but tools will return Chinese guidance errors when invoked, prompting you to complete the configuration. The configuration location is the cordis.patch.yml of the current profile, where you override the calendar line’s config by id.

A minimal example:

- id: calendar
  config:
    provider: custom
    caldavUrl: https://dav.example.com/calendars/me/work/
    username: me
    password: your app-specific password

If you do not want to write the password into the YAML, you can use the environment variable DSH_CALENDAR_PASSWORD.

The uninstall command is as follows:

dsh plugin --profile web remove dsh-calendar

After uninstalling, restart the Web service. If a thorough cleanup is needed, you can manually delete the corresponding plugin line from the cordis.patch.yml in your profile.

Configuration Fields

All configuration resides within the calendar line in cordis.patch.yml. Common fields are as follows:

  • provider: google, icloud, nextcloud, custom
  • caldavUrl: The full calendar collection URL. Required for custom and icloud; google / nextcloud can also be manually filled to override presets
  • username: CalDAV account. For Google / iCloud, usually the account email
  • password: Password. For Google / iCloud, please use an app-specific password
  • proxyUrl: Local proxy address. May be needed when accessing Google / iCloud CalDAV endpoints in China
  • calendarId: Google specific, calendar ID, usually your email
  • host: Nextcloud specific, e.g., https://cloud.example.com
  • user: Nextcloud specific, CalDAV user
  • calendar: Nextcloud specific, calendar name

Typical Usage

Google Calendar

An example for Google is as follows:

- id: calendar
  config:
    provider: google
    username: you@gmail.com
    calendarId: you@gmail.com
    # You can also use DSH_CALENDAR_PASSWORD
    password: your app-specific password

Google’s CalDAV collection URL is constructed by the plugin:

https://apidata.googleusercontent.com/caldav/v2/<calendarId>/events

Google requires the use of an app-specific password; the Google login password cannot be used.

iCloud Calendar

An example for iCloud is as follows:

- id: calendar
  config:
    provider: icloud
    username: you@icloud.com
    caldavUrl: https://caldav.icloud.com/123456789/calendars/<calendarID>/
    # You can also use DSH_CALENDAR_PASSWORD
    password: your app-specific password

iCloud requires manually filling in the full calendar collection URL, including the user ID and calendar ID. The plugin does not perform automatic principal discovery and does not support multi-calendar selection.

iCloud also requires the use of an app-specific password; the Apple ID login password cannot be used.

Nextcloud Calendar

An example for Nextcloud is as follows:

- id: calendar
  config:
    provider: nextcloud
    username: alice
    host: https://cloud.example.com
    user: alice
    calendar: personal
    # You can also use DSH_CALENDAR_PASSWORD
    password: your app-specific password

The plugin will construct a URL similar to:

https://cloud.example.com/remote.php/dav/calendars/alice/personal/

Custom CalDAV

An example for custom CalDAV is as follows:

- id: calendar
  config:
    provider: custom
    caldavUrl: https://dav.example.com/calendars/me/work/
    username: me
    # You can also use DSH_CALENDAR_PASSWORD
    password: your app-specific password

This method is suitable for self-hosted Radicale, Nextcloud, or other servers providing standard CalDAV.

Tool Behavior

calendar_list

calendar_list is used to list events within a specific time range.

Supported parameters:

  • start / end: ISO 8601 time
  • expand: Whether to expand recurring events, default true
  • maxOccurrences: Upper limit for expanding recurring events, default 30, range 1-200

By default, calendar_list will expand recurring events. The expanded instances will carry:

  • isOccurrence: true
  • seriesStart

Non-recurring events will remain:

  • isOccurrence: false

If expand=false is set, recurring events will be returned as original single entries, carrying rrule.

The results are stably sorted by start time.

calendar_create

calendar_create is used to create new events.

Required fields:

  • summary
  • start
  • end

Optional fields:

  • description
  • location
  • allDay
  • rrule

The plugin will validate real calendar dates and require end >= start. For example, dates that do not exist (like 2025-02-30) will be rejected.

calendar_update

calendar_update updates events by uid.

Updatable fields include:

  • summary
  • start
  • end
  • description
  • location
  • allDay
  • rrule

Fields not provided retain their original values. Recurrence rules will not be lost when updating other fields.

calendar_delete

calendar_delete deletes events by uid.

calendar_search is used to search for events by keywords.

It performs client-side filtering on the title, description, location, and UID, case-insensitive.

Supported parameters:

  • keyword
  • limit: Default 50, range 1-200

The results are sorted by start time.

Note: calendar_search returns the original series and does not expand recurring events.

Recurring Event Limits

calendar_update and calendar_delete operate on the entire recurring series via uid.

This means they are suitable for modifying or deleting an entire recurring schedule, but do not support modifying or deleting a single occurrence. In other words, RECURRENCE-ID instance-level modification or deletion is not supported.

If you need to “cancel just Wednesday,” this plugin currently cannot do that directly.

Timezone and Time Format

Input and output use ISO 8601 uniformly.

  • Timed events are output in UTC, for example:
2025-01-15T01:00:00Z
  • All-day events are output in date format:
2025-01-15

Input can include timezone offsets, for example:

2025-01-15T09:00:00+08:00

The plugin converts them to UTC for storage internally.

Events with named timezones (using TZID) will be converted to UTC. Complex timezone rules such as all-day boundaries and Daylight Saving Time are not processed in granular detail.

Proxy and Network Limits

Direct access to Google and iCloud CalDAV endpoints is not possible in China. You can use the proxyUrl configuration to set up a local proxy.

Example:

- id: calendar
  config:
    provider: google
    username: you@gmail.com
    calendarId: you@gmail.com
    password: your app-specific password
    proxyUrl: http://127.0.0.1:7890

Here, proxyUrl should be filled with the actual HTTP port exposed by your local proxy client. For CalDAV services that can be accessed directly in China (e.g., self-hosted Nextcloud or other private CalDAV services), proxy configuration is usually not required.

The overall tool timeout is 60 seconds. The plugin does not propagate AbortSignal through individual network requests.

Use Cases

dsh-calendar is quite suitable for scenarios such as:

  • You use DSH as an agent or assistant and want the model to be able to query the calendar directly
  • You need the model to create, update, delete, or search schedules
  • You already have Google, iCloud, Nextcloud, or other CalDAV services
  • You can maintain plugin configuration via cordis.patch.yml
  • You accept that the current version does not have a Web settings page and configuration is written directly in YAML

Precautions

It is recommended to pay attention to the following points before use:

  1. The plugin runs with the permissions of the current dsh process; it is recommended to check the source code and license before installing.
  2. Only Basic Auth is supported; Google / iCloud OAuth is not supported.
  3. Google / iCloud must use app-specific passwords; login passwords cannot be used.
  4. calendar_update and calendar_delete target the entire recurring series and do not support single-instance operations.
  5. calendar_search does not expand recurring events.
  6. iCloud requires manually filling in the full calendar collection URL.
  7. There is no settings page UI; all configuration goes through cordis.patch.yml.
  8. If the call returns 401 / 403, prioritize checking if you mistakenly used the login password.

Conclusion

The value of dsh-calendar lies in wrapping CalDAV calendar capabilities into five stable model tools, enabling DSH agents to directly perform actions such as querying, creating, updating, deleting, and searching schedules.

GitHub Repository:

https://github.com/STARDUSTLC666/dsh-calendar