land-stack
Use this skill whenever the user asks to land / merge / ship / queue a PR or a PR stack.
Generalized from a real incident in a repo using Mergify Stacks — the specifics below (label names, gh commands) assume that tooling, but the discipline transfers to any stacking workflow: adapt the discovery/merge commands to whatever queue tool the repo actually uses.
Hard rule
Never identify the PR to land by branch name. Two different PRs can share a
branch name (an auto-generated workflow branch PR and the intended stack
PR). You must land by SHA-verified PR number, and every PR must pass a
guard before any write (label, thread-resolve, queue, merge).
Steps
Resolve PR numbers, bottom of stack first. If the user gives numbers or
URLs, use those. If they do not, make a best-effort read-only discovery pass
and suggest the numbers yourself:
- Enumerate open PRs broadly, e.g.
gh pr list --state open --json number,baseRefName,headRefName,headRefOid,title --limit 100.
- Filter to the repo's actual stack-branch naming convention (e.g.
stack/).
- Prefer candidates whose
headRefOid exists in the local clone, so the code
is actually available for review.
- Order the stack by base/head links: the bottom PR targets the trunk; each
later PR targets the previous PR's head branch.
- Detect whether two or more open candidates share the same
headRefName.
If they do, present the exact bottom-up PR numbers and ask the user to
confirm them before landing. This is the only discovery case that requires
confirmation.
- If every candidate
headRefName is unique, run the guard on the suggested
sequence and, when it passes, land it without an additional confirmation.
Never discover by branch name. Do not run gh pr list --head <branch> to
decide what to land — that is the unsafe path this skill exists to prevent.
Verify with a guard before any write. Check, for each PR: head SHA exists
in the local clone (it is the code you reviewed), head branch matches the
repo's real stack-branch convention (rejects raw workflow/auto branches),
the PRs form a proper stack (each base is the previous head; the bottom's
base is the trunk), and all are OPEN. If any check fails, stop and resolve
the mismatch with a fresh discovery pass — do not work around it. The check
is scripts/verify_stack.py in this skill (see below); run it and paste
its output rather than reasoning through the four checks by hand.
python3 scripts/verify_stack.py --repo <owner/name> --trunk <trunk> --git-dir <local clone> <bottom> <next> ...
python3 scripts/verify_stack.py --repo <owner/name> --discover # suggest stacks; exit 3 = confirm with the user
Exit 0 means every check passed for that exact order. Exit 1 lists the failing
check per PR. The script never calls gh pr list --head.
Land bottom-up. Merge the bottom PR, wait for it to actually merge, then
retarget the next PR's base onto the trunk before merging it. Repeat up the
stack. A base change can report an unsettled/unknown mergeability state
immediately after — wait briefly and re-check before merging, don't merge
on a stale read.
Never batch merges without checking each result. A merge command can
look silent on both success and some failure paths; a silent-looking run is
not proof of a merge.
Do not
- Do not bypass the guard by hand-adding a bypass label or merging directly to
skip a broken check — if the queue is unhealthy, that's a different, riskier
operation that needs its own explicit authorization, not this skill.
- Do not resolve review threads to unblock a merge unless the user has decided
to defer those findings; record the deferral on the PR.
- Do not act on a PR whose head SHA is not in your local clone.
Prove state before reporting it
Before telling the user a PR is merged, queued, blocked, or failing CI, re-run
the exact status query in that same turn — do not repeat a status you checked
earlier in the conversation. "Merging" is not "merged"; a queued PR can still
fail a re-run of the full suite.
Why this exists
A raw workflow-branch PR shared a branch name with the intended stack PR.
Landing "the PR on this branch" by name queued the wrong PR. The guard makes
that mistake fail closed instead of merging silently.
1---2name: land-stack3description: Land (queue/merge) a stacked pull request safely, on any repo using a PR-stacking workflow (Mergify, Graphite, or similar). Trigger when asked to land, merge, ship, or queue a PR or PR stack. Enforces that you act only on SHA-verified PR numbers — never a PR found by branch name.4---56# land-stack78Use this skill whenever the user asks to **land / merge / ship / queue** a PR or a PR stack.910Generalized from a real incident in a repo using Mergify Stacks — the specifics below (label names, `gh` commands) assume that tooling, but the discipline transfers to any stacking workflow: adapt the discovery/merge commands to whatever queue tool the repo actually uses.1112## Hard rule1314**Never identify the PR to land by branch name.** Two different PRs can share a15branch name (an auto-generated workflow branch PR and the intended stack16PR). You must land by **SHA-verified PR number**, and every PR must pass a17guard before any write (label, thread-resolve, queue, merge).1819## Steps20211. **Resolve PR numbers, bottom of stack first.** If the user gives numbers or22 URLs, use those. If they do not, make a best-effort read-only discovery pass23 and suggest the numbers yourself:2425 - Enumerate open PRs broadly, e.g. `gh pr list --state open --json number,baseRefName,headRefName,headRefOid,title --limit 100`.26 - Filter to the repo's actual stack-branch naming convention (e.g. `stack/`).27 - Prefer candidates whose `headRefOid` exists in the local clone, so the code28 is actually available for review.29 - Order the stack by base/head links: the bottom PR targets the trunk; each30 later PR targets the previous PR's head branch.31 - Detect whether two or more open candidates share the same `headRefName`.32 If they do, present the exact bottom-up PR numbers and ask the user to33 confirm them before landing. This is the only discovery case that requires34 confirmation.35 - If every candidate `headRefName` is unique, run the guard on the suggested36 sequence and, when it passes, land it without an additional confirmation.3738 Never discover by branch name. Do not run `gh pr list --head <branch>` to39 decide what to land — that is the unsafe path this skill exists to prevent.40412. **Verify with a guard before any write.** Check, for each PR: head SHA exists42 in the local clone (it is the code you reviewed), head branch matches the43 repo's real stack-branch convention (rejects raw workflow/auto branches),44 the PRs form a proper stack (each base is the previous head; the bottom's45 base is the trunk), and all are OPEN. If any check fails, stop and resolve46 the mismatch with a fresh discovery pass — do not work around it. The check47 is `scripts/verify_stack.py` in this skill (see below); run it and paste48 its output rather than reasoning through the four checks by hand.4950 ```sh51 python3 scripts/verify_stack.py --repo <owner/name> --trunk <trunk> --git-dir <local clone> <bottom> <next> ...52 python3 scripts/verify_stack.py --repo <owner/name> --discover # suggest stacks; exit 3 = confirm with the user53 ```5455 Exit 0 means every check passed for that exact order. Exit 1 lists the failing56 check per PR. The script never calls `gh pr list --head`.57583. **Land bottom-up.** Merge the bottom PR, wait for it to actually merge, then59 retarget the next PR's base onto the trunk before merging it. Repeat up the60 stack. A base change can report an unsettled/unknown mergeability state61 immediately after — wait briefly and re-check before merging, don't merge62 on a stale read.63644. **Never batch merges without checking each result.** A merge command can65 look silent on both success and some failure paths; a silent-looking run is66 not proof of a merge.6768## Do not6970- Do not bypass the guard by hand-adding a bypass label or merging directly to71 skip a broken check — if the queue is unhealthy, that's a different, riskier72 operation that needs its own explicit authorization, not this skill.73- Do not resolve review threads to unblock a merge unless the user has decided74 to defer those findings; record the deferral on the PR.75- Do not act on a PR whose head SHA is not in your local clone.7677## Prove state before reporting it7879Before telling the user a PR is merged, queued, blocked, or failing CI, re-run80the exact status query in that same turn — do not repeat a status you checked81earlier in the conversation. "Merging" is not "merged"; a queued PR can still82fail a re-run of the full suite.8384## Why this exists8586A raw workflow-branch PR shared a branch name with the intended stack PR.87Landing "the PR on this branch" by name queued the wrong PR. The guard makes88that mistake fail closed instead of merging silently.