Why stax
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 ~70× faster than Graphite and ~215× faster than Freephite on this repo. - Agent-native. Run parallel AI agents on isolated branches (
st lane), auto-resolve rebase conflicts (st resolve), and generate branch names, commit messages, and PR details from real diffs. - GitHub-native stacks, automatically. When your repo has GitHub's native Stacked PRs enabled and
github/gh-stackis installed,st ssregisters the stack with GitHub under the hood — zero config, zero extra commands. See Native GitHub Stacked PRs. - 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.
Install
The shortest path on macOS and Linux:
cargo-binstall
Prebuilt binaries
Download the latest binary from GitHub Releases:
# macOS (Apple Silicon)
|
# macOS (Intel)
|
# Linux (x86_64)
|
# Linux (arm64)
|
# Ensure ~/.local/bin is on your PATH:
# echo 'export PATH="$HOME/.local/bin:$PATH"' >> ~/.zshrc
Windows (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.
Build from source
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:
# or
No system OpenSSL? Use the vendored feature:
Verify the install:
Native macOS GUI
Download the architecture-specific app from the same GitHub Release as the CLI. For Apple Silicon:
On an Intel Mac, use Stax-x86_64-apple-darwin.zip instead. The app is a separate release artifact, not a new crates.io package, and installing it does not enlarge the stax or st CLI binaries.
Unsigned releases are supported. Download only from the project Releases page, move the app to /Applications, then Control-click Stax.app, choose Open, and choose Open again. If macOS still blocks the first launch, use System Settings → Privacy & Security → Open Anyway for Stax. Do not disable Gatekeeper globally. Releases open normally when the optional signing and notarization credentials are configured.
Contributors can also build or install the app locally:
The bundle id is com.cesarferreira.stax. st gui [path] is macOS-only; it canonicalizes the supplied path, defaults to the current directory when omitted, and launches LaunchServices as open -n -b com.cesarferreira.stax --args <canonical-path>. The -n flag is intentional: every invocation starts a fresh app process/window for exactly one repository.
Quickstart
st setup handles shell integration, AI agent skills, and GitHub auth in a single step:
# Import from GitHub CLI
&&
# Enter a token interactively
# Or via env var
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
# 2. See the stack
# ◉ auth-ui 1↑
# ○ auth-api 1↑
# ○ main
# 3. Submit the whole stack as linked PRs
# 4. After the bottom PR merges on GitHub…
Picked the wrong trunk? Run st trunk main or st init --trunk <branch> to reconfigure.
Next: Quick Start guide · Merge & cascade workflow
Highlights
Parallel AI lanes
Spin up multiple AI agents on isolated branches, all tracked as normal stax branches:
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.
Lanes start warm: instead of deleting a removed worktree, stax parks it as a reusable warm slot (resetting it to trunk and running git clean -fd, which keeps gitignored dependency directories like node_modules or .venv). The next lane adopts that slot instead of a cold checkout, so agents keep their built deps and don't re-install from scratch. Set worktree.reconcile to re-sync deps on adopt, or worktree.reuse_slots = false to opt out.
→ Agent worktrees · Multi-worktree workflow
Native GitHub Stacked PRs
When a GitHub repo has native Stacked PRs enabled, stax can register your submitted PRs as a native GitHub Stack automatically. This requires GitHub's github/gh-stack CLI extension — install it once:
# or let stax install it for you:
That's it — no config needed. From then on, st ss/st bs auto-link multi-PR stacks under the hood, no extra command required. Existing stax PR body/comment stack links keep working; the native GitHub stack map is added on top.
Repos without the feature, users without the extension, and non-GitHub remotes keep the existing stax behavior — this is purely additive and never blocks a submit. stax also strips ambient GH_TOKEN/GITHUB_TOKEN before talking to gh stack, since GitHub's private-preview native-stack API rejects Personal Access Tokens and only accepts an OAuth-authenticated gh login (gh auth login). st doctor recommends gh-stack v0.0.6+ for reliable auth-error diagnostics, and reports whether the extension is missing, outdated, or up to date. st stack unlink delegates to gh stack unstack, so stacks that stax registered with gh stack link may need gh stack checkout <pr> first to create gh-stack's local tracking; otherwise remove the native stack in the GitHub UI.
Cascade stack merge
Merge from the bottom of the stack up to your current branch, with CI and readiness checks:
AI conflict resolution
When 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.
Before each rebase, stax also runs a preflight repair that compares the
stored parent boundary against merge-base(parent, branch). When they diverge
sharply — the “my restack hit conflicts on files I never touched” case — stax
automatically uses the merge-base boundary for that rebase and prints a
one-line notice. Silence the notice with [restack] preflight_warn = false or
--quiet; disable the automatic correction with
[restack] preflight_auto_repair = false.
Undo / redo
restack, submit, and reorder each snapshot branch state before they touch anything. Recovery is one command away.
Interactive TUI
Bare st launches a full-screen TUI for browsing stacks, inspecting branch summaries and cached patches, watching live CI hydrate, and running common ops without leaving the terminal. Stack/Summary/Patch pane visibility is remembered per repo.
Native macOS GUI
The native GUI opens a repository-scoped workspace with searchable Stack, Changes, and Inspector panes. It can check out, create, rename, delete, move, and reorder local branches; restack the selected branch or all tracked branches; submit the current stack as Draft; open the selected PR; and safely undo or redo fully local recorded operations. Destructive and history-rewriting actions show exact previews and confirmations, including explicit auto-stash follow-ups for dirty move/reorder/restack flows.
When the app starts without an explicit path, it reopens the most recently used project. Use the project dropdown in the toolbar to switch between recent projects or choose Add Project… to open another repository. An explicit st gui <path> launch still opens that repository.
Use / to search, 1/2/3 to toggle panes, and drag dividers to resize them; visibility and widths persist per canonical repository. Native menus and keyboard shortcuts dispatch the same typed actions as the buttons. Submit is always confirmed first, pushes the current stack as Draft, and does not show CLI prompts or auto-open PR pages. st gui [path] only launches the app.
AI branch names, PR details, and standups
Each AI feature (generate, standup, resolve, lane) can use a different agent/model. st create --ai, st submit --ai, and st generate / st gen (PR body/title, commit message) share the generate setting. Configure with:
→ PR templates & AI · Reporting
Commands
| Command | What it does |
|---|---|
st |
Launch interactive TUI |
st gui [path] |
Launch the installed native macOS GUI for a repository |
st ls / st ll |
Show stack health and PR status (st ll adds PR URLs/details) |
st watch |
Live auto-refreshing stack status with CI and PR state (adaptive polling: 15s active CI → 60s open PRs → 120s idle) |
st watch --current |
Watch only the current stack |
st create <name> / st add <name> |
Create a branch stacked on current |
st create --ai -a --yes |
Generate branch name + first commit message |
st create <name> --below |
Insert a new branch below current, carrying tracked/untracked prepared changes with it |
| `st get [branch | PR]` |
st ss |
Submit the full stack, open/update linked PRs; temporary-publishes branches that need restack |
st submit --plan [--json] |
Preview fetch, push, PR, retarget, metadata, and stack-link actions without changing local or remote state |
st branch submit |
Submit only the current branch; can publish a temporary rebased head when needed |
st upstack submit |
Submit current branch and descendants, chaining temporary publish heads when needed |
st reviews --stack [--json] |
Stack-wide review/comment inbox, including inline file/line locations on GitHub (st comments remains the current-PR view) |
st next |
Move to the next unmerged branch upstack; fork choices are deterministic |
st merge |
Cascade-merge from bottom to current (--when-ready, --downstack-only/--ds, --stack, --stack --full, --remote, --all) |
st ready |
Interactive PR readiness dashboard for all tracked PRs, newest changed PR first: merge, ping, fix, wait, or draft (--current/--stack for current stack, --plain for table output) |
st ci / st ci --oneline |
CI status — full per-check table, or one compact line per branch across the stack (multi-branch defaults to the roll-up) |
st ci -w --alert |
Watch CI until all checks finish, then play success/error sounds |
st ci -w --strict |
Watch CI but exit as soon as any check fails |
st rs / st rs --restack |
Sync trunk, clean merged branches, optionally rebase |
st sweep |
Classify all local branches (merged/gone/stale/active); --delete removes merged branches (including tracked merged PRs) and upstream-gone branches with no unique work |
st update |
Sync trunk without merged-branch cleanup, restack current stack, then push/update PRs |
st update --force --yes --no-prompt |
Run update without sync or submit prompts |
st update --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 wt promote |
Retire the current lane and check its branch out in the main worktree |
st resolve |
AI-resolve an in-progress rebase conflict |
st create --ai |
Generate a branch name from local changes |
st gen / st generate |
AI: interactive picker, or --pr-body / --pr-title / --commit-msg |
st ss --ai |
Submit with AI-generated PR title/body suggestions |
st standup |
Summarize recent engineering activity |
st tmux status |
Print a tmux-formatted status string (branch, stack position, PR, CI) for status-right |
st tmux popup |
Open stax watch --current in a floating tmux panel |
st undo / st redo |
Recover / reapply risky operations |
st run <cmd> |
Run a command on each branch in the stack |
st run --parallel --jobs 4 <cmd> |
Run checks concurrently in isolated temporary worktrees without switching the main worktree; each command receives STAX_RUN_BRANCH |
st freeze / st unfreeze |
Protect/unprotect a tracked branch from restacks, imported-branch refreshes, and squash-merge cleanup rebases |
st completions <shell> |
Generate completions for Bash, Zsh, Fish, PowerShell, or Elvish |
st doctor --fix |
Check repo/config health and apply safe local repairs after one confirmation |
st draft [branch] / st undraft [branch] |
Toggle a PR between draft and ready-for-review |
st pr / st pr body / st pr list / st pr list --ready / st issue list |
Open current PR · view/edit PR body · list PRs · PR readiness · list issues |
Full reference: docs/commands/core.md · docs/commands/reference.md
Performance
Benchmarked with hyperfine on this repo. Absolute times vary by repo and machine; the ratios do not.
Run make benchmark-status for deterministic cold 10/50/100-branch scaling
fixtures, or add global --trace to a command to see instrumented Git
subprocess and wall-clock timings.
| Benchmark | stax | vs Freephite | vs Graphite |
|---|---|---|---|
st ls |
baseline | 214.76× faster | 69.72× faster |
st rs (sync) |
baseline | 2.41× faster | — |
stax is wire-compatible with Freephite/Graphite for common stacked-branch workflows.
→ Full benchmarks · Compatibility notes
Configuration
Config lives at ~/.config/stax/config.toml. When STAX_CONFIG_DIR is unset,
a repo-root stax.toml overlays only the values it sets:
[]
= "body" # "comment" | "body" | "both" | "off"
= "on" # "on" | "off" — when "off", skip stack-link sync while only one PR exists
Integrations
tmux
stax.tmux is a TPM-compatible plugin that puts your stack in the tmux status bar and adds keybindings for common actions:
- Live status bar — branch, stack position, PR state, CI state; auto-refreshes in the background
- Keybindings —
prefix + Spopup,prefix + ]/[up/down,prefix + M-ssync - Window auto-rename — tmux window title follows the current branch
Install via TPM:
set -g @plugin 'cesarferreira/stax.tmux'
See the stax.tmux README for full setup and configuration options.
AI and editor integration guides:
Shared skill/instruction file used across agents: skills.md
st changelog can generate notes between refs, and st changelog find [query]
or st changelog --find [query] fuzzy-finds commits in the selected range.
Use --path to scope either mode to a subdirectory.
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.st wt promoteperforms the handoff but likewise requires the printedcdcommand.- 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/promote/cleanup/rm/prune/restackall function — only the shell-levelcdis missing. - tmux integration requires WSL or a Unix-like environment. The stax.tmux plugin is Unix-only.
Everything else — stacked branches, PRs, restack, sync, undo/redo, TUI, AI generation — works on Windows without limitation.
Contributing
Before opening a PR, run:
On macOS this uses Docker when available. make test-native is the guarded
fallback: it checks the file-descriptor limit, sanitizes the environment, and
runs nextest with the optimized test profile. Native macOS timings can still
vary substantially with endpoint-security tooling, so Docker remains the
recommended full-suite path.
To cut a release, run:
Release automation regenerates CHANGELOG.md with git-cliff inside cargo release's pre-release hook, grouping the commits since the latest v* tag under the new version (config in cliff.toml). See docs/workflows/releasing.md.
Project docs and architecture: docs/index.md. Contributor guidelines: AGENTS.md.
License
MIT © Cesar Ferreira