扫描 warpdotdev/warp 和 warp-server 中最近合并但尚未在 warpdotdev/docs 中有对应文档 PR 的 PRODUCT.md 规范。当找到完整规范时,自动生成完整的文档草稿 PR 并标记工程师。当规范内容过于简略无法起草时,直接通知工程师。设计为定时运行的 Oz 环境代理(例如每 2-3 天)。用于设置自动文档触发或运行手动文档覆盖检查。
scan-new-specs
扫描 warpdotdev/warp 和 warp-server 中最近合并但缺少对应文档草稿的产品或技术规范。对于每个缺口:
- 如果规范完整 — 自动以环境模式运行
write-feature-docs在warpdotdev/docs中生成完整的草稿 PR,然后通知工程师审阅 - 如果规范简略 — 直接通知工程师,要求其完善规范或手动启动文档工作流
两种情况下,都会在 #growth-docs 频道发布摘要。
配置
运行前确认以下值(或接受默认值):
| 设置项 | 默认值 | 描述 |
|---|---|---|
LOOKBACK_DAYS |
3 |
向后扫描合并规范 PR 的天数 |
SLACK_CHANNEL |
#growth-docs |
用于工程师通知和摘要的 Slack 频道 |
SLACK_BOT_TOKEN |
来自 buzz 环境 |
用于通过 API 发送消息的 Slack 机器人令牌(已在 buzz Oz 环境中可用) |
此技能使用 Slack API (chat.postMessage) 而非传入 webhook,支持真实的用户提及。buzz Oz 环境已包含所需的 SLACK_BOT_TOKEN,无需额外设置密钥。
如果未设置 SLACK_BOT_TOKEN,则将所有消息输出到标准输出。
步骤 1:查找最近合并的规范
列出自回溯日期以来两个仓库中合并的 PR,然后按更改文件过滤。不要使用 --search "in:files"(GitHub 不支持在 PR 搜索中按文件路径过滤),并使用在 Linux 和 macOS 上均可移植的日期命令:
# 可移植的日期计算(兼容 GNU/Linux 和 BSD/macOS)
SINCE=$(date -d "-${LOOKBACK_DAYS} days" +%Y-%m-%d 2>/dev/null \
|| date -v-${LOOKBACK_DAYS}d +%Y-%m-%d)
# 列出所有最近合并的 PR(无文件路径过滤——下一步检查文件)
gh pr list \
--repo warpdotdev/warp \
--state merged \
--search "merged:>${SINCE}" \
--json number,title,author,mergedAt,url \
--limit 100
# 对 warp-server 重复
gh pr list \
--repo warpdotdev/warp-server \
--state merged \
--search "merged:>${SINCE}" \
--json number,title,author,mergedAt,url \
--limit 100
对于每个返回的 PR,通过检查更改的文件来确认是否包含新的 specs/*/PRODUCT.md(这是正确的过滤步骤):
gh pr view <number> --repo warpdotdev/<repo> --json files -q '.files[].path' \
| grep -E '^specs/.+/PRODUCT\.md$'
收集以下列表:规范 ID(specs/ 下的目录名)、规范 PR 编号和 URL、PR 作者的 GitHub 用户名、仓库(warp 或 warp-server)以及合并日期。
对于每个 PR 作者的 GitHub 用户名,解析其 Slack 身份:
# 从 GitHub 获取工程师的姓名和邮箱
ENG_NAME=$(gh api users/<github-username> -q '.name // .login')
ENG_EMAIL=$(gh api users/<github-username> -q '.email // empty')
# 通过邮箱查找其 Slack 用户 ID(真实提及,不仅仅是名称提及)
if [ -n "$ENG_EMAIL" ]; then
SLACK_USER_ID=$(curl -s -H "Authorization: Bearer $SLACK_BOT_TOKEN" \
"https://slack.com/api/users.lookupByEmail?email=${ENG_EMAIL}" \
| python3 -c "import sys,json; d=json.load(sys.stdin); print(d['user']['id'] if d.get('ok') else '')")
fi
# 如果查找成功,使用 <@USER_ID> 进行真实提及;否则回退到 @name
if [ -n "$SLACK_USER_ID" ]; then
ENG_MENTION="<@${SLACK_USER_ID}>"
else
ENG_MENTION="@${ENG_NAME} _(未找到 Slack ID — 请确认这是正确的人)_"
fi
存储 ENG_MENTION、ENG_NAME 和 ENG_GITHUB 以便在 Slack 消息中使用。
步骤 2:检查现有文档覆盖
对于每个找到的规范,检查 warpdotdev/docs 中是否有提及该规范 ID 的开放/草稿或合并的 PR。运行两个独立的查询以避免将已关闭但未合并的 PR 视为覆盖:
# 检查开放或草稿 PR
gh pr list \
--repo warpdotdev/docs \
--state open \
--search "<spec-id>" \
--json number,title,state,url \
--limit 5
# 检查合并的 PR
gh pr list \
--repo warpdotdev/docs \
--state merged \
--search "<spec-id>" \
--json number,title,state,url \
--limit 5
如果任一查询返回结果(存在开放、草稿或合并的 PR),则认为规范已覆盖。跳过已覆盖的规范。
如果两个查询均无结果,则认为规范未覆盖。已关闭但未合并的 PR 不算作覆盖——关闭的 PR 表示工作已放弃,需要重新触发。
步骤 3:评估规范完整性
对于每个未覆盖的规范,读取 specs/<id>/PRODUCT.md 并评估其内容是否足以自动起草:
完整(继续自动起草)如果满足以下所有条件:
- 文件至少 40 行
- 包含
## Behavior部分(或等效部分),其中有编号的不变量或面向用户的步骤 - 描述至少一个具体的用户操作(不仅仅是摘要段落)
简略(直接通知工程师)如果规范是存根——仅包含摘要部分、少于 40 行或没有行为细节。
步骤 4:根据规范完整性执行操作
路径 A:完整规范 → 自动起草
- 以环境模式运行
write-feature-docs(详见write-feature-docs技能)——跳过交互式大纲确认,而是将大纲作为检查清单嵌入 PR 描述中 - PR 在
warpdotdev/docs中打开,包含草稿和需要工程师验证的检查清单 - 请求工程师(
@<github-username>)以及@rachaelrenk和@hongyi-chen审阅 - 向
SLACK_CHANNEL发送以下 Slack 消息:
📄 *文档草稿已自动生成*
功能:*<spec-id>*(来自 `<repo>`)
规范 PR:<spec-pr-url>
<@USER_ID>(GitHub:<github-username>)
我已打开一个文档草稿 PR 供审阅:<docs-pr-url>
请检查 PR 中标有 *[UNVERIFIED]* 和 *[TODO]* 的项目——这些是唯一需要您输入的内容。
路径 B:简略规范 → 通知工程师
向 SLACK_CHANNEL 发送以下 Slack 消息:
📋 *新规范需要文档——细节不足,无法自动起草*
功能:*<spec-id>*(来自 `<repo>`)
规范 PR:<spec-pr-url>
<@USER_ID>(GitHub:<github-username>)
该规范的行为细节不足以让我自动生成文档。请执行以下任一操作:
• 向 `specs/<spec-id>/PRODUCT.md` 添加更多细节(包含面向用户步骤的 Behavior 部分),或者
• 在此频道中通知文档团队,我们将手动起草
如果没有未覆盖的规范,则发送:
✅ *文档覆盖扫描完成* — 所有最近合并的规范均有文档覆盖。
步骤 5:发布到 Slack
使用 Slack API 发布每条消息。使用 jq 构建 JSON 负载,以安全处理 $MESSAGE 中的换行、引号和反斜杠:
jq -n \
--arg channel "$SLACK_CHANNEL" \
--arg text "$MESSAGE" \
'{channel: $channel, text: $text}' \
| curl -s -X POST https://slack.com/api/chat.postMessage \
-H "Authorization: Bearer $SLACK_BOT_TOKEN" \
-H 'Content-type: application/json' \
-d @-
如果未设置 SLACK_BOT_TOKEN,则将消息输出到标准输出。
步骤 6:打印摘要
始终将运行摘要打印到标准输出:
scan-new-specs 运行摘要
扫描的仓库: warpdotdev/warp, warp-server
回溯窗口: <N> 天(自 <date> 起)
找到的规范: <N>
已覆盖: <N>
自动起草: <N> (完整规范 → 已打开草稿 PR)
已通知(简略规范): <N> (不完整规范 → 已通知工程师)
Slack 频道: <channel>
调度
此技能设计为每 2-3 天作为定时 Oz 环境代理运行。Oz 代理配置的建议提示:
"运行 scan-new-specs 检查 warpdotdev/warp 和 warp-server 中新合并但未在 warpdotdev/docs 中有对应文档 PR 的 PRODUCT.md 规范。对于完整规范,自动生成文档草稿 PR 并标记工程师。对于简略规范,在 Slack 中通知工程师。在 #growth-docs 中发布摘要。使用最近 3 天作为回溯窗口。"
建议调度:每周一、周三和周五上午 9 点(太平洋时间)——足够频繁以快速捕获规范,但不会造成干扰。
去重说明
此技能在运行之间不维护持久状态。去重完全依赖于 warpdotdev/docs 中是否存在文档 PR——如果某个规范有开放或合并的 PR,则不会再次标记。这意味着除非有人为规范打开文档 PR(即使是草稿),否则规范将继续生成提醒。
边缘情况: 如果文档草稿 PR 被打开然后关闭(未合并),则规范将在下次运行时被重新标记,因为关闭的 PR 不计入覆盖。这是有意为之——关闭的 PR 表示文档工作已放弃,需要重新触发。
Slack 提及说明
此技能使用来自 buzz Oz 环境的 SLACK_BOT_TOKEN 通过 Slack API (chat.postMessage) 发送消息。这支持真实的 <@USER_ID> 提及——工程师将在检测到其规范时收到直接通知。
用户 ID 通过将工程师的 GitHub 邮箱与 Slack 的 users.lookupByEmail API 进行查找来解析。如果工程师有私密的 GitHub 邮箱,查找将失败,消息将回退为纯文本名称并附带手动验证的说明。
相关技能
write-feature-docs— 工程师在收到通知后运行以生成文档草稿的技能






