Help us improve
Share bugs, ideas, or general feedback.
From brain-os
Runs the 4-step pull request close sequence: reviewer comment, squash-merge, delete branch, close linked issues. Prevents half-done PR landings with dangling branches or open issues.
npx claudepluginhub sonthanh/brain-os-pluginHow this skill is triggered — by the user, by Claude, or both
Slash command
/brain-os:pr-closeThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
Closing a PR is four distinct chores, and the order matters. This skill runs them as one reliable sequence so nothing gets half-done — a merged PR with a dangling branch, or a shipped fix whose issue stays open, is exactly the drift this prevents.
Merges open PRs in dependency order after CI/approval checks, closes linked issues from PRs or .claude-harness/features/active.json, deletes feature branches locally/remotely, prunes refs, and reports summary. Use for completing features, post-review merges, or release cycles.
Merges a reviewed PR via squash or rebase, then cleans up branches and worktrees. Handles integration branches and multi-phase merge plans.
Monitors CI checks and merges a pull request once approved and all checks pass. Supports waiting for CI, immediate merge with --no-wait, and post-merge branch cleanup.
Share bugs, ideas, or general feedback.
Closing a PR is four distinct chores, and the order matters. This skill runs them as one reliable sequence so nothing gets half-done — a merged PR with a dangling branch, or a shipped fix whose issue stays open, is exactly the drift this prevents.
The PR's commits land in the code repo (brain-os-plugin, ai-leaders-vietnam, whatever gh repo view reports). Linked issues usually live in a separate tracker repo — gh_task_repo in ${CLAUDE_PLUGIN_ROOT}/brain-os.config.md (default sonthanh/ai-brain). That split is load-bearing for step 4: a bare Closes #N resolves against the code repo and silently does nothing.
The order is not cosmetic:
Run the prep script — it fetches PR metadata and builds the two strings that are easy to get wrong (the verbatim squash subject and the cross-repo close block), emitting them as JSON so the load-bearing logic is centralized + unit-tested, not improvised:
bun "${CLAUDE_PLUGIN_ROOT}/skills/pr-close/scripts/pr-close.ts" prepare \
--pr <N> --tracker <gh_task_repo>
# → { number, title, subject, headRef, linkedIssues:[{repo,num}], closesBlock, ... }
Then read the human-judgment inputs for the review comment:
gh pr diff <N> # what changed
gh pr checks <N> # what CI verified (feeds "what was tested")
If linkedIssues is empty (the PR body declared no Closes / Fixes / Resolves), ask the user which tracker issue this lands — don't guess.
Merging is a destructive action on a remote — hard to undo. Show the user the plan and get a quick go-ahead, unless they already said "just merge it":
About to land PR #<N> "<title>":
1. Comment: <2-3 line reviewer summary>
2. Squash-merge → subject "<PR title>", body closes <tracker>#<M>
3. Delete branch <headRefName>
4. Close <tracker>#<M> (+ strip status:* labels)
Proceed?
Post a short review on the still-open PR: what changed (from the diff / commits) and what was tested (from gh pr checks + any testing notes in the PR). This is the durable record of why the merge was safe.
gh pr comment <N> --body "<what changed> · Tested: <what was verified>"
One command does the squash (step 2) and the branch delete (step 3) in the correct order. Use the subject and closesBlock from the prep script — they carry the verbatim title and the cross-repo close reference, so a bare Closes #N (which would no-op against the code repo) can't sneak in:
gh pr merge <N> --squash --delete-branch \
--subject "<subject from prepare>" \
--body "<1-line summary>
<closesBlock from prepare>"
Pass --subject so the PR title verbatim becomes the squash subject — without it, gh appends (#N). --delete-branch removes the remote branch only after the merge lands.
Cross-repo Closes <repo>#N does not always auto-fire, so closing is not optional cleanup — it is a required step. Use the central close helper; never inline gh issue close (the helper also strips ghost status:* labels that a bare close leaves behind, and is idempotent if the merge already auto-closed the issue):
bash "${CLAUDE_PLUGIN_ROOT}/scripts/gh-tasks/close-issue.sh" <M>
Run it once per linked issue (use each num from linkedIssues). Note: close-issue.sh is hardwired to the default tracker sonthanh/ai-brain; if your gh_task_repo differs, close with gh issue close <M> --repo <gh_task_repo> --reason completed and strip any status:* labels yourself.
Confirm each step actually took — a silent half-merge is the failure mode this skill exists to kill:
gh pr view <N> --json state,mergedAt # state == MERGED
git ls-remote --heads origin <headRefName> # empty output == branch gone
gh issue view <M> --repo <gh_task_repo> --json state # state == CLOSED
If any check fails, say so explicitly and stop — do not log pass.
If the user is rejecting / abandoning rather than landing: post a comment with the reason, run gh pr close <N> --delete-branch, and leave linked issues open — the work isn't done, so do NOT run close-issue.sh.
Closes <gh_task_repo>#N, with the explicit repo prefix — a bare Closes #N targets the code repo and no-ops.close-issue.sh is the only close site. It strips status:* labels and is idempotent on already-closed issues. Inlining gh issue close re-leaks the ghost labels it was built to fix.--subject so it doesn't drift.Append one line to {vault}/daily/skill-outcomes/pr-close.log (per skill-spec.md § 11):
{date} | pr-close | merge | {code_repo} | PR#{N} | commit:{squash-hash} | {result} | issue={M} args="{pr-title}"
result: pass (all four steps verified), partial (merged but a follow-up step — branch delete or issue close — needed a manual retry), fail (merge blocked or PR rejected).close instead of merge, and issue=none.