SuperAPI AI Directory

release-pr

Coding & development

View repository

Updated 10-16 05:00

About this skill

/release-pr — Release PR title + description generator

Automatically generate for release PRs (the "release to master" PR that aggregates multiple already-merged features)titleanddescriptionand write them back.

Applicable scenario:hotfix → master、develop → master、release/* → master this kind of PR that releases changes accumulated over a period of time.Not a feature PR (for feature PRs use /pr)。

Step 0: Obtain the target PR

  • If the argument gives a PR number / URL → use it.
  • If not given → gh pr list --repo <repo> --state open find the release PR whose head is hotfix/develop/release; if there are multiple, use AskUserQuestion to let the user choose.
  • Infer the repo from the argument URL, or the current directory gh repo view --json nameWithOwner。
gh pr view <PR> --repo <repo> --json number,title,body,baseRefName,headRefName,state,url

Step 1: Obtain the commit range (key — compare with remote, not local)

⚠️ The local base branch may be dozens of commits behind the remote, so be sure to use the GitHub compare API to get the range that "truly belongs only to this PR":

gh api repos/<repo>/compare/<base>...<head> \
  --jq '.commits[] | .commit.message | split("\n")[0]'

When the full message is needed (to extract feature details for the notes), fetch the full body again for important commits:

gh api repos/<repo>/compare/<base>...<head> --jq '.commits[].commit.message'

Step 2: Classify

Ignore merge commits(Merge pull request ... / Merge branch ... / Merge remote-tracking ...) — they are not content, just merge actions. Classify by the Conventional Commit prefix of non-merge commits:

Prefix Classify as
feat Features
fix Bug Fixes
perf / refactor / chore / docs / ci / build / style Improvements

Judgment principles:

  • refactor If it is substantively new behavior (e.g. integrating a new vendor API), it can go under Features; judge by semantics rather than rigidly adhering to the prefix.
  • Merge multiple fixup commits for the same feature into one entry; do not list them commit by commit.
  • Include the corresponding feature PR number where possible (from the merge commit's #NNNN map back), using the format #NNNN(same-repo auto-link is correct).
  • Each entry should clearly state in one sentence "what changed + why / benefit"; do not just paste the commit headline.
  • fix( does not imply "there is a bug in production": if that commit fixes an issue just introduced by an earlier commit in the same batch, that issue was never shipped, and putting it under Bug Fixes would make reviewers misjudge it as a production incident and trigger unnecessary impact assessments and customer-complaint retrospection. See Step 2.5 for the discriminator.

Step 2.5: Check against the diff (mandatory, cannot be skipped)

What Step 1 obtained is commit message, not fact. Commit self-descriptions can be wrong, andthe more detailed they are written, the more likely they are to be copied verbatim. First pull a file list as a shared baseline:

gh api repos/<repo>/compare/<base>...<head> \
  --jq '.files[] | "\(.status)\t+\(.additions)/-\(.deletions)\t\(.filename)"'

Run three checks on this list (all cost nothing; no need to read any patch):

  1. Negative statements——when a commit says "does not touch X" or "does not add X", its truth scope isthe moment that PR wrote it, whereas the scope of release notes is the entire batch. If X appears in the file list, it is directly refuted; the correct fix is to add back the scope qualifier ("this PR does not…; only later #NNNN does…") rather than deleting the sentence.The same applies to contradictions that only surface after juxtaposing across PRs: after writing the whole body, read through it once, specifically looking for two mutually exclusive sentences.
  2. Local execution result numbers——the "N unit suites / M tests green, build succeeded" at the end of a commit can never be verified in the diff, and will inevitably become invalid once subsequent PRs are released.Do not repost, instead point to this PR's check runs; if you want to preserve quality signals (such as mutation testing results), label them as "local verification at the time of PR #NNNN".
  3. In-batch self-correction——.files[] | select(.filename=="X") | .status as added ⇒ the file does not exist at all in base ⇒ all "fixes" within the file must be in-batch self-corrections; move them out of Bug Fixes, downgrade them to a parenthetical note on the corresponding Improvements entry, and explicitly state "in-batch self-correction, not shipped".
  4. Category vs. file scope contradiction——fix:/feat:/refactor: When the category claimed by a prefix such as this contradicts the list of files the commit actually touches (e.g. the message says "fix X" but the file list is all new files, or the scope of changes far exceeds what the message describes), reclassify based on the diff and do not trust the prefix literally; the criterion aligns with the Diff-Grounding rules in section 2 of the evidence-gate skill.

Verify "which N PRs were aggregated": take the union of files from those N merge commits and compare it against the file count of the compare; every discrepancy must be explainable item by item (for files that never existed in base, their delete will not appear in the compare).

For large batches (>20 commits or >40 files), assign one agent to check everything, and the prompt must contain two sentences:"A commit message's self-description cannot serve as evidence; when the commit and the diff conflict, the diff is the truth"、"Classify each item as correct / incorrect / unsupported; anything without direct evidence in the diff must be classified as 'unsupported', and do not loosen this just to make the body look correct"。

(Basis: measured on vocus-web-ui #7969, 28 commits / 64 files, ~62 claims with 2 wrong and 5 misleading, andfile paths and symbol names 0/30 wrong— the verification budget should go to negative statements and cross-PR consistency, not paths. See KB for details wiki/learned/release-notes-transcribed-from-commits-inherit-their-errors.md、intra-batch-self-correction-is-not-a-bug-fix.md)

Step 3: Generate description

Reuse the existing template structure of that PR (usually # Features / # Bug Fixes / # Improvements, separated by --- ). If the original body is an empty template, just fill in the classification results.Keep the original section heading language and separator format.

Each bullet uses - **重點**(#PR):說明。

Step 3.5: Scope proportionality gate (scope proportionality)

After Step 3 is written and before sending it to Step 4, ask the body'severy paragraphone question:

Does the reviewer need to know this in order to decide "whether to approve and deploy this change"?

  • Yes → keep it (what changed, whether it will change serving behavior, when it takes effect, how to roll back, what to watch after deployment)
  • "Needed only when something goes wrong / when verifying" → link out, do not embed(full evidence tables, root-cause derivation, mechanism tutorials, corrections to other documents)
    • Specific actions:Replace the entire section with a one-line pointer + link(e.g. "Background and full evidence see #NNNN /path/to/report.md"), not delete it without mention
    • Do not proceed to Step 4 until the matched paragraphs have been fully revised(see "Execution method" below)

The sharp edge of the criterion: the content that is linked outis not unimportant, but its complete version already exists elsewhere(feature PR, KB report, runbook). Writing it again in the release PR only creates a second maintenance point and a second copy that will go stale.

This is not "the shorter the better." The target of trimming is content unrelated to the approval decision, not length itself—a 64-file batch writing 7,897 characters is entirely legitimate.

Secondary metric: for smelling, not a hard cap

Body character count should scale with the size of the changeSublineargrowth. Existing house rules (measured 2026-09-06):

PR Files Body characters Characters per file
#7969 64 7897 123
#8117 8 3108 389
#8121 3 2658 886
#8124 1 1053 1053

If "characters per file" is significantly higher than similarly-sized neighbors, stop and rerun the primary metric. A single-file but semantically heavy change (feature flag, schema migration, security patch) can reasonably run high, but you must be able to state the reason.

Why this gate is needed

The failure mode is not a judgment problem, it ispositional pressure: the author has just finished the investigation, all the context is in hand, and the PR body is the last place to dump things before letting go.The motivation to dump comes from the author's state, and has nothing to do with the reader's needs.

Isomorphic precedent:knowledge-base/reports/2026-08-19-alert-description-bloat-audit-and-rewrite-proposal.md — Of 106 Grafana rules, 15 stuffed the full RCA into the descriptionthat gets pushed in its entirety to Slack on every firing. That report's conclusion can be transplanted directly: "The root problem is not writing too much, it is writing in the wrong place."

Measured regression: #8124 (1 file/+23−7) initial body 3,993 characters, containing four sections whose full versions already existed in #8123 and the KB report (P95 evidence table, causal derivation, CodePipeline mechanism, correction to a certain KB document); after revision, 1,053 characters.

How to execute (not "reference," but to be run)

Before sending into Step 4, read fixtures/coverage.md, self-check against each listed failure mode one by one, and output the results as a table:

| fixture | failure mode | 本次是否命中 | 依據 |
|---|---|---|---|
| 01 | scope bloat | 否 | 每檔字元 1053,落在區間;四個可外連區塊均已外連 |
| 04 | commit message 照抄 | 否 | 每條 claim 都溯源 diff,非 commit 自述 |
| …  | … | … | … |

If any one hits, go back to Step 3 and rewrite; you must not carry a hit item into Step 4.

fixtures/ If not on this machine (npx skills 's snapshot may only include SKILL.md), fetch from the repo: https://github.com/ashe-li/agent-skills/tree/main/release-pr/fixtures。If it cannot be fetched, state plainly "golden set not obtained, no coverage self-check performed this time"; do not skip it and still claim it was done.

This layer is interpretation, not mechanical checking. CI's scripts/check_release_fixtures.py only verifies the golden set's own integrity (manifest matches files, has negative-control, newly added Steps must update fixtures in sync),it cannot verify "whether this time's trade-offs are correct". The two layers differ in strength; do not treat CI green as this step having been done—for isomorphic failures see KB ci-green-doesnt-mean-your-new-test-ran-check-collected-count。

Step 4: Generate the title

Format:Release:<主軸1>、<主軸2>、…

  • Extract 3-5 main themes from Features + major Improvements, connected with enumeration commas.
  • If the user prefers a version number / date, you may switch to Release YYYY-MM-DD:…(when unsure, ask once with AskUserQuestion, then follow the preference thereafter).

Step 4.5: Gate before writing back (mandatory)

Before the title + body from Steps 3 and 4 enter Step 5, dispatch a fresh-context Agent(subagent_type: general-purpose, requiring Bash to run gh/git) to rerun the four checks of Step 2.5—not a new rule, but having someone who has not seen the draft's creation process re-verify it (core discipline #2 "verification does not self-verify"; Step 2.5 only dispatches an agent when >20 commits, and is a pre-output self-check).

This step is the caller implementation of the evidence-gate skill (Section 6 of that skill, the Caller invocation contract, already lists this step as the corresponding implementation); you may directly Skill({ skill: "evidence-gate" }) Use its Claim Schema (Section 1) and Fact-Checker dispatch template (Section 4); there is no need to redefine the format.

Input: full draft title/body text, PR number, repo.

Output: one row per claim CLAIM | 驗證指令 | 實際結果 | 通過?. Always look up base/head/state fresh gh pr view <PR> --repo <repo> --json baseRefName,headRefName,state; do not reuse values inferred from memory or earlier conversation.

Blocking gate: if any row has "Pass?=No", or the evidence-gate reports any SCHEMA-DEFECT, stop, report the rows that did not pass,and do not automatically write back to the PR; after fixing, rerun this gate, and only proceed to Step 5 if all pass.

Step 5: Write back and verify (write-then-verify)

gh pr edit <PR> --repo <repo> --title "<title>" --body-file /tmp/release-body.md
gh pr view <PR> --repo <repo> --json title,body --jq '.title, .body'

Be sure to gh pr view compare the title and body to confirm they actually took effect (tool success ≠ already in effect).

Rule alignment

  • Title + body must always be inTraditional Chinese; keep Conventional Commit prefixes and technical keywords in English.
  • Use full-name format for external / cross-team refs; for same-repo PR numbers use #NNNN。
  • Do not fabricate changes not within the commit scope; when classification is doubtful, judge based on commit semantics, and ask the user if necessary.