skills/mav-stacked-prs/SKILL.md
How to stack a PR on top of an unmerged sibling branch, and how to retarget it to the repo's default branch once the sibling merges. Prevents orphan-merge incidents when a dependent story is ready before its parent.
npx skillsauth add thermiteau/maverick mav-stacked-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.
Depends on: mav-git-workflow
When story B depends on story A and A's PR isn't merged yet, B branches from
A's branch and opens a PR whose base is feat/A-… rather than the story
base branch. This is a stacked PR. It lets B progress without waiting
for A to merge, and is essential for throughput inside an epic.
Stacking is safe when it is paired with a retarget guard that moves B's PR base back to the story base as soon as A lands. Without the retarget guard, a specific merge-order sequence can orphan B's commits — see the failure mode at the bottom of this document.
Resolve the story base once at the start of any stacking operation:
STORY_BASE=$(uv run maverick git-workflow story-base)
digraph stack_decide {
"Depends on sibling story?" [shape=diamond];
"Sibling PR open but unmerged?" [shape=diamond];
"Stack — branch from sibling" [shape=box];
"Default — branch from $STORY_BASE" [shape=box];
"Depends on sibling story?" -> "Sibling PR open but unmerged?" [label="yes"];
"Depends on sibling story?" -> "Default — branch from $STORY_BASE" [label="no"];
"Sibling PR open but unmerged?" -> "Stack — branch from sibling" [label="yes"];
"Sibling PR open but unmerged?" -> "Default — branch from $STORY_BASE" [label="no — sibling already merged"];
}
| Situation | Stack? | Why |
| --- | --- | --- |
| No cross-story deps | No | Default branch is fine |
| Sibling already merged | No | Branch from default — clean base |
| Sibling PR open, you need its code to compile/test | Yes | Stack on the sibling branch |
| Sibling PR open, you only need it logically but don't import | Yes | Stack anyway — guards against logical surprises |
| Sibling PR ejected (labelled needs-human) | No — block instead | You should have been excluded from the wave |
Fetch the sibling branch before branching off it — another instance may have pushed further commits:
git fetch origin feat/140-bootstrap-provider
git worktree add .maverick/worktrees/feat__142-admin-guard \
-b feat/142-admin-guard-bootstrap \
origin/feat/140-bootstrap-provider
The worktree's HEAD is now pinned to A's tip. Work proceeds normally from
there. Push-per-task applies — each commit flows to
origin/feat/142-admin-guard-bootstrap as usual.
Always pass --base explicitly to target the sibling branch:
gh pr create \
--base feat/140-bootstrap-provider \
--head feat/142-admin-guard-bootstrap \
--title "feat: admin guard (#142)" \
--body "..."
GitHub's PR diff now shows only B's changes — the diff is against A's tip,
not against main. This is exactly what the reviewer should see.
Every push on a stacked branch must check whether the base has merged. This is the single rule that prevents orphan-merge incidents.
digraph retarget {
"Ready to push" [shape=box];
"Stacked branch?" [shape=diamond];
"Sibling PR merged?" [shape=diamond];
"Retarget PR base to $STORY_BASE" [shape=box];
"Rebase onto $STORY_BASE tip" [shape=box];
"Push as normal" [shape=box];
"Ready to push" -> "Stacked branch?";
"Stacked branch?" -> "Sibling PR merged?" [label="yes"];
"Stacked branch?" -> "Push as normal" [label="no"];
"Sibling PR merged?" -> "Retarget PR base to $STORY_BASE" [label="yes — base merged"];
"Sibling PR merged?" -> "Push as normal" [label="no — base still unmerged"];
"Retarget PR base to $STORY_BASE" -> "Rebase onto $STORY_BASE tip";
"Rebase onto $STORY_BASE tip" -> "Push as normal";
}
Use the gh pr view --json state check for the sibling PR — it handles
both merge-commit and squash-merge cases:
STORY_BASE=$(uv run maverick git-workflow story-base)
state=$(gh pr view feat/140-bootstrap-provider --json state -q .state)
if [ "$state" = "MERGED" ]; then
gh pr edit <PR> --base "$STORY_BASE"
git rebase --onto "origin/$STORY_BASE" origin/feat/140-bootstrap-provider
fi
The PR-state check is the authoritative signal. git merge-base --is-ancestor does not work after a squash-merge because the squash
commit carries the content but not the original commit SHAs.
After retargeting, rebase the branch onto the new base so the PR diff stays tidy:
git rebase --onto "origin/$STORY_BASE" origin/feat/140-bootstrap-provider
This strips out commits that are already in $STORY_BASE (from the
sibling's merge) and replays your commits on top of the current
$STORY_BASE.
If rebase produces conflicts:
mav-git-workflow.Orphan-merge incident (seen in practice; see retro §1.1):
The retarget guard prevents step 3 from being possible: B's base is moved to the story base the moment A merges, and B's next push either rebases cleanly or flags a conflict. Either way, B cannot silently merge into an orphan.
mav-git-workflow for conventional commit
format, branch naming, and conflict resolution.development
--- name: do-test description: Write or update tests for a code change. Operates in two modes: `unit` (module-scoped, fast, deterministic) and `integration` (crosses module / service / database boundaries). Intended to be invoked once per testable change from inside a do-issue-* or do-epic phase. Mode is required. argument-hint: mode: unit or integration user-invocable: true disable-model-invocation: false --- **Depends on:** mav-bp-unit-testing, mav-bp-integration-testing, mav-local-verificati
development
Implement a focused code change. Use this skill as the wrapper for any implementation work so the Maverick workflow report captures what was done and so the agent applies the project's coding standards before editing. Intended to be invoked once per task from inside a do-issue-* or do-epic phase, not standalone.
development
Claim, lease, heartbeat, and release protocols for when multiple Claude Code instances may act on the same issue or epic concurrently. GitHub labels and marker comments are the coordination surface; local state is a cache.
documentation
Durability conventions for multi-instance Maverick workflows. Covers cold-start hydration from GitHub, marker-write protocols, push-per-task cadence, and recreating worktrees from remote branches. GitHub is the source of truth; local files are a cache.