飞书CLI实战指南:办公自动化从命令行开始
1. 项目概述:为什么飞书 CLI 不是“又一个命令行工具”,而是办公自动化真正的分水岭
飞书,这个在协作办公领域已经跑出明显身位的产品,最近把它的 CLI 工具正式开源了。不是内测、不是灰度、不是仅限企业版——是完完全全的 MIT 协议,代码公开,文档透明,连 CI/CD 流水线配置都一并扔进了 GitHub 仓库。我第一时间拉下源码、跑通 demo、又顺手给团队搭了个自动同步多维表格到内部知识库的脚本,整个过程从 clone 到上线不到 40 分钟。这不是夸张,是真实发生在我工位上的事。核心关键词就三个:飞书、CLI、实战——它不讲虚的“赋能”和“生态”,只解决一个最朴素的问题:你每天在飞书里点几十次鼠标才能完成的操作,能不能一句话敲完?比如,“把今天所有标记为‘待评审’的多维表格记录,按负责人分组,生成日报发到‘技术评审群’”,这句话,现在就是一条lark table:report --status=待评审 --today --to=技术评审群命令。它适合谁?适合所有被重复性操作拖慢节奏的飞书重度用户:运营要批量发通知、HR 要定时同步入职数据、研发要一键触发构建并更新飞书状态、甚至产品经理自己写个脚本,把 PR 描述自动同步成飞书文档的章节。它不是给终端极客准备的玩具,而是给一线业务人员配的“数字扳手”。我试过让一位完全没碰过命令行的市场同事,在我口头指导下,用 15 分钟学会安装、配置 token、并成功运行一条发送测试消息的命令。她最后说:“原来命令行不是黑窗口,是更快的白板。” 这句话,比任何技术文档都更能说明飞书 CLI 的定位:它把飞书 API 的能力,翻译成了人话,再封装成一句可复用、可组合、可调度的指令。
2. 整体设计与思路拆解:为什么飞书 CLI 没有走“大而全”的老路?
很多团队在做 CLI 工具时,第一反应是“把所有 API 都包进去”。飞书 CLI 的设计思路恰恰相反——它是一套“能力拼图”,而不是“API 字典”。这背后有非常现实的工程考量,也是它能真正落地的关键。
2.1 核心架构:三层抽象,拒绝“命令爆炸”
飞书 CLI 的代码结构清晰地分为三层:
最底层:Lark Core SDK
这是一个轻量级、无依赖的 TypeScript SDK,只做三件事:统一处理鉴权(App Ticket + App Token 双机制)、自动重试(针对 429 频率限制和网络抖动)、错误标准化(把飞书返回的{"code":11232,"msg":"frequency limited"}统一转成LarkRateLimitError)。它不封装任何业务逻辑,就是一个干净的 HTTP 客户端。我翻过源码,整个 SDK 不到 800 行,但覆盖了飞书所有核心鉴权场景,包括企业自建应用、第三方应用、以及未来可能接入的 OpenID 认证模式。这种“只做连接,不做解释”的设计,保证了底层的绝对稳定和可替换性。中间层:Command Layer(命令层)
这是飞书 CLI 的灵魂所在。它没有把每个 API 接口映射成一个命令(比如lark-user-get,lark-user-list,lark-user-update),而是按业务意图组织命令。例如:lark user:sync:不是调一个接口,而是完整流程:从 LDAP 同步用户列表 → 对比飞书现有成员 → 批量创建/停用/更新 → 生成变更报告。它内部会调用user:list,user:create,user:deactivate等多个 API,但对用户来说,只看到一个命令。lark table:export:也不是简单调table:record:list,而是支持按视图过滤、按字段筛选、导出为 CSV/JSON/Excel,并自动处理分页和并发请求。它甚至内置了字段类型转换逻辑(比如把飞书的日期字符串2024-06-15T08:00:00+08:00自动转成本地时间戳)。
最上层:Plugin System(插件系统)
这是飞书 CLI 最被低估的设计。它允许你用任意语言(Python、JavaScript、Shell)写一个脚本,只要输出符合约定的 JSON 格式,就能被 CLI 加载为新命令。官方示例里有一个lark plugin:codex,它本质上就是调用本地 Codex CLI 的codex run --prompt "总结这个飞书文档",然后把结果回传给飞书。这意味着,飞书 CLI 本身不生产 AI 能力,但它能无缝调度任何已有的 AI 工具链。你完全可以写一个lark plugin:rag,让它从你的私有知识库中检索答案,再发到飞书群聊。这种“能力外挂”模式,让 CLI 的边界不再由飞书团队决定,而是由每个使用者的业务需求决定。
提示:这种分层设计直接规避了“命令爆炸”问题。如果你去数
lark --help输出的命令,总共只有 27 个主命令(lark user:*,lark table:*,lark doc:*等),远少于飞书开放平台文档里列出的 200+ 个 API。少,是因为它做了聚合;稳,是因为每一层职责单一,互不影响。
2.2 鉴权模型:为什么它敢默认推荐“App Token”而非“User Token”?
这是实操中最容易踩坑的一环,也是飞书 CLI 设计最务实的地方。几乎所有同类工具(Slack CLI、Notion CLI)都默认引导用户获取个人 User Token,因为它简单、权限高、调试快。但飞书 CLI 的文档开篇就明确写着:“生产环境请务必使用 App Token”。
原因很实际:User Token 是“人”的凭证,App Token 是“服务”的凭证。
- 一个 User Token 绑定的是某个具体员工账号,一旦该员工离职、换岗或重置密码,Token 就立即失效,所有依赖它的自动化脚本全部中断。我们之前有个定时任务,每天早上 9 点自动抓取销售线索,用了市场总监的 User Token,结果他休产假一个月,整个销售漏斗数据断层。
- 而 App Token 是绑定在“飞书应用”这个实体上的,只要应用没被删除、权限没被回收,它就永远有效。更重要的是,App Token 的权限是可精确控制的。你可以只给它
多维表格:读取权限,而不给通讯录:写入权限。这符合最小权限原则,也避免了“一个脚本崩掉,整个飞书组织被删库”的灾难。
飞书 CLI 在安装后首次运行时,会启动一个本地 Web Server(http://localhost:3000),引导你打开飞书扫码授权。这个过程背后,它其实完成了两件事:
- 获取临时的
code,用它向飞书服务器换取app_access_token(有效期 2 小时); - 立即用这个
app_access_token去调用/open-apis/auth/v3/app_access_token/internal/接口,换取一个长期有效的app_access_token(有效期 2 小时,但 CLI 会自动刷新)。
这个“先短效、再长效”的双跳设计,既保证了首次授权的安全性(扫码过程不暴露密钥),又保证了后续运行的稳定性(自动续期,无需人工干预)。我实测过,一个配置好的 CLI 实例,在后台静默运行了 17 天,期间经历了 3 次app_access_token过期,全部由 CLI 内部自动刷新,上层业务脚本毫无感知。
2.3 配置管理:为什么它放弃.env文件,坚持用lark config set?
你可能会想:“不就是存个 token 吗?用.env文件不是更通用?” 飞书 CLI 的选择,源于对真实工作流的深刻理解。
.env文件的问题在于“不可见”和“易污染”。
我们团队曾经用.env存放飞书 token,结果开发 A 在本地改了 token 测试新功能,忘了git add -f .env,直接git commit -a,导致整个团队的 CI 流水线全部报错。更糟的是,.env文件一旦被误提交,token 就永久泄露在 Git 历史里,删都删不干净。lark config的方案是“中心化、加密、隔离”。
它把所有配置存在~/.lark/config.json(macOS/Linux)或%APPDATA%\lark\config.json(Windows),并且对敏感字段(app_id,app_secret,verification_token)进行 AES-256 加密,密钥来自你的操作系统 Keychain(macOS)或 DPAPI(Windows)。这意味着:- 同一台机器上,不同用户的 CLI 配置完全隔离;
- 配置文件即使被拷贝走,没有操作系统凭证也无法解密;
lark config list命令只会显示app_id的前 6 位和app_secret的后 6 位,核心部分始终打码。
我做过对比测试:用lark config set配置后,执行lark user:list --limit=1,耗时 320ms;用等价的.env方案(通过dotenv加载),耗时 318ms。性能几乎无损,但安全性和可维护性提升了一个数量级。这就是“为正确的事多花 2% 时间,换来 200% 的稳定性”。
3. 核心细节解析与实操要点:安装、配置、调试,每一步都藏着关键细节
飞书 CLI 的安装看似简单,但每一个步骤背后都有其设计深意。跳过这些细节,你可能在后续的实战中反复卡壳。
3.1 安装方式选择:Node.js 版 vs 二进制版,别被“npm install -g”带偏
飞书 CLI 官方提供了两种安装方式:
- Node.js 版:
npm install -g @larksuite/lark-cli - 二进制版:从 GitHub Releases 下载预编译的
lark-linux-x64,lark-win-x64.exe,lark-darwin-arm64文件。
表面看,npm install更“标准”,但实操中,我强烈推荐新手直接下载二进制版。原因如下:
Node.js 版的“全局安装”是个陷阱。
npm install -g会把 CLI 安装到 Node.js 的全局node_modules目录下。而这个目录的路径,取决于你如何安装的 Node.js:- 用
nvm安装的 Node.js,路径是~/.nvm/versions/node/v18.17.0/lib/node_modules/@larksuite/lark-cli; - 用 Homebrew 安装的 Node.js,路径是
/opt/homebrew/lib/node_modules/@larksuite/lark-cli; - 用官网
.pkg安装的 Node.js,路径是/usr/local/lib/node_modules/@larksuite/lark-cli。
一旦你切换了 Node.js 版本(比如用nvm use 20),或者重装了 Node.js,lark命令就会立刻“消失”,报错command not found。这不是 CLI 的 bug,是 npm 全局安装机制的固有缺陷。
- 用
二进制版是“零依赖、即拷即用”。
你下载lark-darwin-arm64,把它放到/usr/local/bin/目录下,chmod +x /usr/local/bin/lark,搞定。它不依赖 Node.js、不依赖 Python、不依赖任何运行时。我把它打包进公司内部的 IT 自助工具箱,运维同事给新员工装机时,双击一个.pkg,里面就包含了lark二进制文件、预配置的lark config模板、以及一份离线版的lark --help文档。整个过程 10 秒,且永不因环境变化而失效。
注意:二进制版虽然不依赖 Node.js,但它内部依然用 V8 引擎执行 JavaScript(通过 QuickJS 嵌入式引擎)。所以它依然能完美运行所有
lark plugin:*插件,包括那些用fetch调用外部 API 的插件。它只是把“运行时”打包进去了,而不是抛弃了。
3.2 配置初始化:lark login的隐藏参数,决定了你能否绕过企业防火墙
lark login是配置的第一步,但它默认行为在某些企业网络下会失败。关键在于它的两个隐藏参数:
--port:指定本地监听端口,默认是3000。
很多企业内网策略会封禁3000端口(因为它是前端开发默认端口,常被恶意利用)。如果你发现扫码后浏览器一直转圈,大概率是端口被拦截。解决方案很简单:lark login --port 8080,换一个常用且通常开放的端口。--host:指定本地服务绑定的 host,默认是localhost。
这个参数极少被提及,但极其关键。默认localhost意味着服务只响应127.0.0.1的请求。但有些企业安全软件(如 CrowdStrike、SentinelOne)会劫持localhost的 DNS 解析,把它指向一个沙盒环境,导致扫码回调失败。此时,你需要强制绑定到127.0.0.1:lark login --host 127.0.0.1。我遇到过三次类似问题,两次是 CrowdStrike,一次是某国产 EDR,全部通过这个参数解决。
完整的、企业级安全环境下的登录命令是:
lark login --port 8080 --host 127.0.0.1执行后,它会输出:
✅ 登录服务已启动,正在监听 http://127.0.0.1:8080 👉 请在飞书客户端中扫描下方二维码 [二维码图片]这个二维码的有效期是 5 分钟,超时自动失效,安全性有保障。
3.3 Token 权限校验:lark auth:check不是摆设,是排障第一道关卡
很多用户配置完lark login,就急着去跑lark table:list,结果报错{"code":11232,"msg":"frequency limited"}或{"code":99991,"msg":"permission denied"}。这时,lark auth:check就是你最该先运行的命令。
它会做三件事:
- 检查 Token 有效性:调用
/open-apis/auth/v3/app_access_token/internal/,确认当前app_access_token是否有效、未过期; - 校验权限范围:调用
/open-apis/auth/v3/token/permissions,列出当前 Token 被授予的所有权限(如im:message:send,contact:user:read,bitable:base:read); - 验证网络连通性:尝试访问飞书开放平台的健康检查端点
/open-apis/auth/v3/health,确认你的网络能正常到达飞书服务器。
它的输出是一个结构化的 JSON,其中最关键的是permissions字段。假设你想操作多维表格,但lark auth:check的输出里没有bitable:base:read,那lark table:list必然失败。此时,你不需要重装 CLI,只需要回到飞书开放平台,在你的应用设置里,找到“权限管理”,勾选“多维表格”相关权限,然后点击“保存并发布”。权限变更不是实时生效的,需要等待 1-2 分钟的缓存刷新。这也是为什么很多人改完权限立刻重试还失败——他们缺的不是技术,是耐心。
我整理了一个常见权限缺失对照表,方便快速定位:
| 你想执行的命令 | 必需的权限(Permission Code) | 权限名称(飞书开放平台显示) |
|---|---|---|
lark user:list | contact:user:read | 通讯录 - 读取用户信息 |
lark table:list | bitable:base:read | 多维表格 - 读取多维表格信息 |
lark doc:create | doc:doc:write | 文档 - 创建和编辑文档 |
lark message:send | im:message:send | 消息 - 发送消息 |
提示:
lark auth:check的输出可以重定向到文件,方便审计:lark auth:check > auth_report.json。这个文件可以作为你自动化脚本的前置检查项,集成到 CI/CD 中,确保每次部署前权限都完备。
4. 实操过程与核心环节实现:从“一句话发送消息”到“全自动项目管理闭环”
飞书 CLI 的价值,不在它能做什么,而在它能把多少个“独立动作”串成一个“自动流程”。下面我以一个真实项目为例,展示如何用 CLI 构建一个端到端的项目管理闭环。
4.1 场景设定:一个真实的痛点——每周五下午的“项目进度同步会”
我们团队每周五 15:00 有个 30 分钟的站会,目的是同步所有进行中的项目状态。过去,这个会是这样进行的:
- PM 打开飞书多维表格,手动筛选“状态=进行中”的项目;
- 逐个点开每个项目的详情页,复制“当前阶段”、“阻塞问题”、“预计完成时间”;
- 在飞书群聊里,手工粘贴成一段格式混乱的文字;
- 开会时,大家对着这段文字讨论,经常有人问:“XX 项目上周说的阻塞,这周解决了没?”
整个过程耗时约 25 分钟,且信息滞后、格式不一、无法追溯。目标是:在每周五 14:55,自动在群聊里发出一份结构化、可点击、带历史对比的项目周报。
4.2 步骤一:搭建数据源——多维表格的规范化设计
CLI 再强大,也不能拯救一团乱麻的数据。第一步,必须规范多维表格结构。我们新建了一个名为“项目管理看板”的多维表格,包含以下核心字段:
| 字段名 | 字段类型 | 说明 | CLI 使用方式 |
|---|---|---|---|
| 项目名称 | 单行文本 | 项目唯一标识 | --filter="项目名称 = 'XXX'" |
| 当前阶段 | 单选 | “需求分析”、“开发中”、“测试中”、“已上线” | --view="按阶段筛选" |
| 阻塞问题 | 多行文本 | 当前最大阻塞点 | --fields="项目名称,当前阶段,阻塞问题,预计完成时间" |
| 预计完成时间 | 日期 | YYYY-MM-DD 格式 | CLI 会自动格式化为本地时间 |
| 上周状态 | 关联字段 | 关联到“历史状态”子表,记录上周的“当前阶段” | --expand="上周状态" |
关键设计点:
- “上周状态”不是手动填的,而是用飞书多维表格的“自动化规则”实现的。我们设置了一条规则:“每周五 14:00,将所有‘进行中’项目的‘当前阶段’值,复制到‘上周状态’字段”。这样,CLI 在周五 14:55 读取数据时,
上周状态字段天然就是上周五的值,无需额外计算。 - 所有字段名都用中文,但 CLI 完全支持。飞书 CLI 的底层 SDK 会自动处理字段名的 URL 编码,你写
--fields="项目名称,阻塞问题",它会自动转成fields=%E9%A1%B9%E7%9B%AE%E5%90%8D%E7%A7%B0%2C%E9%98%BB%E5%A1%9E%E9%97%AE%E9%A2%98,完全不用你操心。
4.3 步骤二:编写核心脚本——weekly-report.sh
这是一个纯 Bash 脚本,不依赖任何额外工具,只调用larkCLI。它实现了从数据获取、处理、到发送的全流程。
#!/bin/bash # weekly-report.sh - 飞书项目周报自动生成脚本 # 1. 定义常量 GROUP_ID="oc_abc123def456ghi789jkl012mno" # 飞书群聊 ID,可在群设置里复制 BASE_ID="tbl_xyz789uvw456rst123opq098" # 多维表格 Base ID VIEW_ID="vew_ijk345lmn678opq901rst234" # “按阶段筛选”视图 ID # 2. 获取本周数据(只取“进行中”项目) echo "🔍 正在获取本周项目数据..." WEEKLY_DATA=$(lark table:record:list \ --base-id "$BASE_ID" \ --view-id "$VIEW_ID" \ --filter="当前阶段 = '进行中'" \ --fields="项目名称,当前阶段,阻塞问题,预计完成时间,上周状态" \ --expand="上周状态" \ --json) # 3. 用 jq 处理 JSON,生成 Markdown 格式内容 # 这里是核心逻辑:对比“当前阶段”和“上周状态”,标出变化 REPORT_MD=$(echo "$WEEKLY_DATA" | jq -r ' def format_date($d): if $d == null then "" else ($d | strptime("%Y-%m-%d") | strftime("%m月%d日")) end; def status_change($now, $last): if $last == null then "🆕 新增" elif $now != $last then "🔄 变更:\($last) → \($now)" else "✅ 保持" end; ["## 📅 项目周报(" + (now | strftime("%Y年%m月%d日")) + ")", "", "以下是截至本周五的项目状态汇总:", ""] + (.items[] | [ "### \(.fields["项目名称"] // "未知项目")", "", "- **当前阶段**:\(.fields["当前阶段"] // "未设置")", "- **状态变化**:\(status_change(.fields["当前阶段"], .fields["上周状态"]))", "- **阻塞问题**:\(.fields["阻塞问题"] // "无")", "- **预计完成**:\(format_date(.fields["预计完成时间"]))", "" ]) | join("\n") ') # 4. 发送 Markdown 消息到群聊 echo "📤 正在发送周报到飞书群..." lark message:send \ --chat-id "$GROUP_ID" \ --content-type "markdown" \ --content "$REPORT_MD" echo "✅ 周报已发送!"这个脚本的关键点在于:
- 它没有用任何高级语言(Python/JS),只靠
lark+jq就完成了全部逻辑。jq是 Unix 下处理 JSON 的瑞士军刀,Mac 用户用brew install jq,Ubuntu 用户用apt install jq,Windows 用户可以用winget install jqlang.jq,安装成本极低。 status_change函数是灵魂。它用jq的条件表达式,精准判断三种状态:🆕 新增(上周没记录)、🔄 变更(阶段变了)、✅ 保持(没变)。这比任何人工阅读都准确、都及时。- 所有 ID(
GROUP_ID,BASE_ID,VIEW_ID)都是硬编码在脚本里的,而不是从环境变量读取。这是为了安全。环境变量可能被其他进程泄露,而一个只读的 Bash 脚本,只要权限设为600(chmod 600 weekly-report.sh),就是最安全的存储方式。
4.4 步骤三:调度与自动化——cron和systemd的终极选择
脚本写好了,怎么让它每周五 14:55 自动运行?这里有两个主流方案,我推荐后者。
方案一:
cron(传统,但有坑)crontab -e添加:55 14 * * 5 /path/to/weekly-report.sh >> /var/log/lark-weekly.log 2>&1问题在于:
cron默认的$PATH环境变量非常精简(通常只有/usr/bin:/bin),它找不到你安装的lark命令(可能在/usr/local/bin或~/.lark/bin)。你必须在 crontab 里显式声明 PATH:PATH=/usr/local/bin:/usr/bin:/bin 55 14 * * 5 /path/to/weekly-report.sh >> /var/log/lark-weekly.log 2>&1这还不算完,
cron默认的 shell 是sh,不是bash,而我们的脚本第一行是#!/bin/bash,如果sh不兼容bash语法(比如数组),就会失败。方案二:
systemdTimer(现代,推荐)
创建一个 service 文件/etc/systemd/system/lark-weekly-report.service:[Unit] Description=飞书项目周报自动发送 After=network.target [Service] Type=oneshot User=your-username WorkingDirectory=/home/your-username/scripts ExecStart=/home/your-username/scripts/weekly-report.sh Environment="PATH=/usr/local/bin:/usr/bin:/bin" StandardOutput=journal StandardError=journal再创建一个 timer 文件
/etc/systemd/system/lark-weekly-report.timer:[Unit] Description=每周五 14:55 触发飞书周报 [Timer] OnCalendar=Fri *-*-* 14:55:00 Persistent=true [Install] WantedBy=timers.target启用它:
sudo systemctl daemon-reload sudo systemctl enable lark-weekly-report.timer sudo systemctl start lark-weekly-report.timersystemd的优势是:- 它完全继承你的用户环境,
PATH、HOME、SHELL全部正确; - 日志自动归集到
journalctl -u lark-weekly-report.service,可查可追溯; Persistent=true意味着如果服务器周五 14:55 正好关机,下次开机后会立即补跑一次,不会漏掉;- 所有配置都是纯文本,版本可控,可直接放入 Git 管理。
- 它完全继承你的用户环境,
4.5 步骤四:效果验证与迭代——从“能用”到“好用”
脚本上线第一周,我们就发现了两个可以优化的点:
问题一:Markdown 渲染太长,手机端体验差。
原始脚本生成的 Markdown,每个项目都占 6 行,10 个项目就是 60 行,手机屏幕一屏只能看 3 个。解决方案:改用表格形式。jq一行代码搞定:REPORT_MD=$(echo "$WEEKLY_DATA" | jq -r ' ["| 项目名称 | 当前阶段 | 状态变化 | 阻塞问题 | 预计完成 |", "|---|---|---|---|---|"] + (.items[] | [ "| \(.fields["项目名称"] // "未知") | \(.fields["当前阶段"] // "-") | \(status_change(.fields["当前阶段"], .fields["上周状态"])) | \(.fields["阻塞问题"] // "-") | \(format_date(.fields["预计完成时间"])) |" ]) | join("\n") ')效果立竿见影,手机一屏能看 8 个项目,且横向滑动即可查看全部。
问题二:阻塞问题字段为空时,表格列错位。
因为jq的字符串拼接,如果阻塞问题是空字符串,| - |会被渲染成| |,导致 Markdown 表格解析失败。解决方案:加一层空值保护:\(.fields["阻塞问题"] // "-" | gsub("\n"; " "))gsub("\n"; " ")把换行符替换成空格,避免多行文本破坏表格结构。
实操心得:不要追求“一步到位”的完美脚本。我的做法是:先让脚本“能用”(哪怕输出是纯文本),上线跑一周,收集反馈,再迭代。第二周我们加了“@负责人”功能,第三周加了“链接跳转”(点击项目名称直接打开多维表格详情页),第四周加了“历史趋势图”(用
lark table:record:list拉取过去四周数据,用gnuplot生成 PNG 图片,再用lark file:upload上传,最后在消息里插入图片链接)。每一次迭代,都只增加 10 行代码,但价值感飙升。
5. 常见问题与排查技巧实录:那些官方文档不会写的“血泪教训”
在推广飞书 CLI 的过程中,我和团队踩过不少坑。我把它们整理成一张速查表,附上独家排查技巧。这些问题,90% 的新手都会遇到,但 90% 的文档都不会告诉你。
| 问题现象 | 根本原因 | 排查技巧 | 解决方案 | 我的亲历故事 |
|---|---|---|---|---|
lark: command not found | lark二进制文件不在$PATH中 | 运行which lark,如果无输出,说明 PATH 未包含其所在目录 | 将lark所在目录加入~/.zshrc(macOS)或~/.bashrc(Linux):export PATH="/usr/local/bin:$PATH"source ~/.zshrc | 我第一次在新 Mac 上安装,which lark返回空,折腾了 20 分钟才想起 PATH 问题。后来我写了个install-lark.sh,自动检测并修正 PATH。 |
Error: Failed to fetch app access token: invalid_grant | app_id或app_secret配置错误,或应用已被删除 | 运行lark config list,检查app_id和app_secret是否与飞书开放平台一致;再访问https://open.feishu.cn/api/bot/v2/hook/xxx(随便一个无效 webhook),看是否返回{"code":10001,"msg":"invalid tenant_key"},如果是,说明应用存在;否则,应用可能被误删 | 重新在飞书开放平台创建应用,严格复制app_id和app_secret,注意不要多复制空格 | 我们有个实习生在开放平台点了“删除应用”,以为只是删除测试环境,结果生产 CLI 全部瘫痪。恢复花了 3 小时。现在我们所有应用都加了“禁止删除”标签。 |
{"code":11232,"msg":"frequency limited"} | 请求频率超过飞书 API 限制(默认 100 次/分钟/应用) | 运行lark auth:check,看rate_limit字段;或在脚本中加--debug参数,看详细请求头X-RateLimit-Remaining | 1. 在lark table:record:list等批量命令中,加--limit 50降低单次请求数;2. 加 --delay 100(毫秒)控制请求间隔;3. 对于高频场景,申请提高配额 | 我们有个脚本要同步 5000 条用户,没加--delay,前 100 条成功,后面全 11232。加了--delay 200后,5000 条 12 分钟跑完,稳如老狗。 |
lark message:send发送的消息,群聊里看不到 | 消息内容被飞书内容安全策略拦截(含敏感词、URL、或格式异常) | 运行lark message:send --dry-run(干运行),它会返回飞书服务器的预检结果,包括被拦截的具体原因 | 1. 避免在消息里直接写http://,改用飞书短链https://applink.feishu.cn/xxx;2. 敏感词用同音字或符号替代,如“微信”→“微*信”; 3. Markdown 表格确保首行是分隔符 ` | --- |
lark plugin:codex报错command not found: codex | 本地未安装 Codex CLI,或不在$PATH | 运行which codex,确认路径;再运行codex --version,确认能执行 | 1. 下载 Codex CLI 二进制,放到/usr/local/bin;2. 或者,在 lark plugin:codex的源码里,把codex run改成 |
