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. - 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
# or
No system OpenSSL? Use the vendored feature:
Verify the install:
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.
→ Agent worktrees · Multi-worktree workflow
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.
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 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> |
Fetch a remote branch, create a local upstream-tracking branch, track it in stax as imported, and check it out |
st ss |
Submit the full stack, open/update linked PRs |
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 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 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.
| 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. 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. 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:
To cut a release, run:
Release 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.
License
MIT © Cesar Ferreira