Plugin directory / Developer / calendar
calendar
Verified · install-tested on dsh JohnXu22786
What it does
CalDAV + iCalendar + RRULE calendar integration bundle for DeepSeek Harness (dsh), with Chinese-bias (lunar calendar / holidays / Asia/Shang
Works — verified, early-stage project
CalDAV + iCalendar + RRULE calendar integration bundle for DeepSeek Harness (dsh), with Chinese-bias (lunar calendar / holidays / Asia/Shang It installs cleanly and boots without issues in our testing. It's early-stage but functional.
“Verified” means our automated CI actually ran dsh plugin add in a clean profile and it booted — nothing more. Feature descriptions and version compatibility are the author’s claims. This is not a security audit and not an endorsement of third-party code.
README
# dsh-calendar
A calendar / scheduling integration bundle for
DeepSeek Harness (dsh),
built as a self-contained npm package that follows the dsh bundle convention
("dsh": { "bundle": { "patch": "./cordis.patch.yml" } }).
It connects to any CalDAV server (Google Calendar, iCloud, Nextcloud,
custom), stores and computes iCalendar/RRULE data itself, understands Chinese
calendar context (lunar calendar, holidays, Asia/Shanghai by default), and
detects time conflicts — all without a single runtime dependency.
Features
CalDAV integration —
list/create/update/delete/search
events over standard REPORT/PROPFIND/GET/PUT/DELETE, with automatic
discovery (well-known → current-user-principal → calendar-home-set →
calendars). Two authentication channels:- Basic auth (Nextcloud, iCloud, generic servers)
- Google OAuth2 via the device flow (headless-friendly), with a
refresh-token flow and secure token storage - Credentials come from environment variables or the dsh credential
service (ctx.credentials) or a local chmod-0600 store. Secrets are
never written to logs — aredact()helper masks them in output.
RRULE expansion + single-instance editing — a from-scratch RFC 5545
recurrence engine coveringFREQ(SECONDLY…YEARLY),INTERVAL,COUNT,UNTIL(UTC & local),BYDAY(with ordinals),BYMONTH,BYMONTHDAY,BYYEARDAY,BYWEEKNO,BYSETPOS,WKST,BYHOUR/BYMINUTE/BYSECOND,
plusEXDATEandRDATE. Editing or deleting one occurrence writes aRECURRENCE-IDoverride (STATUS:CANCELLEDfor deletion) and never
touches the series master.Chinese bias — lunar calendar conversion (astronomically computed,
full 2000–2100 coverage), Chinese holidays (春节 / 清明 / 端午 / 中秋 /
元宵 / 七夕 / 重阳 / 除夕 / 元旦 / 劳动节 / 国庆节), 干支/生肖 anchored
at 立春,Asia/Shanghaidefault timezone, and acal_remindtool whose
output plugs straight into dsh's session-localschedule_create.Conflict detection — overlapping events (timed, all-day, and across
recurring instances) are flagged with the overlapping span; updates can
exclude the event itself.Timezone handling — an embedded, dependency-free timezone engine
(present-day rules, 2000–2100) with correct DST transitions; wall-time ↔
UTC conversion with documented ambiguity/gap resolution; TZID-preserving
ICS round-trips.Toolchain — dsh tools under
ctx.tools(cal_list,cal_get,cal_create,cal_update,cal_delete,cal_search,cal_conflicts,cal_holidays, pluscal_calendars,cal_remind) and a standalone CLI
(dsh-calendar).
Bundle layout
| file | purpose |
|---|---|
package.json |
npm manifest with dsh.bundle.patch + peer deps |
cordis.patch.yml |
config layer mounting the bundle entry |
src/index.ts |
dsh plugin entry: name / inject / Config / apply |
src/service.ts |
high-level operations shared by tools & CLI |
src/tools.ts |
cal_* tool definitions |
src/credentials.ts |
secret resolution + redaction |
src/dav/* |
CalDAV client, OAuth2 (Google device flow), XML, store |
src/core/* |
timezone, iCalendar, RRULE, recurrence, conflicts, lunar |
No runtime dependencies — peerDependencies (@deepseek-ai/cordis,@deepseek-ai/dsh-tools, @deepseek-ai/schemastery) are only used by the
entry module and are provided by the dsh runtime.
Install & connect to dsh
Prerequisite: a working dsh profile. Then:
# 1. build the bundle (produces lib/)
npm install
npm run build
# 2. install it into your dsh profile
dsh plugin --profile <name> add ./calendar
This pnpm-links the checkout, appends the bundle to the profile, and dsh then
mounts the entry module via cordis.patch.yml (id: calendar, name: dsh-calendar), registering the cal_* tools.
To iterate without installing, layer the patch directly:
dsh --profile <name> --patch ./cordis.patch.yml
(When installed by git/pack instead of a local checkout, run npm run build
first — the manifest ships built lib/, not sources.)
Configuration
Configuration goes through the bundle's Config schema (set in the patch /
profile overlay):
- insert:
- id: calendar
name: dsh-calendar
config:
defaultTimezone: Asia/Shanghai
serverUrl: https://nextcloud.example.com/remote.php/dav/
# or calendarUrl: https://nextcloud.example.com/remote.php/dav/calendars/me/personal/
authMode: basic # basic | google
or via environment variables / the dsh credential service (see below).
Credentials (never logged)
| secret | meaning |
|---|---|
CALDAV_URL |
full calendar collection URL (Basic) |
CALDAV_USERNAME / CALDAV_PASSWORD |
Basic credentials |
GOOGLE_CLIENT_ID |
Google OAuth client id |
GOOGLE_CALDAV_REFRESH_TOKEN |
long-lived refresh token (see below) |
Set them in the environment, or store them in the dsh credential service
(credentialRef names match the table above, e.g.credentialRef('CALDAV_PASSWORD')), or, for the CLI, in the local.calendar-credentials.json (mode 0600). The resolver checks environment →
dsh credential service → local store.
Google OAuth (device flow)
dsh-calendar auth google --device --client-id <CLIENT_ID>
opens a URL to authorize; the refresh token is saved to the secure store. The
server-side client refreshes the access token automatically when near expiry.
Tools (ctx.tools)
| tool | description |
|---|---|
cal_list |
events in a window (with wall/UTC times) |
cal_get |
one series + its concrete occurrences |
cal_create |
create (RRULE/EXDATE/RDATE/all-day) + conflict check |
cal_update |
update whole series, or one occurrence via recurrenceId |
cal_delete |
delete series, or one occurrence (→ CANCELLED override) |
cal_search |
text search over titles/descriptions/locations |
cal_conflicts |
check a proposed time (incl. recurring) for overlaps |
cal_holidays |
upcoming Chinese holidays + today's 干支/生肖 |
cal_calendars |
list accessible calendars |
cal_remind |
reminder plan, formatted for dsh schedule_create |
Reminder linkage: dsh's schedule surface is deliberately model-facing
(schedule_create / schedule_list / schedule_delete). cal_remind
expands the event and returns { at: { date, time, time_zone }, prompt }
per occurrence — pass those directly to schedule_create to register
session-local reminders in the calendar's timezone.
CLI
dsh-calendar list [--start "2026-01-01" --end "2026-01-31" --tz Asia/Shanghai]
dsh-calendar get <uid>
dsh-calendar create --summary "Team sync" --start "2026-03-02 10:00" --end "2026-03-02 11:00" \
--rrule "FREQ=WEEKLY;COUNT=4"
dsh-calendar update <uid> --summary "Renamed" --recurrence-id "2026-03-09 10:00" --start "2026-03-09 15:00"
dsh-calendar delete <uid> [--recurrence-id "2026-03-09 10:00"]
dsh-calendar search "meeting"
dsh-calendar conflicts --start "2026-06-01 14:00" --end "2026-06-01 15:00"
dsh-calendar holidays --days 60
dsh-calendar calendars
dsh-calendar remind <uid> --before 30m
dsh-calendar auth google --device
dsh-calendar auth status
A .env file in the working directory is loaded (if present) before
credentials are resolved.
Timezone model
The engine embeds present-day IANA-style rules for common zones (Shanghai,
Tokyo, Seoul, London, Paris, Berlin, New York, Chicago, Los Angeles, Sydney,
Auckland, …). Conversions are:
wall (TZID) ↔ UTCwith deterministic DST handling:- a fold (autumn, wall time occurs twice) picks the first occurrence
(the larger offset); - a gap (spring, wall time does not exist) is shifted forward across
the gap.
- a fold (autumn, wall time occurs twice) picks the first occurrence
- All-day dates are stored as dates and interpreted at midnight in the event
/ default timezone. - RRULE instances are expanded on the DTSTART's wall-clock representation, so
a weekly 09:00 meeting stays at 09:00 on both sides of a DST transition.
Lunar calendar
Computed from astronomical principles (Meeus truncated new-moon &
solar-longitude series) rather than a hard-coded table, so the whole
2000–2100 range is covered by construction, including leap months (闰月)
and the famously unusual 2033 闰十一月. The test suite pins 春节 dates across
2000–2100, known leap months (2001–2033), and holiday dates (端午/中秋/清明).
Development
npm install
npm test # vitest: 185 tests (rrule vectors, DST, lunar, conflicts, CalDAV mock)
npm run typecheck
npm run build # compile to lib/
Tests run against an in-process mock CalDAV server (test/helpers/mockCaldav.ts)
and RFC 5545 example vectors — no network access needed.
License
MIT — see LICENSE.
Install
Install the catalog once, then DeepSeek Harness can find and install any plugin from this site automatically:
dsh plugin add dshbase-catalog Then say "install calendar for me" — your agent finds it in the directory and installs it. Docs: dshbase-catalog · verified packs.
This plugin is GitHub source (not published to npm) — install it straight from the repo:
Web profile:
dsh plugin --profile web add github:JohnXu22786/calendar Headless (CLI) profile:
dsh plugin --profile headless add github:JohnXu22786/calendar Test report
Verified: L1 install + L2 load + L3 runtime from GitHub source on dsh 0.1.0-rc.6.