Skip to content
Agentmart
Submit a tool

gh-stack

Native stacked pull requests through the github/gh-stack extension.

Skill by sd0xdev

IndexedMIT★ 194
Write a review

Chalk Labs

Need help deploying gh-stack?

Chalk Labs sets up agents like this inside real teams: connected to your tools, tested on your data, with a human in the loop where it matters.

Book a call

Install

Works with Claude Code, Claude apps, Codex, Cursor, Gemini CLI, GitHub Copilot, VS Code, OpenCode, Goose, Windsurf. Read the repository before you give any tool access to your data.

npx agentmarket install skill/sd0xdev-gh-stack

Asks which of your tools to add it to (Claude Code, Codex, Cursor, VS Code, Windsurf, Gemini CLI, Claude Desktop) and shows the change first. See https://agentmart.dev/cli.

Get the weekly diff

The weekly diff: one email a week with new agent tools, notable updates and grade changes, plus security alerts for tools you follow. Double opt-in, one-click unsubscribe.

We use your email only for this newsletter. Privacy

About

Native stacked pull requests through the github/gh-stack extension. Detects the extension, installs it only after the user approves, resolves the branch chain, and executes `gh stack link` / `gh stack push` / `gh stack submit --auto` under a per-use AskUserQuestion gate. Use when: opening or refreshing a native stack of PRs, linking existing PRs into a stack on GitHub, pushing a stack's branches, or when /create-pr --stack delegates the native path here. Not for: a single PR (use /create-pr), pushing one branch (use /push-ci), merging a chain (use /epic-merge), or any history rewrite — `gh stack rebase` / `sync` / `modify` stay the user's to run. Output: stack table + per-command verdict + attribution verify.

Use cases: devops

No reviews yet. Installed it? Reviews come from verified installers only. How reviews work

Permissions

What this skill can do and what it asks for, from its SKILL.md. Checked Oct 25, 2026.

Tools
No tools found
Secrets
None asked for
Install scripts
None found

Network hosts it talks to 1

  • codeload.github.com · found in install command

Files it touches

  • ~/.claude/skills/gh-stack

Tools it pre-approves 11

From allowed-tools in SKILL.md: the agent may use these without asking you each time.

  • Bash(gh:*),
  • Bash(git:*),
  • Bash(bash:*),
  • Bash(/bin/bash:*),
  • Bash(mktemp:*),
  • Bash(rm:*),
  • Read,
  • Write,
  • Grep,
  • Glob,
  • AskUserQuestion

What's inside

Skill name
gh-stack
Description
Native stacked pull requests through the github/gh-stack extension. Detects the extension, installs it only after the user approves, resolves the branch chain, and executes `gh stack link` / `gh stack push` / `gh stack submit --auto` under a per-use AskUserQuestion gate. Use when: opening or refreshing a native stack of PRs, linking existing PRs into a stack on GitHub, pushing a stack's branches, or when /create-pr --stack delegates the native path here. Not for: a single PR (use /create-pr), pushing one branch (use /push-ci), merging a chain (use /epic-merge), or any history rewrite — `gh stack rebase` / `sync` / `modify` stay the user's to run. Output: stack table + per-command verdict + attribution verify.
License
MIT
Allowed tools
Bash(gh:*),, Bash(git:*),, Bash(bash:*),, Bash(/bin/bash:*),, Bash(mktemp:*),, Bash(rm:*),, Read,, Write,, Grep,, Glob,, AskUserQuestion
Instructions
718 lines in SKILL.md · view on GitHub

Before installing

  • Pre-approves some shell commands
  • Instructions read files in your home folder (~/.ssh, ~/.aws…)

Agent Skills spec issues

  • body: 718 lines (spec recommends under 500)
  • files: referenced but missing: scripts/commit-msg-guard.sh

Files (1)

  • SKILL.md

SKILL.md (first lines)

# GH Stack — Native Stacked PRs

**Read first**: `@skills/push-ci/references/authorization-contract.md` before any `gh stack` operation that pushes — § Push safety for the credential and the unshared attestation, § Efficacy Boundary for what the per-use approval authorizes. If that Read fails, stop and report it; run no pushing operation.


Wraps the `github/gh-stack` extension so a branch chain becomes a real **Stack** on GitHub — one PR per layer, chained bases, per-layer diff view, linked merges — instead of the hand-built chained-base PR set `/create-pr --stack` produces on its own.

## Authorization

```
⚠️ This skill is one of the four workflows Anchor Register #4 enumerates (@rules/discretion.md).
⚠️ It may execute exactly three subcommands of the extension — `gh stack link`, `gh stack push`,
   `gh stack submit --auto` — and nothing else from it, `gh stack view` included: `view` syncs PR
   metadata and writes it back into `.git/gh-stack`, so it is not a read. What this skill needs to
   read, it reads without the extension (the first row of the table below).
⚠️ All three push, and they do not push the same way. Read from the extension's source at v0.1.1
   (§ Force form): `link` runs a plain `git push --atomic`; `push` and `submit --auto` run a
   per-branch, value-bearing `git push --force-with-lease=refs/heads/<b>:<sha>`. The approval
   names the form the chosen subcommand uses.
⚠️ Every `gh stack` invocation REQUIRES explicit per-use user approval via AskUserQuestion
   — no flag, no earlier approval and no delegating skill substitutes for it.
⚠️ Every other subcommand is printed for the user to run, never executed.
```

| Operation | Executor | Authorization |
|-----------|----------|---------------|
| `gh --version`, `gh auth status` (exit status only), `gh extension list`, `gh pr list --json`, `gh pr view --json`, `gh api 'repos/{owner}/{repo}/stacks?pull_request=<n>'` (GET), `git rev-parse`, `git merge-base`, and the extension's tracking file `<git-dir>/gh-stack` read with the Read tool | this skill | read-only |
| `gh extension install github/gh-stack` | this skill | Phase 1 AskUserQuestion — **never** installed silently |
| `gh stack link`, `gh stack push`, `gh stack submit --auto` | this skill | Phase 3 per-use AskUserQuestion naming the push form and the branches |
| `gh stack view`, `gh stack rebase`, `gh stack sync`, `gh stack modify`, `gh stack merge`, `gh stack unstack`, `gh stack init`, `gh stack add`, `gh stack checkout` | **user only** — printed, never run | outside the grant |
| `gh pr edit` for an attribution remediation | this skill | `/create-pr` § 7b contract (CLAUDE.md rule 3, Anchor) |
| `git push` by any other route | `/push-ci` | its own workflow |

**Why that split, rather than "whatever the extension offers".** The three granted subcommands move
**remote refs and PR state**; the ungranted ones rewrite **local history** (`rebase`, `sync`,
`modify`), merge PRs (`merge`), or need a TUI no agent can drive (`modify`, `checkout` without an argument, and `submit` without `--auto`). `sync` is the one that reads like a convenience and is not: it fetches, cascade-rebases,
force-pushes and prunes in one call, so approving "a sync" approves a history rewrite nobody has
seen. It stays the user's. `view` is the one that reads like a query and is not: both its `--json`
and its default form sync PR metadata from GitHub and then call `SaveNonBlocking`, which rewrites
`.git/gh-stack` (`cmd/view.go`, v0.1.1). A read that persists state is a mutation of the
extension's own bookkeeping, and nothing in this skill needs it — the file can be read directly,
and the remote Stack has a REST endpoint of its own.

**`gh stack submit` is never run without `--auto`.** Interactively it opens a full-screen editor;
an agent invoking it hangs the session holding an approved force push. Readiness is the same for **both** publishing forms — `gh stack submit --auto` and
`gh stack link` alike create new PRs as **drafts** unless `--open` is passed, and `--open` is carried into the Phase 3 approval — a caller may propose it, this skill does not
execute it unless that approval affirms readiness.

### Push safety — the obligation this skill carries itself

Every granted subcommand pushes, two of them with force, and the `pre-push` hook is **opt-in**
(@rules/git-workflow.md § Push safety). So:

| Obligation | How this skill meets it |
|------------|-------------------------|
| The **unshared attestation** — *is anybody else working on the branches this push rewrites* | For `gh stack push` and `gh stack submit --auto`, Phase 3 asks it **by name and before the force approval**, listing the branches, and refuses the invocation when the answer is not the attestation. An installed hook may ask again over `/dev/tty`; that is defence in depth, never a reason to skip the question, because where the hook is absent nothing else asks. `gh stack link` rewrites nothing: its push carries no force, so a branch that diverged on the remote is refused by git itself and the run stops there (§ Force form) |
| `ALLOW_PUSH_PROTECTED` and `ALLOW_FORCE_UNSHARED` are developer-set only | Never set by this skill, and **cleared on every invocation it executes** — a value exported earlier in the shell answers the hook's question without anybody being asked now |
| `ALLOW_FORCE_WITH_LEASE` | Set **only** on the single approved `gh stack push` or `gh stack submit --auto` line, in the same phase that obtained the force-form approval — the same shape `/push-ci` uses — and **never on `gh stack link`**, which does not force. Without it the hook refuses the force-form push outright, which is a refusal, not an authorization of anything |
| Protected branches | A protected branch (`main`/`master`/`develop`/`release/*`, plus the project's additions — Phase 2's resolver) may be the stack's **base** and may never appear as a stack **layer**. Phase 2 hard-aborts if one does |

**Why this skill is model-invocable when `/push-ci` and `/epic-merge` are not.** Both set
`disable-model-invocation: true`; this one deliberately does not, because `/create-pr --stack`
reaches it through the `Skill` tool and that flag would block the delegation the routing depends on.
The trade is stated rather than silent, and it is a trade rather than an equivalence: the outer stop
those two get from the flag is **not available here**, and what stands in its place is Phase 3's two
questions — which § Efficacy Boundary's caching weakness still reaches, where the flag would not
have. What Phase 3 does hold absolutely is that no caller, flag or earlier turn substitutes for the
question being asked.

### Force form — read from the source, bound to v0.1.1

`ALLOW_FORCE_WITH_LEASE=1` on the executed line silences one refusal in `pre-push-gate.sh`: the
non-fast-forward `exit 1`. That gate's own comment records why the bypass is safe for the other two
workflows — *"Git hooks cannot distinguish `--force` from `--force-with-lease` (same ref data).
Callers … set `ALLOW_FORCE_WITH_LEASE=1` only when `--force-with-lease` is explicitly requested.
**Bare `--force` enforcement is at the caller level.**"* — and **here the caller does not compose
the flag**: the extension does. The push form is therefore a claim about somebody else's code, and
it is stated from that code, not from its README (which describes `link` as if it forced, and does
not):

| Subcommand | The push it issues — `github/gh-stack` v0.1.1 | Source |
|------------|-----------------------------------------------|--------|
| `gh stack link` | `git push <remote> --atomic refs/heads/<b>:refs/heads/<b> …` — **no force**, only the operands that name local branches | `cmd/link.go` `pushBranchArgs` → `git.Push(remote, branches, false, true)` |
| `gh stack push` | `git push <remote> --force-with-lease=refs/heads/<b>:<sha> … refs/heads/<b>:refs/heads/<b> …` — one lease per branch, `<sha>` read from `refs/remotes/<remote>/<b>`, and an empty value (`refs/heads/<b>:`, *must not exist*) for a branch the remote does not have yet. Not atomic | `cmd/push.go` → `internal/git/gitops.go` `Push` with force=true, atomic=false |
| `gh stack submit --auto` | the same form, one branch per `git push` | `cmd/submit.go` → the same `Push` |

Three consequences, each of them contract:

1. **That version issues no bare `--force`, and every refspec is fully qualified** — a branch named
   `+main` stays a ref name and never becomes a force modifier. This is what the grant covers.
2. **The lease is not a sharedness check.** Both forcing subcommands call `FetchBranches`
   immediately before the push, so `<sha>` is whatever the remote held a moment earlier: the lease
   stops a race between that fetch and the push, and nothing else. A collaborator's commits that
   were already on the remote pass it and are overwritten. That is why Phase 3 asks the unshared
   attestation for these two subcommands, and why a lease being present is never a reason to skip it.
3. **The reading is bound to the version it was read from.** Phase 0 records the installed version
   (`GH_STACK_VERSION`). On anything other than `v0.1.1` the push form is **unverified**, and an
   unverified push form cannot be approved: **every mutating run stops before Phase 3** and reports
   the version it found. A trace is no substitute — `GIT_TRACE=1` records a push that has already
   happened, so a bare `--force` it revealed would already be on the remote; and `GH_DEBUG` logs API
   traffic, not the subprocess argv. The way back is a maintainer reading that version's sources —
   the files the table above cites — and moving the pinned version here and in
   `test/skills/gh-stack.test.js` together. A bare `--force` or an unqualified refspec found in
   **any** version is outside the grant: this skill stops using that subcommand and reports to the
   maintainer — no per-use approval can cover it.

**The push is not the whole of what these subcommands change, and the approval has to cover all of
it.** Read from the same sources, the complete mutation surface of the three at v0.1.1:

| Subcommand | Changes beyond the push |
|------------|-------------------------|
| `gh stack link` | creates a PR for every branch operand without one (draft unless `--open`); **retargets the base** of an existing PR that is not on the expected one; marks existing drafts ready under `--open`; creates the Stack or appends to the one a PR already belongs to. It *refuses* merged, closed, queued and auto-merge PRs rather than changing them |
| `gh stack push` | fetches the stack's branches, then writes `.git/gh-stack`. Its own modify guard refuses only a modify that is `applying` or in `conflict` — a `pending_submit` state passes it, and so does a state file it cannot read (`internal/modify/state.go` `CheckStateGuard`); `push` does not unstack anything, so that state is no hazard to it |
| `gh stack submit --auto` | **resolves a pending `gh stack modify` first — non-interactively, by unstacking the Stack recorded in `<git-dir>/gh-stack-modify-state`, which need not be the one being submitted**; fetches; per layer pushes, then **disables auto-merge** on an existing PR, retargets its base when the stack is not yet on GitHub, marks drafts ready under `--open`, or creates the PR with generated text; creates or extends the Stack; writes `.git/gh-stack` |

Every row is a state change the approval names (Phase 3), except the pending-modify resolution,
which this skill refuses rather than approves (Phase 2): deleting a Stack is outside the grant. The
extension only **warns** when a base retarget, an auto-merge change or a ready-marking fails, and
still exits `0` — which is why Phase 4 reads every one of them back instead of trusting the exit.

From sd0xdev/sd0x-harness, MIT.

Signals

Stars
194
Forks
26
Open issues
5
Last commit (this folder)
Sep 26, 2026 (1 month ago)
Last release
Oct 6, 2026 (26 days ago)

From GitHub (fetched Oct 24, 2026).

Details

License
MIT
First seen
Oct 24, 2026
Last checked
Oct 24, 2026

More from sd0xdev

Done for you

Rather not set it up yourself?

Chalk Labs scopes, builds and runs agents for your team: the task audit, the eval harness, the integrations and the weekly ops report. Fixed scope, priced before we start.

See how we build AI agents →Read the case studies

Chalk Labs is a two-founder AI and growth studio. We build AI agents, CRMs and MVPs for Web3 and AI companies, and have shipped 50+ product and token launches.

launches shipped
50+
launches shipped
media placements
500+
media placements
founders on every account
2
founders on every account

Press we've placed: Forbes · CoinDesk · Decrypt · Cointelegraph · The Block

Rahil Jain, Co-founder, Chalk Labs. Ex-Goldman Sachs engineer. You talk to the person who builds it.

Get gh-stack running in your business

Tell us what you want to automate. A founder replies within one working day with a plan, not a pitch deck.

Goes to the Chalk Labs founders, not the newsletter. Privacy

Need help deploying gh-stack?

CallGet help
Cite this page

gh-stack skill. Agent Mart. https://agentmart.dev/skills/sd0xdev-gh-stack (last updated 2026-10-24)