Gemini got a little aggressive with the description, but I've been running into gh stack sync hanging in my coding agent (Google internal build of Antigravity).
Environment
Issue 1: Bare gh stack sync blocks on ? Prune N merged branches? (Y/n) in PTY-based agent harnesses (and contradicts skills/gh-stack/SKILL.md)
In skills/gh-stack/SKILL.md, the Non-interactive use section specifically warns that AI agent harnesses allocate a PTY (stdout is a TTY):
gh stack branches on whether stdout is a TTY. Piped, most commands error cleanly or print static text; under a PTY the same commands open a prompt or a full-screen TUI and block forever. Agent harnesses differ, so always pass the flags below instead of relying on that detection.
However, under Staying in sync, SKILL.md instructs agents to run bare gh stack sync:
gh stack sync # fetch, reconcile with GitHub, rebase, push, refresh PR state
gh stack sync --prune # also delete local branches for merged PRs
Pruning never happens without `--prune` when non-interactive.
What happens in practice
When an agent runs bare gh stack sync inside a PTY-based terminal harness on a stack where one or more lower PRs have been merged on GitHub, gh stack sync sees isatty(stdout) == true and blocks waiting for interactive input:
? Prune 4 merged branches? (Y/n)
Additionally, gh stack sync only offers a boolean --prune flag—there is no --no-prune (or --yes) flag to run gh stack sync under a PTY without pruning and without prompting.
Suggested Fix
- Add
--no-prune (or --prune=false) to gh stack sync so callers under a PTY can explicitly opt out of both pruning and the interactive (Y/n) prompt.
- Update
skills/gh-stack/SKILL.md (and the "Always run / Never run bare" table) to instruct agents to always pass gh stack sync --prune (or --no-prune) rather than bare gh stack sync.
Issue 2: gh stack sync fails to push with --force-with-lease if branches were already rebased via gh stack rebase
gh stack sync --help states that step 5 pushes with --force-with-lease:
- Pushes all branches atomically (using
--force-with-lease --atomic)
However, if a user or agent rebases locally first (for example, when resolving a rebase conflict via gh stack rebase --upstack -> git add -> gh stack rebase --continue, as instructed by gh stack's conflict recovery message) and then runs gh stack sync:
gh stack sync sees that the local branches are already rebased onto origin/main, so step 4 (cascade rebase) is a no-op.
- Step 5 then attempts a regular (non-force) push instead of
--force-with-lease, which fails:
Skipping 4 merged branches
Pushing 7 branches to origin...
⚠ Push failed — branches may need force push after rebase
Run `gh stack push` to push with --force-with-lease.
Expected Behavior
gh stack sync should push active stack branches using --force-with-lease --atomic even when the rebase happened in a prior gh stack rebase step rather than inside the gh stack sync invocation itself.
Gemini got a little aggressive with the description, but I've been running into
gh stack synchanging in my coding agent (Google internal build of Antigravity).Environment
gh stackversion:v0.1.1Issue 1: Bare
gh stack syncblocks on? Prune N merged branches? (Y/n)in PTY-based agent harnesses (and contradictsskills/gh-stack/SKILL.md)In
skills/gh-stack/SKILL.md, the Non-interactive use section specifically warns that AI agent harnesses allocate a PTY (stdoutis a TTY):However, under Staying in sync,
SKILL.mdinstructs agents to run baregh stack sync:What happens in practice
When an agent runs bare
gh stack syncinside a PTY-based terminal harness on a stack where one or more lower PRs have been merged on GitHub,gh stack syncseesisatty(stdout) == trueand blocks waiting for interactive input:Additionally,
gh stack synconly offers a boolean--pruneflag—there is no--no-prune(or--yes) flag to rungh stack syncunder a PTY without pruning and without prompting.Suggested Fix
--no-prune(or--prune=false) togh stack syncso callers under a PTY can explicitly opt out of both pruning and the interactive(Y/n)prompt.skills/gh-stack/SKILL.md(and the "Always run / Never run bare" table) to instruct agents to always passgh stack sync --prune(or--no-prune) rather than baregh stack sync.Issue 2:
gh stack syncfails to push with--force-with-leaseif branches were already rebased viagh stack rebasegh stack sync --helpstates that step 5 pushes with--force-with-lease:However, if a user or agent rebases locally first (for example, when resolving a rebase conflict via
gh stack rebase --upstack->git add->gh stack rebase --continue, as instructed bygh stack's conflict recovery message) and then runsgh stack sync:gh stack syncsees that the local branches are already rebased ontoorigin/main, so step 4 (cascade rebase) is a no-op.--force-with-lease, which fails:Expected Behavior
gh stack syncshould push active stack branches using--force-with-lease --atomiceven when the rebase happened in a priorgh stack rebasestep rather than inside thegh stack syncinvocation itself.