Commands

All commands are run from within a git repository. Most require the repository to have at least one stack registered (via sdf new or sdf fetch).


Stack management

sdf new [stack-name]

Create a new stack and its first branch

The stack name can be provided as a positional argument or via the --stack flag.
If --branch is omitted, the first branch is named after the stack. The base branch
is auto-detected from origin HEAD if not specified.

  sdf new my-feature                                # positional stack name
  sdf new --stack my-feature                        # explicit flag
  sdf new my-feature --branch db-schema             # custom first branch name
  sdf new my-feature --base develop                 # custom base branch
  sdf new my-feature --json                         # machine-readable output

Flags:

FlagDefaultDescription
--base--base branch (default: auto-detected from origin HEAD)
--branch--name for the first branch (default: stack name)
--json--output machine-readable JSON
--stack--name for the stack (alternative to positional arg)
--worktrees--create each branch as a git worktree (worktree mode)

sdf fetch

Discover and sync PR stacks from GitHub

Scans your open PRs, detects branch chains, and either registers
a new stack or reconciles an existing one.

  sdf fetch                          # auto-detect base, scan all open PRs
  sdf fetch --stack my-feature       # name the stack explicitly
  sdf fetch --base develop           # specify base branch

Flags:

FlagDefaultDescription
--base--base branch (default: auto-detected)
--json--output result as JSON
--stack--name for the stack (default: auto-generated from branches)

sdf branch <name>

Add a new branch to the current stack

Flags:

FlagDefaultDescription
--json--output result as JSON
--no-prefix--create branch without applying the configured prefix
--stack--stack to add the branch to (default: auto-detect)

sdf sync [stack-name]

Detect merged PRs and cascade-rebase downstream branches

Fetches from origin, queries GitHub for PR status, reconciles PR states,
cascade-rebases downstream branches, pushes, and updates PR navigation links.

By default, sync only rebases branches within the stack (e.g. after a PR is
merged or a parent branch is amended). If the base branch has advanced from
unrelated work, a hint is shown. To also rebase onto the latest base branch
tip (e.g. main), use --full.

When a rebase conflict occurs, an interactive menu offers Claude resolution,
manual resolution (pausing sync), skip, or abort.

  sdf sync                          # sync within the stack only
  sdf sync --full                   # also rebase onto latest base branch
  sdf sync my-feature               # sync a specific stack by name
  sdf sync -y                       # skip confirmation prompt
  sdf sync --continue               # resume after manual conflict resolution
  sdf sync --with-content           # also update PR titles and descriptions

Flags:

FlagDefaultDescription
--continue--resume after manual conflict resolution
--full--also rebase onto the latest base branch tip
--json--output result as JSON
--stack--stack to sync (default: auto-detect)
--with-content--update PR titles and descriptions
-y, --yes--skip confirmation prompt

Steps performed:

  1. Fetch from origin and fast-forward the base branch
  2. Query GitHub for the status of each PR in the stack
  3. Reconcile PR states (mark merged nodes, fill in PR numbers)
  4. For each downstream node that needs rebasing: rebase onto new parent, push
  5. Update PR base branches on GitHub when a merged node is skipped
  6. Optionally update PR titles and descriptions (with --with-content or if configured)
  7. Update stack navigation links in all PR descriptions

Merged nodes remain in the stack JSON and are displayed as completed. They are not removed. The ParentBranch() function skips merged nodes to find the effective parent for rebasing.

Conflict resolution: When a rebase conflict occurs, an interactive menu is presented with these options:

  • Ask Claude to resolve (if claude CLI is available)
  • I'll fix it myself — pauses sync; resume later with sdf sync --continue
  • Skip this branch — aborts the rebase for this branch, continues with the rest
  • Abort sync — stops the entire sync

After choosing "I'll fix it myself", resolve the conflicts manually, stage the files with git add, then run sdf sync --continue.

sdf merge

Merge head PR and sync remaining branches

Merges the first open PR in the stack, retargets the next PR's base,
then triggers a sync to cascade-rebase remaining branches.

  sdf merge                          # merge with squash (default)
  sdf merge -y                       # skip confirmation
  sdf merge --auto                   # enable GitHub auto-merge
  sdf merge --method merge           # use regular merge
  sdf merge --stack my-feature       # target a specific stack

Flags:

FlagDefaultDescription
--auto--enable GitHub auto-merge if merge requirements are not yet met
--json--output result as JSON
--methodsquashmerge method: squash, merge, or rebase
--stack--stack to merge (default: auto-detect)
-y, --yes--skip confirmation prompt

Merges the first open PR in the stack (the "head"), then runs sdf sync on the remaining branches. The safe pattern for draining a stack is to run sdf merge repeatedly — this keeps conflicts small by only crossing one squash boundary at a time. See the Sync Deep Dive for details.

sdf status [stack-name]

Show stack topology and sync state

Shows the topology, sync state, and PR status of a stack.

By default, only stack-internal sync state is shown. If the base branch has
advanced from unrelated work, an info hint is displayed. Use --full to include
base-branch drift in the sync state calculation.

  sdf status                        # show stack status (stack-scoped)
  sdf status --full                 # include base branch drift
  sdf status my-feature             # show a specific stack
  sdf status --json                 # output as JSON
  sdf status -v                     # show commit logs per branch

Flags:

FlagDefaultDescription
--full--include base branch drift in sync state
--json--output result as JSON
--stack--stack to show (default: auto-detect)
-v, --verbose--show commit hashes and messages per branch

Fetches from origin and fast-forwards the base branch to ensure sync state is accurate. Shows each branch with its PR number, status (open/merged/closed), and whether it needs syncing. Also performs lightweight reconciliation against GitHub PR states and warns about structural drift.

sdf pr

Create a GitHub PR for the current branch

Flags:

FlagDefaultDescription
--branch--target branch (default: current)
--draft--open the PR as a draft
--json--output result as JSON
--ready--mark the branch's draft PR as ready for review
--title--PR title (default: auto-generated from branch name)

sdf move <commit>...

Move commits from current branch to parent

Cherry-picks listed commits onto the parent branch, strips them from the
current branch via rebase, and cascade-rebases downstream branches.

  sdf move abc1234                   # move one commit
  sdf move abc1234 def5678           # move multiple commits

Flags:

FlagDefaultDescription
--json--output result as JSON

sdf split

Split a branch into a stack of smaller PRs

Uses an AI agent to analyze a branch and decompose it into a chain of
focused, reviewable PRs managed as an sdf stack.

Requires the Claude CLI to be installed. The original branch is never modified.

  sdf split --from feature/big-change --stack my-feature
  sdf split --from feature/big-change --stack my-feature --dry-run
  sdf split --from feature/big-change --stack my-feature --base main -y

Flags:

FlagDefaultDescription
--base--base branch (default: auto-detected)
--dry-run--show the split plan without executing
--from--source branch to split (required)
--no-push--create branches locally without pushing or creating PRs
--stack--name for the new stack (required)
--worktrees--create each split branch as a git worktree (worktree mode)
-y, --yes--skip confirmation prompt

Uses Claude to analyze the source branch's full diff, identify semantic themes, and propose a split plan. The plan groups changed files into layers ordered by dependency (types/schema first, then APIs, then business logic, then UI). Each layer becomes a branch in the new stack.

Pipeline:

  1. Analysis — Claude groups changed files into layers by semantic theme. If a file spans multiple layers, a follow-up phase assigns individual hunks
  2. Plan — SDF displays the split plan showing layers, files, and estimated diffs
  3. Review — Interactive prompt to accept, refine (via Claude session), or abort
  4. Execute — Creates branches by extracting per-layer diffs and applying them as patches. Shared files are split at the hunk level
  5. Validate — Verifies git diff original-branch stack/last-branch is empty (lossless split)
  6. Ship — Pushes branches, creates PRs with stack navigation links

Plan refinement: Choosing "Refine plan" opens a Claude session where you can give natural language instructions to adjust the split (move files between layers, merge layers, rename layers). SDF re-extracts the updated plan automatically.

Safety: The original branch is never modified. If validation fails, the split is rolled back. Use --dry-run to preview the plan without executing.


sdf switch [branch]

Switch to a branch and report its stack

Without arguments, lists all branches across all stacks.
With a branch name, checks it out and shows its stack position.

  sdf switch db-schema              # switch to a specific branch
  sdf switch                        # list all branches from all stacks

Flags:

FlagDefaultDescription
--json--output result as JSON
--path-only--print only the worktree path (worktree mode)

Short alias: sdf <branch> (if no subcommand matches the name).


Configuration

sdf config

Manage sdf configuration

sdf config set <key> <value>

Set a configuration value

  sdf config set branch_prefix.enabled true
  sdf config set --global pr_title.conventional_commits true
FlagDefaultDescription
--global--set value in global config (~/.config/sdf/config.json)
--json--output result as JSON

sdf config show

Display effective merged configuration

FlagDefaultDescription
--json--output config as JSON only


Deprecated commands

sdf register

Deprecated: use `sdf fetch` instead

Discover and sync PR stacks from GitHub



Utilities

sdf doctor

Check that dependencies are available

Reports the status of git (required), gh (needed for PR operations), and claude (needed for conflict resolution and PR descriptions).

  sdf doctor

Flags:

FlagDefaultDescription
--json--output result as JSON

sdf version

Print version


sdf completion <bash|zsh|fish|powershell>

Generate or install shell completion scripts

Generate shell completion scripts for sdf.

To load completions manually:

Bash:
$ sdf completion bash > ~/.local/share/bash-completion/completions/sdf

Zsh:
$ sdf completion zsh > "${fpath[1]}/_sdf"

Fish:
$ sdf completion fish > ~/.config/fish/completions/sdf.fish

PowerShell:
PS> sdf completion powershell | Out-String | Invoke-Expression

Or use 'sdf completion install' to auto-detect your shell and install.

sdf completion install

Auto-detect shell and install completion scripts


Install shell completions for tab-completion of commands, stack names, branch names, and config keys:

sdf completion install          # auto-detects your shell
sdf completion bash > ~/.local/share/bash-completion/completions/sdf
sdf completion zsh > ~/.zsh/completions/_sdf
sdf completion fish > ~/.config/fish/completions/sdf.fish

sdf ai intro

Teaches Claude about SDF by spawning a Claude session that introduces the tool's commands, workflows, and conventions. Claude creates a skill file for future sessions so it remembers SDF context.

sdf ai intro

Requires the Claude CLI.

sdf help

Show usage information and list all available commands.

sdf help