/stack
Publish and merge GitHub native stacked pull requests with the `gh stack` extension. Use when a branch is stacked on another branch rather than the default branch, when linking a chain of branches into a stack on GitHub, or when merging a PR that belongs to a stack. Load before
$ npx -y skills add bendrucker/claude --skill stack --agent claude-codeHow 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.
- You can call itInvoke it directly when you want it.
- Slash command
/stack
Context preview
The summary Claude sees to decide when to auto-load this skill.
Publish and merge GitHub native stacked pull requests with the `gh stack` extension. Use when a branch is stacked on another branch rather than the default branch, when linking a chain of branches into a stack on GitHub, or when merging a PR that belongs to a stack. Load before
SKILL.md
stack.SKILL.mdname: github:stack
description: Publish and merge GitHub native stacked pull requests with the `gh stack` extension. Use when a branch is stacked on another branch rather than the default branch, when linking a chain of branches into a stack on GitHub, or when merging a PR that belongs to a stack. Load before running any `gh stack` command.
allowed-tools:
- Bash(gh stack:*)
- Bash(gh pr:*)
- Bash(gh api:*)
Stacked Pull Requests
`gh stack` (the `github/gh-stack` extension) drives GitHub's native stacked PRs. The stack object on GitHub is the same either way, and so is the merge. What differs is where the branches live locally, which decides how the stack gets built and published.
Layouts
**Native tracking** keeps every layer checked out in one working tree. `gh stack` owns the branches, the rebases, and the publish. This is what the extension is built for, and it gets the interactive PR editor, cascading rebase, and one-command sync.
**External tracking** keeps each layer somewhere else, typically its own worktree. Another tool owns the rebases and `gh stack link` publishes the result. `link` is documented for exactly this and writes no local state.
Pick per stack. The choice can differ across stacks in one repository. Native tracking fits a stack you are actively reshaping, where reordering and folding layers matters more than working two layers at once. External tracking fits a stack whose layers are worked on in parallel or over a long stretch, where each layer wants its own checkout, editor, and running services.
Read the current state with `gh stack view --short` (add `--json` to parse it). It answers from local tracking. Output means native tracking, and an error means the stack is not tracked here. That is a statement about this clone, not about GitHub: a stack published by `link` is real on GitHub and still absent from `view`.
Don't mix them for one stack. The local-tracking commands silently under-perform against branches they can't check out. `gh stack rebase` prints `✓ Rebased <branch>` and changes nothing when that branch is checked out in a different worktree ([gh-stack#35](https://github.com/github/gh-stack/issues/35)).
Exit code 9 means the repository doesn't have stacked PRs enabled. Code 6 means a branch belongs to more than one stack, or more than one remote is configured with no `remote.pushDefault` set. `link`, `submit`, `push`, and `sync` take `--remote` for that second case.
Stack numbers and PR numbers come from one sequence per repository and never overlap. A bare number is unambiguous wherever a command takes either.
Detection
Stack membership lives on the API. This query answers with nothing checked out and under either layout, which makes it the right check for anything holding a PR number rather than a branch.
gh api graphql -f query='query($owner:String!,$repo:String!,$number:Int!){repository(owner:$owner,name:$repo){pullRequest(number:$number){stack{number size}}}}' \
-F owner=<owner> -F repo=<repo> -F number=<n>`"stack": null` means the PR isn't stacked. Otherwise `number` is the stack number and `size` its PR count. `gh pr view` has no stack field. This query is the only PR-level answer.
To read the other layers, ask for the entries. `position` counts up from the base, so position 1 is the bottom and the layers below yours are the ones with a lower position.
gh api graphql -f query='query($owner:String!,$repo:String!,$number:Int!){repository(owner:$owner,name:$repo){pullRequest(number:$number){stackEntry{position stack{entries(first:50){nodes{position pullRequest{number state isDraft reviewDecision mergeStateStatus}}}}}}}}' \
-F owner=<owner> -F repo=<repo> -F number=<n>There is no CI field here. `mergeStateStatus` is the proxy. `CLEAN` is mergeable with checks passing. `BLOCKED` is blocked by a rule or a missing review, `UNSTABLE` is a non-passing commit status, `DIRTY` is a conflict, and `BEHIND` is a stale head ref.
Native Tracking
Build the stack with `init` and `add`. `init` adopts branches that exist and creates the ones that don't, bottom to top.
gh stack init auth-layer api-routes ui-components # adopt or create a whole stack
gh stack init --base develop my-feature # non-default trunk
gh stack add -Am "Add rate limiting" rate-limits # new layer on top, committing staged work
`gh stack submit` pushes every branch, opens the missing PRs, fixes the bases, and creates or updates the stack object. Interactively it opens a single-screen editor to write each new PR's title, description, and draft state before submitting them together. Use it whenever the bodies matter, which is most of the time.
Non-interactively, and with `--auto`, it skips the editor and auto-generates titles. It also creates new PRs as **drafts**. Pass `--open` to get PRs that are ready for review.
`gh stack sync` is the maintenance command: fetch, reconcile against the stack on GitHub, fast-forward the trunk, cascade-rebase each branch onto its parent, push atomically with `--force-with-lease`, and link the open PRs into a stack once two exist. It never opens PRs. `--prune` deletes local branches for merged PRs, which is the cleanup after a stack lands.
Use the narrower commands when sync is too much: `gh stack rebase` for the cascading rebase alone (`--downstack`, `--upstack`, `--no-trunk`, and `--continue` / `--abort` around conflicts), and `gh stack push` to push without rebasing. `push` is per-branch and not atomic. A rejected branch leaves the ones before it already updated.
`gh stack modify` restructures the stack interactively: drop, fold, insert, reorder, rename. Run `submit` afterward, since it changes local branches and leaves GitHub behind.
Move around with `gh stack checkout` (bare, for a picker over local and remote stacks), plus `up`, `down`, `top`, `bottom`, `trunk`, and `switch`.
External Tracking
Let the other tool rebase and push the whole stack first. `link
Read more
name: github:stack description: Publish and merge GitHub native stacked pull requests with the `gh stack` extension. Use when a branch is stacked on another branch rather than the default branch, when linking a chain of branches into a stack on GitHub, or when merging a PR that belongs to a stack. Load before running any `gh stack` command. allowed-tools: - Bash(gh stack:*) - Bash(gh pr:*) - Bash(gh api:*)
Stacked Pull Requests
`gh stack` (the `github/gh-stack` extension) drives GitHub's native stacked PRs. The stack object on GitHub is the same either way, and so is the merge. What differs is where the branches live locally, which decides how the stack gets built and published.
Layouts
**Native tracking** keeps every layer checked out in one working tree. `gh stack` owns the branches, the rebases, and the publish. This is what the extension is built for, and it gets the interactive PR editor, cascading rebase, and one-command sync.
**External tracking** keeps each layer somewhere else, typically its own worktree. Another tool owns the rebases and `gh stack link` publishes the result. `link` is documented for exactly this and writes no local state.
Pick per stack. The choice can differ across stacks in one repository. Native tracking fits a stack you are actively reshaping, where reordering and folding layers matters more than working two layers at once. External tracking fits a stack whose layers are worked on in parallel or over a long stretch, where each layer wants its own checkout, editor, and running services.
Read the current state with `gh stack view --short` (add `--json` to parse it). It answers from local tracking. Output means native tracking, and an error means the stack is not tracked here. That is a statement about this clone, not about GitHub: a stack published by `link` is real on GitHub and still absent from `view`.
Don't mix them for one stack. The local-tracking commands silently under-perform against branches they can't check out. `gh stack rebase` prints `✓ Rebased <branch>` and changes nothing when that branch is checked out in a different worktree ([gh-stack#35](https://github.com/github/gh-stack/issues/35)).
Exit code 9 means the repository doesn't have stacked PRs enabled. Code 6 means a branch belongs to more than one stack, or more than one remote is configured with no `remote.pushDefault` set. `link`, `submit`, `push`, and `sync` take `--remote` for that second case.
Stack numbers and PR numbers come from one sequence per repository and never overlap. A bare number is unambiguous wherever a command takes either.
Detection
Stack membership lives on the API. This query answers with nothing checked out and under either layout, which makes it the right check for anything holding a PR number rather than a branch.
gh api graphql -f query='query($owner:String!,$repo:String!,$number:Int!){repository(owner:$owner,name:$repo){pullRequest(number:$number){stack{number size}}}}' \
-F owner=<owner> -F repo=<repo> -F number=<n>`"stack": null` means the PR isn't stacked. Otherwise `number` is the stack number and `size` its PR count. `gh pr view` has no stack field. This query is the only PR-level answer.
To read the other layers, ask for the entries. `position` counts up from the base, so position 1 is the bottom and the layers below yours are the ones with a lower position.
gh api graphql -f query='query($owner:String!,$repo:String!,$number:Int!){repository(owner:$owner,name:$repo){pullRequest(number:$number){stackEntry{position stack{entries(first:50){nodes{position pullRequest{number state isDraft reviewDecision mergeStateStatus}}}}}}}}' \
-F owner=<owner> -F repo=<repo> -F number=<n>There is no CI field here. `mergeStateStatus` is the proxy. `CLEAN` is mergeable with checks passing. `BLOCKED` is blocked by a rule or a missing review, `UNSTABLE` is a non-passing commit status, `DIRTY` is a conflict, and `BEHIND` is a stale head ref.
Native Tracking
Build the stack with `init` and `add`. `init` adopts branches that exist and creates the ones that don't, bottom to top.
gh stack init auth-layer api-routes ui-components # adopt or create a whole stack gh stack init --base develop my-feature # non-default trunk gh stack add -Am "Add rate limiting" rate-limits # new layer on top, committing staged work
`gh stack submit` pushes every branch, opens the missing PRs, fixes the bases, and creates or updates the stack object. Interactively it opens a single-screen editor to write each new PR's title, description, and draft state before submitting them together. Use it whenever the bodies matter, which is most of the time.
Non-interactively, and with `--auto`, it skips the editor and auto-generates titles. It also creates new PRs as **drafts**. Pass `--open` to get PRs that are ready for review.
`gh stack sync` is the maintenance command: fetch, reconcile against the stack on GitHub, fast-forward the trunk, cascade-rebase each branch onto its parent, push atomically with `--force-with-lease`, and link the open PRs into a stack once two exist. It never opens PRs. `--prune` deletes local branches for merged PRs, which is the cleanup after a stack lands.
Use the narrower commands when sync is too much: `gh stack rebase` for the cascading rebase alone (`--downstack`, `--upstack`, `--no-trunk`, and `--continue` / `--abort` around conflicts), and `gh stack push` to push without rebasing. `push` is per-branch and not atomic. A rejected branch leaves the ones before it already updated.
`gh stack modify` restructures the stack interactively: drop, fold, insert, reorder, rename. Run `submit` afterward, since it changes local branches and leaves GitHub behind.
Move around with `gh stack checkout` (bare, for a picker over local and remote stacks), plus `up`, `down`, `top`, `bottom`, `trunk`, and `switch`.
External Tracking
Let the other tool rebase and push the whole stack first. `link
Showing the first part of this file.
My personal plugin marketplace for Claude Code, Anthropic's AI coding assistant.
Repo: bendrucker/claude
Other skills on bendrucker-claude.
- /agent-ideas
Harvest agent-tooling ideas from prominent developers.
Open skill - /cleye
Type-safe CLI argument parsing with cleye, the standard parser for this repo's Bun scripts. Use when writing or editing any script that takes arguments (flags, positional parameters, subcommands, --help) instead of reading existing scripts for the pattern.
Open skill - /coverage
Measure Bun test coverage and close gaps on a specific file. Use when adding or editing tests, when asked about coverage, or when the PostToolUse coverage hook reports uncovered lines.
Open skill - /activity
Report real device usage from ActivityWatch. Covers per-app time, window titles, and active vs idle spans. Use when asked "what apps did I use", "how long was I in X", "what did I work on today", "how much was I active vs idle", or to mine usage patterns for automation.
Open skill - /history
Report shell history from atuin's local capture. Covers what commands ran, when, where, and how they exited. Use when asked "what commands did I run", "what was I working on in the terminal", "have I ever run X", "how do I usually invoke X", or about recent shell activity,
Open skill - /bun
Bun runtime patterns. Use when running bun commands, working with package.json/bun.lock, writing TypeScript scripts under Bun, or developing Claude Code plugins.
Open skill

