关于 lark-event
lark-event 是 Lark CLI 中的 skill,用于订阅飞书事件并以 NDJSON 形式输出到标准输出,供 AI 代理或脚本消费。它提供事件目录查询、字段结构查看和本地事件总线的状态管理。
主要功能
- 01事件目录与字段结构查询
- 02阻塞式消费事件并输出 NDJSON
- 03支持 --jq 过滤与转换事件
- 04支持按最大事件数或超时结束运行
- 05结构化退出码与 reason 标记
适用场景
- 01AI 代理实时接收飞书消息事件
- 02脚本按事件数量或时长采集飞书事件
- 03用 jq 表达式筛选特定群聊或发送者的消息
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ larksuite/ cli --skill lark-event安装后在 Claude Code 中输入/lark-event确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
references/lark-event-application.mdlark-event-approval.mdlark-event-im.mdlark-event-minutes.mdlark-event-task.mdlark-event-vc.mdlark-event-whiteboard.md详细介绍
飞书事件
**前提条件:**请先阅读
../lark-shared/SKILL.md,了解身份验证、--as user/bot切换、Permission denied处理方式和安全规则。
核心命令
| 命令 | 用途 |
|---|---|
lark-cli event list [--json] | 列出所有可订阅的 EventKey |
lark-cli event schema <EventKey> [--json] | 显示 EventKey 的参数和输出架构 |
lark-cli event consume <EventKey> [flags] | 阻塞式消费;事件 → stdout NDJSON |
lark-cli event status [--json] [--fail-on-orphan] | 检查本地总线守护进程的状态 |
lark-cli event stop [--all] [--force] | 停止总线守护进程 |
常用标志
| 标志 | 说明 |
|---|---|
--param key=value / -p | 业务参数(可重复;多值时以逗号分隔)。未知键会导致失败,并在提示中列出有效名称 |
--jq <expr> | 使用 jq 表达式筛选/转换每个事件;输出为空时跳过该事件 |
--max-events N | 收到 N 个事件后退出。默认值 0 = 不限数量 |
--timeout D | 在持续时间 D 后退出(例如 30s、2m)。默认值 0 = 不设超时。--max-events 和 --timeout 中先触发的条件生效 |
--output-dir <dir> | 将每个事件写入文件(仅限相对路径;防止路径遍历) |
--quiet | 隐藏就绪/退出标记及每个事件的 stderr 诊断信息,包括丢弃警告。这可能导致事件丢失被隐藏。AI 不应使用此选项——它会移除就绪和完整性信号 |
--as user|bot|auto | 会话身份(参见 lark-shared) |
示例
# Default: stream every event for the key (no filter, no projection)
lark-cli event consume im.message.receive_v1 --as bot
# List every EventKey of one domain (the authoritative, always-current catalog)
lark-cli event list --domain vc --json
# Grab one sample event to inspect payload shape
lark-cli event consume im.message.receive_v1 --max-events 1 --timeout 30s --as bot
# Run for 10 minutes then auto-exit
lark-cli event consume im.message.receive_v1 --timeout 10m --as bot
# Consume multiple EventKeys concurrently (one shape per process, no dispatcher)
lark-cli event consume im.message.receive_v1 --as bot > receive.ndjson &
lark-cli event consume im.message.reaction.created_v1 --as bot > reaction.ndjson &
wait
调用流程
lark-cli event list --json→ 选择有效的键。--domain <d>可将范围缩小到一个域;可选域为application、approval、board、card、im、minutes、task、vc。未知域会导致失败,并在提示中列出有效域。lark-cli event schema <key> --json→ 查看resolved_output_schema+jq_root_path,以确定字段路径lark-cli event consume <key> [--jq '<expr>']→ 消费事件
子进程约定
就绪标记
event consume 会在 stderr 输出固定行 [event] ready event_key=<key>。**父进程应阻塞读取 stderr,直到出现此行,然后开始读取 stdout。**不要改用 sleep。
stdin EOF = 正常退出
event consume 将 stdin 关闭视为关机信号(为 AI 子进程调用方接入)。**有界运行不受此规则影响:设置 --max-events 或 --timeout(> 0)时,会忽略 stdin EOF,且仅在达到自身限制、超时或收到 SIGTERM 时退出。**对于无界运行,< /dev/null / nohup / systemd 的默认 StandardInput=null 会导致立即正常退出(stderr reason: signal)。若要让无界运行保持运行:
- 为 stdin 提供一个不会到达 EOF 的来源:
< <(tail -f /dev/null) - 或运行有界任务:
--max-events N/--timeout D
退出代码与原因
退出时,stderr 的最后一行是 [event] exited — received N event(s) in Xs (reason: ...)。
| 退出代码 | 原因 | 触发条件 |
|---|---|---|
| 0 | reason: limit | 达到 --max-events |
| 0 | reason: timeout | 达到 --timeout |
| 0 | reason: signal | Ctrl+C / SIGTERM / stdin EOF(stdin EOF 仅适用于无上限运行) |
| 1 | stderr 上的 JSON 错误封装 | 消费前设置期间 Lark API 业务失败(例如创建/删除订阅) |
| 2 | stderr 上的 JSON 错误封装(无 exited 行) | 验证失败(未知 EventKey、无效的 --param / --jq、已有其他总线连接) |
| 3 | stderr 上的 JSON 错误封装 | 身份验证失败(缺少令牌、缺少权限范围) |
| 4 / 5 | stderr 上的 JSON 错误封装 | 网络/内部故障(总线启动、握手、文件 I/O) |
启动和运行时故障会在 stderr 上输出结构化 JSON 封装:{"ok":false,"error":{"type","subtype","param","message","hint",...}}(封装也可能包含顶层的 identity / _notice 同级字段)。使用 error.type / error.subtype 进行分支处理(例如,missing_scope 会携带 missing_scopes 列表),通过 error.param 查找有问题的标志,并根据 error.hint 执行恢复操作——不要使用正则表达式匹配消息文本。
编排器应将 reason: limit/timeout/signal(均为退出代码 0)视为“业务完成”,将非零退出代码视为“失败”。
切勿使用 kill -9
对于 PreConsume 会注册服务端订阅、且在退出时会取消订阅的 EventKey(minutes、vc、board 键),避免对消费进程使用 kill -9:kill -9 会跳过 OAPI 取消订阅,导致服务端订阅泄漏(表现为重启时出现“subscription already exists”、重复投递事件)。订阅是持久关系且无需清理的键(task、approval 键)不会因此泄漏,但对所有键而言,使用 SIGTERM 或关闭 stdin 仍是正确的关闭方式。
一次消费一个 EventKey(多个键 = 多个 Shell)
该命令只接受一个位置参数;不支持 k1,k2 和通配符。监听 N 个键意味着运行 N 个子进程——这是有意设计:
- 每个进程的 stdout 只有一种结构;AI 无需实现分发逻辑
- 故障隔离(一个键失败不会影响其他键)
- 每个键的
--as/--jq/--max-events/--timeout都可以独立设置
所有 N 个消费者共用一个总线守护进程(UDS 本地 IPC),因此开销很小
根据架构编写 jq
event schema <key> --json 是编写 --jq 的事实依据。需要查看以下四项:
(1) 字段从哪里开始 — 查看 jq_root_path
- 值为
"."→ 字段位于顶层,写.chat_id - 值为
".event"→ 字段位于 V2 信封内,写.event.chat_id
(2) 字段列表和类型 — 查看 resolved_output_schema.properties.<name>
每个字段都带有 type / description,部分字段还带有 format。示例(来自 event schema im.message.receive_v1 --json):
{
"chat_id": {"type":"string", "format":"chat_id", "description":"Chat ID, prefixed with oc_"},
"sender_id": {"type":"string", "format":"open_id", "description":"Sender open_id, prefixed with ou_"},
"create_time": {"type":"string", "format":"timestamp_ms", "description":"Send time as ms-epoch string"}
}
(3) 字段语义 — 查看 format 标签
由 Lark 定义的语义标签(不是 JSON Schema 的标准 format)。常见值:open_id / chat_id / message_id / timestamp_ms / email。用途:区分“类型相同但含义不同”的字段,以便通过 API 反向查询或转换格式。
(4) 解码状态 — 阅读字段的 description
event consume 会运行 Process 钩子,可能会预先解码某些载荷字段(展平 V2 信封、将 .content 渲染为纯文本等)——其行为与原始 OAPI 不同。编写 jq 前务必阅读字段的 description,尤其是 content / data / body / payload 等通用字段名。
为何重要:对已解码的文本字段盲目应用 fromjson,会导致 jq 对每个事件都报错并静默丢弃该事件——消费者看似仍在运行,却不输出任何内容,stderr 中只埋着一行 WARN。(这是通用行为:任何 jq 运行时错误都会跳过该事件并输出一行 WARN;循环不会中止。)
不要跳过架构检查:使用 jq 投影 event schema --json 时,不要从 properties 中剥除 .description ——该字段会告诉你某个字段是否已解码。请输出完整的属性对象,而不仅仅是键。
补充:--param 的有效参数也在架构中——params 部分列出了 name / type / required / enum / default / description;缺少该部分 = 此 key 不接受任何 --param。
主题索引
| 主题 | 参考 | 覆盖范围 |
|---|---|---|
| 应用 | references/lark-event-application.md | Application EventKey 目录,包括用于自定义机器人菜单推送事件的 application.bot.menu_v6 + 扁平化的 event_key / 操作者字段 + jq 示例 |
| 审批 | references/lark-event-approval.md | 2 个 Approval EventKey(approval.instance.status_changed_v4、approval.task.status_changed_v4)目录 + 可选/多值 subscription_type 预注册 + 用户授权订阅生命周期 + 扁平输出字段参考 |
| IM | references/lark-event-im.md | 12 个 IM EventKey 目录 + 结构说明(扁平与 V2 信封格式)+ im.message.receive_v1 字段注意事项(sender_id 仅为 open_id;.content 是纯文本,interactive 卡片除外)+ 常用 jq 示例(按 chat_type / message_type / sender 筛选);对于 card.action.trigger,另请参阅 ../lark-im/references/lark-im-card-action-reply.md |
| 任务 | references/lark-event-task.md | 1 个 Task EventKey(task.task.update_user_access_v2)目录 + 原生 V2 信封格式 + 任务提交类型 + 用户/机器人订阅说明 |
| VC | references/lark-event-vc.md | 7 个 VC EventKey 目录(会议生命周期 participant_meeting_started/joined/ended_v1、vc.note.generated_v1、录制 recording_started/transcript_generated/ended_v1)+ 字段参考 + 来源类型语义;实时列表始终以 lark-cli event list --domain vc --json 为准 |
| 纪要 | references/lark-event-minutes.md | 1 个 Minutes EventKey(minutes.minute.generated_v1)目录 + 字段参考 + 来源类型语义(仅限会议) |
| 白板 | references/lark-event-whiteboard.md | 1 个 Board EventKey(board.whiteboard.updated_v1)目录 + 按白板订阅的模型(需要 -p whiteboard_id=<token>)+ 负载字段参考(whiteboard_id / operator_ids 三元 ID) |