Before starting, first read ../lark-shared/SKILL.md(authentication, permission handling).
CRITICAL — whenever booking events/meeting rooms, adjusting times, or querying/searching meeting rooms is involved, the first step MUST be to read references/lark-calendar-schedule-meeting.md. When only editing fields (changing title/description) or adding/removing attendees (without involving time and meeting rooms), you may skip it and directly read references/lark-calendar-update.md。
Identity
Choose identity byevent ownership:
- View/manage the logged-in user's own events →
--as user(default, the vast majority of scenarios). - View/manage events created/owned by the bot itself →
--as bot
Conversational person mapping: "I" = the logged-in user, "you" = the application (bot); persons used as field values (attendees, meeting owner, etc.) do not participate in identity determination, e.g. "you create the event, invite me, and the meeting owner is me" → --as bot creates it, and the logged-in user is only the attendee and meeting owner.
# 用户本人日程 → user
lark-cli calendar +agenda --as user
# bot 自建或参与的日程 → bot
lark-cli calendar +agenda --as bot
Shortcuts
| Shortcut | Description |
|---|---|
+agenda |
View schedule (defaults to today) |
+meeting |
Get the associated video meeting information (meeting_id, meeting_note) via the event ID; a meeting_id only exists if the event has had a video meeting,Note: to get the video meeting link, use the +get command |
+create |
Create an event and invite attendees (ISO 8601 time) |
+update |
Update existing event fields, or independently incrementally add/remove attendees and meeting rooms; recurring events/exceptions must pass --apply-to(see Recurring Event Operation Guidelines) |
+delete |
Delete an event; recurring events/exceptions must pass --apply-to(see Recurring Event Operation Guidelines) |
+freebusy |
Query the primary calendar's availability/RSVP status/free time slots. (If you need to book/recommend time slotsuse +suggestion— it recommends based on working hours, busy intervals, and break times.) |
+room-find |
For one or moreexplicittime blocks, find available meeting rooms (when there is no explicit time, calling directly is prohibited; you must first use +suggestion) |
+rsvp |
Respond to an event (accept/decline/tentative) |
+join-event |
Join an event with a share token (share link/QR code/share card/RSVP card) |
+suggestion |
Based on a non-explicit time or a time range, recommend multiple available time block options |
+transfer |
Transfer event ownership to another user or bot; irreversible, requires --yes |
+list-attendees |
List an event's attendees and meeting rooms (supports filtering by --type : user / resource / chat / third_party) |
+get — Single event details
Get via calendar_id + event_id thesingle eventdetails.
# calendar_id不传,默认primary
lark-cli calendar +get --calendar-id <calendar_id> --event-id <event_id>
Event descriptions uniformly use the description single field, handled as Markdown rich text. When reading an event, description returns Markdown rich text (when there is only a plain text description, that plain text is returned); when creating/updating an event, it is also via --description Pass in Markdown.
+getReturns results without attendees and meeting rooms. For the attendee perspective (user / meeting room / group / third-party email), call+list-attendees。
+search-event — Search schedules by keyword, time range, and attendees
Returns only basic fields (event_id/summary/start/end , etc.). For details, use +get。
# query 按关键词 可选
# start/end 按时间范围(ISO 8601 或 YYYY-MM-DD)可选
# attendee-ids 按参会人(自动识别 ou_ 用户 / oc_ 群聊 / omm_ 会议室前缀)可选
# page-token 分页游标,用于继续翻页 可选
# page-size 每页数量,默认 30 可选
lark-cli calendar +search-event --query "周会" --start 2026-04-20 --end 2026-04-27 --attendee-ids "ou_user1,oc_chat1,omm_room1" --page-token <page_token> --page-size 30
--attendee-ids multi-value semantics:Within the same type, it is OR (union)— as long as a schedule matches any one ID of the same type in the list, it will be returned.
--attendee-ids "ou_A,ou_B"= A or Schedules attended by B (not attended by both A and B).
+delete — Delete schedule
# calendar_id不传,默认primary
lark-cli calendar +delete --calendar-id <calendar_id> --event-id <event_id> --notify=true
+agenda — View recent schedule arrangements
By default, query the current day. Results should be organized into an easy-to-read timeline grouped by date and sorted ascending by start time.
# start/end 时间范围(ISO 8601 / YYYY-MM-DD / Unix 秒),均可选;默认当天
# calendar-id 日历 ID(默认primary)可选
lark-cli calendar +agenda --start 2026-03-10 --end 2026-03-17 --calendar-id <calendar_id>
Note:
- Canceled schedules are automatically filtered out; when there are no schedules, directly state "schedule cleared".
- If the time range exceeds 40 days, queries will be automatically split and results merged.
+freebusy — Query primary calendar busy/free periods / events / public free time
+freebusy One entry point handles four perspectives: geometric calculation type (busy / free / common_free) goes through automatic merging; event dimension type (raw_busy) retains each upstream schedule + rsvp_status。
# start/end 时间范围(ISO 8601 / YYYY-MM-DD / Unix 秒),均可选;默认当天
# user-id 目标用户 open_id,可重复或用逗号分隔;默认当前登录用户,bot 身份必须显式传至少一个
# type 视角四选一(默认 busy):
# busy 每个 user 合并后的忙碌区间(找空档、看忙碌时段)
# raw_busy 每个 user 的原始日程块 + rsvp_status(数会议、看每个会的 rsvp)
# free 每个 user 在时间窗内的空闲区间(可带 --min-duration 过滤)
# common_free 所有 user 的共同空闲区间(可带 --min-duration 过滤)
# min-duration 仅对 free / common_free 生效;Go duration 格式,例如 30m、1h、90m
# 查询忙碌时间段(去重并合并相邻/重叠段)
lark-cli calendar +freebusy --start 2026-03-11 --end 2026-03-11 --user-id ou_a,ou_b --type busy
# 看别人有几个会、每个会的起止 + rsvp(不合并相邻/重叠段,带rsvp状态)
lark-cli calendar +freebusy --start 2026-03-11 --end 2026-03-11 --user-id ou_a,ou_b --type raw_busy
# 查询用户空闲时间段
lark-cli calendar +freebusy --start 2026-03-11 --end 2026-03-11 --user-id ou_a,ou_b --type free
# 多人公共空闲时间段(推荐替代手工合并)
lark-cli calendar +freebusy --start 2026-03-11T09:00:00+08:00 --end 2026-03-11T18:00:00+08:00 --user-id ou_a,ou_b --type common_free --min-duration 30m
Usage tips:
+freebusyonly applies to querying the fact of busy/free time periods. If the goal is "recommendrecommenda suitable time slot for a meeting" (single-person or multi-person), you must prioritize using+suggestion— it comprehensively considersworking hours, busy periods, and break periodsto make recommendations;+freebusyonly answers "which intervals are free" and does not judge whether an interval is suitable for scheduling a meeting.- Multi-person public free time: if you only want "which intervals are commonly unoccupied" →
--type common_free [--min-duration <dur>]; if you want "recommended meeting time slots" → use+suggestion。
Precondition routing
First determine whether it is a recurring schedule: if the operation target is a recurring schedule, you must first read Recurring Schedule Operation Guidelines, and when the user has not specified the scope, first confirm "this occurrence only / all / this and following" (do not default to this occurrence only), then proceed to the specific operation flow according to the table below.
| Scenario | Prerequisite |
|---|---|
| Book schedule/meeting, adjust time, check meeting rooms | First read lark-calendar-schedule-meeting.md |
| Edit only fields (title/description) or add/remove attendees | First locate event_id, then read lark-calendar-update.md |
| Call any Shortcut | First read its corresponding reference document |
Write operation feedback
After write operations such as create, update, delete, and RSVP are completed, provide feedback to the user directly based on the command return result; do not proactively initiate a second query just to "confirm whether it took effect." Only when the user explicitly requests a recheck, or when the information returned by the command is insufficient to answer the user's question, is another query needed.
Core concepts
- Schedule instance (Instance): the specific time instance after a recurring schedule is expanded. For "this occurrence only" operations, use the specific instance's
event_id; for "all" or "this and following" operations, operate on the original recurring schedule (using the original scheduleevent_id), and handle exceptions as needed. - Recurring schedule exception (Exception): An independent event generated after a "this instance only" edit is made to one instance of a recurring event (with its own independent
event_id). When deleting/updating "all", exceptions must be handled at the same time, otherwise the exceptions will remain. - All-day Event: An event that occupies time only by date, with no specific start or end time; the end date is included in the event's time.
- Time block vs time range: A time block is a specific, definite continuous period of time (such as
14:00~15:00); a time range is a general reference (such as "this afternoon").+room-findmust be based on a definite time block, not on a vague range. - Room: "room" is not "room", it is "meeting room". A meeting room is a type of event participant (resource attendee) and cannot be booked separately from an event.
- Meeting ID: The event's historical video meeting ID; it exists only if a video meeting has been held on the event.
- Event share link vs meeting link: The two are different things and cannot be used interchangeably.
- Event share link:
https://<domain>/calendar/share?token=<token>, points to the event itself and is used to share event details.To share an event with someone, a group, or paste it into a document, what is needed is this event share link (obtained viacalendar events share_info), not an applink; it is forbidden to construct an applink yourself or use an applink as a substitute. - Meeting link:
https://<domain>/j/<number>, points to the video meeting entrance; all instances of the same recurring event series share the same meeting link.
- Event share link:
Term mapping
When users casually say "help me schedule a calendar" or "check today's calendar", the actual intent is the creation or query of an **event**, not operating the calendar container itself. Automatically map the colloquial "calendar" intent to an "event" operation.
Intent routing
Relationship between events and meetings: What users call a "meeting" usually does not distinguish between an event and a video meeting. For definitions and the routing rules for the three query intents (current/future/past), see Relationship between events and video meetings。
| User intent | Route to |
|---|---|
| Query past meetings ("yesterday's meeting", "last week's meeting") / what meetings are there today / meetings currently in progress | First read Relationship between events and video meetings |
| Future meetings / tomorrow's or next week's meetings | This skill: video meetings do not exist in the future; equivalent to querying events |
| Search events by keyword | This skill (+search-event) |
| Obtain the associated video meeting ID or the user-bound meeting notes document from the event | This skill (+meeting) |
View the event's attendees / meeting rooms (including --type resource show only meeting rooms) |
This skill (+list-attendees) |
| Share the event with someone / a group / paste into a document | This skill: first calendar events share_info getevent share link, then use lark-im to send or paste the link;To share an event with someone, a group, or paste it into a document, what is needed is the event share link, not an applink, do not concatenate it yourself or substitute it with applink |
| Further retrieve AI smart notes / verbatim transcript / Minutes artifacts from the calendar event | First +meeting retrieve meeting_id, then enter lark-meeting:vc +detail → note +detail / minutes +detail |
| Book/reschedule a calendar event, adjust the time, add/change a meeting room, check meeting rooms | First determine new vs edit, then enter the schedule-meeting workflow |
| Only edit calendar event fields (title/description) or add/remove attendees (not involving time or meeting rooms) | First locate event_id, then read +update to perform the changes |
| Edit/delete recurring calendar events ("change this recurring event", "delete the following ones", "cancel all", etc.) | First read the recurring calendar event operation guidelines;+update / +delete all through `--apply-to=single |
| Transfer the calendar event organizer ("hand this calendar event over to XX", "change the organizer to XX", "transfer this meeting to me", "give it back to me after the bot creates it") | Read +transfer;--as usecurrent organizeridentity,--to-user-id pass the recipient, allowing arbitrary transfers between the user and the bot |
Task type triage
When handling "book/reschedule a calendar event, add/remove attendees, add/change a meeting room, adjust the time", you must first determine new vs edit:
- Strong signal for editing an existing calendar event: the user mentions an anchor of an existing calendar event (title, time range,
这个日程、这场会) and expresses a modification action (add, remove, move to, change meeting room, adjust time). By default, follow the edit flow; never treat it as new. - New calendar event: the user expresses an intent to add something ("schedule a new meeting", "create a calendar event", "arrange a meeting"), and there is no modification action pointing to an existing calendar event.
Time inference guidelines
- Definition of weekdays: Monday is the first day of the week, and Sunday is the last day. When calculating relative dates such as "next Monday", infer based on the current real date.
- Range of a day: when the user mentions "tomorrow", "today", etc. referring generally to a day, the time range should cover the whole day; do not narrow it on your own.
- Historical time constraint: you cannot book a time that has already completely passed. The only exception is a calendar event that "spans the current time" (starts in the past and ends in the future).
Meeting room rules
- Whenever it is "book/query/search for available meeting rooms", you must enter the schedule-meeting workflow. For meeting room parameter specifications, see +room-find。
+room-findtime input must be a definite time block, and cannot be a time range search.- When the user only asks to "check meeting rooms" but does not provide a definite time, you must first call
+suggestionto obtain available time blocks, then pass the time blocks to+room-find. It is strictly forbidden to guess the time and call blindly. - When editing an existing calendar event, "add a meeting room" by default has incremental semantics, retaining existing meeting rooms; only when the user explicitly says "change meeting room" or "remove meeting room" should the old meeting room be deleted.
API Resources
# 通用调用格式
lark-cli calendar <resource> <method> [flags]
# 查询用户主日历
lark-cli calendar calendars primary
# 获取日程分享链接(分享给他人/群前必须先拿到)
# 返回形如 {{domain}}/calendar/share?token=<token> 的分享链接,不是 applink;直接把该链接发给对方(对方可凭链接中的 token 走 +join-event 加入)
lark-cli calendar events share_info --calendar-id <calendar_id> --event-id <event_id>
# 删除日程
lark-cli calendar events delete --calendar-id <calendar_id> --event-id <event_id>
calendar_idcan directly passprimary, representing the primary calendar ID of the current calling identity.
List of methods for querying resources and how to use the methods
- List methods under a resource:
lark-cli calendar <resource> -h - View the method's CLI flag:
lark-cli calendar <resource> <method> -h - View method API parameters:
lark-cli schema calendar.<resource>.<method>
<resource> is calendars(calendar itself) / events(event) / event.attendees(attendee) / freebusys(free/busy). Example:lark-cli schema calendar.events.delete。
Common commands for other domains
# 批量搜索多个用户,更多参数详见 lark-contact
lark-cli contact +search-user --queries "<q1>,<q2>" --as user
# 搜索群聊,更多参数详见 lark-im
lark-cli im +chat-search --query <query> --as user
Searching users/groups does not support bot identity; you must use
--as user。When it cannot be resolved or the type is unclear, clarify the attendee type with the user; do not guess the type based on the name format.
Not within the scope of this skill
- Query past video conference records → lark-meeting
- To-do task management → lark-task
- Contacts → lark-contact
- Instant messaging → lark-im
- Meeting room physical facility management → admin backend
Note (mandatory):
- When converting between date (time) strings and timestamps, be sure to call external tools such as system commands or script code to process it, to ensure the absolute accuracy of the conversion; for conversion,do not rely on the container's default time zone(often UTC, which will cause an 8-hour offset); you must explicitly specify the target time zone. Violation will lead to serious logical errors!