PR Stacker
Splits a large feature branch into smaller, focused pull requests using stacked branches and cherry-pick. Groups commits by concern (infrastructure, application logic, tests, housekeeping), proposes descriptive branch names for user approval, creates stacked branches, and generates What/Why MR titles and descriptions. Use when the user says a PR is too big, asks to split a PR, wants to decompose a branch, or needs to break work into reviewable chunks.
npx skills add github:pantheon-org/tekhne --skill project-mgmt--planning-toolkit--pr-stackerMindset
A large PR fails reviewers because it mixes concerns — infrastructure sits next to business logic sits next to test cleanup. Reviewers cannot build a mental model of any single change when everything changes at once.
The fix is to group commits by what kind of thing changed, not by when they were written or what ticket they belong to. Each group becomes its own PR targeting the previous one (stacked branches), so changes can be reviewed and merged in order without blocking unrelated work.
Two failure modes to avoid:
- The monolith — one PR with everything, reviewers give up or rubber-stamp
- The over-split — one PR per commit, stacked 10 deep, merge overhead exceeds the benefit
The sweet spot is 2–4 PRs where each one can be understood by a reviewer who only knows that domain.
When to use
- A PR has more than ~15 files changed across unrelated concerns
- A reviewer says “this is too big to review”
- Commits already have phase or step markers in their messages
- Changes span infrastructure, application code, and cleanup in a single branch
When not to use
- The branch has 2–4 commits that all touch the same component — keep it together
- All files are test files for a single feature — one PR is correct
- The work is already in review and splitting restarts the cycle with more overhead than benefit
- Commits are tightly coupled (each depends on the previous for tests to pass) — cherry-pick reordering will produce broken intermediate branches
Trigger phrases
- “This PR is too big”
- “Split this PR”
- “Break this into smaller PRs”
- “Decompose the branch”
- “Too many changes for reviewers”
Workflow
Load Workflow Steps for full commands. Summary: analyse → group → propose (table, wait for approval) → name → stack (cherry-pick) → describe (What/Why) → remind about target branches.
Consider adapting concern labels to the codebase — if there is no infrastructure layer, you may optionally collapse to two groups (application logic + tests).
# Step 1 — read commits and files changed before grouping
git log <base>..<branch> --oneline --reverse
git diff-tree --no-commit-id -r <sha> --name-only
Anti-patterns
❌ NEVER name branches with sequence numbers (wave-1, phase-2, part-1)
WHY: Sequence names lose meaning after any rebase or reorder. A reviewer cannot determine scope without reading the full diff.
# BAD — reviewer cannot tell what changes without reading the diff
feature/PROJ-123-wave-1
feature/PROJ-123-phase-2
# GOOD — scope is clear from the name alone
feature/PROJ-123-add-cdk-stack-and-iam
feature/PROJ-123-add-jwt-handler-and-tests
Consequence: Reviewers rubber-stamp because they cannot build a mental model.
❌ NEVER create branches or cherry-pick before the user approves the grouping
WHY: Grouping requires domain knowledge the agent does not have. A misassigned commit means deleting and recreating branches.
Consequence: Wasted cycles cleaning up wrong branches; conflicts from reordering.
❌ NEVER split commits that share a single failing test (broken intermediate state)
WHY: If PR 1 removes a handler and PR 2 adds its replacement, PR 1 alone fails CI.
Consequence: The merge queue blocks. The entire decomposition must restart.
❌ NEVER write MR descriptions as file lists or commit logs
WHY: A reviewer can already read the diff. The What/Why format gives the context that a reviewer without prior knowledge actually needs.
# BAD — no context, reviewer learns nothing
# - Updated auth-stack.ts
# - Added auth-role.ts
# GOOD — answers what changed and why it was necessary
# **What:** Provisions the CDK stack and IAM role the new auth service requires.
# **Why:** Without dedicated infrastructure, the service cannot deploy to any environment.
Consequence: Reviewers miss architectural intent and are more likely to approve problematic changes.
❌ NEVER leave cherry-pick conflicts unresolved before reporting completion
WHY: A branch with conflicts is not buildable. The user discovers this only when CI runs.
ALWAYS resolve every conflict and verify the branch actually builds before reporting success —
do not just check that git cherry-pick exited 0:
git checkout feature/PROJ-123-add-cdk-stack-and-iam
npm run build && npm test
# or, for a Makefile-based repo:
make build && make test
Consequence: The entire decomposition must restart. Partial branches pollute the remote.
Example proposal
Given commits touching infra (CDK, IAM), application logic (handlers + tests), and housekeeping (lock file, Makefile), the grouping table looks like:
| PR | Branch | Concern |
|---|---|---|
| 1 | feature/PROJ-123-add-cdk-stack-and-iam |
Infrastructure |
| 2 | feature/PROJ-123-add-handlers-and-tests |
Application logic + tests |
| 3 | feature/PROJ-123-housekeeping |
Housekeeping |
See Worked Example for the complete walkthrough.
References
- Workflow Steps — Full step-by-step git commands; load when executing a decomposition
- Anti-Patterns — NEVER/WHY/Consequence patterns with BAD/GOOD examples; load when explaining a failure mode
- Worked Example — Complete 9-commit walkthrough; load when verifying output format
Explicit NEVER/WHY/consequence triplets with side-by-side bad/good examples. Generic warnings score low — concrete failure modes with real impact (security, correctness, performance) score high.
Runtime validation via eval scenarios proving the skill actually changes agent behaviour. Requires evals/ directory, instructions.json, ≥3 scenarios, and ≥80% instruction coverage in summary.json.
Appropriate rigidity for the skill type: strict rules for critical/security skills, balanced steps for process skills, flexible options for tool skills. Mismatched calibration (too rigid or too loose) reduces score.
Expert-only knowledge the AI couldn't derive on its own — domain-specific patterns, production gotchas, decision frameworks, and non-obvious tool behaviour. High scores mean <5% redundancy with what the model already knows.
A clear philosophy plus numbered step-by-step workflows with explicit entry/exit points. Should answer: what is the core principle, how to execute it, and when (and when not) to apply it.
Rich activation keywords and trigger scenarios in the description so the skill fires when needed. Best descriptions read like an exhaustive list of the tasks and concepts that should invoke this skill.
Copy-paste-ready code, complete runnable examples, real file paths and commands. Pseudocode and abstract descriptions score low — concrete, executable content scores high.
SKILL.md as a <100-line navigation hub pointing to focused references/ files. Content should be lazy-loaded on demand, not front-loaded. Includes actionable 'When to Use' conditions per reference.
Proper frontmatter, single-task focus, activation keywords, and cross-harness portability. Skills must work across 40+ agentic harnesses without hardcoded paths or agent-specific references.
Expert-only knowledge the AI couldn't derive on its own — domain-specific patterns, production gotchas, decision frameworks, and non-obvious tool behaviour. High scores mean <5% redundancy with what the model already knows.
A clear philosophy plus numbered step-by-step workflows with explicit entry/exit points. Should answer: what is the core principle, how to execute it, and when (and when not) to apply it.
Explicit NEVER/WHY/consequence triplets with side-by-side bad/good examples. Generic warnings score low — concrete failure modes with real impact (security, correctness, performance) score high.
Proper frontmatter, single-task focus, activation keywords, and cross-harness portability. Skills must work across 40+ agentic harnesses without hardcoded paths or agent-specific references.
SKILL.md as a <100-line navigation hub pointing to focused references/ files. Content should be lazy-loaded on demand, not front-loaded. Includes actionable 'When to Use' conditions per reference.
Appropriate rigidity for the skill type: strict rules for critical/security skills, balanced steps for process skills, flexible options for tool skills. Mismatched calibration (too rigid or too loose) reduces score.
Rich activation keywords and trigger scenarios in the description so the skill fires when needed. Best descriptions read like an exhaustive list of the tasks and concepts that should invoke this skill.
Copy-paste-ready code, complete runnable examples, real file paths and commands. Pseudocode and abstract descriptions score low — concrete, executable content scores high.
Runtime validation via eval scenarios proving the skill actually changes agent behaviour. Requires evals/ directory, instructions.json, ≥3 scenarios, and ≥80% instruction coverage in summary.json.
Expert-only knowledge the AI couldn't derive on its own — domain-specific patterns, production gotchas, decision frameworks, and non-obvious tool behaviour. High scores mean <5% redundancy with what the model already knows.
A clear philosophy plus numbered step-by-step workflows with explicit entry/exit points. Should answer: what is the core principle, how to execute it, and when (and when not) to apply it.
Explicit NEVER/WHY/consequence triplets with side-by-side bad/good examples. Generic warnings score low — concrete failure modes with real impact (security, correctness, performance) score high.
Proper frontmatter, single-task focus, activation keywords, and cross-harness portability. Skills must work across 40+ agentic harnesses without hardcoded paths or agent-specific references.
SKILL.md as a <100-line navigation hub pointing to focused references/ files. Content should be lazy-loaded on demand, not front-loaded. Includes actionable 'When to Use' conditions per reference.
Appropriate rigidity for the skill type: strict rules for critical/security skills, balanced steps for process skills, flexible options for tool skills. Mismatched calibration (too rigid or too loose) reduces score.
Rich activation keywords and trigger scenarios in the description so the skill fires when needed. Best descriptions read like an exhaustive list of the tasks and concepts that should invoke this skill.
Copy-paste-ready code, complete runnable examples, real file paths and commands. Pseudocode and abstract descriptions score low — concrete, executable content scores high.
Runtime validation via eval scenarios proving the skill actually changes agent behaviour. Requires evals/ directory, instructions.json, ≥3 scenarios, and ≥80% instruction coverage in summary.json.
No eval scenarios available.
Anti-Patterns
NEVER name branches with sequence numbers
WHY: Sequence names (wave-1, phase-2, part-1) become meaningless after any rebase or reorder. A reviewer cannot determine scope without reading the full diff.
# BAD
feature/PROJ-123-wave-1
feature/PROJ-123-phase-2
# GOOD
feature/PROJ-123-remove-cdk-glue-table
feature/PROJ-123-add-eligibility-handler
Consequence: Future git blame and bisect queries return useless results.
Reviewers rubber-stamp because they cannot build a mental model from the branch name.
NEVER create branches or cherry-pick before the user approves the grouping
WHY: Grouping decisions require domain knowledge the agent does not have. A misassigned commit means deleting and recreating branches.
Consequence: Wasted cycles cleaning up wrong branches; cherry-pick conflicts introduced by reordering commits incorrectly.
NEVER split commits that share a single failing test
WHY: If PR 1 removes a handler and PR 2 adds its replacement, the stack has a broken intermediate state. CI fails on PR 1 and blocks the merge queue.
# BAD — handler removed in PR 1, replacement added in PR 2
# PR 1 alone: tests fail on missing handler
# GOOD — removal and replacement travel together in one PR
Consequence: The stacked PR approach collapses — each PR must be independently green before the next can merge.
NEVER leave cherry-pick conflicts unresolved
WHY: A branch with conflicts is not buildable. The user discovers this only when CI runs.
Consequence: The entire decomposition must restart. Partial branches pollute the remote.
NEVER write MR descriptions as file lists or commit logs
WHY: A reviewer can read the diff. A file list adds zero information. The What/Why format gives context a reviewer without prior knowledge needs.
# BAD
- Updated auth-stack.ts
- Added auth-role.ts
- Modified session.ts
# GOOD
**What:** Provisions the CDK stack and IAM role that the new auth service requires.
**Why:** Without dedicated infrastructure, the service cannot deploy to any environment.
Consequence: Reviewers have no context for why the change exists and are more likely to miss architectural issues.
Worked Example
Input: 9 commits on feature/PROJ-123-data-pipeline-refactor
a1b2c3 chore: update CDK stack for new Glue job
d4e5f6 chore: remove eligibility table construct
g7h8i9 feat: add eligibility data handler
j0k1l2 feat: add pipeline orchestrator module
m3n4o5 test: add unit tests for eligibility handler
p6q7r8 test: add integration tests for orchestrator
s9t0u1 chore: update lock file
v2w3x4 chore: remove unused Makefile targets
y5z6a7 docs: update README with new pipeline diagram
Step 2 grouping output
| PR | Branch name | Commits | Concern |
|---|---|---|---|
| 1 | feature/PROJ-123-remove-cdk-glue-eligibility-table |
a1b2c3, d4e5f6, s9t0u1 |
Infrastructure |
| 2 | feature/PROJ-123-add-eligibility-and-orchestrator |
g7h8i9, j0k1l2, m3n4o5, p6q7r8 |
Application logic + tests |
| 3 | feature/PROJ-123-housekeeping-and-docs |
v2w3x4, y5z6a7 |
Housekeeping |
Notes on grouping decisions:
s9t0u1(lock file) goes with the infra group — it was caused by the CDK dependency change- Tests travel with the source they cover (
m3n4o5withg7h8i9,p6q7r8withj0k1l2) - README update goes with housekeeping since it documents the removed Glue job
Step 6 MR description for PR 2
Title: feat(PROJ-123): add eligibility data handler and pipeline orchestrator
Description:
**What:** Adds the eligibility handler and orchestrator modules that replace
the removed Glue job, including unit and integration test coverage.
**Why:** The Glue job was removed in PR 1; this introduces the replacement
application-layer logic that processes eligibility data via the new pipeline.
Step 5 cherry-pick commands
# PR 1 — from main
git checkout -b feature/PROJ-123-remove-cdk-glue-eligibility-table main
git cherry-pick a1b2c3 d4e5f6 s9t0u1
# PR 2 — from PR 1
git checkout -b feature/PROJ-123-add-eligibility-and-orchestrator \
feature/PROJ-123-remove-cdk-glue-eligibility-table
git cherry-pick g7h8i9 j0k1l2 m3n4o5 p6q7r8
# PR 3 — from PR 2
git checkout -b feature/PROJ-123-housekeeping-and-docs \
feature/PROJ-123-add-eligibility-and-orchestrator
git cherry-pick v2w3x4 y5z6a7
Workflow Steps
Step 1 — Analyse the branch
Read all commits between the current branch and the base branch:
git log <base>..<branch> --oneline --reverse
Then get files changed per commit:
git log <base>..<branch> --format='%h %s' | while read hash msg; do
echo "=== $hash: $msg ==="
git diff-tree --no-commit-id -r "$hash" --name-only
done
Step 2 — Group commits by concern
Map each commit to one of these concern types:
| Concern | Typical files |
|---|---|
| Infrastructure | CDK stacks, Terraform, CloudFormation, VPC config, CI config |
| Application logic | Source handlers, business logic, shared modules |
| Tests | Unit tests, integration tests, fixtures, test data |
| Housekeeping | Dependencies, lock files, Makefile, generated files, tooling config |
A commit that touches both application logic and tests belongs to the group that represents the majority of the change. Supporting commits (lock files, generated code) go with the group they enable.
Adapt concern labels to the codebase — if there is no infrastructure, collapse to two groups (application logic + tests). If the codebase uses a different taxonomy (frontend/backend/data), use those labels instead. The table is a communication tool; exact label names matter less than grouping accuracy.
Step 3 — Propose the split
Present the proposed grouping as a table for user approval before taking any action:
| PR | Branch name | Commits | Concern |
|---|---|---|---|
| 1 | feature/<ticket>-<what-changes> |
abc123, def456 |
Infrastructure |
| 2 | feature/<ticket>-<what-changes> |
789abc |
Application logic |
| 3 | feature/<ticket>-<what-changes> |
cde012, fgh345 |
Housekeeping |
Wait for explicit confirmation before proceeding.
Step 4 — Name branches descriptively
Branch names must reflect the actual content — not sequence numbers, wave numbers, or phase numbers.
Good: feature/PROJ-123-remove-cdk-glue-and-eligibility-table
Bad: feature/PROJ-123-wave-1, feature/PROJ-123-phase-1, feature/PROJ-123-part-1
The name should let a reviewer understand the scope without reading the diff.
Step 5 — Create stacked branches
PR 1 targets the base branch. Each subsequent PR targets the previous one:
<base> ← PR-1 ← PR-2 ← PR-3
Use cherry-pick to distribute commits:
# PR 1 — from base
git checkout -b feature/<ticket>-<name-1> <base>
git cherry-pick <sha1> <sha2> <sha3>
# PR 2 — from PR 1
git checkout -b feature/<ticket>-<name-2> feature/<ticket>-<name-1>
git cherry-pick <sha4> <sha5>
# PR 3 — from PR 2
git checkout -b feature/<ticket>-<name-3> feature/<ticket>-<name-2>
git cherry-pick <sha6> <sha7> <sha8>
Resolve any conflicts that arise from the reordering.
Step 6 — Generate MR titles and descriptions
For each PR, produce a title and a short description that answers What and Why:
Title format: <type>(<ticket>): <imperative summary of the change>
Description format:
**What:** <one sentence summary of what changed — the diff in plain English>
**Why:** <one sentence on why this was necessary — motivation, consequence of not doing it>
The description is not a file list. It is not a commit log. It explains the change to a reviewer who has no prior context.
Step 7 — Remind about target branches
After creating branches, remind the user to set the correct target branch when opening each MR:
- PR 1 →
<base branch> - PR 2 → PR 1’s branch
- PR 3 → PR 2’s branch
Merge in order.