skills/merge-pr/SKILL.md
Use when merging a PR after implementation is complete - verifies CI, runs local tests, checks repo safety, and monitors post-merge health. Triggers on 'merge pr', 'merge this', 'land this PR', or any task executing a PR merge.
npx skillsauth add raddue/crucible merge-prInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Safely merge a PR with full CI verification, local test validation, and post-merge health monitoring.
Core principle: Verify CI -> Check working tree -> Repo safety scan -> Local tests -> Merge -> Post-merge CI -> Cleanup.
Announce at start: "I'm using the merge-pr skill to safely land this PR."
Verify all CI checks pass before anything else:
gh pr checks <pr-number>
If any checks are failing:
CI checks failing. Cannot merge.
FAILED:
- <check-name>: <url>
- <check-name>: <url>
Fix these before attempting merge.
Stop. Don't proceed to Step 2.
If checks are pending: Wait. Re-check with gh pr checks <pr-number> after a reasonable interval. Don't proceed until all checks resolve.
If all checks pass: Continue to Step 2.
Verify no uncommitted work is hiding:
git status
If untracked or modified files exist:
Working tree is not clean:
Untracked:
- <file>
- <file>
Modified:
- <file>
Should these be committed before merge? (y/n)
Stop. Wait for user decision. If user says yes, commit them first. If user says no, proceed.
If working tree is clean: Continue to Step 3.
Determine repo visibility:
gh repo view --json isPrivate -q .isPrivate
If the repo is PUBLIC (false):
gh pr view <pr-number> --json body -q .body
gh pr view <pr-number> --json commits --jq '.commits[].messageHeadline'
Look for: proprietary company names, internal tool references, API keys, internal URLs, employee names, infrastructure details.
If anything looks sensitive:
PUBLIC REPO — potential sensitive content detected:
- PR body: <what was found>
- Commits: <what was found>
Confirm this is safe to merge publicly? (y/n)
Stop. Wait for explicit confirmation.
If the repo is private: Note it and continue.
If all clear: Continue to Step 4.
Run the project's test suite locally:
# Detect and run the appropriate test command
npm test / cargo test / pytest / go test ./... / dotnet test
If tests fail:
Local tests failing (<N> failures). Cannot merge.
[Show failures]
Fix these before merge.
Stop. Don't proceed to Step 5.
If tests pass: Continue to Step 5.
Only reach this step after ALL above checkpoints pass.
Ask the user:
All checks passed. Merge method?
1. Merge commit
2. Squash and merge
3. Rebase and merge
Wait for choice. Then execute:
# Option 1
gh pr merge <pr-number> --merge
# Option 2
gh pr merge <pr-number> --squash
# Option 3
gh pr merge <pr-number> --rebase
If merge fails:
If merge succeeds: Continue to Step 6.
Don't walk away after merge. Verify CI on the target branch:
# Get the target branch (don't assume main)
TARGET_BRANCH=$(gh pr view <pr-number> --json baseRefName -q .baseRefName)
gh run list --branch $TARGET_BRANCH --limit 5
If a run is in progress:
gh run watch <run-id>
If post-merge CI fails:
gh run view <run-id> --log-failed
Surface the failure summary to the user immediately:
POST-MERGE CI FAILURE on $TARGET_BRANCH:
Run: <run-id>
Failed step: <step-name>
Error: <summary>
This needs immediate attention. The target branch is broken.
Do NOT proceed to cleanup until the user acknowledges the failure and decides next steps.
If post-merge CI passes: Emit compass update, then continue to Step 7.
<!-- Compass emit — orchestrator only (D14). CANONICAL: shared/compass-protocol.md --># Capture merge commit SHA with 3-retry null guard (DEC-5 / R15-M1)
PR="<pr-number>"
SHA=""
for ATTEMPT in 1 2 3; do
SHA=$(gh pr view "$PR" --json mergeCommit --jq '.mergeCommit.oid')
[ -n "$SHA" ] && [ "$SHA" != "null" ] && break
SLEEP_S=$((ATTEMPT * 2)) # 2s, 4s, 6s
sleep "$SLEEP_S"
done
SUBJ=$(gh pr view "$PR" --json title --jq '.title')
if [ -n "$SHA" ] && [ "$SHA" != "null" ]; then
# compass update --field last_meaningful_commit --value "<sha>:<subject>"
python scripts/compass.py update --field last_meaningful_commit --value "${SHA}:${SUBJ}" \
2>&1 || echo '[compass] emit failed; continuing' >&2
else
# gh cache lag after 3 retries — write pending-merge marker
# compass update --field last_meaningful_commit --value "<pending-merge:#NNN>"
python scripts/compass.py update --field last_meaningful_commit --value "<pending-merge:#${PR}>" \
2>&1 || echo '[compass] emit failed; continuing' >&2
fi
<!-- END compass emit -->
Ask before deleting anything:
Merge complete. Clean up branches?
- Delete remote branch origin/<branch-name>? (y/n)
- Delete local branch <branch-name>? (y/n)
Wait for confirmation. Then execute as directed:
# Delete remote branch
git push origin --delete <branch-name>
# Delete local branch
git branch -d <branch-name>
# Switch to target branch
git checkout main && git pull
Report final state:
PR #<number> merged successfully.
Branch <branch-name> cleaned up.
Main branch CI: passing.
If the merged PR's title/type is fix(*) (a conventional-commit bug fix), record a grudge so the bug it fixed can never silently re-ship. Best-effort — a failed record logs to stderr and never fails the merge (which has already completed):
# only for fix(*) PRs
plugin_root="$(realpath "<this-skill-base-dir>/../..")"
python3 "$plugin_root/scripts/grudge_append.py" \
--symptom "<PR title minus the fix() prefix>" \
--root-cause "<from PR body, if stated>" \
--files "<comma-separated files the PR changed>" \
--commit "<squash/merge SHA>" \
--why "<from PR body, if stated>"
Non-fix(*) PRs record nothing. See skills/grudge/SKILL.md.
Merging without checking CI
gh pr checks first. No exceptions.Skipping local tests
Not monitoring post-merge CI
Force-merging past branch protection
--admin flag. Report the protection rule and let the user resolve it properly.Deleting branches without confirmation
Never:
--admin to bypass branch protectionAlways:
Called by:
Relationship to finish:
Pairs with:
Before completing this skill, confirm every mandatory checkpoint was executed:
If any checkbox is unchecked, STOP. Go back and execute the missed gate.
testing
Standalone instance-bug reviewer — runs a parallel finder fan-out + verify gate over a diff or a path and prints ranked, verified findings. Use when the user says "delve", "find bugs in this diff", "review this for bugs", "scan this file/subsystem for defects", "instance-bug sweep", or wants concrete reproducible defects (not a merge verdict, not systemic health). Works on a PR id, a base..head range, or a path, on any forge (GitHub, GitLab, Bitbucket, self-hosted).
testing
Render the Crucible calibration ledger weekly report — the honest "Crucible caught N silent bugs" headline, verdict breakdown, per-skill severity rates, and the inflation detector. Triggers on "/ledger", "weekly report", "weekly ledger", "caught N", "quality ledger", "calibration report", "render the ledger".
development
The Book of Grudges — cross-session bug graveyard. Every fixed bug is recorded as a structured "grudge"; before touching code, skills query the grudgebook for the files in scope and surface past regressions as forced "DO NOT REPEAT" context. Read mode (pre-flight) and write mode (on bug resolution / fix(*) PR). Machine-local, per-repo, never committed. Triggers on /grudge, "check grudges", "record a grudge", "any past bugs here", "regression oracle", "bug graveyard".
testing
Reconcile the Crucible calibration ledger — walk merged fix/hotfix branches to falsify the originating gating-verdicts, compute per-skill Brier calibration scores, and append a falsification log. Triggers on "/calibration-reconcile", "reconcile ledger", "reconcile calibration", "falsify verdicts", "brier score", "calibration reconcile", "compute brier".