Full command reference¶
The complete command surface. For day-to-day commands only, see Core commands. For navigation specifically, see Navigation.
Global diagnostics¶
Add --trace before or after any subcommand to print instrumented Git
subprocess timings, the summed Git time, and command wall time. URL- and
token-shaped arguments are redacted.
st --trace status --json >/dev/null
Stack operations¶
| Command | Alias | Description |
|---|---|---|
st status |
ls |
Show stack |
st ll |
Show stack with PR URLs and full details | |
st log |
l |
Show stack with commits and PR info |
st submit |
ss |
Submit full current stack |
st stack link |
Register the current PR stack as a native GitHub Stack via gh stack link |
|
st stack unlink [<stack-number>] |
Unstack a remote native Stack by number, or the active locally tracked stack when omitted | |
st merge |
Cascade-merge from bottom to current (see flags below) | |
st merge-when-ready |
mwr |
Backward-compatible alias for st merge --when-ready |
st sync |
rs |
Pull trunk, delete merged branches (incl. squash merges), reparent children |
st sync --restack |
rs --restack |
sync plus rebase current stack onto updated parents |
st sync --delete-upstream-gone |
Also delete local branches whose upstream tracking ref is gone | |
st sync --stash |
rs --stash |
Stash the current working tree before sync starts without prompting; works with --quiet and --json; does NOT auto-confirm branch deletions; conflicts with --no-stash at parse time |
st sync --no-stash |
rs --no-stash |
Fail if the working tree is dirty; overrides --force; conflicts with --stash at parse time |
st sync --dry-run / st sync --plan |
Preview what sync would do — ls-remote only, no fetch/stash/ref-writes/push/metadata writes; always exits 0; composes with --restack, --delete-upstream-gone, --safe; --force, --auto-stash-pop, --full, --stash, --no-stash, and --verbose emit a warning and are otherwise ignored; --continue is rejected |
|
st sync --dry-run --json |
Same as --dry-run but emits a single JSON document (kind: "sync_plan", schema_version: 1, dry_run: true) instead of human text |
|
st sync --json |
Emit the sync result as a single JSON document (kind: "sync", schema_version: 1); implies non-interactive; failures emit JSON + non-zero exit; conflicts with --continue |
|
st sweep |
Classify all local branches as merged / upstream-gone / stale / active (read-only by default) | |
st sweep --delete |
Delete merged branches (including tracked merged PRs) and upstream-gone branches with no unique work after confirmation | |
st sweep --delete --include-stale |
Also delete stale branches (older than --stale-days / branch.stale_days config key) |
|
st sweep --delete --force |
Skip confirmation prompt | |
st sweep --stale-days <N> |
Override stale threshold in days (default: 30) | |
st sweep --json |
Machine-readable branch classification (conflicts with --delete) |
|
st stats |
Single-screen, local-only snapshot of stacking health (stack shape, PR mix, health, worktrees, hygiene, next action); --current scopes to the current stack |
|
st stats --json |
Machine-readable RepoStats document |
|
st stats --ci |
Add an opt-in CI roll-up (network call, reuses the standup CI pattern); omitted (and non-fatal) without forge auth | |
st refresh |
r |
Sync trunk without merged-branch cleanup, restack, then push and create/update PRs for the current stack (pass --delete-merged to opt into sync-style cleanup) |
st refresh --force --yes --no-prompt |
Run the full refresh flow without sync or submit prompts | |
st refresh --verbose |
Same as st refresh, with detailed sync/restack/submit timing |
|
st refresh --all-stacks |
Refresh every stack in the repo (fetch/trunk sync once, then restack + submit each stack); stops at the first conflict | |
st restack |
Rebase current stack locally — auto-normalizes missing/merged parents; --stop-here limits scope |
|
st cascade |
Restack the stack and submit updates, without fetching trunk (offline-friendly) | |
st diff |
Show per-branch diffs vs parent | |
st range-diff |
Show range-diff for branches needing restack | |
st stack |
s |
Stack command namespace for submit and restack (st stack submit, st stack restack) |
st merge variants¶
st merge— local cascade merge with provenance-aware descendant rebases, thenst rs --forceunless--no-syncst merge --when-ready— wait for CI + approvals + mergeability; incompatible with--dry-run,--no-wait,--remote, and--queuest merge --downstack-only/--ds— merge ancestors below the current branch, then rebase the current branch onto trunk; composes with--stack, and is incompatible with--all,--full,--remote, and--queuest merge --stack— GitHub/GitLab stack merge: target every selected PR/MR to trunk, merge only the selected tip with SHA-preservingmerge, and poll lower items for authoritative merged state; timed-out items stay open. Multi-PR GitHubrebase/squashfails before mutation because rewritten SHAs prevent genuine lower-PR merged state; a single selected GitHub PR may still use them. GitLab first verifies project merge settings, sendssquash: false, and rejects explicitrebase/squash. Gitea/Forgejo is unsupportedst merge --stack --full— include descendants above the current branch and land the full stack through the actual stack tipst merge --remote— merge entirely via GitHub API, no local git operations (GitHub only)st merge --queue— enqueue PRs into GitHub merge queue / GitLab merge trains, polling only within the configured timeout deadline
See also: Merge and cascade
Navigation¶
| Command | Alias | Description |
|---|---|---|
st checkout |
co, bco |
Interactive branch picker |
st trunk |
t |
Switch to trunk (or set trunk with st trunk <branch>) |
st up [n] |
u |
Move up to child |
st down [n] |
d |
Move down to parent |
st top |
Stack tip | |
st bottom |
Stack base | |
st prev |
p |
Toggle to previous branch |
st next |
n |
Move to the first unmerged branch upstack (deterministic on forks) |
Branch management¶
| Command | Alias | Description |
|---|---|---|
st create <name> |
c, add, bc |
Create stacked branch (TTY menu when nothing staged and -m) |
st create --ai |
Generate a branch name from local changes (-a also generates a first commit message) |
|
st create <name> --below |
Insert a new branch below current | |
st get [branch|PR] |
Sync current stack, or fetch, sync/create, checkout, and track a remote branch/PR | |
st modify |
m |
Amend staged changes into current commit (-a stages all, -r restacks after) |
st rename |
Rename current branch | |
st move [target] |
mv |
Move the current branch and descendants onto a new parent (st upstack onto parity alias; picker when omitted) |
st branch track |
Track an existing branch | |
st branch track --all |
Track every untracked non-trunk local branch under its nearest cycle-safe strict local ancestor | |
st branch track --all-prs |
Track all open PRs (GitHub, GitLab, Gitea); sets upstream on branches it fetches | |
st branch untrack |
ut |
Remove stax metadata |
st branch reparent |
Change parent | |
st branch submit |
bs |
Submit current branch only; can temporarily restack the publish head when the excluded parent is remote-synced |
st branch delete |
Delete branch | |
st fold / st branch fold |
b f |
Fold current branch into its parent (preserves commits, reparents descendants, rebases siblings; --keep keeps current name) |
st branch squash |
Squash commits | |
st detach |
Remove branch from stack, reparent children | |
st reorder |
Interactively reorder branches in stack | |
st absorb |
Distribute staged changes to the correct stack branches (file-level) |
st branch track --all is local and metadata-only: it does not contact a forge,
fetch or change remotes/upstreams, load remote configuration, or switch branches.
It snapshots the untracked non-trunk local branches before writing metadata and
leaves existing tracked metadata and the trunk untouched. For each target, it
chooses the cycle-safe strict local ancestor with the fewest commits between
that ancestor and the target, breaking equal-distance ties lexically by branch
name. Non-trunk branches at the same commit are never selected as one another's
parent. When no cycle-safe strict local ancestor exists, including for unrelated
histories, the branch is parented to trunk; trunk remains the fallback root even
when it points at the same commit. --all conflicts with --parent and
--all-prs.
Up/down scopes¶
| Command | Description |
|---|---|
st upstack restack |
Restack current + descendants |
st upstack onto [branch] |
Reparent current + descendants onto a new parent |
st upstack submit |
Submit current + descendants; temporary publish heads are chained for stale descendants |
st downstack get |
Show branches below current |
st downstack submit |
Submit ancestors + current |
Interactive modes¶
| Command | Description |
|---|---|
st |
Launch the TUI |
st web [path] [--port <n>] [--no-open] |
Start the localhost HTMX workspace; a busy requested port falls back to a free OS-selected port |
st split |
Split branch into stacked branches (commit-based; needs 2+ commits) |
st split --hunk |
Split a single commit by selecting individual diff hunks |
st split --file <pathspec> |
Split by extracting matching files into a new parent branch |
st edit · e |
Interactively edit commits (pick, reword, squash, fixup, drop) |
Recovery¶
| Command | Description |
|---|---|
st resolve |
AI-resolve an in-progress rebase conflict |
st abort |
Abort the in-progress rebase / conflict resolution |
st undo |
Undo the last operation |
st undo <op-id> |
Undo a specific operation |
st redo |
Re-apply the last undone operation |
Health and testing¶
| Command | Description |
|---|---|
st validate |
Check stack metadata for orphans, cycles, and staleness |
st fix |
Auto-repair broken metadata (--dry-run previews) |
st run <cmd> |
Run a command on each branch (alias: st test); --stack[=<branch>], --all, --fail-fast, or --parallel --jobs <N> |
st freeze [branch] / st unfreeze [branch] |
Protect/unprotect a tracked branch from direct/upstack/get restacks and sync history rewrites, including imported refreshes and squash-merge cleanup rebases |
CI, PRs, and reporting¶
| Command | Description |
|---|---|
st ci |
Live CI status for the current PR head — full per-check table (with elapsed/ETA learned from recent runs) |
st ci --stack / --all |
Scope to stack / all tracked branches; multi-branch views default to the one-line roll-up |
st ci --oneline / -1 |
One compact line per branch (icon · branch · #PR · draft/ready · title · checks + timing) |
st ci --watch |
Watch modes (--watch --strict fail-fasts on failure) |
st ci -w --alert / --alert <file> / --no-alert |
Success/error completion sounds for watch mode |
st ci --verbose / --json |
Grouped summary cards · JSON output |
st pr · st pr open |
Open current branch PR |
st pr body · st pr body --edit |
Print or edit the current branch PR description |
st pr list |
List open PRs (GitHub, GitLab, Gitea) |
st pr list --ready |
Interactive PR readiness TUI for unmerged tracked PRs; remotely merged PRs disappear on live refresh (--current/--stack limits to the current stack, --plain for a static table) |
st ready |
Same as st pr list --ready — interactive TUI with CI, review approval, and merge state; filtering merged PRs does not clean up local branches (--current, --stack, --all, --plain, --json, --interval) |
st board / st home |
Interactive repository dashboard — PULL REQUESTS / ISSUES tabs, a detail pane (branch, files/+/−, CI checks, labels, body, comment count), inline diff and comment viewers, label add/remove, draft toggle, and confirm-then-merge (squash, API-only). GitHub only — errors on other forges. --limit, --tab prs\|issues, --interval (default 60s), --plain for static PR/issue tables |
st draft [branch] |
Mark the current or named branch's PR as a draft |
st draft --stack |
Mark every PR in the current stack as a draft |
st undraft [branch] |
Mark the current or named branch's PR as ready for review |
st undraft --stack |
Mark every PR in the current stack as ready for review |
st issue list |
List open issues |
st comments / st reviews |
Show current PR comments; --stack or --all creates a review inbox, GitHub review comments include inline file/line locations, and --json emits a versioned machine-readable view |
st copy · st copy --pr |
Copy branch name · PR URL |
st standup |
Recent activity (--ci for opt-in live CI; --ai for AI spoken version; --jit for Jira context) |
st changelog [from] [to] |
Generate changelog (auto-resolves last tag when from omitted) |
st changelog find [query] |
Fuzzy-find commits in the selected changelog range |
st changelog --find [query] |
Flag form of commit fuzzy-find |
st generate · st gen |
AI generation: interactive picker, or --pr-body / --pr-title / --commit-msg |
st ss --ai |
Submit with AI-generated PR title/body suggestions |
st watch |
Live auto-refreshing stack status with CI and PR state (--current, --interval <seconds>); --iterations <N> performs exactly N total refreshes (1 renders exactly once; 0 is rejected), then returns without a final sleep. For N > 1, use --interval <seconds> to control the delay between refreshes. |
Utilities¶
| Command | Description |
|---|---|
st auth |
Configure GitHub token (--from-gh, --token <token>, status) |
st config |
Show current configuration |
st user |
View or set personal preferences (branch-prefix, branch-date, branch-replacement, editor, tips, submit-body) |
st config --set-ai |
Interactively set AI agent/model (global or per-feature) |
st config --reset-ai |
Clear saved AI defaults and re-prompt (--no-prompt to clear only) |
st --default-config |
Print annotated config template (all options and allowed values) |
st --skill |
Print bundled AI agent skill document (SKILL.md format with frontmatter) |
st init |
Initialize stax or reconfigure trunk (--trunk <branch>) |
st update |
Detect install method and run the matching upgrade, then check installed AI agent skill files and offer to refresh them. Skips the CLI upgrade if already on the latest version — pass --force to upgrade anyway |
st doctor |
Check repo health |
st doctor --fix |
Apply safe local repairs after one confirmation (recommended Git config, stale AI skills for selected harnesses, and optional gh-stack install) |
st skills |
Manage installed AI agent skill files (list, update, update --all, update --skills <list>, update --dry-run) |
st continue |
Continue after conflicts |
st open |
Open repository in browser |
st demo |
Interactive tutorial — no auth or repo required |
st skills update fetches the remote body and compares each fully rendered harness file byte-for-byte, rewriting instructions that differ even when the installed package-version marker matches. It leaves byte-identical files untouched; --dry-run reports the same decision without writing. st skills list is intentionally local-only: its current/stale indicator compares the installed package-version marker with this stax binary and does not verify fetched content. When a symlink at the skill directory or file position no longer resolves, st skills update removes it and replaces it with a real path (working symlinks are left intact and written through); if a harness cannot be written for any other reason it is reported and skipped so the remaining harnesses still update, and the command exits non-zero afterwards.
st tmux¶
| Command | Description |
|---|---|
st tmux status |
Print a compact tmux-formatted status string for status-right |
st tmux popup |
Open stax watch --current in a tmux display-popup |
Worktrees¶
Full guide: Worktrees · AI lanes
| Command | Aliases | Description |
|---|---|---|
st worktree |
wt |
Open the interactive dashboard (TTY only) |
st worktree create [name] |
wt c, wtc |
Create or reuse a lane (random name if omitted) |
st lane [name] [prompt] |
AI-lane entrypoint; bare st lane opens a picker |
|
st worktree list |
wt ls, w, wtls |
List all worktrees |
st worktree ll |
wt ll |
Rich status view |
st worktree go [name] |
wt go, wtgo |
Navigate to a worktree (shell integration required for cd) |
st worktree path <name> |
Print absolute path (scripting) | |
st worktree remove [name] |
wt rm, wtrm |
Remove a worktree (wt rm removes the current lane) |
st worktree promote |
wt promote |
Retire the current lane and check its branch out in the main worktree |
st worktree prune |
wt prune, wtprune |
Clean stale git worktree bookkeeping |
st worktree cleanup |
wt cleanup, wt clean |
Prune + remove safe detached/merged lanes (--dry-run previews) |
st worktree restack |
wt rs, wtrs |
Restack all stax-managed worktrees |
st setup¶
| Command | Description |
|---|---|
st setup |
One-shot onboarding: shell integration + optional skills + auth |
st setup --yes |
Accept defaults, install skills, import auth from gh when available |
st setup --install-skills / --skip-skills |
Control AI agent skills prompt |
st setup --skills <list> |
Choose harnesses (all, detected, auto, none, or comma-separated ids) |
st setup --auth-from-gh / --skip-auth |
Control auth onboarding |
st setup --print |
Print shell integration snippet for manual install |
Lane launch examples¶
st lane
st lane review-pass "address PR comments"
st lane fix-flaky --agent claude --yolo "stabilize the flaky tests"
st lane big-refactor --agent claude --agent-arg=--verbose "split the auth module"
st wt go ui-polish --run "cursor ." --tmux
Flags by command¶
st modify¶
-astage all and amend-am "msg"stage all and amend with a new message-rrestack after amending-arstage all, amend, restack- With nothing staged in a TTY: menu to stage all,
--patch, amend message only, or abort
st create¶
st add <name>is an alias forst create <name>-m "msg"set commit message (with nothing staged in a TTY: menu for stage all,--patch, empty branch, or abort)-am "msg"stage all and commit--aigenerate missing branch name and/or first commit message from local changes--ai -a --yesstage all changes, generate branch name + commit message, and skip AI value review promptsst create <name> --ai -akeeps<name>and generates the first commit messagest create --ai -m "msg"keeps the commit message and generates the branch name-n,--no-verifyskip pre-commit and commit-msg hooks when creating a commit-m/-amcreate the commit before creating the destination branch, including with--fromand--below, so hook failures or interrupts do not leave orphan branches-m/--aiderived branch names refuse collisions instead of creating-2duplicates; pass an explicit different name or checkout/reparent the existing branch--insertreparent children of the current branch onto the new branch--belowcreate from the current branch's parent and reparent the current branch onto the new branch; prepared tracked and untracked changes are auto-stashed and reapplied onto the new lower branch, and-m/-amcommits staged changes therest branch create --message "msg" --prefix feature/
Prepared-work --below example:
# On an upstack branch, after editing a CVE hotfix that belongs lower down:
st create cve-hotfix --below
# Or commit it immediately on the inserted lower branch:
st create --below -am "fix: patch CVE-2026-0001"
If the stash cannot apply cleanly while committing below, Stax restores the original branch and prepared changes so the same command can be retried after resolving the conflict. For name-only --below, the inserted branch is left in place and the auto-stash remains available for a manual git stash apply.
st status / st ll / st log¶
--stack <branch>·--current·--compact·--json·--quiet
st submit¶
--dry-run/--planprints a read-only plan without fetching, pushing, editing metadata, or calling forge mutation APIs; add--jsonfor the versioned machine-readable schema (currently version 2; action strings are extensible)- Plans query live remote head IDs with
git ls-remotewithout updating local tracking refs;--no-fetchdeliberately plans from cached tracking refs instead - A stale branch, and each submitted descendant that must follow its temporary publish head, reports
evaluate_after_temporary_restackbecause the final push decision depends on the rewritten commit ID - Stack-link plans report
update_unless_native_link_succeedswhen native-stack success would suppress Stax-managed links - Stack-link and native-stack plans report
evaluate_after_pr_discoverywhen PRs missing from local metadata could change link or fork eligibility at runtime - Native-stack plans otherwise report
skipfor known exclusions orattemptwhen the prerequisites are known --draft/--publish/--no-pr/--no-fetch/--no-verify/--open/--quiet/--verbose--no-verify(-n) skips pre-push hooks while pushing branches--reviewers alice,bob --labels bug,urgent --assignees alice--squashsquash commits on each branch before pushing--aigenerate PR title and body with AI; narrow with--titleor--body--template <name>/--no-template/--edit--rerequest-review/--update-title--native-stackforce-attempt native GitHub Stack registration for this submit;--no-native-stackskips it--forkif the upstream push is denied for lack of write access, fall back to submitting the branch from a fork (single branch, GitHub only)--yes/--no-prompt
Config: [submit] stack_links = "comment" | "body" | "both" | "off" and native_stack = "auto" | "off" | "link"; [remote] auto_fork and [remote] fork_remote control the fork fallback — see Configuration → Fork fallback for submit.
st completions¶
Generate a completion script without requiring an initialized repository:
st completions bash
st completions zsh
st completions fish
st completions powershell
st completions elvish
st merge¶
--dry-run/--yes--all/--downstack-only(--ds) /--stack/--stack --full/--method squash|merge|rebase--when-ready·--when-ready --interval 10--remote·--remote --all·--remote --timeout 60 --interval 10--queue·--queue --all --yes--timeout <minutes>— positive whole minutes (default: 30); zero is rejected--interval <seconds>— positive whole seconds (default: 15) for--when-ready,--remote,--queue, and--stack --when-ready; zero is rejected--no-wait/--no-sync/--no-delete/--quiet--ignore-failed-ci— merge even when CI checks have failed; still blocks on draft, changes-requested, conflicts, and closed. Incompatible with--queue. Use when only optional checks failed and branch protection does not require them.
For --queue, the timeout is a real deadline: stax caps the final sleep to the remaining budget and does not start another forge status poll once the deadline is reached.
st sync / st rs¶
--restack·--restack --auto-stash-pop--delete-upstream-gone--force/--safe/--continue/--quiet/--verbose--stash/--no-stash— dirty-tree handling before sync starts:--stashauto-stashes without prompting (works with--quiet/--json; does NOT auto-confirm branch deletions);--no-stashfails on a dirty tree and overrides--force; the two conflict at parse time; the dirty-tree error message names--stash. In dry-run mode both flags are accepted but ignored (stderr warning emitted).- Interactive Sync plan — applies to
st sync/st rsonly (notst refresh, which skips this prompt). After fetch, stax refreshes PR metadata, then prints one Sync plan (trunk moves, merged/upstream-gone branches with PR numbers when known, optional--restackpreview) and asks how to proceed. When deletions are listed: continue and delete all (non-blocking), per-branch prompts, or cancel (Aborted., no undo receipt). When only trunk/restack changes are pending: Proceed with restack / Cancel, or Continue sync / Cancel sync when no restack is requested. Skipped when--quiet,--json,--force, or when there is nothing to confirm. --prune— deprecated; accepted for compatibility and emits a stderr warning; use--fullto fetch--pruneall remote-tracking refs--full— classicgit fetch --prune <remote>for all remote-tracking refs; unlike the default trunk-only fetch it does not pass--no-tags, so tags reachable from fetched refs are downloaded too. Slower on large repos.--dry-run(alias--plan) — read-only preview: probes the remote with ls-remote (no fetch, no FETCH_HEAD write), patches PR states in-memory, classifies the trunk transition, reports merged/upstream-gone candidates and per-branch disposition, previews the restack scope with conflict predictions; always exits 0.--force,--auto-stash-pop,--full,--stash,--no-stash, and--verboseare accepted but ignored (stderr warning emitted for each).--continueconflicts and is rejected by clap.--json— emit the sync result as a single JSON document on stdout (schema version 1). Implies non-interactive (quiet=true); does not imply--force(branches that need confirmation are recorded inskipped_branchesand left intact). Conflicts with--continue(rejected by clap). Failures still emit the JSON envelope withsuccess: falseand exit non-zero.--verboseis ignored (stderr warning emitted).--dry-run --jsonemitskind: "sync_plan"withdry_run: trueand always exits 0.- JSON schema (
kind: "sync",schema_version: 1; action/kind strings are extensible — consumers should treat unknown values as forwards-compatible additions):
| Field | Type | Notes |
|---|---|---|
schema_version |
number |
Always 1 |
kind |
string |
"sync" (run) · "sync_plan" (dry-run) |
success |
bool |
false on any error |
dry_run |
bool |
true for --dry-run --json |
duration_ms |
number |
Wall-clock time in milliseconds |
trunk.branch |
string |
Local trunk name |
trunk.remote_ref |
string |
Remote-tracking ref (e.g. origin/main) |
trunk.action |
string |
up_to_date · fast_forwarded · reset · diverged · failed · unknown |
trunk.commits? |
number |
Present on fast_forwarded |
trunk.files? |
number |
Present on fast_forwarded |
trunk.additions? |
number |
Present on fast_forwarded |
trunk.deletions? |
number |
Present on fast_forwarded |
deleted_branches[] |
array |
Absent when empty |
deleted_branches[].name |
string |
Branch name |
deleted_branches[].category |
string |
merged · upstream_gone |
deleted_branches[].scope |
string |
both · local · remote |
deleted_branches[].tip? |
string |
Tip SHA at deletion time |
deleted_branches[].metadata_deleted |
bool |
Whether the metadata ref was also deleted |
skipped_branches[] |
array |
Absent when empty; branches that needed confirmation but --force was not given |
skipped_branches[].name |
string |
Branch name |
skipped_branches[].reason |
string |
Why deletion was skipped (e.g. "not confirmed") |
protected_branches[] |
array |
Absent when empty; upstream-gone branches skipped due to unique local commits |
partially_merged[] |
array |
Absent when empty; branches with a signal of merging but with uncommitted local commits |
partially_merged[].name |
string |
Branch name |
partially_merged[].reason |
string |
pr_merged · pr_closed · history_merged |
partially_merged[].pr_number? |
number |
Present when a PR was detected |
partially_merged[].extra_commits |
number |
Number of local commits beyond what was merged |
restacked_branches[] |
array |
Absent when empty |
imported_branches_updated[] |
array |
Absent when empty |
checkout_change? |
object |
Present when the current branch changed during sync; {from, to} |
stash.stashed |
bool |
Whether working tree was auto-stashed |
stash.restored |
bool |
Whether the stash was successfully restored |
stash.left_stashed |
bool |
stashed && !restored |
merged_candidates[] |
array |
sync_plan only. Absent when empty; per-branch disposition for merged-branch candidates |
merged_candidates[].name |
string |
Branch name |
merged_candidates[].disposition |
string |
would_delete · would_prompt_then_delete · would_keep_worktree · would_skip · would_rebase_children |
merged_candidates[].scope? |
string |
both · local; present when disposition is would_delete or would_prompt_then_delete |
merged_candidates[].keep_reason? |
string |
Human-readable reason; present when disposition is would_keep_worktree or would_skip |
merged_candidates[].children? |
array |
Child branch names; present when disposition is would_rebase_children |
upstream_gone_protected[] |
array |
sync_plan only. Absent when empty; upstream-gone branches protected because they have unique local commits |
upstream_gone_deletable[] |
array |
sync_plan only. Absent when empty; upstream-gone branches that would be deleted |
upstream_gone_deletable[].name |
string |
Branch name |
upstream_gone_deletable[].disposition |
string |
would_delete (with --force) or would_prompt_then_delete |
frozen_branches[] |
array |
sync_plan only. Absent when empty; branches skipped because they are frozen |
branches_to_restack[] |
array |
sync_plan only. Absent when empty; branches that would be restacked |
predicted_conflicts[] |
array |
sync_plan only. Absent when empty; branches predicted to have merge conflicts during restack |
predicted_conflicts[].branch |
string |
Branch that would conflict |
predicted_conflicts[].onto |
string |
Parent branch it would rebase onto |
predicted_conflicts[].files |
array |
Files predicted to conflict |
would_stash |
bool |
sync_plan only. Whether the working tree is dirty (real sync would auto-stash) |
error? |
object |
Present on failure; {kind, message} |
error.kind |
string |
dirty_working_tree · restack_conflict · error |
- On early-bail paths (e.g. dirty working tree in non-interactive mode) and on restack-conflict paths where finalize never runs,
trunk.actionis"unknown"— this is intentional. - Sync is transactional and undoable via
st undo. A single receipt covers trunk fast-forwards, deleted branch heads, deleted metadata refs, reparented children's metadata, and the optional restack phase. A no-op sync (nothing changed) writes no receipt so the previous undoable operation remains on the undo stack. - Imported branches from
st getare remote-delete exempt: once they are detected as merged or upstream-gone, sync may delete the local support branch and metadata, but it will not push-delete the imported remote branch. - The completion footer summarizes the trunk commit, file, and line delta together with non-zero merged-cleanup, imported-update, and restack counts. It reuses sync's existing results and does not perform extra network or Git work.
- When sync itself leaves exceptional work behind, it reports skipped cleanup with its reason, trunk update failures, and cleanup-driven checkout changes. It prints one prioritized next command: a diverged trunk gets non-destructive guidance to inspect and reconcile it with its remote; other trunk failures suggest
st trunk; blocked cleanup suggestsst sweep. Routine restack health remains visible inst lsand the TUI instead of appearing after every sync. - When
--restackis requested, sync fails closed if its fetch did not succeed or the local trunk did not reach the fetched remote-trunk commit. It restores any sync auto-stash and exits non-zero before imported-branch refresh, merged-branch cleanup, or restacking can rewrite feature refs.st refreshinherits this guard and exits before its submit phase, so it does not push or update PRs after either failure. - Deletion output lines for locally deleted branches (merged or upstream-gone) append the branch's tip SHA (first 7 characters, dimmed) so you can reference the exact commit that was removed.
- If sync auto-stashed your working tree and then fails on an error path that cannot restore the stash, it prints a warning to stderr naming the stash "stax auto-stash" with instructions to run
git stash popto restore your changes.
st restack¶
--all/--continue/--quiet--stop-here--submit-after ask|yes|no
Temporary publish restack¶
st submit, st downstack submit, st branch submit, and st upstack submit can publish a temporary rebased head without moving local branch tips. When a submitted branch needs restack, Stax creates an internal temporary ref, replays the branch's current commits onto the submitted parent for the push, and keeps local metadata unchanged. Descendants chain onto those temporary publish heads so the remote stack stays linear.
If the excluded parent has local-only commits, scoped submit still refuses and asks you to include ancestors with st downstack submit / st submit or restack first. --squash also requires a local restack first because squashing rewrites local branch history.
st resolve¶
--agent codex --model gpt-5.3-codex --max-rounds 5
st cascade¶
Restack the stack and submit updates, without fetching trunk (offline-friendly).
--no-pr/--no-submit/--auto-stash-pop
st checkout¶
--trunk/--parent/--child 1
st web¶
st webdiscovers the enclosing Git worktree from the current directory, starts its localhost HTMX workspace, and opens it in the browser.st web <path>accepts a repository or any path inside one and opens the enclosing worktree.st web --port <n>binds on a specific port (default 8787).--port 0picks an ephemeral port. If the requested port is busy, stax warns and uses a free OS-selected port.st web --no-openstarts the server and prints the URL without opening the browser.- Binds 127.0.0.1 only; no
--hostflag is available. - Each session URL embeds an unguessable 48-hex session token:
/s/<token>/. Requests with a wrong or missing token return 404. - Every mutating POST requires a matching CSRF token field; mismatches return 403.
Hostmust be local. Requests withoutOriginare allowed, but a presentOriginmust exactly equalhttp://127.0.0.1:<actual-bound-port>(including an ephemeral or busy-port fallback port); cross-site, malformed, duplicate, and wrong-port values return 403. This check is independent of the session token and CSRF protections.- Only one mutation runs at a time; mutating controls are disabled while an operation is in flight.
- All git operations run in
spawn_blockingto avoid blocking the async Tokio runtime. - Session state is in-memory; restarting the server generates a new token and URL.
-
See Web workspace guide for the full routes reference, keyboard shortcuts, and layout details.
-
With no argument,
st getsyncs and restacks the current stack, equivalent to the Graphitegt getcurrent-stack flow. - The argument may be a remote branch name,
origin/<branch>, or a PR number when forge auth is configured. --parent <branch>records a non-trunk parent in stax metadata--no-checkoutfetches and tracks without switching branches--downstackskips local upstack branches when the target already exists locally.--remote-upstackincludes remote-only upstack PR branches discovered from open PR base/head metadata. This is best-effort without Graphite's central backend.--no-restackskips the default restack after checkout.--unfrozenunfreezes the requested branch before syncing it; frozen targets are otherwise skipped.- Existing local branches fast-forward when possible, or rebase local-only commits onto the fetched remote tip when branch histories diverge.
--forceresets an existing local branch to the remote tip instead of preserving local commits.- Branches checked out in another linked worktree are skipped instead of being moved from the current worktree.
- New remote-only branches imported by
st getare read-only support branches: submit uses them as stack bases but does not push them or update their PRs. Existing Stax-managed branches keep their ownership metadata when synced withst get. st sync --restackrefreshes imported branches from their remote tips before restacking descendants; if an imported branch is checked out in a dirty worktree, sync skips it unless--forceis used.
st run¶
--paralleluses detached temporary worktrees, so the main worktree never changes branch.--jobs <N>sets the positive concurrency cap (default 8) and requires--parallel.- Each parallel command receives
STAX_RUN_BRANCHwith the original logical branch name; Git itself remains on a detached HEAD inside the temporary worktree. - Output is captured concurrently and printed in deterministic branch order.
- Clean temporary worktrees are removed after success or failure. If a command leaves uncommitted tracked or untracked changes, that worktree is preserved and its recovery path is printed; the branch is counted as failed. Ignored artifacts do not prevent cleanup.
--parallelconflicts with--fail-fast, because commands may already be running concurrently.
st ci¶
--stack/--all/--oneline(-1) /--verbose/--watch/--watch --strict/--interval 30/--json- For tracked PRs, CI is fetched for the forge's live PR head, so commits added remotely by formatters or other automation are reflected without moving the local branch. If the live PR revision cannot be resolved, stax falls back to the local branch revision.
- CI status is always fetched live.
--refreshremains accepted for compatibility but does not change the fetch behavior. - On GitHub, all commit-status and check-run pages are collected before the latest result for each check is selected and the overall state is calculated.
- Three render modes: the full per-check table (single branch, default), grouped summary cards (
--verbose/-v), and the one-line roll-up (--oneline/-1). Any multi-branch view (--stack/--all) defaults to the roll-up;--verboseoverrides it back to cards.--onelineand--verbosecannot be combined. - The roll-up renders one line per branch, base→tip: CI status icon · branch ·
#PR·draft/ready· PR title · trailing check-count and timing. A bare--onelinedefaults its scope to the current stack. - By default,
--watchwaits until every check is terminal, even if one check has already failed. Add--strictto exit as soon as any check fails. --watch --alertplays built-in success/error sounds;--watch --alert <file>uses one custom sound for either outcome;--watch --no-alertsuppresses[ci] alert = truefor one run.- Config can enable alerts by default with
[ci] alert = true; setsuccess_alert_soundand/orerror_alert_soundto override the per-outcome built-in sounds.
st standup¶
--all/--hours 48/--json/--ci--ai·--ai --agent claude·--ai --hours 48--ai --style slack--ai --plain-text/--ai --json/--ai --jit--cichecks only the selected branches and may add network latency; combine it with--allto check all tracked branches.- GitHub authored reviews come from one time-bounded, maximum-100 GraphQL query. GitLab and Gitea mark that signal unsupported rather than scanning every MR/PR.
- JSON preserves
reviews_givenandneeds_attention.ci_failing; usesignals.<name>.status(available,unsupported,unavailable, ornot_requested) to interpret empty arrays.
st stats¶
--currentscopes to the current stack (ancestors + current + descendants); when the current branch is untracked, the scope is empty and the command still exits0.--jsonemits a singleRepoStatsdocument with top-level keys:scope("all"or"current"),trunk,current,repo(project slug, omitted with no forge remote),trunk_ahead/trunk_behind(omitted with no remote-tracking branch),stack_shape,pr_mix,health,worktrees,ci(omitted unless--ciproduced counts),ci_unavailable_reason(present when--ciwas requested but unavailable),attention,biggest_stacks,hygiene,next_actions.stack_shape:tracked,independent,deepest,avg_height.pr_mix:open(includes drafts),draft,ready(open - draft),no_pr,merged,closed,frozen.health:need_restack,missing_parent,dirty_worktrees(repo-wide, not scoped by--current;nullwhen the dirty check was skipped for having too many worktrees).worktrees:linked,idle_slots.hygiene:merged_but_local,upstream_gone,stale,stale_days— same ancestry-based classificationst sweepuses.--ciis opt-in because it makes a network call; without forge auth configured,ciis omitted andci_unavailable_reasonexplains why.st statsalways exits0regardless of CI availability.
st pr / st issue¶
st pr list --limit 50 --jsonst issue list --limit 50 --json
st generate · st gen¶
- Bare
st genopens an interactive picker (PR body, PR title, commit message). --pr-body— refresh the open PR body from the branch diff (PR templates:--template/--no-template).--pr-title— refresh the open PR title from the branch diff.--commit-msg— amendHEADwith an AI-generated message from the last commit’s patch.- Shared:
--no-prompt/--edit/--agent <name>/--model <name>(--modelrequires--agent).
st changelog¶
--tag-prefix release/ios--path src/find [query]/search [query]— fuzzy-find commits in the selected range; omitqueryfor an interactive picker.--find [query]/--search [query]— flag form of the same fuzzy finder.--json
st auth¶
--from-gh/--token <token>/status
st init¶
--trunk main
st undo / st redo¶
--yes/--no-push/--quiet
st absorb¶
--dry-run(preview) ·-a(stage all first)
st edit¶
--yes(skip final confirmation) ·--no-verify(skip pre-commit hooks)
st split¶
--file <pathspec>(or-f "src/api/*"with glob support)--hunk(single-commit hunk-based split)