feishu-cli-event について
feishu-cli-eventは、Feishu Open PlatformのイベントをWebSocketで購読するコマンドラインスキルです。イベントをリアルタイム処理するAIエージェント向けに、NDJSON出力と購読プロセスの管理機能を備えています。
主な機能
- 01WebSocket経由のリアルタイムイベント受信
- 02NDJSON形式でのイベント出力
- 03イベントキー一覧とペイロードスキーマの確認
- 04イベント数または時間による購読制限
- 05購読中プロセスの確認と停止
活用シーン
- 01Botが受信するユーザーやグループのメッセージ監視
- 02承認・カレンダー・ドライブイベントの処理
- 03イベントストリームのスクリプトやAIエージェントへの転送
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ riba2534/ feishu-cli --skill feishu-cli-eventインストール後、Claude Code で/feishu-cli-eventを入力して読み込まれたか確認します。
詳細
飞书实时事件订阅技能(WebSocket)
通过 feishu-cli event 子命令族订阅飞书开放平台事件,使用 WebSocket 长连接接收事件并以 NDJSON 输出到 stdout,适合 AI Agent 做 bot 实时响应、群消息监听、审批回调消费等场景。
feishu-cli:如尚未安装,请前往 riba2534/feishu-cli 获取安装方式。
发消息? 请使用 feishu-cli-msg 技能。本技能专注于事件订阅(接收应用事件),不负责发送。
核心概念
进程模型 = 1 个 EventKey 1 个 consume 进程
event consume <EventKey>
│
├─ 启动 WebSocket 长连接(飞书 SDK ws.Client + AutoReconnect)
├─ 注册到 bus.json(PID / EventKey / 启动时间 / max-events / timeout)
├─ stderr 输出 [event] ready event_key=<key>
├─ 接收事件 → 写 stdout(NDJSON,每条一行 JSON)
├─ 可选:dump 每条事件为 <event_id>.json 文件
├─ 退出条件:--max-events / --timeout / SIGTERM / Ctrl-C / stdin EOF / pipe broken
└─ 退出时自动 unregister bus.json
与 lark-cli event 的差异:lark-cli 用 Unix domain socket 跑独立 bus 守护进程做事件 fan-out;feishu-cli 简化为「每个 consume 直接连一条 WebSocket」,不做事件分发——足够覆盖 AI Agent 单 EventKey 订阅的主线场景。
状态文件与跨进程互斥
| 路径 | 作用 |
|---|---|
~/.feishu-cli/events/<app_id>/bus.json | 活跃 consumer 列表(PID/EventKey/启动时间/参数) |
~/.feishu-cli/events/<app_id>/bus.lock | flock 文件锁;bus.json 读写串行化,fd 关闭自动释放 |
每个 AppID 一个子目录,不同应用互不干扰。event status 查询会主动剔除已不存活的 PID 条目(kill -9 / 崩溃残留)。bus.json 用 tmp + rename 原子写,防半写。
输出协议(NDJSON + ready marker)
| 流 | 内容 |
|---|---|
| stdout | 每条事件一行 JSON(NDJSON),适合 jq / 脚本管道 |
| stderr | 诊断日志;启动时一行 [event] ready event_key=<key> (init complete; WS handshake in progress) |
AI Agent 推荐:父进程把 consume 跑后台(
run_in_background=true),先阻塞 stderr 等到[event] ready那一行再开始读 stdout。注意:ready marker 只表示进程初始化完成,WS 握手在后台异步执行;父进程见到 marker 后还需额外等 1-3s 让 WS 握手真正完成,生产环境建议父进程发自检事件 + 等 echo 回环来确认链路通。
退出码与退出 reason
| 退出码 | 含义 |
|---|---|
| 0 | 正常退出(达到 --max-events / --timeout / SIGTERM / Ctrl-C / stdin EOF) |
| 非 0 | startup 失败 / WebSocket 不可恢复错误 / 参数错误 |
stderr 末尾会输出 [event] exited — elapsed=<d> reason=<r>,reason 有 4 个:
limit— 达到--max-eventstimeout— 达到--timeoutsignal— 上下文取消(Ctrl-C / SIGTERM / stdin EOF / 下游 pipe broken)error— WebSocket 连接持续失败
命令速查
feishu-cli event list [--json] # 1. 列所有支持的 EventKey
feishu-cli event schema <event_key> [--json] # 2. 看某 key 的 EventType / scope / payload schema
feishu-cli event consume <event_key> [flags] # 3. 启动订阅(阻塞)
feishu-cli event status [--json] # 4. 看本机活跃 consume 进程
feishu-cli event stop {--pid N | --event-key K | --all} [--force] [--json] # 5. 停 consume
1. event list:列出支持的 EventKey
按 domain 分组展示当前支持的 22+ EventKey(im / contact / calendar / drive / approval / vc)。
# 表格视图(默认)
feishu-cli event list
# JSON 输出,jq 提取 IM 域所有 EventKey
feishu-cli event list --json | jq -r '.[] | select(.domain=="im") | .key'
输出字段(JSON 模式):key / event_type / description / domain / scopes[] / payload_schema。
2. event schema:看 payload schema 与 scope
feishu-cli event schema im.message.receive_v1
feishu-cli event schema im.message.receive_v1 --json
输出 4 部分:Key / Event Type / Domain / Description / Scopes + 可选 Payload Schema (示例)。Payload schema 为手工 curated,订阅后实际 payload 以飞书开放平台文档为准。
3. event consume:启动 WebSocket 订阅(阻塞)
# 基础订阅,Ctrl-C 退出
feishu-cli event consume im.message.receive_v1
# 调试:抓 5 条消息,最多跑 60s
feishu-cli event consume im.message.receive_v1 --max-events 5 --timeout 60s
# 落盘 + 静默
feishu-cli event consume im.message.receive_v1 --output-dir ./events --quiet
# 配合 jq 实时过滤群消息
feishu-cli event consume im.message.receive_v1 | jq 'select(.event.message.chat_type=="group")'
# 后台并发订阅多个 EventKey(每个 EventKey 一个进程)
feishu-cli event consume im.message.receive_v1 > receive.ndjson 2> receive.log &
feishu-cli event consume im.message.reaction.created_v1 > reaction.ndjson 2> reaction.log &
feishu-cli event status
关键 flag:
| Flag | 默认 | 说明 |
|---|---|---|
--max-events N | 0(不限制) | 接收 N 条事件后退出,reason=limit |
--timeout <duration>(示例 60s) | 0(不限制) | 运行 D 时长后退出,reason=timeout |
--jq .event.xxx | "" | 极简点路径过滤,不支持完整 jq 语法(用 pipe 接外部 jq) |
--output-dir ./events | "" | 每条事件额外 dump 为 <event_id>.json 落盘(不影响 stdout) |
--quiet | false | 抑制 stderr 诊断;AI Agent 慎用——会一起抑制大部分 stderr,但 ready marker 仍走真实 os.Stderr 不受影响 |
--jq 限制:只识别 .a.b.c 形式的 map 取值(如 .event.message),不支持 select / 数组下标 / 管道。复杂过滤请用 feishu-cli event consume ... | jq '<expr>'。
--output-dir 限制:必须是安全相对路径;不做 ~ 展开,不接受绝对路径或 .. 路径段。
4. event status:看本机活跃 consume 进程
feishu-cli event status
feishu-cli event status --json | jq '.consumers[] | .pid'
输出:App ID / State file 路径 / PID / EVENT_KEY / UPTIME / EXTRA(max-events / timeout / output-dir / jq)。
查询时会主动剔除已不存活的 PID 条目(清理 kill -9 / 崩溃残留的僵尸记录)。
5. event stop:停止 consume 进程
feishu-cli event stop --pid 12345 # 按 PID
feishu-cli event stop --event-key im.message.receive_v1 # 按 EventKey(所有订阅该 key 的进程)
feishu-cli event stop --all # 当前 AppID 下全部 consume
feishu-cli event stop --all --force # SIGKILL(紧急情况)
默认 SIGTERM 优雅退出(consume 进程会自动 unregister bus.json),等最多 3s 验证进程已退出;--force 升级为 SIGKILL,会留下 bus.json 僵尸条目,下次 event status 会自动清理。
EventKey クイックリファレンス(domain 別)
完全な一覧は feishu-cli event list で確認できます。よく使うもの:
| Domain | EventKey | 説明 |
|---|---|---|
| im | im.message.receive_v1 | メッセージを受信(ユーザー/グループチャットから Bot への送信) |
| im | im.message.message_read_v1 | メッセージの既読レシート |
| im | im.message.recalled_v1 | メッセージの取り消し |
| im | im.message.reaction.created_v1 / deleted_v1 | メッセージへのリアクションの追加/削除 |
| im | im.chat.updated_v1 | グループチャット情報の更新 |
| im | im.chat.member.user.added_v1 / deleted_v1 | ユーザーのグループへの参加/退出 |
| im | im.chat.member.bot.added_v1 / deleted_v1 | Bot のグループへの追加/グループからの削除 |
| im | im.chat.disbanded_v1 | グループチャットの解散 |
| contact | contact.user.created_v3 / updated_v3 / deleted_v3 | 従業員の入社/変更/退職 |
| calendar | calendar.calendar.event.changed_v4 | 予定の変更(作成/更新/削除) |
| calendar | calendar.calendar.acl.created_v4 | カレンダー権限の変更 |
| drive | drive.file.title_updated_v1 | ドキュメントタイトルの変更 |
| drive | drive.file.permission_member_added_v1 | ドキュメントへの共同編集者の追加 |
| approval | approval_instance | 承認インスタンスの状態変更 |
| approval | approval_task | 承認タスクの変更 |
| vc | vc.meeting.meeting_started_v1 / meeting_ended_v1 | VC 会議の開始/終了 |
EventKey と EventType は通常一致します。受信した payload の
header.event_typeはevent_typeフィールドと同じです。
権限とオープンプラットフォームの設定
デフォルトの App Token を使用するため、auth login は不要です
イベントの購読には App ID(app_id + app_secret)を使用するため、user token は必須ではありません。~/.feishu-cli/config.yaml を設定するか、環境変数 FEISHU_APP_ID / FEISHU_APP_SECRET を設定してください。
Feishu オープンプラットフォームでの 2 段階設定
open.feishu.cn のアプリコンソールで設定します。
- 「イベント購読 - 長時間接続でイベントを受信」で長時間接続モードを有効にします(feishu-cli は WebSocket を使用します。webhook URL モードではありません)
- **「イベントとコールバック - イベント購読」**で対象の EventType(
event schema <key>の出力にある Event Type と同じ)を選択し、バージョンを公開します - scope の有効化:各 EventKey に必要な scope は
event schema <key>のScopesフィールドで確認できます。「権限管理」ページで有効にします。eventdomain は--domain event --recommendの推奨リストに追加されているため、IM/contact/calendar/drive/approval/vc でよく使う scope の和集合をまとめて申請できます
よくあるエラー
| 現象 | 原因 | 解決方法 |
|---|---|---|
| WS 接続に失敗し、stderr に ws error が表示される | 長時間接続モードが有効になっていない | Feishu オープンプラットフォームで「イベント購読 - 長時間接続でイベントを受信」を有効にします |
| 起動後に ready が表示されるが、イベントを受信できない | 対象の EventType が「イベント購読」で選択されていない/バージョンが公開されていない | もう一度選択して、バージョンを公開します |
| イベントは受信できるが、payload フィールドが不足している | App に対応する scope がない(例:im:message.p2p_msg:readonly) | event schema <key> で Scopes を確認し、権限管理ページで有効にしてから再度購読します |
event consume が reason=error ですぐに終了する | App ID/Secret が誤っている/ネットワークに接続できない/ドメインに lark を使用しているのに BaseURL に feishu を設定している | config.yaml を確認します。lark の国際版では --base-url https://open.larksuite.com または対応する設定が必要です |
AI Agent のバックグラウンド購読におすすめの使い方
単一 EventKey のバックグラウンド購読(run_in_background=true)
# 1. 后台启动 consume,stderr/stdout 各 redirect
task = Bash(
command='feishu-cli event consume im.message.receive_v1 --output-dir ./events 2> consume.log',
run_in_background=True,
)
# 2. tail consume.log 阻塞等 "[event] ready event_key=im.message.receive_v1"
# 3. 额外 sleep 1-3s 让 WS 握手完成
# 4. 业务逻辑:tail stdout / 读 ./events/*.json 处理新事件
# 5. 退出:feishu-cli event stop --event-key im.message.receive_v1
# 或父进程 kill 后台 Bash task(SIGTERM 触发 graceful shutdown + unregister)
子プロセスの stdin EOF プロトコル(非 TTY)
非 TTY モードでは、stdin を閉じると正常終了がトリガーされます(reason=signal)。Python の subprocess.Popen で stdin=subprocess.PIPE を使用する場合、処理後に p.stdin.close() を呼び出すほうが SIGTERM より確実です。consume は現在のイベントの処理を完了してから終了します。
実行時間/イベント数の上限設定
デバッグ時は必ず最初に --max-events N --timeout Ds を指定し、stop を忘れてバックグラウンドプロセスが API quota を消費し続けるのを防ぎます。
feishu-cli event consume im.message.receive_v1 --max-events 1 --timeout 30s
# 抓 1 条事件 demo / 30 秒超时双保险
注意点と落とし穴
- daemon プロセスは常駐します:
event consumeはシグナル/タイムアウト/EOF を受け取るまでブロッキング実行され、自動では終了しません。AI Agent のバックグラウンド実行では--max-events/--timeoutを指定するか、明示的にevent stopを実行してください。指定しないと長時間実行されるプロセスが残ります - flock によるプロセス間排他制御:bus.json の読み書きには flock を使用するため、複数の
event consumeを同時に起動して登録しても安全です。ただし、bus.json を手動で編集しないでください - pipe broken で自動終了:下流の jq / tee が stdout を閉じると(典型例:
event consume ... | head -1)、SIGPIPE が発生し、consume は reason=signal で自発的に終了します。Ctrl-C を待ったまま停止しなくなることはありません --quietでも ready marker は出力されます:ready marker は実際のos.Stderrを使用し、--quietによるリダイレクトを回避するため、AI Agent が--quietを指定していても親プロセスは ready 行を待つことができます。ただし、[event] exitedreason を含むその他の診断情報は表示されません- AutoReconnect は無限に再試行します:oapi-sdk-go v3 ws.Client はデフォルトで
WithAutoReconnect(true)を使用し、切断後も無限に再試行します(間隔は 2 分、初回はジッターあり)。長時間の切断が想定される場合は、--timeoutで明示的に終了させ、外部の監視プロセスから再起動する方法をおすすめします。内部で無限に retry するよりも制御しやすくなります - status はプロセスに対して能動的に ping しません:
event statusはsignal(0)で生存確認を行います。PID が再利用された場合、理論上は誤判定する可能性があります(確率は極めて低いです)。event stop --pid Nも syscall.Kill を使用するため、誤った PID に対しては ESRCH で失敗し、誤って別のプロセスを終了させることはありません - イベントごとに個別のファイルを作成します:
--output-dirモードでは各イベントが<event_id>.jsonとして保存されます。短時間にイベントが頻発すると、小さなファイルが大量に作成される可能性があります。ファイルへの保存は記録用であり、実際のイベント処理には stdout NDJSON の使用をおすすめします --jqがサポートするのはドットパスのみです:--jq .event.messageは各イベントをサブツリーに射影してから出力します。一致しないイベントはスキップされ(空行は出力されません)、複雑なフィルタリングには外部の jq を pipe で使用してください--output-dirがサポートするのは安全な相対パスのみです:~/events、/tmp/events、../eventsを指定するとエラーになります。./eventsまたはevents/todayを使用してください
何时转其他 skill
| 任务 | 路由 |
|---|---|
| 发消息 / 回复 / 卡片 / 通知 | feishu-cli-msg |
| 构造 interactive 卡片 JSON | feishu-cli-card |
| 处理收到的消息事件 → 写多维表格 | feishu-cli-bitable(解析 payload 后调 record 命令) |
| 处理收到的审批事件 → 查审批详情 | feishu-cli-toolkit(approval 子命令) |
| 收到群消息后查群信息/成员 | feishu-cli-chat |
| Webhook URL 模式(HTTP 回调,非长连接) | 不在本技能范围;走飞书开放平台的「请求网址配置」+ 自建 HTTP server |
| 历史消息批量拉取(非实时) | feishu-cli-chat 的 msg history / msg list |
参考
- 飞书开放平台事件订阅文档:https://open.feishu.cn/document/server-docs/event-subscription-guide/event-list
- 项目 CHANGELOG:本模块新增详情见仓库
CHANGELOG.mdevent 模块段落 - 源码:
cmd/event*.go+internal/event/{bus,keys,runtime}.go
安全 — event_id 文件名净化
--output-dir 启用时每条事件 dump 为 <event_id>.json。v1 PR 加 sanitizeEventID 防御:
- 只保留
[A-Za-z0-9_-]字符,长度截到 128 ..、/、空格、特殊符号都被丢弃- 净化后空串 → 跳过 dump(不写空文件名文件)
防御场景:服务端 payload 异常或恶意构造 header.event_id = "../etc/passwd" 类 payload 时,writeFile 不会逃出 --output-dir。