Stacked PRs, flown from the cockpit
GitHub's stacked pull requests break a large change into a chain of small, individually-reviewable PRs — each layer targeting the one below it. coop supports them end to end: the built-in feature-implement workflow can finish a plan as a ready-made stack, and the status bar reads any stack — coop-emitted or hand-built — as a live position chip with a full ladder one click away.
01 · Emit a stack from a plan
The finish line is a knob on the built-in feature-implement workflow. The default ("branch") is exactly the classic behavior: one integrated branch, nothing pushed. The two stacked modes chain the plan's workstreams instead — one layer per workstream, in dependency order — and open them as pull requests after review approves.
// one-off, per run: /workflow-run feature-implement args={"plan":"plans/my-feature.md","finishLine":"draft-stack"} // or set a repo default in .coop/workflow-config.json: { "finishLine": "draft-stack" } // "branch" (default) · "draft-stack" · "stack"
draft-stack— layers open as draft PRs; you mark them ready after a look.stack— layers open ready for review immediately.- Emission happens only after the review loop approves. Until then everything is local — no pushes, and force-push doesn't exist in this design.
- If the gh-stack CLI is installed, coop links the layers into a first-class GitHub stack (the stack map in the PR header). Without it the chain still works classically — per-layer diffs and retarget-on-merge — and the run tells you how to link later.
Layer branches are namespaced stack/<feature>/<i>-<workstream>, and the run never touches branches it didn't create. If anything fails mid-emission, the result reports exactly which layers landed — pushed, PR'd, or neither — so recovery is a table, not an archaeology dig.
02 · Read the chip

the status bar — the chip anchors your current branch's PR and shows its position in the stack
The k/n≡ fragment is your layer's position, counted from the trunk. Hover (or focus) the chip for the plain-words version — "stacked PRs — layer 2 of 2, landing on main." When attention is needed somewhere, the chip compresses to keep the flag visible:
| State | Chip |
|---|---|
| Healthy, in a stack | PR #2 · 2/2≡ · open · ✓ mergeable |
| A sibling layer needs someone | PR #102 · 2/3≡ · ⚑ #101 |
| Several layers blocked | PR #102 · 2/3≡ · ⚑ #101 (+1⚑) |
| Your layer: changes requested | PR #102 · 2/3≡ · ⚑ changes |
| Your layer: failing checks | PR #102 · 2/3≡ · ⚑ checks ✕ |
| Your layer: merge conflict | PR #102 · 2/3≡ · ✕ conflicts |
| Your layer merged (pre-retarget) | PR #102 · 2/3≡ · merged |
The chip details at most one blockage — yours outranks a sibling's — and the (+N⚑) overflow guarantees a second blocked layer is never silent. Screen readers hear the whole thing in words, not glyphs.
03 · The ladder

click the chip (or Tab + Enter) — the ladder, top of stack down to the trunk
The cursor opens on your row — Enter opens that PR on GitHub. ↑↓ walk the layers, Home/End jump the rails, Esc closes. Every layer shows its state in words next to the node, so nothing rides on color alone. The ladder shrinks honestly as layers merge and GitHub re-stacks what's above them.
04 · When the ladder goes flat
coop never guesses a ladder. If the chain can't be resolved with certainty, the chip falls back to the ordinary flat PR view — and tells you why, in the chip tooltip and a quiet line in the overlay:
| Cause | Note |
|---|---|
Default branch unknown (no origin/HEAD) | couldn't resolve the repo's default branch |
| A layer isn't in this session's set | a layer in the chain isn't in this session's set |
| Two PRs target the same base | two PRs target the same base |
| The base chain loops | the base chain loops |
05 · The safety model
- Opt-in is the consent. The default finish line never touches the remote. Choosing a stacked mode — per run or in repo config — is the authorization; when it comes from repo config, the run's transcript says so.
- Nothing ships un-reviewed. Emission is gated on the workflow's independent review approving the full diff.
- No force-push, ever. A diverged remote layer stops the run and asks for a human decision.
- No duplicate PRs. Re-runs re-use existing PRs per layer instead of opening new ones.
06 · Good to know
- The stack ladder tracks the PRs your session knows about; a fresh session re-learns them from the current branch and any PR URLs that pass through tool output.
- The ladder refreshes with pr-tracker's normal cadence — after a merge it can take a few minutes to reflect GitHub's re-stacking.
- Works with hand-built stacks too: any chain of PRs whose bases point at each other reads as a ladder, however it was made.