Skip to content
Development
Skill

/stack-mode

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.

From plugin
claude-night-market
337200 skills59 agents162 commands1 MCP
Install
$ npx -y skills add athola/claude-night-market --skill stack-mode --agent claude-code

How it fires

How this skill gets triggered: by you, by Claude, or both.

  • Fires itselfAuto-invocation. Claude auto-loads it when your prompt matches the work.Auto-invocation is when the right skill fires by itself at the right moment, driven by a FLOW.md router and a hook, instead of you invoking it by name. It is the difference between a skill being installed and a skill actually getting used.Read the full definition →
  • You can call itInvoke it directly when you want it.
  • Slash command/stack-mode

Context preview

The summary Claude sees to decide when to auto-load this skill.

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.

SKILL.md

stack-mode.SKILL.md
name: stack-mode
description: 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.
alwaysApply: false
category: workflow-automation
tags:
- git
- stacked-diffs
- pr
- review
- fix-pr
- iteration
tools: []
complexity: medium
model_hint: standard
estimated_tokens: 1100
dependencies:
- sanctum:stack-create
- sanctum:stack-push
- sanctum:stack-rebase
- leyline:git-platform

Stack Mode

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:

1. Accept a `--stack` boolean flag AND a `--base <branch>` override (default: `master`). 2. Call Step 1 below to resolve stack membership BEFORE running its main workflow. 3. Run its main workflow per PR in the resolved order. 4. Emit per-PR outputs unchanged (thread replies, issue links, etc.). 5. Emit ONE stack-level summary comment on the root PR using the format in Step 4. 6. Respect per-PR Gate rules (every PR still needs its own thread resolution and issue tracking).

A calling command MAY:

  • Auto-detect stack membership and prompt the user rather

than requiring `--stack` explicitly.

  • Short-circuit iteration when a per-PR failure leaves

downstream PRs with stale context.

Required Progress Tracking

The caller creates `TodoWrite` items:

1. `stack-mode:membership-resolved` 2. `stack-mode:iteration-complete` 3. `stack-mode:root-summary-posted`

Step 1: Resolve Stack Membership (`membership-resolved`)

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; do
    pr=$(gh pr list --head "$branch" \
      --json number --jq '.[0].number')
    [ -n "$pr" ] && STACK_PRS+=("$pr")
  done

  echo "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 reference
if [ -z "$TABLE" ]; then
  ROOT_REF=$(echo "$BODY" \
    | grep -oE 'stack/[^ `]+' | head -1)
  # ... resolve ROOT_REF -> root PR number and re-fetch
fi

# 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)
while true; 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=$PARENT
done

# 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")
  done
done

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=$p
    break
  fi
done

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 -

Read more
Ships withclaude-night-market

A plugin marketplace for Claude Code. Install only the plugins you need to run git workflows, code review, spec-driven development, and autonomous agents from inside your Claude Code session.

Get the whole plugin

Other skills on claude-night-market.