SuperAPI AI Directory

apple-smart-schedule

General & other

View repository

Updated 10-15 20:10

About this skill

apple-smart-schedule · Apple Smart Schedule Reminder

⚠️ Platform limitation (read first)

This skill runs only on macOSit uses osascript/remindctl to call the built-in "Calendar" and "Reminders" apps on the Mac to create schedules.

  • ✅ The creation results are automatically synced via iCloudto your iPhone / iPad signed in with the same Apple ID.
  • ❌ It cannot be used directly on Windows / Android / Linux, nor can these scripts run directly on iPhone.
  • Authorization (important): When the script is run for the first time, macOS will pop up a "xxx wants to control "Calendar"/"Reminders"" dialog.Just click "OK"(only this once).Each time you switch to a different terminal app or use it for the first time in a new environment, it will pop up again—because authorization is recorded separately by "the calling terminal app" (authorizing Terminal does not mean iTerm is also authorized); just click it and there is no need to look for it in Settings. Only when the pop-up does not appear, or when you have previously clicked "Don't Allow", should you go to "System Settings › Privacy & Security › Automation" and manually turn on the Calendar / Reminders switch for the corresponding terminal.

What it does

The user says something in plain language (or sends a screenshot), and this skill:

  1. Parses event title, start time, end time (optional), location, event type;
  2. Applies default lead timeaccording to event type (plane/high-speed rail/court hearing/meeting/deadline/social each differ);
  3. Creates in Apple Calendar 1 event(if a similar event already exists that day,updateit instead of creating a duplicate), and creates in Reminders a set of advance reminders;
  4. and reports back to the user what was created.

General scenarios (the same logic, not limited to travel):

Type Example input Smart default lead time
✈️ Flight "China Eastern MU5137 7/20 8:30 departing from Pudong" 1 day before at 9 AM + 3h before + 1h before
🚄 High-speed rail "G1234 Beijing South→Shanghai Hongqiao 8/1 14:00" 1h before + 30min before
⚖️ Court hearing "next Wednesday 14:00 court hearing" 1 day before at 9 AM + 3h before + 1h before
💼 Meeting "meeting tomorrow morning at 10" 1 day before at 9 AM + 1h before
⏰ Deadline "appeal period deadline on the 15th" 3 days before + 1 day before + 9 AM on the day
🍻 Social "dinner with Mr. Zhang on Friday evening" 1 day before at 9 AM + 2h before
🎯 Other "health check-up the morning after tomorrow" 1h before

Core workflow (AI execution steps)

Step 0: Read the configuration (every time)

Read $SKILL_DIR/config/config.json, and get: time zone, default calendar name default_calendar, default reminder list name default_reminder_list, lead time for each event type lead_times. Then read $SKILL_DIR/references/lead-times.md, and master theevent type determination rulesandlead time calculation method。

Step 1: Parse the input

  • Text input: extract directly from the user message the time (date + hour and minute), event, location, flight number/train number, etc.
  • Screenshot input(flight ticket confirmation page, 12306, WeChat invitation, etc.): use visual capability to read out the above fields.
  • Interpret the time according to config.timezone(default Asia/Shanghai). When ambiguous (e.g., "next Wednesday" without a specified time zone, or only "afternoon"), use the most common interpretation andstate your interpretation in the receipt, so the user can correct it at a glance.
  • No end time given → default event duration is 60 minutes (enough for meetings/social events; for flights/high-speed rail, it is better if the duration can be inferred).

Step 2: Determine the event type

Classify into one of references/lead-times.md according to the keyword list in flight / train / court / meeting / deadline / social / default . One message may contain multiple events (e.g., a business trip = flight + meeting after arrival); handle them separately.

Step 3: Calculate the absolute time of each reminder

Take the array from config.lead_times[类型] , and convert each one into lead-times.md according to the format rules inabsolute time(ISO,Asia/Shanghai)。

User's override for this instance takes precedence: if the user explicitly says "X hours in advance" or "remind only once", then for this instance use only what the user specified and ignore the defaults.

Step 4: Duplicate check and write (update or create new)

By default, check for duplicates first, to avoid creating duplicate events when the user supplements flight/hotel/rebooking information. Only when the user explicitly says "create another one" or "record separately" should you skip the duplicate check and create a new one directly.

# 1) 查事件日期当天的已有事件(默认查 default_calendar;用户提过别的日历就查那个;指称模糊用 ALL)
$SKILL_DIR/scripts/find_event.sh "<日历名|ALL>" "<事件日期YYYY-MM-DD>"

# 2a) 唯一匹配 → 更新已有事件(第 2–6 参数传 "-" = 不改该项;备注是整段替换,补充信息要先合并原备注再写入)
$SKILL_DIR/scripts/update_event.sh "<uid>" ["<新标题>"] ["<新开始ISO>"] ["<新结束ISO>"] ["<新地点>"] ["<新备注>"]
#     定位也可用标题关键词兜底;多匹配会拒绝并列出候选。详见下文「修改已有事件」一节。

# 2b) 无匹配 → 新建
$SKILL_DIR/scripts/create_event.sh "<标题>" "<default_calendar>" "<开始ISO>" ["<结束ISO>"] ["<地点>"] ["<备注>"]

# 3) 提醒:对每个提前量建一条
$SKILL_DIR/scripts/create_reminder.sh "<标题>" "<default_reminder_list>" "<提醒绝对ISO>"

Duplicate match rules(judge each candidate in the find output one by one):

  • Same day, and the title contains the same key identifier (flight number/train number/case number/activity name)or the time is close (±3 hours) and the topic is consistent → same event;
  • All-day events (starting at 00:00, with no clear duration) participate in matching by "that day";
  • Unique match → update; if there are multiple candidates or you are unsure → list the candidates for the user to choose,do not guess;
  • 0 matches but the user says "I already created it" → expand the window to 1 day before and after and search again (find_event.sh "<日历>" "<前一天>" "<后两天>");
  • if you have taken the update path, thendo not create a new reminder again(it was most likely already created before, and creating it again = harassment); in the receipt, ask whether to also add a reminder;
  • If what is being updated is an event manually created by the user, explain clearly in the receiptwhich fields were changed(time/location/notes).

Writing key points:

  • One business trip = one calendar event: for the same itinerary, the outbound trip/accommodation/return trip (and multiple local arrangements) are merged by default intooneevent—start/end = outbound departure → return landing, title = itinerary name (e.g., XX大学 · 行业前沿讲座(西安)), and flight/hotel details are written hierarchically into the notes (✈️ Outbound… / 🏨 Accommodation… / ✈️ Return…).Do notSplit into multiple events by transportation/accommodation; reminders are still created based on key milestones within the itinerary (e.g., 3h before each flight).
  • Details within the itinerary are also merged into the overview: the exact time slots, locations, meeting room numbers, online meeting IDs, and agenda highlights of lectures/meetings — all go into the overview event'snotesorlocationfields,do not create new lecture/meeting sub-events, and do not create separate reminders for them either. Criterion: any "detail that occurs on the day the business trip overview event starts/ends or on a day in between" is handled by merging; only schedules that are truly independent and do not depend on any travel overview get new events. Written into DEC-006.
  • Example title for a single-segment itinerary (only one flight/one meeting):✈️ MU5137 上海浦东→北京首都
  • Key fields for flight/travel entries: refer to the "Flight detailed field entry template" in references/lead-times.md , and organize airline/cabin class/aircraft type/flight duration into the eventnotes(the notes parameter of update/create), terminal goes intolocation。Do not recordpassenger/ticket number/order number (unnecessary and raises privacy concerns).
  • Add distinguishing suffixes to reminder titles so users can see them clearly in the list:✈️ MU5137 值机打包(前1天)、🚄 G1234 该去车站了(前1h)、⚖️ 开庭准备(前3h)。
  • The script will automatically degrade: when remindctl is not installed, use osascript(reminders can still be created, just cannot be queried/modified/deleted).

Step 5: Receipt

Give the user a brief list, for example:

已为你安排 ✈️ MU5137(2026-07-20 08:30,上海浦东 T2)
📅 日历事件已建 →「个人」日历
⏰ 提醒事项已建 3 条:
   • 07-19 09:00  值机打包(前1天)
   • 07-20 05:30  该去机场了(前3h)
   • 07-20 07:30  开始登机(前1h)
(经 iCloud 同步到你的 iPhone/iPad,稍等片刻可在手机上看到)

When updating an existing event, change the receipt to "what was changed", for example:

✈️ MU5137 已改签为 08:50 起飞——更新的是你 7/20 已有的那条日历事件(未新建)
📅 改动:开始时间 08:30 → 08:50,备注补充了舱位信息

First-time setup (important)

  1. If config/config.json does not exist yet, copy one from the template:
    cp config/config.example.json config/config.json
    
  2. Run the self-check to get the real calendar names and reminder list names on your machine:
    bash $SKILL_DIR/scripts/setup_check.sh
    
  3. Put the output'scalendar nameinto config.json 's default_calendar,list nameinto default_reminder_list. If you fill it in wrong, no error will be reported — the script will fall back to the first calendar/default list, but only the correct name will land where you want it.

config.json is your local configuration (ignored by .gitignore and not committed);config.example.json is the default template checked into the repository.

To adjust the lead time for various types of events, directly modify config.json 's lead_times(format see references/lead-times.md)。

Lead time is the personal configuration entry point: when the user expresses preferences such as "too many reminders/only 3 hours in advance/no reminder needed 1 day before", put itinto config.json 's lead_times(configured once and effective long-term), do not verbally ignore the default each time — otherwise next time in a new session a string will be created according to the default again.

Install a stronger backend (optional)

Reminders use osascriptby default (create only). After installing remindctl , you can also query/modify/delete:

brew install steipete/tap/remindctl

Whether installed or not does not affect the creation function; this skill will automatically detect it.

Script reference

Script Purpose
scripts/create_event.sh Create calendar events (osascript)
scripts/find_event.sh Query existing events by date window + keywords (deduplication/location, output uid and each field)
scripts/update_event.sh Modify existingcalendar events (located by UID or title,- = do not change that item; create_event.sh can only create new ones)
scripts/create_reminder.sh Create reminder (prefer remindctl, fall back to osascript)
scripts/list_calendars.sh List all calendar names
scripts/list_reminder_lists.sh List all reminder lists
scripts/setup_check.sh Initial self-check: dependencies, permissions, calendar/list names

Modify an existing event (use update_event.sh, do not rebuild with create_event.sh)

When the user says "add the itinerary to that existing schedule of mine", "change the time", or "add the hotel info", it ismodify, not create. create_event.sh only creates; repeated calls produce duplicate events—for this kind of request always use:

$SKILL_DIR/scripts/update_event.sh "<UID 或 标题关键词>" ["<新标题>"] ["<开始>"] ["<结束>"] ["<地点>"] ["<备注>"]

Parameter rules: pass - for the 2nd–6th parameters to mean "do not change this item"; for start/end you may change only one, and fill -。

Lookup order: first exact match by UID → if no match, then match by title containing → if the title matchesmultipleevents, refuse to modify and return the candidate list (to prevent mistaken edits); in this case switch to using UID.

Look up before modifying: when you do not know the UID, first use osascript to list candidate events by keyword (including UID, start/end, calendar name), then modify precisely by UID.

Example: correct the existing "Xi'an business trip" placeholder and add the hotel info

update_event.sh "西安出差" "-" "2026-09-08 10:10" "2026-09-09 12:35" "西安 · XX大学" "去程 CA1234 …"
update_event.sh "XX酒店" "-" "-" "-" "-" "预订号 888888 · 客户经理 …"

⚠️ Two pitfalls of changing dates in AppleScript (already encountered)

  1. Component order: must first set day of d to 1, then set year / month / dayin order, and finally set hours / minutes / seconds. If the order is reversed, it may overflow because the target month does not have enough days (for example, putting day 31 into September).
  2. Do not use subtraction to cross days: to mean "the 9th at 17:00",directlyset day=9, hours=17;do notwrite it as day=9, hours=0 then 减 7 小时—subtraction rolls back across the day to the 8th at 17:00, squeezing two days of itinerary into the same day.

After modifying, be sure to re-check the start/end times with osascript to confirm that a cross-day event really crosses days.

Note

  • This is an operation that modifies the user's personal calendars/reminders.Creationis safe and reversible (the user can delete it in the app); but if this skill is extended in the future to deletion/batch operations, be sure to confirm the target with the user first.
  • Reminder data is personal privacy; do not send calendar/reminder contents to the network or third-party services. Parsing is done locally only.
  • If the user actually wants a non-Apple calendar such as Feishu/DingTalk/Outlook, this skill does not apply—those require their own tools.