Last updated 2026-05-07

The Stacked-diff Workflow

A diff is a single, reviewable, logical change. A feature is a stack of diffs that ship together. stax's CLI is built around this — every verb maps to a step in the loop.

The full loop

# Set up
stax clone myorg/repo
cd repo
# Start
stax feature "user auth"
# Iterate
# ... edit code ...
stax diff "Add login form"
# ... edit more ...
stax diff "Add JWT validation"
# Stay current
stax sync
# Open for review
stax submit
# After approval
stax land

Starting work

Pick the verb that matches the change type. They all do the same thing — the verb just sets the Conventional-Commit prefix used for diff titles and the branch prefix.

CommandBranch prefixCommit prefix
stax feature <name>feature/feat:
stax fix <name>fix/fix:
stax docs <name>docs/docs:
stax chore <name>chore/chore:
stax start <name>feature/(detected later)

Each command auto-saves any uncommitted work on the current branch as a WIP: auto-save before switching context commit, then cuts a new branch from origin/main.

Saving a diff

stax diff [message]
  • With [message], the diff title is <type>(scope): <message> verbatim.
  • Without a message, stax uses the local LLM helper (internal/llm) to generate a Conventional-Commit title from the diff content.
  • --preview prints what would be staged without committing.
  • --update amends the diff currently being edited (see stax diff edit Dn).

Editing an earlier diff

stax diff edit D1 # focus on diff position 1
# ... change code ...
stax diff --update # amend it
stax diff # leave edit mode and append a new diff

Running CI for a diff

stax diff check # run CI on the most recent diff
stax diff check D2 # run CI on a specific diff

Triggers the runner on the diff's commit and streams output. Useful for finding the exact diff that broke a test.

Splitting a sloppy diff

stax split # walk through hunks, group them into multiple diffs
stax split --preview # see the proposed split without applying it

Staying current

stax sync # rebase the stack on origin/main
stax sync --continue # after resolving conflicts
stax sync --abort # bail out

sync fetches origin/main, rebases the feature branch, and re-orders diff metadata so the position numbers stay correct. If a conflict occurs, you resolve it in your editor and call stax sync --continue.

Switching context

stax features # list all features
stax switch <query> # fuzzy-switch to another feature
stax context # tell me where I am

Switching auto-saves uncommitted work on the current branch first. No work is lost.

Submitting for review

stax submit # opens or updates the PR via gh CLI
stax submit --preview # see what would be pushed without doing it

Each diff in the stack becomes a commit on the PR branch. The PR body lists the diffs in stack order. submit prints both the GitHub URL and the local dashboard URL when both are available.

Landing

stax land # land the lowest approved diff onto main
stax land D2 # land a specific diff
stax land --force # skip approval / CI checks

Default behaviour: squash-merge the lowest-position diff that has been approved on GitHub, advance origin/main, and rebase the remaining stack on top.

Inspecting state

stax features # all features (with diff counts and current marker)
stax diffs # diffs in the current feature, with file counts
stax context # one-line "where am I" summary
stax status # like git status, plus diff metadata
stax log -n 50 # last 50 activity-log entries

Recovering

stax undo # undo the last action
stax undo --list # see what's undoable

The activity log records every state-changing command (start, diff, sync, switch, etc.) with enough metadata to reverse it.