pr
Skill1 starsChanged 21 days agoMITView on GitHub
Create, promote, or clean up the GitHub PR for the current branch; keep the description brutally short, preserve durable acceptance evidence in comments, and handle review threads. On an explicit `merge`, merge it once CI is green and reviewers are settled.
- Commits and pushes
The file
We split this skill into the rules it gives an agent
9 rules. About 0 are common, 4 are distinctive, and 5 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈4
Distinctive · estimate
This author's own choices. Worth a look.
5
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Very specific: line 10
Create/update the GitHub PR for the current branch.
- Distinctive: line 16
Never operate on main. Confirm branch and PR state.
- Distinctive: line 29
no redundant file/function inventory.
- Distinctive: line 34
no AI self-credit/co-author lines.
- Distinctive: line 46
When it resolves false, skip straight to "Only then read the thread list" below — there is no bot request to make or confirm.
- Very specific: line 90
wait for CI on the current head with the shared poller (${CLAUDE_PLUGIN_ROOT}/scripts/ci_poll.sh poll <pr> --repo <the PR's base …
- Very specific: line 91
when ship.request_ci_reviewer resolves true and the automated reviewer has not reviewed the current head, request it per §3 and wait in the …
- Very specific: line 114
Only squash composes a subject/body.
- Very specific: line 120
Every subagent dispatch resolves its model and effort from config and passes them as the Agent invocation's actual model and effort …
≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
Create/update the GitHub PR for the current branch. $ARGUMENTS may provide emphasis, draft, or merge (§4).
This skill inherits caller model/effort. Assess scope before reading: a handful of short comments can be read directly; long review/thread tails go to sy:sweep and return briefs.
1. Detect state
Never operate on main. Confirm branch and PR state.
- No PR ⇒ create with
gh pr create --base <branch>, the base the caller names, else the repo default; never infer a base from a branch name. Push first if needed. - Draft exists ⇒ promote/refresh when caller requests readiness.
- Open non-draft exists ⇒ cleanup/update. If called directly by a human, ask via
AskUserQuestionbefore rewriting mutable metadata (${CLAUDE_PLUGIN_ROOT}/skills/shared/references/user-interaction.md); when/sy:shipexplicitly invokes promotion/refresh, that invocation is authorization for that operation.
2. Description contract
Base on real diff/log. The mutable description is the PR's human-attention section — the judgment a reviewer has to make — so mechanical detail belongs in the dedicated PR comment /sy:ship posts separately rather than here. Keep the body concise:
- a link to the tracker ticket: its issue key or URL, so the PR and the durable record each reach the other;
- why and why this approach;
- 2–4 single-line summary bullets;
- no redundant file/function inventory;
- caveats only when reviewers cannot infer them from the diff;
- manual-only test plan; omit if none;
- optional small table only when genuinely clearer;
- image placeholder only when needed;
- no AI self-credit/co-author lines.
Acceptance criteria/evidence never live only in the mutable description. /sy:ship posts them as a dedicated PR comment so promotion/refresh cannot erase them.
What belongs in which of those two, and how hard to cut each, is ${CLAUDE_PLUGIN_ROOT}/skills/shared/references/context-economy.md; /sy:tighten is the pass that applies it, and the description goes through it — destination a PR description — before it is written.
Title: <TICKET> - <imperative summary> when branch carries a ticket key.
3. Review threads
Resolve ship.request_ci_reviewer — get_config {"key": "ship.request_ci_reviewer"} (see ${CLAUDE_PLUGIN_ROOT}/skills/shared/references/config-values.md) — before requesting a review. This gates only the automated-reviewer request below; it is additive to, never a substitute for, sy:gate's own independent review, which always runs regardless of this setting.
When it resolves false, skip straight to "Only then read the thread list" below — there is no bot request to make or confirm.
When it resolves true: an automated reviewer (Copilot and similar) reviews only when requested, draft or ready, and each head needs its own request. gh pr ready <pr> is promotion only and requests nothing. Walk this ladder only on a review request (a caller asking for one, §4 step 2, or a human's direct create/promote); a thread-fetch, reply, or /sy:ship promote call requests nothing and goes straight to "Only then read the thread list". Stop at the first rung that lands:
- By login —
gh pr edit <pr> --add-reviewer "@copilot"(gh ≥2.87.0), or the repo's configured automated reviewer login. gh special-cases@copilotonto GitHub's bot path, so this is not the same call as a raw REST review request and usually succeeds where one does not. By node id over GraphQL — a raw REST
POST .../requested_reviewersnaming the bot's login fails422 Reviews may only be requested from collaborators, because a review bot is not a repository collaborator; rung 1 fails the same way on a gh old enough to lack the special case. The bot is also absent fromsuggestedActors, so read its node id off any review it has already left in this repo, then request by id:gh api graphql -f query='{repository(owner:"<o>",name:"<r>"){pullRequest(number:<n>){reviews(first:20){nodes{author{__typename login ... on Bot{id}}}}}}}' # <n> is a PR the bot has previously reviewed, not necessarily this one gh api graphql -f query='{repository(owner:"<o>",name:"<r>"){pullRequest(number:<this pr>){id}}}' # this PR's own node id, separate from <n> above gh api graphql -f query='mutation($pr:ID!,$bot:ID!){requestReviews(input:{pullRequestId:$pr,botIds:[$bot],union:true}){clientMutationId}}' \ -f pr=<this PR's node id> -f bot=<bot node id>union:trueadds the bot without clearing reviewers already requested.- Surface it loudly — when no rung lands, including a repo with no prior bot review to read an id from, report the failure and hand off to the repo's manual "request review" control. Never skip it silently.
Then confirm the request actually landed, over GraphQL and not REST — gh pr view <pr> --json reviewRequests renders [] for a bot reviewer that is requested, so it is a false negative rather than a confirmation:
gh api graphql -f query='{repository(owner:"<o>",name:"<r>"){pullRequest(number:<n>){reviewRequests(first:10){nodes{requestedReviewer{__typename ... on Bot{login}}}}}}}'Only then read the thread list. An empty one is never evidence of "reviewed, nothing to say": it is indistinguishable from a review nobody requested, and only a confirmed request reaching a terminal state tells the two apart. A bot review whose body says it could not review (quota reached, or similar) is a failed request, never clearance.
Reconcile the reviewer's threads by author bot-type, not a hardcoded login. The same reviewer's bot login is not stable across the GitHub REST and GraphQL surfaces (e.g. a -bot suffix or [bot] bracket form differs between them), so a query filtered to one literal login silently returns zero threads on the other surface and reports a false "0 new comments". Enumerate all review comments/threads and select by author type being a bot — for example gh api repos/<o>/<r>/pulls/<pr>/comments --jq '[.[] | select(.user.type=="Bot")]' (or the GraphQL reviewThreads with author { __typename } matched against Bot) — so every bot thread is caught regardless of which login form that surface reports. Reconcile against comment/thread ids, not login strings.
Every relevant review thread gets an answer; push back on bad trade-offs instead of rubber-stamping. When a thread surfaces a small, adjacent, low-risk fix, fold it into this branch rather than deferring to a follow-up that loses the context — the follow-up must justify itself (see ${CLAUDE_PLUGIN_ROOT}/skills/shared/references/scope-discipline.md). A reply is a posted record: one later found wrong is corrected on the thread, not left standing (${CLAUDE_PLUGIN_ROOT}/skills/shared/references/write-integrity.md, retroactive honesty).
- small thread set ⇒ read directly;
- long auto-reviewer/multi-round tail ⇒
sy:sweepbrief with open suggestion, targetfile:line, and addressed/unaddressed state.
Caller reads decisive threads and writes replies. Stage each reply body as a file, then post it by reading the file — never by handing @path to a literal-string flag:
- inline thread reply ⇒
gh api --method POST repos/<o>/<r>/pulls/<pr>/comments/<id>/replies -F body=@<file>(or--input <file>); - top-level PR comment ⇒
gh pr comment <pr> --body-file <file>; - edit an existing comment ⇒
gh api --method PATCH repos/<o>/<r>/pulls/comments/<id> -F body=@<file>.
gh api -F/--raw-field key=@file reads the file; -f/--field key=@file posts the literal @file — a silent-corruption trap. After posting, read the stored body back (gh api .../comments/<id> --jq .body) and confirm it is the intended prose, not a value starting with @.
4. Merge (verified-head only)
Merging is never part of the create/promote/cleanup flow. Two callers reach it: /sy:ship's explicit-authorization path (ship/references/merge-accounting.md), and merge in $ARGUMENTS for a PR that never went through /sy:ship. That argument is the user's authorization for this one PR, so it counts only when the user typed it or asked for the merge in their own words; never infer it from a request to create or tidy a PR. For it, merge once CI is green and reviewers are settled:
- wait for CI on the current head with the shared poller (
${CLAUDE_PLUGIN_ROOT}/scripts/ci_poll.sh poll <pr> --repo <the PR's base repository> --head <head SHA>, run in the background, adding--allow-no-checksonly for a repository already known to have no CI, never inferred from an empty check set); a failure stops and reports; - when
ship.request_ci_reviewerresolves true and the automated reviewer has not reviewed the current head, request it per §3 and wait in the background for its review of that head, bounded byci.poll_timeout; - reconcile every thread per §3. A thread asking for a code change stops the merge and reports it: this mode pushes nothing. So does a requested review still pending at
ci.poll_timeout, or any reviewer whose latest review isCHANGES_REQUESTED, inline threads or not;--adminnever bypasses either; - re-read the head and its checks. If the head moved since step 1, start again from step 1; a check on the same head that is now pending is waited for with the poller, and one that failed stops the merge; otherwise merge that SHA below;
- retarget dependents, immediately before the merge call and after every step above, so no earlier stop leaves them retargeted: list
gh pr list --base <this PR's head branch> --state open --json numberand retarget each withgh pr edit <n> --base <this PR's base>, since deleting the merged branch auto-closes a PR still based on it. If the merge call then fails for any reason, restore each retargeted PR's base. This step is the single owner of that duty; every other merge site cites it.
This mode runs no sy:gate: the merge rests on CI and on the reviewers the PR already has.
Resolve the configured strategy once — get_config {"key": "ship.merge_strategy"} (one of squash, merge, rebase; see ${CLAUDE_PLUGIN_ROOT}/skills/shared/references/config-values.md) — and gate every merge on the exact validated commit regardless of strategy:
# squash: compose the message from the PR's own description (§2) rather than accepting GitHub's
# default, which concatenates every branch commit subject into the body
gh pr merge <pr> --squash \
--subject "<TICKET> - <imperative summary>" \
--body-file <staged summary file> \
--match-head-commit <CI-green + reviewed SHA>
# merge/rebase: no subject/body to compose
gh pr merge <pr> --merge --match-head-commit <CI-green + reviewed SHA>
gh pr merge <pr> --rebase --match-head-commit <CI-green + reviewed SHA>--match-head-commitaborts the merge if the head moved since validation, so only the reviewed/CI-green commit can land, never a race-pushed one — true for every strategy. Composing a message never relaxes that guard — drop the subject and body before you drop the head match.- Only
squashcomposes a subject/body; stage it from the description's why plus its summary bullets, so the squashed commit reads as the changelog entry for the change rather than as build noise.mergeandrebasepass neither flag. gh pr merge -F/--body-filetakes a plain file path, a different convention from the-F key=@fileform used for comment bodies in §3 above; conflating the two silently posts the wrong thing.- add
--adminwhenship.merge_adminresolves true (get_config {"key": "ship.merge_admin"}), the repo's standing choice; otherwise only when the owner's go-ahead names the admin bypass itself, since a plainmergeauthorizes the merge, not the bypass. It clears a ruleset the author cannot satisfy alone (e.g. a required approval the author can't self-give) and bypasses the ruleset, not CI/review freshness.
This skill never runs tests or review; /sy:ci and sy:gate own those gates. End by printing the PR URL and what state change/comment action occurred.
Every subagent dispatch resolves its model and effort from config and passes them as the Agent invocation's actual model and effort parameters, per ${CLAUDE_PLUGIN_ROOT}/skills/shared/references/model-dispatch.md; a nested dispatch inherits nothing and must resolve again.
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

