Detects shared stack membership and iterates a command across all PRs in base-to-tip order. Use when a command supports --stack flag for multi-PR iteration.
Instalar com Codex ou Claude Copie este prompt, cole no Codex, Claude ou outro assistente e deixe que ele revise a página da skill e instale para você.
Um comando direto ignora o prompt de revisão. Verifique a origem antes de executá-lo.
Detects shared stack membership and iterates a command across all PRs in base-to-tip order. Use when a command supports --stack flag for multi-PR iteration.
Shared contract for commands that need to operate across a
whole stack of dependent PRs in one invocation.
Used by /pr-review --stack and /fix-pr --stack.
The goal is one simple thing: when a PR is part of a stack
targeting a common base branch, loop the command's normal
workflow across every PR in the stack in base-to-tip order
and emit one consolidated summary on the stack root.
When To Use
Load this skill when a command accepts a --stack flag
(or auto-detects stack membership) and needs to iterate
its normal workflow across multiple PRs.
Do NOT load this skill for single-PR workflows. The
per-PR workflow stays unchanged; stack mode wraps it.
When NOT To Use
Creating the stack (use sanctum:stack-create)
Cascading a rebase through it (use sanctum:stack-rebase)
Contract
A calling command MUST:
Accept a --stack boolean flag AND a --base <branch>
override (default: master).
Call Step 1 below to resolve stack membership BEFORE
running its main workflow.
Run its main workflow per PR in the resolved order.
Given a starting PR number $PR_NUM and optional base
$BASE (default: master), try three strategies in
order and stop at the first that yields a stack of size
= 2.
Strategy A: Branch-name convention (cheapest)
START_HEAD=$(gh pr view "$PR_NUM" \
--json headRefName -q .headRefName)
# stack/<feature-name>/<slice-name>if [[ "$START_HEAD" =~ ^stack/([^/]+)/.+$ ]]; then
FEATURE="${BASH_REMATCH[1]}"
PREFIX="stack/${FEATURE}/"# All local branches with the same prefix
STACK_BRANCHES=$(git branch --list "${PREFIX}*" \
| sed 's/^[* ]*//' | sort)
# Map branches -> PR numbers (skip branches with no PR)
STACK_PRS=()
for branch in$STACK_BRANCHES; dopr=$(gh pr list --head"$branch" \
--json number --jq '.[0].number')
[ -n "$pr" ] && STACK_PRS+=("$pr")
doneecho"strategy=A prs=${STACK_PRS[*]}"fi
Strategy B: Stack summary comment (most reliable)
stack-push posts a ## Stack markdown table on the
root PR with columns # | Branch | PR. Parse it:
# Find the root PR of the stack containing $PR_NUM# The current PR may be the root, or may link to it via# a "Part of stack `stack/<feature>`" phrase in its body
BODY=$(gh pr view "$PR_NUM" --json body -q .body)
# Look for a "## Stack" table in THIS PR's comments
TABLE=$(gh pr view "$PR_NUM" --json comments \
--jq '.comments[] | select(.body | contains("## Stack"))
| .body' | head -1)
# If not on this PR, look for the root PR referenceif [ -z "$TABLE" ]; then
ROOT_REF=$(echo"$BODY" \
| grep -oE 'stack/[^ `]+' | head -1)
# ... resolve ROOT_REF -> root PR number and re-fetchfi# Parse the table: extract all `#<num>` from the PR column
STACK_PRS=($(echo"$TABLE" \
| grep -oE '#[0-9]+' | tr -d '#' | sort -un))
echo"strategy=B prs=${STACK_PRS[*]}"
Strategy C: Base-chain walk (fallback)
Walk both directions from $PR_NUM:
Up: repeatedly resolve baseRefName until it equals
$BASE. Each visited head is a stack member.
Down: find open PRs whose baseRefName equals one of
the visited heads. Recurse.
# Ascend from $PR_NUM to the root
CUR=$PR_NUM
CHAIN=($CUR)
whiletrue; do
BASE_REF=$(gh pr view "$CUR" \
--json baseRefName -q .baseRefName)
[ "$BASE_REF" = "$BASE" ] && break
PARENT=$(gh pr list --head"$BASE_REF" \
--state open --json number --jq '.[0].number')
[ -z "$PARENT" ] && break
CHAIN=("$PARENT""${CHAIN[@]}")
CUR=$PARENTdone# Descend from the root collecting children
ROOT=${CHAIN[0]}
FRONTIER=("$ROOT")
while [ ${#FRONTIER[@]} -gt 0 ]; do
PARENT=${FRONTIER[0]}
FRONTIER=("${FRONTIER[@]:1}")
PARENT_HEAD=$(gh pr view "$PARENT" \
--json headRefName -q .headRefName)
CHILDREN=($(gh pr list --base "$PARENT_HEAD" \
--state open --json number --jq '.[].number'))
for c in"${CHILDREN[@]}"; do
CHAIN+=("$c")
FRONTIER+=("$c")
donedone
STACK_PRS=("${CHAIN[@]}")
echo"strategy=C prs=${STACK_PRS[*]}"
Ordering
Regardless of strategy, order the final list base-to-tip
(root PR first, leaf PR last). The root is the PR whose
baseRefName equals $BASE.
ROOT_PR=""for p in"${STACK_PRS[@]}"; do
base=$(gh pr view "$p" --json baseRefName -q .baseRefName)
if [ "$base" = "$BASE" ]; then
ROOT_PR=$pbreakfidone
If the stack size is 1, the command MUST fall back to
single-PR mode and emit a warning: stack-mode: only one PR found; --stack has no effect, proceeding as single-PR.
GitLab / Bitbucket
See Skill(leyline:git-platform) for glab / Bitbucket
equivalents of the gh calls above. The three strategies
translate directly: GitLab MR dependencies replace
base-chain walks, and the glab mr view --output json
shape matches gh pr view.
Step 2: Confirm With User (if not explicit)
When the caller did NOT pass --stack but Step 1 resolved
a stack of size >= 2, print the stack and ask:
Detected stack of N PRs rooted at #<root>:
1. #<root> <title>
2. #<p2> <title>
...
Run the workflow on the full stack? [y/N]
Default to "N" (single-PR mode). With --stack explicit,
skip this prompt.
Step 3: Iterate (iteration-complete)
Run the caller's main workflow once per PR in base-to-tip
order:
FAILED_PRS=()
for p in"${STACK_PRS[@]}"; doecho"=== stack-mode: PR #$p ($(($idx+1))/${#STACK_PRS[@]}) ==="# Caller hook: run the single-PR workflow on $p# This includes Gate 1 (thread resolution) and# Gate 2 (issue tracking) per the caller's contract.if ! run_single_pr_workflow "$p"; then
FAILED_PRS+=("$p")
# Stop iteration: downstream PRs may now be stalebreakfidone
If any PR fails, the command MUST stop and report
stack-mode: halted at #<pr>; downstream PRs untouched.
Downstream PRs are intentionally left alone because
their context may have shifted.
Step 4: Post Stack Summary on Root (root-summary-posted)
After successful iteration, post ONE consolidated summary
comment on the root PR. This does NOT replace per-PR
summaries: it links them together.
## Stack <CommandName> Summary**Stack**: N PRs rooted at #<root>, base `<base-branch>`**Command**: <command> (e.g., /fix-pr, /pr-review)
**Run**: <timestamp>
| # | PR | Branch | Status | Per-PR Summary |
|---|----|--------|--------|----------------|
| 1 | #<root> | `stack/<feat>/<root-slice>` | <done/skipped/failed> | [link to comment] |
| 2 | #<p2> | `stack/<feat>/<slice-2>` | <done/skipped/failed> | [link to comment] |
| ... | ... | ... | ... | ... |
### Cross-PR Notes-<AnyobservationsthatspannedmultiplePRs>-<IssuescreatedthatreferencemultiplestackPRs>-<Base-PR-mergedcascadereminders, ifany>### Next Steps- If root PR merges, run `Skill(sanctum:stack-rebase)` to
cascade the base update through descendants.
- Reviewers: rebase-triggered stale-review flags on
descendants are expected after any force-push.
Post via gh pr comment "$ROOT_PR" --body-file <file>.
Failure Modes and Recovery
Failure
Detection
Recovery
Stack of size 1
Step 1 returns one PR
Emit warning, fall back to single-PR mode
Base chain loops
Visited set on ascent
Halt, report stack-mode: cycle detected
Mid-stack PR failed its Gates
Caller raises
Halt iteration, leave downstream untouched
Strategy B table malformed
Parse fails
Fall through to Strategy C
Auth scope insufficient
gh returns 403
Halt with clear error; caller surfaces to user
Notes
Stack mode is ADDITIVE: single-PR behavior is unchanged.
Only the iteration and root summary are new.
Per-PR Gate 1 (thread resolution) and Gate 2 (issue
tracking) remain unchanged: each PR still passes its
own gates independently.
Never merge Gate 1 across the stack. A resolved thread
on one PR is not a resolved thread on another.
The root summary is idempotent: re-running stack mode
should update (not duplicate) the summary comment.
Match on ## Stack <Command Name> Summary as the key.
stack-mode is a read/orchestration skill; it does NOT
push, rebase, or edit branches. Those concerns are in
stack-create, stack-push, and stack-rebase.
Exit Criteria
Stack membership resolved using at least one of the three
strategies (A: branch names, B: stack comment, C: base-chain
walk) and PRs ordered base-to-tip before iteration starts
The 3 required TodoWrite items (stack-mode:membership-resolved,
stack-mode:iteration-complete, stack-mode:root-summary-posted)
are created and marked complete in sequence
Root PR receives exactly one consolidated ## Stack <Command> Summary comment after all PRs are processed
If stack size is 1, warning stack-mode: only one PR found; --stack has no effect is emitted and single-PR mode used
If a PR fails its gates, iteration halts and downstream PRs
are left untouched with a stack-mode: halted at #<pr> report