From 157d7b5b8d2b19a2dbdc701e89a8ac2beba37b85 Mon Sep 17 00:00:00 2001 From: Yuri Oksuzian Date: Sat, 1 Aug 2026 12:38:47 -0500 Subject: [PATCH 1/2] Add post-pr-review skill (v1.0.0) Companion to reviewing-pull-requests: publishes a staged review (~/pr_reviews/pr_review.md) to the GitHub PR via gh, fail-closed behind four gates -- review file exists, staleness (review head must match live PR head), decision-to-event mapping (red=request-changes, yellow=comment, green=approve; never upgraded implicitly), and a duplicate check against existing PR comments/reviews. Body is posted verbatim; overrides (--force-stale, --allow-duplicate) must be explicit. Co-Authored-By: Claude Fable 5 --- skills/post-pr-review/SKILL.md | 75 ++++++++++++++++++++++++++++++++++ 1 file changed, 75 insertions(+) create mode 100644 skills/post-pr-review/SKILL.md diff --git a/skills/post-pr-review/SKILL.md b/skills/post-pr-review/SKILL.md new file mode 100644 index 0000000..3746a55 --- /dev/null +++ b/skills/post-pr-review/SKILL.md @@ -0,0 +1,75 @@ +--- +name: post-pr-review +description: Publish a staged PR review (from ~/pr_reviews/) to GitHub as a formal review or comment. Use after /reviewing-pull-requests has staged a review and the user asks to post it. Enforces a staleness gate, decision-to-event mapping, and a duplicate check before anything is sent. +compatibility: Requires gh CLI authenticated with review permission on the target repo +metadata: + version: "1.0.0" + last-updated: "2026-08-01" +--- + +# Post PR Review + +## Purpose + +Publish a review staged by `/reviewing-pull-requests` to the GitHub PR, +fail-closed: every gate must pass before `gh` is invoked. Invoking this +skill IS the user's go-ahead to post — but only if the gates pass. + +## Arguments + +``` +/post-pr-review [comment|approve|request-changes] [review-file] [--allow-duplicate] [--force-stale] +``` + +- Review file defaults to `~/pr_reviews/pr_review.md`. +- The event defaults to the review's own Decision line (see mapping); + an explicit event argument overrides it. + +## Workflow + +1. **Locate the review file.** Default `~/pr_reviews/pr_review.md`. + Missing file → stop and report (do not synthesize a review here; + that is `/reviewing-pull-requests`' job). + +2. **Staleness gate.** Extract the head SHA from the review's + "Reviewed at head ``" line and compare with the live PR head + (`gh api repos///pulls/ --jq .head.sha`). + - Mismatch → STOP. Report old vs new head and recommend re-running + `/reviewing-pull-requests` first. Only `--force-stale` overrides, + and the posted body must then be edited to say which head it + reviewed. + +3. **Decision mapping.** Read the Decision line: + - 🔴 / "request changes" → `gh pr review --request-changes` + - 🟡 / "comment" → `gh pr review --comment` + - 🟢 / "approve" → `gh pr review --approve` + Ambiguous or missing Decision line → STOP and ask. An explicit + event argument overrides the mapping; say so in the report. + +4. **Duplicate check.** Fetch existing PR comments and reviews + (`gh api .../issues//comments`, `.../pulls//reviews`) and + search them for the review's first finding headline and its + summary-header line. + - Hit → STOP. Report which comment already carries the content and + suggest posting only the delta (edit the file first) or + re-invoking with `--allow-duplicate`. + +5. **Post.** + ``` + gh pr review --repo / -- --body-file + ``` + The body is posted verbatim — never rewrite it at post time. If the + file needs changes, edit and re-stage first, then re-invoke. + +6. **Report** the posted review URL, the event used, and which gates + were overridden (if any). + +## Hard rules + +- Never post to a PR the review file does not name. +- Never upgrade the event beyond the review's Decision (a 🟡 review is + not posted as request-changes without an explicit argument). +- Never post when the staleness or duplicate gate fails, absent the + matching override flag. +- One post per invocation; no follow-up comments without a new + invocation. From 3ff7f883b2819eab025aa1afd302fdadcfe80fcf Mon Sep 17 00:00:00 2001 From: Yuri Oksuzian Date: Sat, 1 Aug 2026 20:56:58 -0500 Subject: [PATCH 2/2] post-pr-review: parameterize draft location, document why it exists (v1.0.1) The review-draft directory is per-user scratch space, not shared state: default ~/pr_reviews, overridable via PR_REVIEW_DIR. New 'Why a local draft at all' section makes the design explicit -- everything durable is GitHub-to-GitHub (the posted review is the canonical record; re-reviews read from the PR); the local file exists only so a human can edit the draft before anything becomes visible on the PR, and is disposable after posting. Co-Authored-By: Claude Fable 5 --- skills/post-pr-review/SKILL.md | 25 +++++++++++++++++++------ 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/skills/post-pr-review/SKILL.md b/skills/post-pr-review/SKILL.md index 3746a55..9abb056 100644 --- a/skills/post-pr-review/SKILL.md +++ b/skills/post-pr-review/SKILL.md @@ -1,9 +1,9 @@ --- name: post-pr-review -description: Publish a staged PR review (from ~/pr_reviews/) to GitHub as a formal review or comment. Use after /reviewing-pull-requests has staged a review and the user asks to post it. Enforces a staleness gate, decision-to-event mapping, and a duplicate check before anything is sent. +description: Publish a locally drafted PR review to GitHub as a formal review or comment. Use after /reviewing-pull-requests has staged a draft and the user asks to post it. Enforces a staleness gate, decision-to-event mapping, and a duplicate check before anything is sent. compatibility: Requires gh CLI authenticated with review permission on the target repo metadata: - version: "1.0.0" + version: "1.0.1" last-updated: "2026-08-01" --- @@ -21,15 +21,18 @@ skill IS the user's go-ahead to post — but only if the gates pass. /post-pr-review [comment|approve|request-changes] [review-file] [--allow-duplicate] [--force-stale] ``` -- Review file defaults to `~/pr_reviews/pr_review.md`. +- Review file defaults to `$PR_REVIEW_DIR/pr_review.md`, where + `$PR_REVIEW_DIR` falls back to `~/pr_reviews` if unset. The directory + is a personal drafting location, not shared state — see "Why a local + draft" below. - The event defaults to the review's own Decision line (see mapping); an explicit event argument overrides it. ## Workflow -1. **Locate the review file.** Default `~/pr_reviews/pr_review.md`. - Missing file → stop and report (do not synthesize a review here; - that is `/reviewing-pull-requests`' job). +1. **Locate the review file.** Default `$PR_REVIEW_DIR/pr_review.md` + (fallback `~/pr_reviews/`). Missing file → stop and report (do not + synthesize a review here; that is `/reviewing-pull-requests`' job). 2. **Staleness gate.** Extract the head SHA from the review's "Reviewed at head ``" line and compare with the live PR head @@ -64,6 +67,16 @@ skill IS the user's go-ahead to post — but only if the gates pass. 6. **Report** the posted review URL, the event used, and which gates were overridden (if any). +## Why a local draft at all + +Everything durable in this workflow is GitHub-to-GitHub: once posted, +the review on the PR is the canonical record, and re-reviews read prior +findings from the PR itself (see reviewing-pull-requests, "Re-Reviews +and Carry-Forward"). The local file exists only for the drafting stage +— so a human can read and edit the review with ordinary tools before +anything becomes visible on the PR. It is per-user scratch space, never +shared state, and disposable after posting. + ## Hard rules - Never post to a PR the review file does not name.