掃描 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 Bot Token(已在 buzz Oz 環境中可用) |
此技能使用 Slack API(chat.postMessage)而非 incoming 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> 進行真實標記;否則回退到 @名稱
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 中是否有開啟/草稿或合併的 PR 提及該規格 ID。執行兩個獨立的查詢,以避免將已關閉但未合併的 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— 工程師在被提醒後執行以產生文件草稿的技能






