Turn school or university timetables into checked .ics calendars. Use when an agent needs to normalize and verify schedules from xls/xlsx, screenshots, PDFs,...
Coding
calendar-subscribe
Try itTurn a school or work timetable (xlsx / csv) into a shareable HTTPS ICS subscription. Split class blocks into sessions, add one travel alarm per day (first class only), host a WeChat/iOS/Android landing page. Use when the user says 课表订阅, 日历订阅, timetable to ICS, calendar subscription, 同步到日历, webcal, 开学课表, share calendar with classmates. NOT FOR one-off local Calendar.app AppleScript dumps, Google Calendar API event-by-event writes, or todo/reminder apps.
What it does
Turn a school or work timetable (xlsx / csv) into a shareable HTTPS ICS subscription. Split class blocks into sessions, add one travel alarm per day (first class only), host a WeChat/iOS/Android landing page. Use when the user says 课表订阅, 日历订阅, timetable to ICS, calendar subscription, 同步到日历, webcal, 开学课表, share calendar with classmates. NOT FOR one-off local Calendar.app AppleScript dumps, Google Calendar API event-by-event writes, or todo/reminder apps.
The skill document
Calendar Subscribe
Turn a timetable file into a subscription calendar (one HTTPS .ics + a tiny landing page). Classmates add it once; you update the file when the schedule changes.
When this skill is on
User wants classmates / family to subscribe, not import a one-shot dump. Typical: school timetable, weekend MBA grid, recurring office hours.
Workflow
- Parse the source (xlsx grid or csv event list). Skip holiday / "no class" cells.
- Split each teaching block into the actual session times (do not merge a whole morning into one 3-hour event unless the user asks).
- ICS with a real timezone (
TZID, not floating local), CRLF, UTF-8 line fold on character boundaries. - Travel alarm once per calendar day, on the earliest class only. Default offset 90 minutes. Later sessions that day get no commute alarm.
- Host the
.icson any public HTTPS static path.Content-Type: text/calendar. - Landing page that branches: WeChat → "open in browser"; iOS →
webcal://; Android → Google Calendarcid=+ raw ICS. - Verify in the same turn:
curl -sIboth/pathand/path/; countBEGIN:VEVENTandBEGIN:VALARM;VALARMcount must equal distinct class days.
Source formats
A. Event list CSV (preferred when you can export it)
date,start,end,title,location,notes
2026-09-12,09:00,10:30,Finance,Room 222,week 1
B. Chinese-university weekend grid xlsx
- Row of week labels, row of Excel serial dates, row of 周六/周日
- Time-slot rows (morning / afternoon / evening)
- Merged holiday cells: read the merge origin; if text matches skip patterns, emit nothing
Default skip regex: 不上课|放假|补班
If the sheet only lists two clock ranges per period (e.g. 09:00–10:30 and 10:45–12:15), emit two events, not four 45-minute 节.
ICS rules
METHOD:PUBLISH,X-WR-CALNAME,X-WR-TIMEZONE,REFRESH-INTERVAL;VALUE=DURATION:P1DDTSTART/DTENDwithTZID=(defaultAsia/Shanghai)- Stable
UIDfrom date+start+title so republishing does not duplicate on clients that key on UID - Fold lines at ≤73 UTF-8 bytes on codepoint boundaries (do not split a Chinese character)
- Escape
\,;,,, newlines VALARMTRIGGER:-PT{N}Monly on the day's first event
Use scripts/build_ics.py. Example:
python3 scripts/build_ics.py \
--xlsx timetable.xlsx \
--out timetable.ics \
--name "Fall timetable" \
--location "Room 222" \
--tz Asia/Shanghai \
--travel-minutes 90
CSV path: --csv events.csv instead of --xlsx.
Hosting
Any HTTPS static file is enough. Apple Calendar, Google Calendar, and most Android calendars fetch from their servers, so the URL must be reachable from the public internet, not only the author's LAN.
Minimum nginx (adapt root and URL prefix):
location = /cal {
return 301 /cal/;
}
location ^~ /cal/ {
alias /var/www/cal/;
index index.html;
types {
text/calendar ics;
text/html html;
image/jpeg jpg jpeg;
image/png png;
}
add_header Cache-Control "public, max-age=3600";
}
Landing template: references/landing.html. Replace ICS_URL and PAGE_URL.
Poster / QR: generate a real QR of PAGE_URL (script or qrcode lib). Never let an image model draw the code. Leave a square hole on the poster and composite.
Verify (same turn, or do not claim it works)
curl -sI https://example.com/cal # must 301 → /cal/
curl -sI https://example.com/cal/ # text/html 200
curl -sI https://example.com/cal/timetable.ics # text/calendar
Count:
BEGIN:VEVENT= number of real sessions (not holidays)BEGIN:VALARM= number of distinct class days- zero holiday phrases in summaries
Gotchas
/calwithout a trailing slash is not/cal/. A prefix location^~ /cal/misses/cal. On a SPA host the bare path falls through toindex.html. If that app sendsCross-Origin-Embedder-Policy: require-corp, the page looks "broken" or blank. Always addlocation = /cal { return 301 /cal/; }.- Do not write nginx backups into
sites-enabled/. A.bakis loaded as a second server; duplicatelisten 443failsnginx -t. - Port 80
return 404(leftover certbot) makes http links look dead. 301 to https. - A location that sets any
add_headerdrops parentadd_headers. COOP/COEP on the server block will not apply — usually what you want for a calendar page. - WeChat in-app browser cannot add calendars. Detect
MicroMessengerand tell the user to open in the system browser first. - Google Calendar mobile app cannot subscribe from a URL. The
https://calendar.google.com/calendar/r?cid=link works in a browser; OEM calendars can open the raw.icsas a one-shot import (no later refresh). - Commute alarm is per day, not per session. 09:00 class → 07:30 leave. Do not also alarm 10:45 / afternoon / evening.
- UTF-8 fold: taking
bytes[:73]can land inside a 3-byte Chinese character and crash encode. Fold on characters, measuring encoded length. - Excel dates are serials from 1899-12-30 when
data_only=True. - Image-model QR codes do not scan.
- Domestic clients vs a US VPS: the author's phone may not reach the host. Give the raw ICS URL as a fallback; Google/Apple fetchers are usually outside the same firewall.
Examples
User: 把这张课表做成可以分享的日历订阅
→ parse xlsx → ICS → host → landing → verify VEVENT/VALARM
User: 通勤提前一个半小时,别每节课都响
→ --travel-minutes 90, first class of each day only
Related skills
Sync one or more source Google calendars into private Busy hold events in one or more target calendars using gog. Use when users need idempotent double-booki...
Manage Apple Calendar events from the command line on macOS — create, update, delete, search, export, and check availability with full JSON output for agent use.
通过 gcalcli 管理 Google 日历事件,支持创建、列出和删除日程,适合个人时间管理。Use when 需要项目管理、任务规划、进度跟踪、团队协作时使用。不适用于实际人员绩效评估。适用于独立开发者、企业团队和自动化工作流场景。支持中文交互,无需复杂配置即开即用。输出结果可直接使用,减少二次加工成本。
Use when the user wants the macOS 12+ Apple-enhanced SYSU workflow layer, especially natural-language requests such as 把课表同步到日历、把雨课堂 ddl 加到提醒事项、把宣讲会或招聘会写进日历、...
Extract calendar events from Gmail and create Google Calendar entries after your confirmation.