Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions .changes/source-control/work-resolve-issue-issue-11391-8d3f1a64.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
---
bump: minor
---

### Added

- `/source-control:pull-request evidence` posts one evidence comment per pull request after the verifier passes for its head, and updates it in place for a new head with `gh pr comment --edit-last --create-if-none --attach`. It attaches only the captures in the run's `publishable` list, a video only when every frame passed the masking check, in collapsed sections laid out by `templates/evidence-comment.md`, and links the CI capture artifact with its expiry or says media was not uploaded. A file outside the list, a leak-scan hit on the body, or an account that posts other comments on the PR posts nothing. When `gh` rejects `--attach` beside `--edit-last`, it deletes the earlier evidence comment and posts a new one ([#11391](https://github.com/melodic-software/claude-code-plugins/issues/11391)).

### Changed

- `create`'s Visual evidence step no longer asks the person to drag captures into the PR description: it points at the evidence step, which attaches them ([#11391](https://github.com/melodic-software/claude-code-plugins/issues/11391)).
Original file line number Diff line number Diff line change
Expand Up @@ -100,8 +100,8 @@ directory**, or from `GH_REPO`. Out of tree, run the call from the worktree
## Body overrides the template

A body passed with `gh pr create --body-file` (or `--body`) fully overrides
`.github/PULL_REQUEST_TEMPLATE.md` (cli/cli #10751). `gh pr create` has no option that uploads a
file.
`.github/PULL_REQUEST_TEMPLATE.md` (cli/cli #10751). Create passes no `--attach` (gh 2.99.0 and
later): captures go to the PR through the pull-request skill's `evidence` action.

## Open the draft PR

Expand Down
6 changes: 4 additions & 2 deletions plugins/source-control/skills/pull-request/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,13 @@
description: "When the bundled pr skill or built-in commit-push-pr command resolves in this session, prefer pr for a one-shot PR from committed work and commit-push-pr to commit, push and open one at once, only when no draft, body contract, or later ready, monitor, or merge step applies; this skill otherwise. Orchestrate the full PR lifecycle: prep (review + verify), create, ready (merge the base, security review + verify, flip), monitor CI + review comments, merge, and fetch CI logs. Use when: 'create pr', 'ship it', 'pr prep', 'mark ready', 'ready for review', 'fix CI', 'address comments', 'monitor PR', 'merge this', 'check pr status', not for the all-PR babysit loop (use /babysit-prs), branch/worktree lifecycle (use /worktree), or committing without a PR (use /commit)."
user-invocable: true
disable-model-invocation: false
argument-hint: "[prep|create|ready|monitor|comments|ci|merge|status|full|fetch-logs|view…] [--unattended] [args]"
argument-hint: "[prep|create|ready|monitor|comments|ci|merge|evidence|status|full|fetch-logs…] [--unattended] [args]"
metadata:
workflow-stage: pr
summary: Full PR lifecycle. Prep, create, monitor CI, address reviews, merge
---

**Arguments.** `[prep|create|ready|monitor|comments|ci|merge|status|full|fetch-logs|view…] [--unattended] [args]`. Full set: the Arguments table below. e.g., /pull-request prep, /pull-request create, /pull-request ready, /pull-request monitor, /pull-request comments, /pull-request merge, /pull-request status, /pull-request full, /pull-request fetch-logs <pr|run>, /pull-request view <pr> --diff, /pull-request list --head <branch>, /pull-request review-venue
**Arguments.** `[prep|create|ready|monitor|comments|ci|merge|evidence|status|full|fetch-logs…] [--unattended] [args]`. Full set: the Arguments table below. e.g., /pull-request prep, /pull-request create, /pull-request ready, /pull-request monitor, /pull-request comments, /pull-request merge, /pull-request evidence <pr> --evidence <file>, /pull-request status, /pull-request full, /pull-request fetch-logs <pr|run>, /pull-request view <pr> --diff, /pull-request list --head <branch>, /pull-request review-venue

## Repository context. Gather first

Expand Down Expand Up @@ -73,6 +73,7 @@ For PR lifecycle runs spanning 3+ phases, copy `${CLAUDE_PLUGIN_ROOT}/skills/pul
| `dependency --ci` | Phase 3.5 (CI) | The pr-unblock lane's unattended review of one risky Dependabot update: reads the context file, the checkout and the upstream release notes as data, leaves a scoped fix outside `.github/` uncommitted for a later job to push, and returns a merge, fix, close or escalate verdict as structured output, running no head code. See [reference/dependency-ci.md](reference/dependency-ci.md) |
| `ci --ci` | CI | The pr-unblock lane's unattended fix of a PR's failing checks: reads the runner's context file as data, reproduces each check with the repository's own command, fixes the cause, reruns it, and leaves the fix uncommitted for the runner's patch; never weakens a check, and escalates what it cannot fix with a named reason. See [reference/ci-ci.md](reference/ci-ci.md) |
| `merge` | Phase 4 | Squash merge, or merge or enqueue without asking once the PR is `CLEAN` and the AI review checks have passed on the reviewed head, with the plain merge command (a refusal is reported, never handed to the user or retried in another shape), then confirm a merge-queue PR entered the queue (enqueue a `CLEAN` one left out, report the refusal text verbatim; §4.2.2) and wait for `MERGED` (no strategy flag behind a merge queue, `--auto` only pinned to the reviewed head; [reference/merge.md](reference/merge.md) §4.2.1) + worktree transition (reuse it, or release this session's lock) + verify. Never removes a worktree: that is `/source-control:worktree cleanup` |
| `evidence <pr> --evidence <file> [--attach <path>]... [--summary <file>] [--artifact-url <url> [--retention-days <n>]]` | Evidence | After the verifier passed for the PR's head, post one evidence comment, or update it in place for a new head, with `gh pr comment --edit-last --create-if-none --attach`: the text summary, publishable captures only in collapsed sections laid out by `templates/evidence-comment.md`, and the CI capture artifact link with its expiry. A file outside the `publishable` list, or a leak-scan hit on the body, posts nothing. See [reference/evidence.md](reference/evidence.md) |
| `status` | Report only | Unified status across all phases |
| `full` | Phase 1-4 | Run prep → create → monitor → merge end-to-end |
| `fetch-logs <pr\|run> [--raw\|--job <job-id>]` | CI log retrieval | Pull failed-CI evidence: default = `::error`/`::warning` annotations only (cheapest); `--raw` = full ZIP dump for archive review; `--job <id>` = per-job plain text |
Expand Down Expand Up @@ -147,6 +148,7 @@ Execute in order. Each phase is self-contained. Read the relevant file for detai
| 3.5 (CI) | [reference/dependency-ci.md](reference/dependency-ci.md) | `dependency --ci` |
| CI | [reference/ci-ci.md](reference/ci-ci.md) | `ci --ci` |
| 4. Merge | [reference/merge.md](reference/merge.md) | `merge` |
| Evidence | [reference/evidence.md](reference/evidence.md) | `evidence` |

---

Expand Down
41 changes: 41 additions & 0 deletions plugins/source-control/skills/pull-request/evals/evals.json
Original file line number Diff line number Diff line change
Expand Up @@ -807,6 +807,47 @@
"It classifies both lanes ABSENT and runs a local substitute review over the pull request's diff",
"The `Review lanes:` line names each absent lane and its substitute"
]
},
{
"id": 61,
"name": "evidence-refuses-file-not-in-publishable-list",
"narration": true,
"prompt": "/pull-request evidence 640 --evidence /tmp/run/e2e-summary.json --attach /tmp/run/checkout-cart-01-screenshot.png --attach /tmp/run/account-profile-01-screenshot.png. PR 640's head is 3c1d9e0aa1b2c3d4e5f60718293a4b5c6d7e8f90 and confirm-verdict.sh show prints `confirm: CONFIRMED for head 3c1d9e0aa1b2c3d4e5f60718293a4b5c6d7e8f90`. The e2e-summary.json `publishable` list holds checkout-cart-01-screenshot.png and e2e-summary.json only; account-profile-01-screenshot.png is not in it.",
"expected_output": "The evidence step reads the publishable list, finds that account-profile-01-screenshot.png is not in it, and refuses: it names that file and posts nothing, no comment created or edited and no file uploaded, rather than posting the one publishable capture or attaching the refused one.",
"files": [],
"expectations": [
"It names account-profile-01-screenshot.png as not in the publishable list",
"It runs no `gh pr comment` call, so no comment is created or edited and no file is uploaded",
"It does not attach account-profile-01-screenshot.png in any form"
]
},
{
"id": 62,
"name": "evidence-second-head-updates-existing-comment",
"narration": true,
"prompt": "/pull-request evidence 640 --evidence /tmp/run2/e2e-summary.json. PR 640 has a new head, 9a8b7c6d5e4f30211223344556677889900aabbc, and confirm-verdict.sh show prints `confirm: CONFIRMED for head 9a8b7c6d5e4f30211223344556677889900aabbc`. The publishable list holds checkout-cart-01-screenshot.png. The account gh is logged in as has one comment on PR 640, the evidence comment posted for the previous head, which starts with `<!-- evidence-verification -->`. The leak scan of the rendered body finds nothing, and `gh pr comment --help` lists `--attach`.",
"expected_output": "The step finds the account's only comment on the PR is the evidence comment, so it updates it in place with `gh pr comment 640 --edit-last --create-if-none --body-file <body> --attach <checkout-cart-01-screenshot.png>`, the body rendered from templates/evidence-comment.md and naming the new head. It does not post a second comment, and the read-back finds exactly one comment starting with the marker.",
"files": [],
"expectations": [
"It checks that every comment the logged-in account has on PR 640 starts with `<!-- evidence-verification -->` before editing",
"It posts with `gh pr comment 640 --edit-last --create-if-none` and `--attach` for the publishable capture",
"It renders the body from templates/evidence-comment.md, naming the new head 9a8b7c6d5e4f30211223344556677889900aabbc",
"It does not create a second evidence comment, and its read-back finds exactly one comment starting with the marker"
]
},
{
"id": 63,
"name": "evidence-no-artifact-says-media-not-uploaded",
"narration": true,
"prompt": "/pull-request evidence 641 --evidence /tmp/run/e2e-summary.json --summary /tmp/run/summary.md. PR 641's head is 5f5e5d5c5b5a59585756555453525150504f4e4d and confirm-verdict.sh show prints `confirm: CONFIRMED for head 5f5e5d5c5b5a59585756555453525150504f4e4d`. The e2e-summary.json capture status is `not-applicable` and its `publishable` list holds only e2e-summary.json. No --artifact-url was given. The logged-in account has no comment on PR 641, and the leak scan of the rendered body finds nothing.",
"expected_output": "With no capture to attach and no artifact URL, the step renders the body from the template with the text summary from summary.md and an artifact line reading `Media not uploaded: <reason>`, such as no capture was publishable. It creates the one evidence comment with `gh pr comment 641 --edit-last --create-if-none --body-file <body>` and attaches no file.",
"files": [],
"expectations": [
"The comment body carries the text summary from summary.md",
"The comment body has a line starting `Media not uploaded:` that names the reason",
"It attaches no file: e2e-summary.json is not an image or video",
"It creates the comment through `gh pr comment 641 --edit-last --create-if-none`"
]
}
]
}
Original file line number Diff line number Diff line change
Expand Up @@ -386,11 +386,11 @@ from the item-sourced text, the `## Remaining` bullets included, before it enter

The content inside those headings is prose a reviewer reads: plain language, bottom line first, no filler, by invoking `/writing:be-concise` via the Skill tool when the `writing` plugin is installed; otherwise apply that discipline inline. It rewords section content only, so the closing-keyword line, the resolved `${REQUIRED_SECTIONS[@]}` headings, `${REFS_LINES}`, the acceptance criteria copied from the plan, and the quoted Intent in the Problem and intent line are untouched and the §2.4.2 gate sees the same shape either way.

**Visual evidence.** When the diff changes rendered visual or audio output, the section that records verification (`Verification`, or `Test plan` under `summary-test-plan`) carries before/after media captured while verifying, for example by `/testing:run-e2e` or the Chrome screenshot and GIF tools. The PR create command has no option that uploads a file ([GitHub](../../../reference/providers/github/pull-request/create.md#body-overrides-the-template)), so the section lists each capture's local path and asks the person to drag the files into the PR description on GitHub; when no media could be captured, it says no visual evidence was attached. A project turns this step off in its own CLAUDE.md or AGENTS.md.
**Visual evidence.** When the diff changes rendered visual or audio output, the section that records verification (`Verification`, or `Test plan` under `summary-test-plan`) carries before/after media captured while verifying, for example by `/testing:run-e2e` or the Chrome screenshot and GIF tools. Create attaches no file itself. The captures reach the PR through the evidence step, `/source-control:pull-request evidence` ([reference/evidence.md](evidence.md)), which attaches the publishable ones in one comment after the verifier passes. So the section names each capture and says it goes to the evidence comment; when no media could be captured, it says no visual evidence was attached. A project turns this step off in its own CLAUDE.md or AGENTS.md.

- **Pointer**: when the person asks how to add the captures, fetch GitHub's [Attaching files](https://docs.github.com/en/get-started/writing-on-github/working-with-advanced-formatting/attaching-files) live for the upload routes and size limits.
- **As of**: 2026-10-02
- **Recheck trigger**: a GitHub CLI release adds an option to its PR create or edit command that uploads a file, at which point the step attaches the captures itself.
- **Pointer**: the [`gh pr comment` manual](https://cli.github.com/manual/gh_pr_comment) for `--attach`, and GitHub's [Attaching files](https://docs.github.com/en/get-started/writing-on-github/working-with-advanced-formatting/attaching-files) for the upload routes and size limits.
- **As of**: 2026-11-01
- **Recheck trigger**: a `gh` release note that changes `--attach`.

**Left out.** The section that records verification (`Verification`, or `Test plan` under the portable default) ends with one `Left out:` line naming what was not run or checked, each with its reason (for example, `Left out: end-to-end suite, needs a staging environment`), so a reviewer can tell a gap from an omission; when everything relevant was run, it says `Left out: nothing`. When that section closes the body, the §2.4.3 attribution line still follows it as the body's footer.

Expand Down
Loading
Loading