agentsclimarketplace

Ready to merge

Skill flurdy/agent-skills/skills/ready-to-merge

Pre-merge gate — verify a PR is green, approved, in sync, and free of obvious risk, then (on explicit approval) squash-merge it. Composes /pr-status, /contract-check, and /review-pr rather than reimplementing them.From its SKILL.md

Install
npx -y skills add flurdy/agent-skills --skill ready-to-merge

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

One thing to look at

  • 7 stars7 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.

SKILL.md

15.2 KB, ~3.8k tokens by cl100k_base, as published. Nobody here has run it

Ready to Merge — Pre-Merge Gate

Verify a PR is safe to merge, present a terse readout, and — only after explicit user approval — squash-merge it.

This skill is a synthesis layer: it calls into /pr-status's scripts, optionally /contract-check, and reuses /review-pr's view/diff scripts. It does NOT reimplement those skills.

Relationship to other skills

  • /pr-status — passive multi-PR dashboard. This skill is single-PR, decision-oriented, and ends with an action.
  • /review-pr — deep AC-vs-diff review. Linked but not auto-invoked. Suggest it if the diff is large or AC fit is unclear.
  • /contract-check — read-only contract health audit. Auto-invoked only when pacts are present in the repo, and scoped to status (summary only).
  • /contract-test — contract test runner (generate → sync → verify). Never auto-invoked here — CI already ran the tests on push. Surfaced as a remediation pointer when /contract-check flags stale or uncommitted pacts.
  • tracking-auditor (agent) — branch-vs-ticket scope check. Suggest it if the diff looks broader than the ticket.

Usage

/ready-to-merge              # PR for current branch
/ready-to-merge 5753         # explicit PR number
/ready-to-merge --no-merge   # report only, never offer to merge

Procedure

Phase 1 — Resolve PR

# If no number given:
~/.agents/skills/review-pr/scripts/gh-pr-current-number.sh
# Fallback: gh pr view --json number --jq '.number'

Resolve owner/repo from git remote get-url origin.

Phase 2 — Gather (run in parallel where possible)

Run these in parallel — they're independent fetches:

  1. PR details (state, mergeState, reviewDecision, checksState, approvers, threads, isDraft, base, head):
    ~/.agents/skills/pr-status/scripts/gh-pr-details.sh {owner} {repo} {pr}
    
  2. PR view (title, body, additions, deletions, changedFiles, files):
    ~/.agents/skills/review-pr/scripts/gh-pr-view.sh {pr}
    
  3. Diff:
    ~/.agents/skills/review-pr/scripts/gh-pr-diff.sh {pr}
    
  4. Stacked children — PRs that target THIS PR's head branch:
    gh pr list --base {head-branch} --state open --json number,title,headRefName,url
    
  5. Local working copy — if the resolved PR matches the current branch, also:
    git status --porcelain
    ~/.agents/skills/ready-to-merge/scripts/git-unpushed.sh   # unpushed commits
    
    Uncommitted/unpushed work is a hard blocker. Use the wrapper for the unpushed-commits check — never inline git log @{u}..HEAD. The sandbox flags the bare @{u}..HEAD as brace expansion, so it can never be auto-approved.

Phase 3 — Ticket cross-reference

Extract the Jira key from branch name first, then PR title (/[A-Z]+-\d+/).

If found:

mcp__jira__jira_get
  path: /rest/api/3/issue/{key}
  jq: "{key: key, summary: fields.summary, status: fields.status.name, issuetype: fields.issuetype.name}"

Flag if Jira status is not one of: Code Review, In Progress, Test/Review, Ready for Test. Specifically:

  • Done → ⚠️ already closed before merge — unusual, confirm with user.
  • Backlog / Ready to Work → ⚠️ ticket never moved to In Progress — flow drift.
  • Blocked → ❌ confirm before merging.

Beads: if bd is available, look for a bead referencing this Jira key:

bd list --status=in_progress
bd list --status=open

Match by Jira key in title or description. Note id + status. If a bead is in_progress for this work it will need closing after merge.

Trello: only if ./scripts/trello-api exists in the repo. Look for a card matching the branch or ticket — best effort, skip silently if none found.

Phase 4 — Diff risk scan

Walk the changed files list (don't re-read the whole diff). Flag only what's present — quiet success, loud risk:

RiskDetection (heuristic)
Migration / schema changepath matches migrations/, migrate/, *.sql, schema.prisma, alembic/
Dependency changepackage.json, package-lock.json, pnpm-lock.yaml, yarn.lock, requirements.txt, Cargo.lock, go.mod, Gemfile.lock, build.sbt
Secrets / sensitive.env*, *.pem, *.key, files matching credential / secret
CI / infra changes.github/workflows/*, Dockerfile*, terraform/, helm/
Public-API deletegrep diff for removed export , pub fn, public def
Feature flag absentnew behaviour added but no flag toggle — flag only if PR description claims to be gated
Leftover debugconsole.log, dbg!, println!, pp , binding.pry, debugger added in diff
Lingering TODOsnew TODO/FIXME/XXX lines added
Test/code rationon-trivial code change (≥50 LOC added in non-test files) with zero new/modified test files → flag low coverage

Skip rows that have nothing to report — only show risks that fired.

Phase 5 — Gate evaluation

Compute three buckets:

  • Blockers (❌) — anything in this list and the PR cannot merge:
    • isDraft: true
    • reviewDecision != APPROVED
    • CI checks not SUCCESS
    • unresolved threads > 0
    • mergeState is DIRTY (conflict), BLOCKED, or BEHIND
    • base is not main/master (PR is stacked — should be merged via parent, not directly)
    • uncommitted or unpushed local changes (if PR matches current branch)
    • Jira status Blocked
  • Warnings (⚠️) — proceed-with-caution, don't auto-block:
    • any risk fired in Phase 4
    • mergeState: UNKNOWN — GitHub hasn't computed mergeability yet; usually transient. Suggest a retry before merging.
    • stacked children exist (they'll need rebasing post-merge)
    • Jira status drift (Backlog, Done, missing)
    • bead still in_progress (will need closing post-merge)
    • large diff (≥500 LOC or ≥20 files changed) — recommend /review-pr for depth
  • Notes (ℹ️) — informational only:
    • post-merge follow-ups (close bead, transition Jira, rebase children)

Phase 6 — Optional contract check

Only if pacts are present in the repo (./scripts/contract-check exists, or **/pacts/ directory present, or *Consumer*.scala/*.consumer.test.* files exist):

Skill /contract-check status

Add a row to the gate table for Contracts. If WARN or FAIL, move to Warnings (don't auto-block — contract drift rarely blocks a single PR merge but should be visible).

Do NOT auto-run /contract-test — it's the runner (generate → sync → verify) and is redundant with CI, which already ran on push. If /contract-check surfaces stale, uncommitted, or sync-gap pacts, recommend /contract-test (or /contract-test sync / full) as the remediation under Risks, and let the user run it before re-invoking /ready-to-merge.

Phase 7 — Draft squash commit

The user squash-merges by default. Pre-draft the squash commit so they can approve or tweak:

  • Subject: the PR title, verbatim (already conventional-commit style at PR creation time).
  • Body: 2–5 bullets summarising the change, derived from the PR description and diff. Strip boilerplate (template sections that weren't filled in). Always include a trailing Jira: {KEY} line if a ticket is linked.

Keep the body under ~10 lines. The user can edit if they want more.

Phase 8 — Render the readout

Render compactly. Skip empty sections.

## PR #{number} — Ready-to-Merge Check

**{title}**
[#{number}]({url}) · `{head}` → `{base}` · +{additions} / -{deletions} across {changedFiles} files

| Gate         | Status                              |
|--------------|-------------------------------------|
| CI           | ✅ / ❌ / ⏳                         |
| Approvals    | ✅✅ alice, bob (or 🔔 awaiting)      |
| Threads      | ✅ 0 / 💬 N unresolved               |
| Sync w/ base | ✅ clean / ❌ behind / 💥 conflict   |
| Mergeable    | ✅ / ❌ {reason}                     |
| Contracts    | ✅ / ⚠️ / —                          |
| Tests        | ✅ N test files touched / ⚠️ none    |

**Linked work**
- Jira: [{KEY}]({url}) — {summary} _(status: {status})_
- Bead: `{bead-id}` — {status}
- Trello: {card-name} (or `—`)

**Stacked children** _(omit section if none)_
- ⚠️ #{n} {title} — will need `/rebase-merged-parent` after this merges.

**Diff summary**
- 3–5 bullets, each one short, derived from the diff. No file lists.

**Risks** _(omit section if empty — do not pad with "no secrets" etc.)_
- ⚠️ Migration added `db/migrate/20260511_xxx.sql` — verify backwards compatible.
- ⚠️ 87 LOC added without new tests in `src/foo.ts`.

**Drafted squash commit**

{subject}

  • bullet 1
  • bullet 2

Jira: {KEY}


### Verdict

❌ Blocked — {reason}  
or  
⚠️ Mergeable with warnings — review risks above.  
or  
🚀 Ready to squash-merge.

Phase 9 — Ask for go/no-go

If verdict is ❌ blocked, stop here. Print the blockers and suggest next steps (often /rebase-main, /review-comments, /clean-code).

If --no-merge was passed, stop here regardless.

Otherwise ask the user via AskUserQuestion:

Question: Squash-merge PR #{n} now?
Options:

  • Yes — merge with drafted commit (recommended when verdict is 🚀)
  • Edit commit message first — user supplies new subject/body, then re-prompt
  • Wait — print no further action, end the skill

Phase 10 — Merge

Only on explicit "Yes". Use the GitHub CLI's squash mode with the drafted (or edited) commit.

Do NOT pass --delete-branch. It makes gh run local git operations (switch to the default branch, pull, delete the local branch) as a side effect of the merge. In a worktree checkout — where main/master is checked out in a different worktree — that local step fails with fatal: '{branch}' is already used by worktree at ... even though the remote merge succeeded. The merge is done; only the local cleanup errored, which reads as a scary failure for a no-op. Branch deletion is handled separately below, against the remote only.

gh pr merge {number} --squash \
  --subject "{subject}" \
  --body "$(cat <<'EOF'
{body}
EOF
)"

Idempotency: if the command prints Pull request ... was already merged (e.g. a prior attempt merged remotely before erroring on local cleanup), treat that as success — do not retry or alarm. Confirm with gh pr view {number} --json state --jq .state (expect MERGED) if unsure.

After the merge succeeds, delete the remote branch separately — this is a pure remote ref delete with no local git involvement, so it's worktree-safe. But check it still exists first — many repos auto-delete the head branch on merge, and skipping the DELETE avoids both a wasted call and a permission prompt:

gh api "repos/{owner}/{repo}/branches/{head-branch}" --jq '.name'
# 404 → auto-deleted on merge; report "Remote branch auto-deleted." and skip the DELETE
gh api -X DELETE "repos/{owner}/{repo}/git/refs/heads/{head-branch}"

The DELETE is best-effort: it may be denied by branch permissions/SSO. On any error, don't retry — just note that the remote branch wasn't deleted and add it to the follow-ups. A local permission denial (the harness/user declining the Bash call) is the user saying no — treat exactly like any other failure: never re-run the same command, note it, move on. Never delete the local branch or switch worktrees yourself.

After merge succeeds, print:

✅ Merged #{number}.{branch-note}

where {branch-note} is Remote branch deleted. on success, Remote branch auto-deleted. when the pre-check 404'd, or (remote branch not deleted — {reason}; delete manually if wanted.) otherwise.

Then list post-merge follow-ups as a checklist (do NOT execute them):

  • Transition Jira {KEY} → Test/Review (or Done)
  • bd close {bead-id} if a bead is still in_progress
  • /rebase-merged-parent on stacked child PR(s): #{n1}, #{n2}
  • Pull the default branch locally and remove the merged worktree/branch (only if the remote-branch delete above was denied or skipped)

Don't auto-perform these — they're explicit user follow-ups, often touching other branches/repos. In particular, do not switch the local checkout to the default branch or run git worktree/git branch -d yourself.

Operating rules

  • Never merge without explicit go-ahead. AskUserQuestion answer must be "Yes" — anything else (silence, "Wait", a clarifying comment) means do not merge.
  • Never --admin merge. Branch protections exist for a reason. If a check is failing, surface it, don't bypass it.
  • Never --no-verify. Same reason.
  • Don't auto-run /review-pr or tracking-auditor. They're expensive. Recommend them when their value is high (large diff, scope concerns).
  • Quiet success. Only render risks that fired; only render sections with content. Padding the readout with "✅ no issues" lines defeats the terseness.
  • Reuse, don't reimplement. Call into pr-status / review-pr scripts directly. Don't re-fetch CI status with bespoke gh calls.
  • Honour --no-merge. When passed, the skill is a report only — never prompt to merge.

Failure modes

  • No PR for branch: tell the user to /create-pr first.
  • No Jira MCP: skip Jira cross-reference. Render _Jira MCP not configured._ and continue.
  • No bd: skip beads cross-reference. Continue.
  • Contract-check script missing: skip silently (project has no contracts).
  • GraphQL/gh failure on a single fetch: render that gate as ? rather than aborting. Surface the failed fetch under Risks so the user knows the check was incomplete.
  • gh pr merge errors with fatal: '{branch}' is already used by worktree: this is the --delete-branch local-cleanup failure (Phase 10) — the remote merge already succeeded. Don't pass --delete-branch; verify with gh pr view {number} --json state (expect MERGED) and delete the remote branch via the API call in Phase 10. Never resolve it by switching worktrees or deleting local branches.
  • gh pr merge prints was already merged: success, not an error — a prior attempt merged remotely before its local step failed. Proceed to remote-branch cleanup and follow-ups.

What ships with it: 1 file

204 B alongside SKILL.md, 1 of them executable

scripts/

Keep looking

Skills are one crate of 325,949. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.