Skip to content
Back to skills

Review Inbox

ASecurity

"Use when the user wants to discover and review PRs across the team awaiting their attention. NOT for a single specific PR (use review-pr). Supports three discovery modes: Label (GitHub label scan), Slack (channel-wide scan), Thread (specific Slack thread URL). Trigger: '掃 PR', 'review 大家的 PR', '批次 review', '有哪些 PR 要我看', Slack thread URL + review intent ('review <slack_url>', '幫我看這串'). Key: '我的 PR' → request-pr-review; '大家的 PR' / Slack URL → here; single PR URL → review-pr." 要掃出團隊裡等著自己看的 PR。...

  • 5 stars
  • 0 votes
  • 0 copies
  • 3 views
  • Added May 27, 2026
toolsbashgitapi

Works with

  • cli
  • api
  • mcp

Security analysis

A100/100

Pro scans all 20 files and shows the line behind each finding

Scanned September 21, 2026

npx -y skills add HsuanYuLee/polaris --skill review-inbox --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Review Inbox?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Review Inbox
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/hsuanyulee-review-inbox/badge)](https://www.skillsdirectory.com/skills/hsuanyulee-review-inbox)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: review-inbox
description: |
  "Use when the user wants to discover and review PRs across the team awaiting their attention. NOT for a single specific PR (use review-pr). Supports three discovery modes: Label (GitHub label scan), Slack (channel-wide scan), Thread (specific Slack thread URL). Trigger: '掃 PR', 'review 大家的 PR', '批次 review', '有哪些 PR 要我看', Slack thread URL + review intent ('review <slack_url>', '幫我看這串'). Key: '我的 PR' → request-pr-review; '大家的 PR' / Slack URL → here; single PR URL → review-pr."

  要掃出團隊裡等著自己看的 PR。例如「掃 PR」「review 大家的 PR」
  「有哪些 PR 要我看」,或給一個 Slack thread URL 要人看那一串。

  分辨:「我的 PR」→ request-pr-review;「大家的 PR」或 Slack URL → 這裡;
  單一個 PR URL → review-pr。
metadata:
  author: Polaris
  version: 3.0.0
  requires:
    - skill: review-pr
      why: 本支的輸入解析(resolve-pr-work-source.sh、pr-state-snapshot.sh)整個在它那裡;沒有它就拿不到要看的那個 PR
scope: universal
tools:
  - name: gh
    provision: manual
    why: 開 PR、讀 review、建 release、查 CI
    fix: 裝 GitHub CLI 並完成 `gh auth login`——二進位檔裝得起來,登入只有人做得到
  - name: jq
    provision: framework
    why: 解析 API 回應的 JSON
    install: mise:aqua:jqlang/jq
  - name: rg
    provision: framework
    why: 掃樹用;這支的 selftest 缺了它就跑不完
    install: mise:aqua:BurntSushi/ripgrep
---

# Review Inbox — 批次 Review 待審 PR

找出 team 內需要自己 first review、re-approve、或 re-review 的 PR,批次執行 review,
並依來源回 Slack 通知。

## Contract

此 skill 只處理多 PR discovery + batch review orchestration。單一 PR URL 轉 `review-pr`;
「我的 PR」approval 狀態轉 `request-pr-review`。

支援三個來源:

| Source | Use when |
|---|---|
| Slack | 預設;掃 PR channel 最近訊息中的 PR URLs——**含 thread 回覆**,不只 top-level |
| GitHub 條件掃描 | 一律與 Slack 取聯集:我投過票而 head 已推進的 open PR,不靠任何人說話 |
| Thread | 使用者提供 Slack thread URL 並要求 review |
| Label | 使用者明確提到 need review label |

不得 review 自己的 PR。不得對 `waiting_for_author` PR 重複 review。
Review inbox 屬 reviewer-side read-only lane;它可以 advisory,但對 `awaiting_re_review`、
`mergeable_ready`、`unsupported_mutation`、`changes_requested` 的解釋必須沿用 shared PR state。
它不得把 batch review 結果升格成 author-side completion / release authority;所有
「可 merge / 已修完 / 可 release」語句只能轉述 shared state,不可自行推論。

## Reference Loading

| Situation | Load |
|---|---|
| Any run | `context-budget-contract.md`, `review-inbox-discovery-flow.md`, `stale-approval-detection.md`, `workspace-config.yaml` |
| Batch review execution | `review-inbox-batch-review-flow.md`, `.claude/skills/review-inbox/dispatch-context-bundle.md` |
| Slack notification | `review-inbox-slack-reporting.md`, `slack-message-format.md`, `../review-pr/references/github-slack-user-mapping.md`, `scripts/validate-language-policy.sh` |

**每張 PR 交給一個 sub-agent 執行。** 用哪一種 agent、幾個並行、先跑哪一張,由執行的人
當下判斷——這一支提供判斷需要的事實(姊妹單關係、規模、風險等級、授權狀態),不提供結論。
它不指名任何一種 agent 型別,要求與禁止都不指名:一支 `scope: universal` 的 skill 指名一個
它不 ship 的東西,換一個環境就不成立。

**主 session 不讀完整 diff。** 這一條與怎麼派無關,它由 `context-budget-contract.md` 直接
規定,任何 sub-agent 都滿足它。以前這件事由一條「禁用 general-purpose sub-agent」的規定
代理,那條規定引用的證據從來沒有產出過(DP-575);代理拿掉了,被代理的沒有。

Batch review dispatch 由 main session 讀 `dispatch-context-bundle.md` 一次,把它 inline 注入
每個 review packet。**Packet 自帶執行 review 需要的全部內容**;另外附上延伸參考的路徑,
要不要讀、讀多少由 sub-agent 自己判斷。

## Flow

1. 讀 workspace config 與 defaults,取得 GitHub org、PR channel、approval threshold。
2. 解析 mode:Thread 優先,其次 explicit Label,其餘走 Slack。
3. 取得 current GitHub username,作為 exclude author 與 review-status 判定依據。
4. 依 discovery reference 產生 candidates JSON(Label mode 走 `scripts/scan-need-review-prs.sh`,
   Slack mode 走 channel dump + `scripts/extract-pr-urls.py`);派工前照〈Scan Freshness〉重核
   一次,60 秒從那次重核起算。
   Slack channel scan 使用 MCP 時指定 **detailed** output——`concise` 不輸出
   `=== Message from ` 與 `Message TS: ` 這兩個 marker,parser 會找不到 message header 而
   **靜默回傳 0 個 URL**(stderr 只印一行 WARN,離場碼仍然是 0),而那跟「channel 真的空」
   分不開;fallback CLI 的 `--oldest` 可接受
   Slack timestamp 或 ISO date/datetime。
   **產出 candidates 之前要先過 `scripts/review-inbox-discovery-probe.sh`。** 它非零就停在
   那裡、把 marker 與說明回報出來——**不要宣告空的收件匣,也不要靜默改走 label scan**。
   它現在除了「讀不讀得懂」也問「讀完了沒」:時間窗翻到底了嗎、窗內有新回覆的 thread
   讀進來了嗎。`--window-seconds` 在 channel 模式必填,值是這一趟宣告的回溯時間窗。
4b. **Slack 那條做完,再跑兩支 GitHub 條件掃描,逐支取聯集**。頻道掃描的前提是有人說話,
   這兩支都沒有這個前提,而它們的定義域不重疊——**兩支都要跑**:

   - `scripts/scan-my-stale-reviews.sh --my-user <u> --org <org> --merge-with <Slack 的 candidates>`
     ——我投過票、而 head 已經推進的 open PR。2026-09-04 兩輪 discovery 都空手,而同一時間
     有五顆 PR 擋在我方舊票上、作者早就推了修正。
   - `scripts/scan-unreviewed-prs.sh --my-user <u> --org <org> --repo <name>... --merge-with <上一支的輸出> --open-prs-out <表>`
     ——指名的 repo 裡**我一票都沒投過**的 open PR。前兩條來源都錨在「有人針對我做了動作」,
     一顆沒有人貼、我也還沒碰過的 PR 結構上進不了它們。實跑一趟:43 秒撈 29 顆,其中
     **13 顆是另外兩條都撈不到的**;那 13 顆批次讀完 28 秒。
     `--open-prs-out` 順手把那幾個 repo **全部** open PR 的 head 與預設分支寫成一份表——
     它取的是那三道濾網(draft、作者、更新窗)**之前**那一份,因為判「這一顆疊在誰身上」
     問的是「誰是 open PR」,不是「誰該被派」。第 5 步的 `--open-prs` 讀它。

   要問哪幾個 repo 是呼叫者的知識,讀公司自己的 config,這一支不掃整個 org。其餘旗標、
   預設值與為什麼判準不是「有人指名要我」,都在 discovery reference 的第三來源那一節。
5. 將 candidates JSON 經 `annotate-review-candidates.py --open-prs <上一步的表>` enrich,補上 sister PR cluster
   metadata 與 `model_tier` semantic class。Slack mapping 若含 `root_ticket_key`,cluster
   必須優先使用 root ticket;若沒有 umbrella ticket 但同一 Slack root message 有可辨識
   topic,使用 `root_topic_key`;最後才 fallback 到每張 PR 自己的 ticket。

   **鍵相同不等於同一批改動。** 同一個 repo 的兩顆 PR 要進同一個 cluster,還要量得到改動
   交集——共用一個檔案,而且該檔在 base 那一側的 hunk 區塊重疊。量不到就兩顆都走完整
   review:sibling 走的是 lead summary 的六條判準,判錯的代價是一顆 PR 只被半審過,而判成
   standalone 的代價只是多花一次 review。**跨 repo 的兩顆不套這條**,因為那裡量不到交集,
   而「同一件事在三個 repo 各開一顆」正是 sister PR 要服務的形狀。每一顆都帶著一句
   `cluster_reason` 說出憑什麼——它分得出這一顆的交集是量到的(`same_repo_overlap`)還是
   量不到而放行的(`cross_repo_key_only`)。

   這條規則來自一次真跑的收件匣:同一則 thread 裡有兩張不同單的 PR,同一個 repo、
   同一個 controller 檔案,而區塊零重疊。舊的判準讓後面那顆走 sibling,於是它只被
   lead 的六條判準看過,漏掉一條 must-fix。

   **但交集量得到也還不夠,因為它對串行堆疊恆為真。** 同一個 repo 裡第二顆踩在第一顆改過
   的檔案上往前疊,交集必然量得到——而第 N 顆帶的是它自己那一段沒有人讀過的改動,只是
   順便帶著前面那幾顆的行。所以同一個 repo 的兩顆還要問**這一顆從哪裡長出來的**:base 落在
   同一個 repo 任何一顆 open PR 的 head 上就是串行,那幾顆一律走完整 review
   (`stacked_on_candidate` 或 `stacked_on_open_pr`,看 parent 在不在這一輪的候選集裡)。
   問不到其中一顆的 base 時分不出平行與串行,也走完整 review
   (`same_repo_lineage_unmeasurable`)——量不到不得讀成可以半審。

   2026-09-16 的實例,一批八顆:`b2c-web` 的 PR-1 建護欄、後七顆逐顆疊在上面,八顆同一張
   單、同一則 thread。舊的判準把它們判成一個 cluster,其中 +3155/+6578/+11222 行的三顆
   走了 sibling 的半審,由人手動覆寫回來。
6. 若 candidates 為空**而且 probe 回的是 `POLARIS_DISCOVERY_LEGITIMATE_EMPTY`**,回報目前
   沒有需要 review 的 PR 並停止。probe 沒過的空清單不是空的收件匣,是來源壞掉了。
7. 顯示排序後清單,然後全部進入 review。**不問「先看哪一批」、不問「要不要送」、不因為
   張數多或 diff 大自行縮小範圍。** 這一支只在兩種情況停下來,而且要說出是哪一種:來源
   拿不到,或是需要授權而授權不存在。
8. 用 `build-review-prompt.sh` 產生 review packets + manifest。人已經授權送出時,把授權
   一起傳進去(`--authorized-by` 與 `--authorization-quote`),packet 才有一條到得了執行
   那一層的路——**沒有這兩個參數時 packet 明講「未授權」**,sub-agent 產出 payload 但不送出。
   **蒐證放在 sub-agent 那一層**:主 session 的 per-PR 預算不會被 diff 灌爆,而讀 diff 以外
   的檔案(追消費端、對照姊妹 repo、實跑驗證)只有在那一層做得到。
9. 執行 per-PR review packets,一張都不留。**每張 PR 的 head 與完整 diff
   在那張 PR 的 review 開始的那一刻才取,計畫時不整批預取**——理由與量到的形狀寫在
   `review-inbox-batch-review-flow.md` 的〈什麼時候取那份 diff〉。Prompt 必須使用
   deterministic handbook resolver 列出已存在的 project handbook paths,空清單時明確標示
   no project handbook。Prompt 必須要求執行者先讀 changed-file names,再依 diff size
   sampling;existing inline comments 的完整 body 不進**主 session**,reviewer envelope 內
   讀得到。Cluster lead 先跑完整 review;cluster sibling 使用 sibling-diff mode 與
   `small_fast` model class hint(那是一個事實,不是一道指令——adapter 認不認得由執行的人判斷),不確定時標記 `needs_standard_review`——但**兩端行為對不上
   本身就是一個發現**,不是只是一個要標記的例外。
10. 收斂結果,依來源模式發 Slack summary 或 thread replies。**跟 review 一樣做完就回**,
    不在這裡再問一次要不要送。
11. **對帳這一輪真的送出去了什麼。** 同一支腳本的 `--verify-delivered` 模式回讀這個帳號
    在輪次起點之後送出的 review,把「看起來沒有把正文送到」的那幾則指名出來;有可疑的就
    非零離場:

    ```bash
    bash .claude/skills/review-inbox/scripts/measure-review-inbox-session.sh --verify-delivered \
      --my-user {my_user} --since {輪次起點 ISO8601} --pr OWNER/REPO#N [--pr ...]
    ```

    **這一層不在送出者手上**,所以繞過腳本自己 `gh api` 的那幾次它也看得到——它問的是
    GitHub 上的最終狀態,誰送的、之後怎麼改的都不影響。判準是三條腿:送出時間在標記上線
    之後、`body` 長度大於 0、而且缺 `polaris-review-target` 標記。空 body 是合法形狀
    (只帶 inline comment 的那一種),不進可疑。
12. 跑 `measure-review-inbox-session.sh` 產生 telemetry JSON,並用
    `polaris-learnings.sh add --type telemetry --tag review-inbox` 寫入
    `metadata.review_inbox_run`。若無法取得完整 transcript,仍需用 line-count proxy
    記錄 candidate count、reviewed count 與 artifact volume。
13. 在對話中回報每個 PR 的 review result、approve status 與 telemetry run_id。

## Write And Notification Rules

- Review body 與 inline comments 由 `review-pr` 流程負責。
- Slack message 送出前必須通過 `scripts/validate-language-policy.sh`。
- Slack mode 不發 channel-wide summary;只回覆原始 PR threads。
- Label mode 發一則 channel summary。
- Thread mode 回覆指定 thread。
- Thread replies 不設 `reply_broadcast: true`。

## Completion

輸出 reviewed count、APPROVE / REQUEST_CHANGES / COMMENT counts、Slack notification count、
任何 blocked PR 的原因,以及 telemetry run_id。Telemetry 可用:

```bash
POLARIS_WORKSPACE_ROOT={workspace_root} .claude/skills/review-inbox/scripts/polaris-learnings.sh query --type telemetry --tag review-inbox
```

查到 `metadata.review_inbox_run.main_session_input_tokens`。


<!-- PROSE-EXTERNAL-PATHS: docs-manager/ — 動手對象:那是 specs 站台自己的 repo,這支 skill 往它寫東西、讀它的結構,不是我們抄一份放著的知識 -->

Files in this skill

  • SKILL.md5.9 KB
  • dispatch-context-bundle.md1.4 KB
  • scripts/annotate-review-candidates-selftest.sh5.4 KB
  • scripts/annotate-review-candidates.py8.3 KB
  • scripts/build-review-prompt-selftest.sh5.2 KB
  • scripts/build-review-prompt.sh11.3 KB
  • scripts/build-review-runtime-plan-selftest.sh5.1 KB
  • scripts/build-review-runtime-plan.py12.1 KB
  • scripts/check-my-review-status-selftest.sh4.8 KB
  • scripts/check-my-review-status.sh7.3 KB
  • scripts/extract-pr-urls-selftest.sh5.7 KB
  • scripts/extract-pr-urls.py10 KB
  • scripts/fetch-prs-by-url.sh3.4 KB
  • scripts/inspect-pr-section-selftest.sh1 KB
  • scripts/inspect-pr-section.sh1.8 KB
  • scripts/measure-review-inbox-session-selftest.sh2.1 KB
  • scripts/measure-review-inbox-session.sh4.4 KB
  • scripts/resolve-handbook-paths-selftest.sh1.4 KB
  • scripts/resolve-handbook-paths.sh1.2 KB
  • scripts/scan-need-review-prs.sh2 KB

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.