Install
openclaw skills install @flyinghanger/feishu-meeting-room-book飞书会议室偏好初始化与预定。适用于:初始化/刷新个人会议室列表、创建会议并预定会议室、 给已有会议补订会议室。使用本地状态文件保存首选会议室列表;第一版只维护一个 base 地(默认城市,内部字段为 default_city) 的会议室列表,跨城市时只创建会议不自动订房。
openclaw skills install @flyinghanger/feishu-meeting-room-book基于飞书日历事件学习个人常用会议室,并按本地偏好列表预定会议室。
state/feishu-meeting-room-book.jsonskills/feishu-meeting-room-book/scripts/meeting_room_booker.pytmp/meeting-room-refresh-plan.jsonopenclaw-lark or any equivalent Feishu/Lark plugin that exposes:
feishu_calendar_eventfeishu_calendar_event_attendeefeishu_calendar_freebusypython3state/feishu-meeting-room-book.jsontmp/meeting-room-events-*.json and tmp/meeting-room-candidates-*.jsoncalendar:calendar.event:read for reading recent calendar events during init/refreshcalendar:calendar.event:create for creating new calendar eventscalendar:calendar.event:update for attaching meeting rooms and updating event attendeescalendar:calendar.free_busy:read for checking room availabilityresource attendeefeishu_calendar_eventfeishu_calendar_event_attendeefeishu_calendar_freebusyIf any Feishu tool returns auth or scope errors, finish the OAuth flow first and retry. The normal scopes for this skill are:
calendar:calendar.event:readcalendar:calendar.event:createcalendar:calendar.event:updatecalendar:calendar.free_busy:readdefault_city.state/feishu-meeting-room-book.json does not exist and the user asked to create/book a room or book an existing event, do not ask the user to initialize separately. Tell the user you are starting first-time initialization, run init immediately, and continue the original request after the default room order has been saved.会议default_city.create_and_book: still create the event without a roombook_existing: keep the event unchanged and tell the user to refresh after manually seeding more roomsUse these rules when the user asks how to update the candidate room list.
resource attendee.刷新会议室列表, 更新会议室列表, 重新学习会议室, or 更新会议室候选表.--room-id list.now - 1 day to now + 7 days.now - 7 days to now + 7 days.now - 20 days to now + 20 days - 1 minute.Use this flow when the user says:
When init is triggered implicitly because the state file does not exist, explicitly tell the user:
Steps:
default_refresh: when state already exists and the user says 刷新会议室列表, 更新会议室列表, 重新学习会议室, or 更新会议室候选表
now - 1 day to now + 7 daysinit: when the state file does not exist or the user explicitly says 初始化会议室偏好 or 初始化会议室预定技能
now - 7 days to now + 7 daysfull_rebuild: only when the user explicitly says 全量刷新会议室列表 or 重建会议室列表
now - 20 days to now + 20 days - 1 minutepython3 skills/feishu-meeting-room-book/scripts/meeting_room_booker.py plan-refresh \
--mode <default_refresh|init|full_rebuild> \
--output tmp/meeting-room-refresh-plan.json
tmp/meeting-room-refresh-plan.json.
Use exactly the slices[].start_time, slices[].end_time, slices[].event_file, and slices[].candidate_file values from that plan.
Do not invent your own temp filenames or time windows.feishu_calendar_event with action=listevent_file from the planpython3 skills/feishu-meeting-room-book/scripts/meeting_room_booker.py extract \
--input <event_file_from_plan> \
--output <candidate_file_from_plan>
extract fails with invalid JSON in <event_file> or any other parse error, treat that slice file as damaged or truncated.finalize-refresh.state/feishu-meeting-room-book.json during refresh:python3 skills/feishu-meeting-room-book/scripts/meeting_room_booker.py finalize-refresh \
--input <candidate_file_from_plan_1> \
--input <candidate_file_from_plan_2> \
--mode <default_refresh|init|full_rebuild> \
--state state/feishu-meeting-room-book.json \
--output tmp/meeting-room-candidates.json
tmp/meeting-room-candidates.json.
If the helper command failed or returned saved != true, stop, tell the user refresh failed, and keep the previous state unchanged.<default_city>default_refresh, explain that the existing list was preserved and newly discovered rooms were appendedpython3 skills/feishu-meeting-room-book/scripts/meeting_room_booker.py save \
--input tmp/meeting-room-candidates.json \
--state state/feishu-meeting-room-book.json \
--default-city "<city>" \
--output tmp/meeting-room-candidates-confirmed.json \
--room-id omm_first \
--room-id omm_second
Rules:
rsvp_status=accept.rsvp_status is missing in the event payload, keep the room candidate.default_refresh is incremental:
display_name, score, last_seen_at, and location_hints for rooms that were seen againfull_rebuild and then confirm a smaller subset.feishu_calendar_event tool does not expose reliable paging controls for list, so keep each time slice small enough that a single slice result remains manageable.now - 20 days to now + 20 days - 1 minute.write, edit, or any other direct file-writing tool on state/feishu-meeting-room-book.json.write is allowed only for raw per-slice temp files under tmp/meeting-room-events-*.json.> with meeting_room_booker.py JSON commands. Use the helper's --output flag so it writes atomically.event_file is truncated or malformed, extract will fail. Treat that as the real failure cause; do not continue with an empty or partially written candidate file.feishu_calendar_event JSON into another file.state/feishu-meeting-room-book.json.state/meeting-room-preferences.json or any other alternate state filename.extract / plan-refresh / finalize-refresh / save fails, stop immediately, tell the user refresh failed, and keep the previous state unchanged.Use this flow when the user wants to create a new event and also book a meeting room.
Steps:
state/feishu-meeting-room-book.json is missing, run init first.
python3 skills/feishu-meeting-room-book/scripts/meeting_room_booker.py show --state state/feishu-meeting-room-book.json --json
会议.user_open_id is always passed.start_time + 1 hour.default_city.feishu_calendar_freebusy with action=list and room_id=<room_id>.freebusy_items is empty.feishu_calendar_event action=create.
user_open_idattendees only when the user explicitly provided themfeishu_calendar_event_attendee action=create.feishu_calendar_event_attendee action=list once to inspect the room attendee status.Do not tell the user that topic, attendees, and duration are required. The user can simply give a start time; the defaults above fill the rest.
Interpretation:
accept: room booked successfullyneeds_action: event created and room booking submitted; tell the user it is pendingdecline or attendee-create failure: keep the event and tell the user no room was bookedUse this flow when the user wants to add a room to an existing event.
Steps:
state/feishu-meeting-room-book.json is missing, run init first.
event_idfeishu_calendar_event action=search or action=listfeishu_calendar_event_attendee action=list.accept or needs_action, stop and report the current room state.feishu_calendar_freebusy and attach the first free room with feishu_calendar_event_attendee.The helper script writes:
{
"version": 1,
"default_city": "Shanghai",
"updated_at": "2026-03-17T20:00:00+08:00",
"rooms": [
{
"room_id": "omm_xxx",
"display_name": "A5-01",
"rank": 1,
"score": 18,
"last_seen_at": "2026-03-16T10:00:00+08:00",
"location_hints": ["Shanghai HQ"]
}
]
}
This file is renewable runtime state. Keep it in state/.