Skip to content

feat(claude-code): bake gh-stack extension and add stacked-PRs skill - #167

Merged
gatezh merged 2 commits into
masterfrom
feat/gh-stack
Sep 23, 2026
Merged

gatezh merged 2 commits into
masterfrom
feat/gh-stack

Conversation

@gatezh

@gatezh gatezh commented Sep 23, 2026

Copy link
Copy Markdown
Owner

What

Bakes the official github/gh-stack gh extension into the claude-code images and the repo-root devcontainer, and adds a stacked-prs skill that tells agents to use native stacked PRs.

Why

Agents fell back to hand-chaining PRs with gh pr create --base, and GitHub can't merge that kind of chain atomically. A runtime gh extension install writes to ~/.local/share/gh on the container overlay, and only ~/.config/gh is a volume, so the extension disappears on every rebuild. In claude-sandbox the firewall probably blocks the runtime install too. Installing at build time fixes both problems.

Changes

  • Dockerfiles: claude-code/.devcontainer/Dockerfile (in base, so both default and sandbox get it) and the root .devcontainer/Dockerfile run gh extension install github/gh-stack --pin "v${GH_STACK_VERSION}" as node.

    • In claude-code, the step sits just before the Claude Code install, so daily claude-code bumps don't re-run it.
    • A comment says that a volume over ~/.local/share/gh would hide the baked copy.
  • Renovate: GH_STACK_VERSION gets a # renovate: datasource=github-releases depName=github/gh-stack annotation. The ARG holds the bare version, like GH_VERSION, and extractVersion strips the v. github/gh-stack joins the "devcontainer tools" group, which auto-merges after a 3-day soak.

  • CI: gh stack --version is added to the claude-code verify commands in ci.yml (PR time) and build-claude-code.yml (post-build, amd64 and arm64, both variants).

  • Skill: new claude-code/.claude/skills/stacked-prs/SKILL.md covering:

    • init/add/submit --auto for new work
    • link <bottom>…<top> for PRs that already exist
    • merge <pr> --yes for an atomic merge up to that PR
    • the non-interactive flags and --remote when there are several remotes
    • never hand-chaining --base PRs

    It is named stacked-prs so it doesn't clash with the upstream gh-stack skill, which it points to. The skill is added to the devcontainer-upstream-sync manifest, and that skill goes to version 1.2.0.

  • Docs: claude-code/README.md gets a What's Included row, the Automatic Rebuilds list, a skill section, the file tree and the Build Args table. The root README's Renovate paragraph also mentions gh-stack.

Notes

  • gh extension install works without authentication at build time. It was checked in a container from the published image with no GH_TOKEN (exit 0, gh stack --version → gh stack version 0.1.1). It does call api.github.com without a token, so the 60 requests/hour per-IP rate limit applies during the build.
  • The verify step uses gh stack --version rather than gh extension list, because gh extension list fails without gh auth.
  • The release publishes no checksums file, only API asset digests. The install is pinned by tag, and there is no checksum verification, the same as rtk, ralphex and the gh .deb.
  • The firewall allowlist option from the issue is out of scope.
  • Not built locally: Docker Desktop's VM disk on the dev host was full, so no image build ran. hadolint 2.12.0 (CI's version), actionlint and renovate-config-validator all pass, and the install and every skill command were checked in a container from the published image. CI's build-and-verify is the first full build.
  • Merge order with feat(claude-code): upgrading-dependencies skill; sync skill 1.2.0 #136: both PRs bump devcontainer-upstream-sync to 1.2.0. Whichever merges second should bump to 1.3.0.

Fixes #160

Agents in claude-code containers fell back to hand-chaining PRs with
`gh pr create --base`, which GitHub cannot merge atomically. Native stacks
need the github/gh-stack extension, but a runtime `gh extension install`
writes to ~/.local/share/gh on the container overlay (only ~/.config/gh is
a volume), so it vanished on every rebuild. A runtime install is also
likely blocked by the sandbox firewall (release-assets.githubusercontent.com).

- Install gh-stack at build time as node in both the claude-code image
  (default + sandbox, via base) and the repo-root devcontainer. The install
  works unauthenticated. Pinned via GH_STACK_VERSION with a renovate
  annotation, grouped with the other devcontainer tools (3-day soak).
- Assert `gh stack --version` in the PR-time and post-build verify steps.
  `gh extension list` is not usable there: it requires gh auth.
- Add a stacked-prs skill: gh stack init/add/submit for new work, link for
  existing PRs, merge <pr> --yes for atomic merges, the non-interactive
  flags, and never hand-chain --base PRs. Track it in the
  devcontainer-upstream-sync manifest (skill bumped to 1.2.0).
- Document the extension, arg and skill in the READMEs.

Fixes #160
# Conflicts:
#	.github/workflows/build-claude-code.yml
#	.github/workflows/ci.yml
@gatezh
gatezh merged commit fe6f63e into master Sep 23, 2026
11 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[FEATURE] Bake gh-stack into the claude-code image and tell agents about native PR stacks

1 participant