skills/stage-prs/SKILL.md
Break a large changeset into ordered, reviewable PRs — idempotent, call again to advance the stack after merges
npx skillsauth add mattdurham/bob bob:stage-prsInstall 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.
You orchestrate splitting a large changeset into a series of small, ordered, reviewable pull requests. Each PR targets ≤200 lines changed (excluding tests and docs). PRs may depend on each other and are stacked (each PR's base is the previous PR's branch).
This workflow is idempotent — call it multiple times. On each invocation it checks for an existing plan and PR states first, advancing the stack if the frontier PR has merged, before falling through to plan/create new PRs if needed.
You are a pure orchestrator — you never write code or run git commands yourself beyond scoping queries.
RESUME ──── no plan found ──────────────────→ ANALYZE → PLAN → CONFIRM → EXECUTE → COMPLETE
│
├── plan found, PRs pending/open ────────→ report status, exit
│
└── plan found, frontier PR merged ──────→ ADVANCE → report status, exit
│
└── more PRs to advance → loop ADVANCE
You ONLY:
git and gh read-only commands to scope the changeset and check PR status.bob/state/stage-prs-*.md filesYou NEVER:
git commit, git push, gh pr create, git rebase directlyrun_in_background: trueGoal: Detect an existing plan and check the current state of the PR stack. This phase runs on EVERY invocation before anything else.
Actions:
Check for an existing plan:
ls .bob/state/stage-prs-plan.md 2>/dev/null
If no plan exists → fall through to Phase 1 (ANALYZE). Done with this phase.
If a plan exists, read .bob/state/stage-prs-plan.md and extract:
Check the status of every PR that has a URL by running for each:
gh pr view <url> --json number,title,state,mergedAt,baseRefName,headRefName
States are: OPEN, MERGED, CLOSED.
Build a mental state table:
| # | Title | Branch | State | Merged? | |---|-------|--------|-------|---------| | 1 | ... | ... | MERGED | ✓ | | 2 | ... | ... | OPEN | — | | 3 | ... | ... | not created | — |
Routing:
| Condition | Action | |-----------|--------| | All PRs merged | → Report "Stack complete, all PRs merged." and exit | | All created PRs open, none merged | → Report current status table and exit | | Some PRs not yet created | → Report status + note which haven't been created, exit | | Latest merged PR's successor has not been rebased yet | → Go to ADVANCE phase | | No change since last run | → Report status and exit |
How to detect "needs advance": The PR immediately after the last merged PR should have its branch rebased onto main (or the current merge target). Check:
# Is the next PR's branch already based on current main?
git fetch origin
git merge-base --is-ancestor origin/main origin/<next-branch>
# Exit 0 = main is ancestor (already up to date)
# Exit 1 = needs rebase
Goal: Rebase the next PR's branch onto main after the previous PR merged, producing a clean diff.
Context: GitHub auto-retargets stacked PRs to main when their base PR merges. But the branch itself still contains the previous PR's commits. A rebase removes those commits and makes the diff accurate.
Actions:
Identify the "next" PR — the first PR in the series whose state is OPEN or not created and whose predecessor is MERGED.
Write .bob/state/stage-prs-advance-N.md:
# Advance PR N: <title>
## Situation
PR <N-1> ("<previous title>") has merged into `main`.
PR <N> ("<this title>") branch `<branch>` needs to be rebased onto `main`
so that its diff is clean (no carry-over commits from PR <N-1>).
## Steps
1. Fetch latest main:
```bash
git fetch origin
Rebase this PR's branch onto main:
git rebase origin/main origin/<branch> --onto origin/main
# or if already checked out:
git checkout <branch>
git rebase origin/main
If rebase conflicts:
git rebase --abort) and report back with detailsForce-push the rebased branch:
git push --force-with-lease origin <branch>
Verify the PR base is now main (GitHub should have auto-retargeted):
gh pr view <pr-url> --json baseRefName
If base is still the old branch (not yet auto-retargeted by GitHub):
gh pr edit <pr-url> --base main
Write status back to this file:
STATUS: COMPLETE
Branch rebased: <branch>
PR URL: <url>
New base: main
Or on failure:
STATUS: CONFLICT
Conflicting files: [list]
Rebase aborted. Manual resolution required.
Spawn commit-agent to perform the rebase and force-push:
Task(subagent_type: "commit-agent",
description: "Advance stack: rebase PR N onto main",
run_in_background: true,
prompt: "Read `.bob/state/stage-prs-advance-N.md` for full instructions.
Rebase the branch onto main and force-push. Update PR base if needed.
Write status back to that file.")
After completion, read .bob/state/stage-prs-advance-N.md:
STATUS: COMPLETE → report to user: "✓ PR N (<title>) rebased onto main. PR: <url>"STATUS: CONFLICT → report conflict details to user, exit. Do not attempt further advances.After a successful advance, check if the next PR in the series also needs advancing (i.e., PR N+1's predecessor is now considered "merged + rebased"). If yes, loop back to ADVANCE for PR N+1.
Once no more advances are needed, report the full current status table and exit.
Goal: Understand the full scope of the changeset.
Actions:
Ensure working tree is clean (or warn user):
git status --short
If there are uncommitted changes, warn the user: staged PRs require committed changes. Ask if they want to continue (skipping uncommitted changes) or stop to commit first.
Determine base branch (default: main or master; accept as argument):
git symbolic-ref refs/remotes/origin/HEAD --short 2>/dev/null || echo "origin/main"
Collect the changeset statistics (excluding tests and docs):
# All changed files with line counts
git diff <base>...HEAD --stat
# File list only
git diff <base>...HEAD --name-only
# Line counts per file (additions + deletions), raw
git diff <base>...HEAD --numstat
Identify test and doc files to exclude from the 200-line budget:
*_test.go, **/*_test.go, **/testdata/**, **/fixtures/***.md, *.rst, *.txt, docs/**, *.yaml (config-only), *.json (config-only)Compute net non-test/non-doc line changes per file.
Write .bob/state/stage-prs-analysis.md:
# Changeset Analysis
Base branch: <base>
Current branch: <branch>
Total files changed: N
Total lines changed (all): N
Total lines changed (excl. tests/docs): N
## Files (sorted by logical area)
| File | +lines | -lines | net | test/doc? |
|------|--------|--------|-----|-----------|
...
## Commit history (base..HEAD)
<git log --oneline output>
Move to PLAN phase.
Goal: Group files into ordered, logically coherent PRs under the 200-line limit.
Actions:
Write .bob/state/stage-prs-plan-prompt.md:
# PR Staging Plan Instructions
Read `.bob/state/stage-prs-analysis.md` for the full changeset.
## Your Task
Group the changed files into a series of ordered pull requests where:
1. **Each PR is ≤200 lines changed** (count only non-test, non-doc files).
Test and doc files travel with the code they test/document — they don't count toward the limit.
2. **PRs are logically coherent** — each PR should represent a single, reviewable unit of work
(e.g., "add config struct", "wire up HTTP handler", "add integration test + docs").
3. **PRs are ordered by dependency** — if PR B depends on types or functions introduced in PR A,
PR A must come first. A reviewer should be able to understand each PR in isolation.
4. **Prefer smaller PRs** — if a file group is well under 200 lines, consider if another small
logical unit could be added without exceeding the limit. But don't force unrelated things together.
5. **Foundational changes first** — data types, interfaces, config structs should come before
the code that uses them.
## Output Format
Write your plan to `.bob/state/stage-prs-plan.md` using this format:
```markdown
# Staged PR Plan
Base branch: <base>
Total PRs: N
## PR 1: <short title>
**Branch:** `<suggested-branch-name>`
**Base:** `<base branch or previous PR branch>`
**Summary:** One sentence describing what this PR does and why it comes first.
**Lines changed (excl. tests/docs):** N
### Files
- `path/to/file.go` (+N/-N)
- `path/to/file_test.go` (+N/-N) [test]
- `docs/thing.md` (+N/-N) [doc]
## PR 2: <short title>
...
If you cannot group the changeset under the 200-line limit per PR without creating too many tiny incoherent PRs (more than ~8), note this and suggest a slightly higher limit or an alternative grouping strategy.
Spawn Explore agent to produce the plan:
Task(subagent_type: "Explore",
description: "Plan staged PR groupings",
run_in_background: true,
prompt: "Read `.bob/state/stage-prs-plan-prompt.md` for full instructions.
Read `.bob/state/stage-prs-analysis.md` for the changeset details.
Read the actual file contents for any files where you need to understand
logical relationships (imports, types used, function calls).
Write the PR plan to `.bob/state/stage-prs-plan.md`.")
After completion, read .bob/state/stage-prs-plan.md and move to CONFIRM.
Goal: Present the plan to the user and get explicit approval before touching git.
Actions:
Read .bob/state/stage-prs-plan.md in full.
Present the plan to the user clearly:
Ask the user:
"Does this PR breakdown look right? You can:
- Approve to proceed with creating branches and PRs
- Adjust to change groupings (describe what to move)
- Cancel to stop here (no git changes made)"
WAIT for user response before proceeding.
If Approved: move to EXECUTE.
If Adjust requested: update .bob/state/stage-prs-plan.md to reflect requested changes,
then re-present the updated plan and ask again.
If Cancelled: write .bob/state/stage-prs-status.md with STATUS: CANCELLED and exit.
Goal: Create branches and PRs for each staged PR in order.
For each PR in the plan (in order):
Write .bob/state/stage-prs-execute-N.md (where N is the PR number):
# Execute PR N: <title>
## Branch
- Branch name: <branch>
- Base branch: <base or previous PR branch>
## Files to include
<list of files from plan>
## Instructions
1. From the base branch, create the PR branch:
```bash
git checkout <base>
git checkout -b <branch>
For each file in this PR, cherry-pick the final version from the feature branch:
git checkout <feature-branch> -- <file1> <file2> ...
Stage and commit all files for this PR:
git add <files>
git commit -m "<conventional-commit message summarizing this PR>"
Push the branch:
git push -u origin <branch>
Create PR targeting <base-branch>:
gh pr create --base <base> --title "<title>" --body "..."
PR body should:
Write PR URL and status to .bob/state/stage-prs-execute-N.md:
STATUS: COMPLETE
PR URL: <url>
Branch: <branch>
Spawn commit-agent:
Task(subagent_type: "commit-agent",
description: "Create branch and PR N: <title>",
run_in_background: true,
prompt: "Read `.bob/state/stage-prs-execute-N.md` for full instructions.
Follow the steps exactly. Write status and PR URL back to that file.")
After each PR completes:
.bob/state/stage-prs-execute-N.md for the PR URLIf a PR creation fails:
Goal: Report the full series of PRs to the user.
Write .bob/state/stage-prs-status.md:
# Stage PRs: Complete
STATUS: COMPLETE
Timestamp: <ISO timestamp>
## PR Series
| # | Title | Branch | Base | PR URL |
|---|-------|--------|------|--------|
| 1 | ... | ... | main | https://... |
| 2 | ... | ... | pr-1-branch | https://... |
...
## Merge Order
Merge in order: PR 1 → PR 2 → ... → PR N
Each PR should be merged before the next is reviewed/merged,
so that the base branch is correct when GitHub evaluates the diff.
Present the summary to the user with:
| File | Written By | Purpose |
|------|-----------|---------|
| .bob/state/stage-prs-analysis.md | Orchestrator | Changeset statistics and file list |
| .bob/state/stage-prs-plan-prompt.md | Orchestrator | Instructions for the Explore agent |
| .bob/state/stage-prs-plan.md | Explore agent | The PR grouping plan (persists across invocations) |
| .bob/state/stage-prs-execute-N.md | Orchestrator | Per-PR execution instructions + status |
| .bob/state/stage-prs-advance-N.md | Orchestrator | Per-PR advance (rebase) instructions + status |
| .bob/state/stage-prs-status.md | Orchestrator | Final completion status |
# Split current branch against main
/bob:stage-prs
# Split against a specific base
/bob:stage-prs --base origin/release-1.2
Merge commits / complex histories:
If the feature branch has merge commits (not a linear history), note this in ANALYZE and warn
the user. The cherry-pick approach works best on linear histories; suggest git rebase main
before running this workflow if the history is tangled.
Files that can't be split: If a single file has >200 non-test/doc lines changed, it must go in its own PR. Note this in the plan and flag it as "oversized — consider breaking up the file if review feedback requires it."
Already-stacked branches: If the current branch already stacks on another non-main branch, honor that as the base.
Draft PRs: All PRs in the series should be created as drafts except the first one (or per user preference). This prevents reviewers from starting on PR 2 before PR 1 is merged.
development
Team-based development workflow using experimental agent teams - INIT → WORKTREE → BRAINSTORM → PLAN → EXECUTE → REVIEW → COMPLETE
development
Implements code changes following plans and specifications
data-ai
Autonomous brainstorming agent for workflow orchestration
testing
Specialized testing agent for running tests and quality checks