From 8127307278160a2a7a744169180d2eea7c3bf731 Mon Sep 17 00:00:00 2001 From: Craig Jennings Date: Sun, 19 Apr 2026 16:41:58 -0500 Subject: feat: add finish-branch skill (clean-room synthesis from obra/superpowers pattern) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Clean-room synthesis of the 'finishing a development branch' pattern from obra/superpowers (MIT) — adopted as the forced-choice workflow scaffold, not the substantive rules. Substantive rules defer to existing ones: - Verification → verification.md - Commit conventions + no AI attribution → commits.md - Review discipline → review-code Core patterns implemented: - Phase 1 verify-before-options (hard-stop on failing tests) - Phase 2 base branch + commit range + worktree detection - Phase 3 forced-choice menu (exactly 4 options, no editorializing, stop+wait) - Phase 4 execution per-option with: - Option 1 (merge locally): re-verify after merge, delete branch, prompt about remote-branch cleanup separately - Option 2 (push + PR): gh pr create with inline template (no AI attribution in the body); do NOT remove worktree - Option 3 (keep): no git state changes; preserve worktree - Option 4 (discard): typed-word "discard" confirmation gate required; lists what will be permanently lost; force-delete + remote cleanup - Phase 5 worktree cleanup matrix (cleanup for 1 and 4; preserve for 2 and 3) Notable over the upstream superpowers skill: - Explicit delegation to verification.md / commits.md / review-code rather than re-teaching those standards inline - Cross-references to /review-code (pre) and /arch-evaluate (if architectural) - Handles remote-branch cleanup question separately from local branch (upstream conflates them) - "Common Mistakes" section names the specific failure modes this skill prevents (open-ended "what now", accidental deletes, merge-then-oops, worktree amnesia, trailing AI attribution in PRs) Rubric coverage vs upstream: M (verify → options → execute → cleanup); M (forced-choice menu pattern); M (typed-discard confirmation gate); M (worktree cleanup matrix); M (hard-stop on failing tests); + (explicit deferral to existing rules vs upstream's inline rules); + (remote-branch cleanup as separate prompt); + (skill integration notes for /review-code and /arch-evaluate); no dropped capabilities. Makefile SKILLS extended; make install symlinks globally at ~/.claude/skills/finish-branch. --- finish-branch/SKILL.md | 249 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 249 insertions(+) create mode 100644 finish-branch/SKILL.md (limited to 'finish-branch') diff --git a/finish-branch/SKILL.md b/finish-branch/SKILL.md new file mode 100644 index 0000000..5cb02ef --- /dev/null +++ b/finish-branch/SKILL.md @@ -0,0 +1,249 @@ +--- +name: finish-branch +description: Complete a feature branch with a forced-choice menu of outcomes (merge locally / push + open PR / keep as-is / discard). Runs verification before offering options (tests, lint, typecheck per the project's conventions — delegates to `verification.md`). Requires typed confirmation for destructive deletion (no accidental work loss). Handles git worktree cleanup correctly: tears down for merge and discard, preserves for keep and push (where the worktree may still be needed for follow-up review or fixes). References existing rules for commit conventions (`commits.md`), review discipline (`review-code`), and verification (`verification.md`) — this skill is the workflow scaffold, not a re-teach of the underlying standards. Use when implementation is complete and you need to wrap up a branch. Do NOT use for mid-development merges (that's normal git flow), for the wrap-up *of a whole session* (different scope — session-end is narrative + handoff, not branch integration), for creating a new branch (no skill for that — just `git checkout -b`), or when review hasn't happened yet (run `/review-code` first, then this). +--- + +# /finish-branch + +Complete a development branch cleanly. Verify, pick one of four outcomes, execute, clean up. + +## When to Use + +- Implementation is done, tests are written, you believe the branch is ready to move forward +- You're about to ask "okay, now what?" — this skill exists to stop you asking and start you choosing +- You need to integrate, preserve, or discard a branch's work deliberately + +## When NOT to Use + +- Mid-development merges — that's regular git flow, not "finishing" a branch +- Full session wrap-up (closing the day's work, recording context for next time) — different scope, not about branch integration +- Creating a new branch — just `git checkout -b ` +- Before review has happened on a significant change — run `/review-code` first; this skill assumes the work has been judged ready + +## Phase 1 — Verify + +Before offering any option, run the project's verification. Delegate to `verification.md` discipline: + +- Tests pass (full suite, not just the last one you wrote) +- Linter clean (no new warnings) +- Type checker clean (no new errors) +- Staged diff matches intent (no accidental additions) + +Commands vary by stack. Use what the project's Makefile, `package.json` scripts, or convention dictates. Examples: + +- JavaScript / TypeScript: `npm test && npm run lint && npx tsc --noEmit` +- Python: `pytest && ruff check . && pyright` +- Go: `go test ./... && go vet ./... && golangci-lint run` +- Elisp: `make test && make validate-parens && make validate-modules` + +**If verification fails:** stop. Report the failures with file:line, do not offer the outcome menu. The branch isn't finished — fix the failures and re-invoke `/finish-branch`. + +**If verification passes:** continue to Phase 2. + +## Phase 2 — Determine Base Branch + +The four outcomes need to know what the branch is being integrated into. Find the base: + +```bash +git merge-base HEAD main 2>/dev/null \ + || git merge-base HEAD master 2>/dev/null \ + || git merge-base HEAD develop 2>/dev/null +``` + +If none resolves, ask: "I couldn't find a merge base against `main`, `master`, or `develop`. What's the base branch for this work?" Don't guess. + +Also collect: +- Current branch name: `git branch --show-current` +- Commit range to integrate: `git log ..HEAD --oneline` +- Unpushed commits on the remote: `git log @{u}..HEAD` if the branch tracks a remote, otherwise all commits are local +- Whether the current directory is in a git worktree: `git worktree list | grep $(git branch --show-current)` + +These details feed the outcome prompt and the execution phases. + +## Phase 3 — Offer the Menu + +Present exactly these four options. Don't editorialize. Don't add a "recommendation." The user picks. + +``` +Branch is ready. It has N commits on top of . + +What would you like to do? + +1. Merge locally into (integrate now, delete the branch) +2. Push and open a Pull Request (remote integration flow) +3. Keep as-is (preserve branch and worktree for later) +4. Discard (delete branch and commits — requires confirmation) + +Pick a number. +``` + +If the branch already has a remote and the user chose 1 (merge locally), note: "The branch is pushed to `origin/`. After merging locally, do you also want to delete the remote branch?" Ask; don't assume. + +**Stop and wait for the answer.** Don't guess, don't infer from context, don't proceed to Phase 4 until the user picks. + +## Phase 4 — Execute the Chosen Outcome + +### Option 1 — Merge Locally + +```bash +git checkout +git pull # ensure base is current +git merge --no-ff # --no-ff preserves the branch point in history +``` + +**Re-verify the merged result.** Run tests / lint / type check on the merged state — the merge may have integrated cleanly at the text level while breaking semantically. + +If verification passes: +```bash +git branch -d # safe delete (refuses unmerged branches, which this one is merged) +``` + +If the branch had a remote: +- If user confirmed removing the remote: `git push origin --delete ` +- Otherwise: leave the remote branch, note that the user should clean it up manually + +Clean up the worktree (Phase 5). + +### Option 2 — Push and Open a Pull Request + +```bash +git push -u origin # -u sets upstream on first push +``` + +Open the PR. Use the project's `gh` CLI (install via `deps` target if missing): + +```bash +gh pr create \ + --base \ + --title "" \ + --body "$(cat <<'EOF' +## Summary + + + +## Test Plan + +- [ ] +EOF +)" +``` + +**Commit message and PR body discipline:** no AI attribution, no "🤖 Generated with" footer, conventional message style — see `commits.md`. If the project has a `.github/pull_request_template.md`, use it instead of the template above. + +**Do NOT clean up the worktree.** The branch is not yet merged; you may need the worktree for reviewer feedback, fixes, or rebase. (Phase 5 table.) + +### Option 3 — Keep As-Is + +No git state changes. Report: + +``` +Keeping branch as-is. +Worktree preserved at (or "same working directory" if not a worktree). +Resume later with `git checkout ` or re-invoke `/finish-branch`. +``` + +**Do NOT clean up the worktree.** The user explicitly wants to come back. + +### Option 4 — Discard + +**Confirmation gate — required.** Write out what will be permanently lost: + +``` +Discarding will permanently delete: + +- Branch: +- Commits that exist only on this branch (N commits): + +- Worktree at (if applicable) +- Remote branch origin/ (if it exists) + +This cannot be undone via `git checkout` — only via the reflog (≤30 days by default). + +To proceed, type exactly: discard +``` + +**Wait for the user to type the literal word `discard`.** Anything else — "yes," "y," "confirm," a number — does not qualify. Re-prompt. + +If confirmed: + +```bash +git checkout +git branch -D # force delete +git push origin --delete 2>/dev/null # delete remote if it exists; ignore error if not +``` + +Clean up the worktree (Phase 5). + +## Phase 5 — Worktree Cleanup + +| Option | Cleanup worktree? | +|---|---| +| 1. Merge locally | **Yes** | +| 2. Push + PR | **No** (may still be needed for review feedback) | +| 3. Keep as-is | **No** (user explicitly wants it) | +| 4. Discard | **Yes** | + +**If cleanup applies:** + +```bash +git worktree list # confirm you're in a worktree +git worktree remove # non-destructive if clean +``` + +If `git worktree remove` refuses (unclean state somehow): surface the reason to the user. Don't force removal without their consent — a dirty worktree may contain work they intended to rescue. + +**If no cleanup:** done. Report final state. + +## Output + +Short final report, not a celebration: + +``` +Branch : + - Outcome: <1 | 2 | 3 | 4> + - + - Next: +``` + +No emojis. No "🎉 all done!" No AI attribution. See `commits.md`. + +## Critical Rules + +**DO:** +- Run verification before offering the outcome menu. No exceptions. +- Present exactly four options, clearly labeled. The forced choice is the point. +- Require the literal word `discard` for Option 4. +- Re-verify after a merge (Option 1) — merges can integrate textually while breaking semantically. +- Clean up worktrees only for Options 1 and 4. + +**DON'T:** +- Offer options with failing verification — the branch isn't finished. +- Editorialize the menu ("you should probably do option 2"). The user picks. +- Accept "y" or "yes" for the discard gate. Literal word `discard`. +- Clean up worktrees after Option 2 or 3 — the user needs them. +- Add AI attribution to commit messages, PR descriptions, or output. + +## Common Mistakes This Prevents + +- **Open-ended "what now?" at the end of work.** Natural but corrosive — the user either has to improvise the workflow or restate their preference each time. The four-option menu ends the improvisation. +- **Accidental destructive deletes.** "Discard this branch?" → "y" → 3 days of work gone. The typed-word gate turns one muscle-memory keystroke into a deliberate action. +- **Merge-then-oops.** Text-level merge completes; semantic integration is broken; the user didn't notice because they didn't re-run the tests on the merged result. Phase 4 Option 1 re-verifies. +- **Worktree amnesia.** Cleaning up a worktree after Option 2 (push + PR) means losing local state just when the reviewer asks for a fix. The cleanup matrix keeps the worktree exactly when it's still needed. +- **"Generated by Claude Code" trailing into a PR.** The no-attribution rule from `commits.md` applies here too — the PR body is committed content under the project's identity, not Claude's. + +## Integration with Other Skills + +**Before this skill:** +- `/review-code` — run a review on the branch before finishing it for significant changes +- `/arch-evaluate` — if the branch touches architecture, audit against `.architecture/brief.md` + +**After this skill:** +- If Option 2 (PR opened): reviewer feedback comes in → address → `/finish-branch` again on updated state +- If Option 1 (merged locally): branch is done; if this closes a ticket / ADR, update tracking +- If Option 3 (kept): resume later; re-invoke when ready +- If Option 4 (discarded): often paired with `/brainstorm` or `/arch-design` to retry the problem differently + +**Companion rules (not skills) this skill defers to rather than re-teaching:** +- Verification discipline → `verification.md` +- Commit message conventions + no AI attribution → `commits.md` +- Review discipline (for anything pre-merge) → `review-code` -- cgit v1.2.3