Stacked Git branches and PRs — fast, safe, and built for humans and AI agents.
Install · Quickstart · Commands · Docs
One giant PR is slow to review and risky to merge. A stack of small PRs is the answer — but managing stacks by hand with git rebase --onto is a footgun. stax makes stacks a first-class Git primitive.
- Stack, don't wait. Keep shipping on top of in-review PRs.
st create,st ss, done. - Native-fast. A single Rust binary that starts in ~25ms.
st lsbenches ~16× faster than Graphite/Freephite on this repo. - Agent-native. Run parallel AI agents on isolated branches (
st lane), auto-resolve rebase conflicts (st resolve), and generate PR bodies from real diffs. - Undo-first. Every destructive op snapshots state.
st undo/st redorescue risky rebases instantly. - Batteries-included TUI. Run bare
stto browse the stack, inspect diffs, and watch CI hydrate live.
staxinstalls two binaries:staxand the short aliasst. This README usesst.
The shortest path on macOS and Linux:
brew install cesarferreira/tap/staxOther installation methods — cargo-binstall, prebuilt binaries, Windows, from source
cargo binstall staxDownload the latest binary from GitHub Releases:
# macOS (Apple Silicon)
curl -fsSL https://github.com/cesarferreira/stax/releases/latest/download/stax-aarch64-apple-darwin.tar.gz | tar xz
# macOS (Intel)
curl -fsSL https://github.com/cesarferreira/stax/releases/latest/download/stax-x86_64-apple-darwin.tar.gz | tar xz
# Linux (x86_64)
curl -fsSL https://github.com/cesarferreira/stax/releases/latest/download/stax-x86_64-unknown-linux-gnu.tar.gz | tar xz
# Linux (arm64)
curl -fsSL https://github.com/cesarferreira/stax/releases/latest/download/stax-aarch64-unknown-linux-gnu.tar.gz | tar xz
mkdir -p ~/.local/bin
mv stax st ~/.local/bin/
# Ensure ~/.local/bin is on your PATH:
# echo 'export PATH="$HOME/.local/bin:$PATH"' >> ~/.zshrcWindows (x86_64): download stax-x86_64-pc-windows-msvc.zip from Releases, extract stax.exe and st.exe, and place them on your PATH. See Windows notes.
Prereqs:
- Debian/Ubuntu:
sudo apt-get install libssl-dev pkg-config - Fedora/RHEL:
sudo dnf install openssl-devel - Arch:
sudo pacman -S openssl pkg-config - macOS: OpenSSL included
Then:
cargo install --path . --locked
# or
make installNo system OpenSSL? Use the vendored feature:
cargo install --path . --locked --features vendored-opensslVerify the install:
st --versionst setup handles shell integration, AI agent skills, and GitHub auth in a single step:
st setup --yesAlternative auth options
# Import from GitHub CLI
gh auth login && st auth --from-gh
# Enter a token interactively
st auth
# Or via env var
export STAX_GITHUB_TOKEN="ghp_xxxx"By default stax ignores ambient GITHUB_TOKEN. Opt in with auth.allow_github_token_env = true.
Now ship a two-branch stack end-to-end:
# 1. Stack two branches on trunk
st create auth-api
st create auth-ui
# 2. See the stack
st ls
# ◉ auth-ui 1↑
# ○ auth-api 1↑
# ○ main
# 3. Submit the whole stack as linked PRs
st ss
# 4. After the bottom PR merges on GitHub…
st refresh # sync trunk, restack this stack, update PRs
st refresh --force --yes --no-prompt # same flow without promptsPicked the wrong trunk? Run st trunk main or st init --trunk <branch> to reconfigure.
Next: Quick Start guide · Merge & cascade workflow
Spin up multiple AI agents on isolated branches, all tracked as normal stax branches:
st lane fix-auth-refresh "Fix the token refresh edge case from #142"
st lane stabilize-ci "Stabilize the 3 flaky tests in the checkout flow"
st lane api-docs "Update API docs for the /users endpoint"Each lane is a real Git worktree with normal stax metadata — it appears in st ls, participates in restack/sync/undo, and re-attaches via tmux any time. No hidden scratch directories, no lost work.
st wt # open the worktree dashboard
st wt rs # restack every lane at once when trunk moves
st ss # submit PRs for the ones that are ready→ Agent worktrees · Multi-worktree workflow
Merge from the bottom of the stack up to your current branch, with CI and readiness checks:
st merge # local cascade merge
st merge --when-ready # wait/poll until PRs are mergeable
st merge --remote # merge remotely on GitHub while you keep working
st merge --all # merge the whole stack regardless of positionWhen a rebase stops on a conflict, st resolve sends only the conflicted text files to your configured AI agent, applies the result, and resumes the rebase automatically. If the AI returns invalid output, touches a non-conflicted file, or leaves extra conflicts behind, stax bails out and preserves the in-progress rebase so you can inspect or continue manually.
st resolve
st resolve --agent codex --model gpt-5.3-codexrestack, submit, and reorder each snapshot branch state before they touch anything. Recovery is one command away.
st restack
st undo
st redoBare st launches a full-screen TUI for browsing stacks, inspecting branch summaries and patches, watching live CI hydrate, and running common ops without leaving the terminal.
st generate --pr-body # draft/refresh PR body from branch diff + context
st standup --summary # spoken-style daily engineering summaryEach AI feature (generate, standup, resolve, lane) can use a different agent/model. Configure with:
st config --set-ai→ PR templates & AI · Reporting
| Command | What it does |
|---|---|
st |
Launch interactive TUI |
st ls / st ll |
Show stack (with PR status / with PR URLs and details) |
st create <name> |
Create a branch stacked on current |
st ss |
Submit the full stack, open/update linked PRs |
st merge |
Cascade-merge from bottom to current (--when-ready, --remote, --all) |
st rs / st rs --restack |
Sync trunk, clean merged branches, optionally rebase |
st refresh |
Sync trunk, restack current stack, then push/update PRs |
st refresh --force --yes --no-prompt |
Run refresh without sync or submit prompts |
st refresh --verbose |
Include detailed sync/restack/submit timing |
st restack |
Rebase current stack onto parents locally |
st cascade |
Restack + push + open/update PRs |
st split |
Split a branch into stacked branches (by commit or --hunk) |
st lane <name> "<task>" |
Spawn an AI agent on a new lane |
st wt |
Open the worktree dashboard |
st resolve |
AI-resolve an in-progress rebase conflict |
st generate --pr-body |
Draft/refresh PR body with AI |
st standup |
Summarize recent engineering activity |
st undo / st redo |
Recover / reapply risky operations |
st run <cmd> |
Run a command on each branch in the stack |
st pr / st pr list / st issue list |
Open current PR · list PRs · list issues |
Full reference: docs/commands/core.md · docs/commands/reference.md
Benchmarked with hyperfine on this repo. Absolute times vary by repo and machine; the ratios do not.
| Benchmark | stax | vs Freephite | vs Graphite |
|---|---|---|---|
st ls |
baseline | 16.25× faster | 10.05× faster |
st rs (sync) |
baseline | 2.41× faster | — |
stax is wire-compatible with Freephite/Graphite for common stacked-branch workflows.
→ Full benchmarks · Compatibility notes
st config # open the config editor
st config --set-ai # pick AI agent + model
st config --reset-ai # clear saved AI pairing and re-promptConfig lives at ~/.config/stax/config.toml:
[submit]
stack_links = "body" # "comment" | "body" | "both" | "off"AI and editor integration guides:
Shared skill/instruction file used across agents: skills.md
Windows notes — shell integration, worktrees, tmux
stax runs on Windows (x86_64) with prebuilt binaries on Releases. Most commands work identically, with these limitations:
- Shell integration is not available.
st setupsupports bash/zsh/fish only. On Windows:st wt c/st wt gocreate and navigate worktrees but cannot auto-cdthe parent shell. Manuallycdto the printed path.- The
swquick alias is not available. st wt rm(bare) cannot relocate the shell. Specify:st wt rm <name>.
- Worktree commands still work.
st wt c/go/ls/ll/cleanup/rm/prune/restackall function — only the shell-levelcdis missing. - tmux integration requires WSL or a Unix-like environment.
Everything else — stacked branches, PRs, restack, sync, undo/redo, TUI, AI generation — works on Windows without limitation.
Before opening a PR, run:
make test # or: just testTo cut a release, run:
make release # default minor bump
make release LEVEL=patch
just release-patch # or: just release-minor / just release-majorRelease automation now finalizes the next versioned entry in CHANGELOG.md from commits since the latest v* tag inside cargo release's pre-release hook, refreshes the compare links, and leaves a fresh Unreleased header for follow-up work. If there are no commits since the last tag, the release exits early instead of creating an empty changelog entry.
Project docs and architecture: docs/index.md. Contributor guidelines: AGENTS.md.
MIT © Cesar Ferreira
