Skip to content

wiseiodev/dubstack

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

143 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

DubStack

DubStack (dub) is a local-first CLI for stacked branch workflows.

It is designed for the Graphite mental model: small, dependent PRs that are easy to review, update, and rebase.

Why DubStack

Large PRs are hard to review and painful to keep up to date.

Stacked branches let you split work into focused layers:

(main)
  └─ feat/auth-types
       └─ feat/auth-login
            └─ feat/auth-tests

When a lower branch changes, dub restack propagates it upstack.

Install

Homebrew (recommended)

brew tap wiseiodev/dubstack
brew install dubstack

Update:

brew upgrade dubstack

npm

npm install -g dubstack

From source

git clone https://github.com/wiseiodev/dubstack.git
cd dubstack
pnpm install
pnpm build
pnpm link --global

Graphite Mental Model

If you have gt muscle memory, use this as a fast map:

Graphite (gt) DubStack (dub)
gt create dub create
gt modify dub modify or dub m
gt submit / gt ss dub submit / dub ss
gt sync dub sync
gt checkout / gt co dub checkout / dub co
git checkout - dub back
gt log / gt ls dub log / dub ls
gt up / gt down dub up / dub down
gt top / gt bottom dub top / dub bottom
gt info dub info
gt pr dub pr
gt restack dub restack
gt continue dub continue
gt abort dub abort
gt track --parent dub track --parent
gt untrack dub untrack
gt delete dub delete
gt parent dub parent
gt children dub children
gt trunk dub trunk
gt undo dub undo (multi-level; pair with dub redo)

Quick Start

# 1) Start from trunk
git checkout main
git pull

# 2) Create stacked branches
# Create + stage all + commit
dub create feat/auth-types -am "feat: add auth types"
dub create feat/auth-login -am "feat: add login flow"
dub create feat/auth-tests -am "test: add auth tests"

# 3) View stack
dub log

# 4) Submit stack PRs
dub ss

# 5) Open PR for current branch
dub pr

# 6) Open docs or the current repository homepage
dub docs
dub repo

For a more detailed walkthrough, see QUICKSTART.md.

Contributing

See CONTRIBUTING.md for contributor workflow, coding-agent guidance, commit conventions, and PR expectations.

Command Reference

dub init

Initialize DubStack state in the current git repository.

dub init

Notes:

  • dub create auto-initializes state if needed.
  • Running dub init manually is still useful for explicit setup.

dub docs

Open the DubStack docs site in your browser.

dub docs

dub repo

Open the current repository GitHub page in your browser.

dub repo

dub create [branch]

Create a branch stacked on top of the current branch.

# branch only
dub create feat/my-change

# create + commit staged changes
dub create feat/my-change -m "feat: ..."

# stage all + create + commit
dub create feat/my-change -am "feat: ..."

# stage tracked-file updates + create + commit
dub create feat/my-change -um "feat: ..."

# interactive hunk staging + create + commit
dub create feat/my-change -pm "feat: ..."

# AI-generate branch + conventional commit from staged changes
dub create --ai

# override repo AI defaults for one invocation
dub create --no-ai feat/my-change

# stage all, then AI-generate branch + commit (supports -ai shorthand)
dub create -ai

Flags:

  • -m, --message <message>: commit message
  • -a, --all: stage all changes before commit (requires -m or --ai)
  • -u, --update: stage tracked-file updates before commit (requires -m or --ai)
  • -p, --patch: select hunks interactively before commit (requires -m or --ai)
  • -i, --ai: AI-generate branch + conventional commit from staged changes
  • --no-ai: disable AI generation for this invocation

If the repo configures git config commit.template, DubStack includes that template when generating AI commit messages so the body follows the repo's expected structure.

dub modify / dub m

Amend or create commits on the current branch, then restack descendants.

# amend current commit
dub modify

# create a new commit
dub modify -c -m "fix: ..."

# interactive staging
dub modify -p

# stage all tracked updates
dub modify -u

# show staged diff before modify
dub modify -v

# show staged + unstaged diff before modify
dub modify -vv

# interactive rebase of this branch's commits
dub modify --interactive-rebase

Flags:

  • -a, --all
  • -u, --update
  • -p, --patch
  • -c, --commit
  • -e, --edit
  • -m, --message <message> (repeatable)
  • -v, --verbose (repeatable)
  • --interactive-rebase

dub checkout / dub co

Checkout a branch directly or use interactive search.

# checkout explicit branch
dub checkout feat/auth-login

# interactive picker
dub checkout

# checkout trunk for current tracked stack
dub checkout --trunk

# interactive picker including non-tracked local branches
dub checkout --show-untracked

# interactive picker scoped to current stack
dub checkout --stack

dub log / dub ls / dub l

Render tracked stacks as an ASCII tree. On tree-shaped stacks, the current branch's ancestor path is shown in bold, sibling sub-trees are dimmed, and the current branch is highlighted in bright cyan.

dub log
dub ls
dub l

# show only current stack
dub log --stack

# show all stacks explicitly
dub log --all

# reverse branch ordering for quick top-down scan
dub log --reverse

# disable ANSI colors (falls back to `*` for current, `>` for ancestor)
dub log --no-color

Navigation: dub up, dub down, dub top, dub bottom

# move one branch upstack
dub up

# move multiple levels upstack
dub up 2
# or: dub up --steps 2

# move downstack
dub down
dub down 2

# jump to tip branch in current path
dub top

# jump to first branch above root
dub bottom

dub info and dub branch info

Show tracked metadata for a branch, optionally including the parent-relative diff.

# current branch
dub info

# current branch with parent-relative diff
dub info --diff

# explicit branch
dub info feat/auth-login

# equivalent legacy style
dub branch info

Orientation: dub parent, dub children, dub trunk

Quickly inspect where the current branch sits in its tracked stack.

dub parent     # direct parent of current branch
dub children   # direct children
dub trunk      # stack root/trunk branch

All three commands accept an optional branch argument:

dub parent feat/auth-login
dub children feat/auth-types
dub trunk feat/auth-tests

If branch metadata is missing, these commands print a remediation path using dub track.

dub back

Return to a previously checked-out branch from DubStack checkout history.

# return to the previous branch
dub back

# go two available branch visits back
dub back 2

# inspect recent checkout history without switching
dub back --list

Deleted local branches are skipped with a warning, and consumed history entries are removed so repeated dub back calls continue farther back instead of bouncing between the same two branches.

dub track [branch] [--parent <branch>]

Track an existing local branch or re-parent a tracked branch.

# track current branch
dub track

# track explicit branch
dub track feat/auth-login --parent feat/auth-types

# repair parent metadata
dub track feat/auth-login --parent main

Notes:

  • If --parent is omitted, DubStack tries to infer a safe default.
  • In interactive shells, DubStack prompts when parent choice is ambiguous.
  • Re-parenting can require follow-up rebasing via dub restack.

dub untrack [branch] [--downstack]

Remove branch metadata from DubStack without deleting local git branches.

# untrack current branch only
dub untrack

# untrack explicit branch and descendants
dub untrack feat/auth-login --downstack

Use this when branch exists locally but should no longer participate in stack operations.

dub delete [branch] [--upstack|--downstack] [--force] [--quiet]

Delete local branches with stack-aware expansion and metadata repair.

# delete one branch (with confirmation)
dub delete feat/auth-login

# delete branch and descendants
dub delete feat/auth-login --upstack

# delete branch and ancestors toward trunk
dub delete feat/auth-login --downstack

# fully non-interactive destructive delete
dub delete feat/auth-login --upstack --force --quiet

Flags:

  • --upstack: include descendants
  • --downstack: include ancestors (excluding root)
  • -f, --force: force delete unmerged branches
  • -q, --quiet: skip confirmation prompt

dub continue / dub abort

Unified recovery pair for interrupted restacks and rebases.

# continue active restack/rebase
dub continue

# abort active restack/rebase
dub abort

Use these when the CLI reports conflicts or an in-progress operation.

dub submit / dub ss

Push branches and create or update PRs.

dub submit
dub ss

# preview only
dub submit --dry-run

# AI-generate PR description body
dub submit --ai

# create new PRs as drafts
dub submit --draft

# promote existing draft PRs to ready for review
dub submit --publish

# submit current branch + ancestors to trunk (default)
dub submit

# submit current branch + all descendants
dub submit --upstack

# submit the whole stack graph (trees supported)
dub submit --stack

# submit only a single named branch
dub submit --branch feat/api

# open GitHub PR create forms in the browser for new PRs
dub submit --web

# queue GitHub auto-merge for submitted PRs
dub submit --merge-when-ready
dub submit --merge-when-ready --method rebase

# re-request existing reviewers after updating PRs
dub submit --rerequest-review
dub submit --rerequest-review-only monalisa,hubot

Scope flags (--upstack, --downstack, --stack, --branch) are mutually exclusive. Passing more than one is a validation error.

--draft creates new PRs as drafts. Existing PRs are left in their current lifecycle state.

--publish promotes existing draft PRs in the submit scope to ready for review. It errors if any selected branch does not already have an open PR.

--path current and --path stack still work but emit a deprecation warning and will be removed in v2. Use --downstack and --stack respectively.

Notes:

  • --no-ai disables AI PR description generation for one invocation.
  • AI submit only writes the PR description body; the PR title still comes from the last commit message.
  • --web pushes branches and opens GitHub compare/create URLs for branches without open PRs, with the title and body prefilled. Existing PRs still update through gh as usual. If the generated body is longer than 4000 characters, DubStack writes it to a temp file and opens a title-only URL so you can paste the body manually.
  • --rerequest-review re-requests review on updated PRs only. New PRs are skipped because they have no existing reviewers.
  • --rerequest-review-only <users> limits re-requests to a comma-separated reviewer list.
  • --merge-when-ready queues GitHub auto-merge on every PR in the submit scope. The default strategy is squash; pass --method merge, --method squash, or --method rebase to choose another strategy. DubStack starts with the requested strategy and falls back across repository-allowed methods.
  • Enabling auto-merge on every submitted PR is safer than only enabling it on the bottom PR: GitHub still respects stacked-base ordering, and the queue survives later rebases of the stack.
  • If the repo has a PR template in a supported GitHub template location, DubStack preserves that structure when generating AI PR descriptions.

dub flow / dub f

Stage, preview, create, and submit an AI-assisted change.

# stage all, preview, create, commit, and submit
dub flow --ai -a

# auto-approve after staging tracked files
dub flow -y -u

# preview only
dub f --dry-run

dub flow requires an interactive terminal for approval. In non-interactive environments, pass -y to auto-approve after the preview is rendered.

Flags:

  • -a, --all
  • -u, --update
  • -p, --patch
  • -y, --yes
  • -i, --ai
  • --no-ai
  • --dry-run

dub pr [branch-or-number]

Open a PR in browser via gh.

# current branch PR
dub pr

# explicit branch / PR target
dub pr feat/auth-login
dub pr 123

dub sync

Synchronize tracked branches with remote refs and repair stack state after manual merges.

# sync current stack
dub sync

# sync all tracked stacks
dub sync --all

# non-interactive mode
dub sync --no-interactive

# force destructive sync decisions
dub sync --force

# keep sync conservative if you need to skip rebases
dub sync --no-restack

Current sync behavior includes:

  • fetch tracked refs from origin
  • attempt trunk fast-forward (or overwrite with --force)
  • auto-clean local branches for merged PRs (and closed PRs confirmed in trunk)
  • retarget surviving child PRs after merged-parent cleanup
  • refresh affected branch PRs after post-merge maintenance
  • reconcile local/remote divergence states per branch
  • restack by default unless --no-restack is set

Recommended post-merge flow:

# merged in GitHub or another UI
dub sync

If sync hits a real conflict, prefer:

dub continue --ai

When two AI providers are configured, dub continue --ai and dub ai resolve ask both providers and rank lower-confidence files first. Use --no-adjudicate for the single-provider path, or --adjudicate to require two providers.

dub doctor

Run health checks for stack metadata and submit readiness.

dub doctor

# check all stacks
dub doctor --all

# skip remote fetch if needed
dub doctor --no-fetch

Checks include:

  • in-progress operation detection (dub continue/dub abort)
  • missing tracked local/remote branches
  • submit branching blockers
  • local/remote SHA drift
  • structural parent/child ancestry drift that can leave GitHub conflicted while local refs look clean
  • remote GitHub base drift, where the remote PR head is no longer descended from the base branch GitHub is actually evaluating

If dub doctor reports a GitHub base mismatch, refresh that base first, then replay and resubmit:

git checkout main && git pull --ff-only origin main
dub restack
dub submit

dub ready

Run pre-submit checklist (doctor + submit preflight). --scope controls how much of the stack the preflight covers (current | downstack | stack).

# default: current branch + ancestors (downstack)
dub ready

# just the current branch
dub ready --scope current

# every branch in the stack (siblings included)
dub ready --scope stack

dub prune

Preview or remove stale tracked branch metadata.

# preview only
dub prune

# apply removals
dub prune --apply

# include every stack
dub prune --all --apply

dub merge-check

Validate merge order and GitHub mergeability for a stack PR. --scope walks a wider set of branches (current default | downstack | stack); --pr forces single-PR mode and ignores --scope.

# check current branch PR (scope: current, default)
dub merge-check

# check current branch + ancestors
dub merge-check --scope downstack

# check every branch in the stack (siblings included)
dub merge-check --scope stack

# check explicit PR number (scope ignored)
dub merge-check --pr 123

dub merge-next / dub land

Merge the next safe PR in your current stack path. On direct-merge branches, DubStack pre-retargets direct child PRs to the parent base, then runs post-merge maintenance. On GitHub merge-queue protected trunk branches, DubStack enqueues the PR instead and tells you to run dub sync after the queue processes.

dub merge-next
# alias
dub land

# preview only
dub merge-next --dry-run

# force GitHub native merge queue mode
dub merge-next --queue

# bypass queue auto-detection and direct-merge
dub merge-next --no-queue

dub post-merge

Repair stack metadata and retarget remaining PRs after manual merges.

dub post-merge

# preview only
dub post-merge --dry-run

# include all stacks
dub post-merge --all

dub restack

Rebase stack branches onto updated parents.

dub restack

# continue after resolving conflicts
dub restack --continue

dub move

Insert a tracked branch between two existing branches in the same stack. Updates state, retargets open PRs, and restacks descendants in one step.

# Insert <branch> as <target>'s new parent
dub move feat/inserted --before feat/auth-login

# Insert <branch> as a child of <target> (absorbs <target>'s old children)
dub move feat/inserted --after feat/auth-base

dub stash / dub stash pop / dub stash list

Branch-aware stash. Records which branch a stash was created on so pop can refuse a branch-mismatched apply. Useful when you started work on the wrong branch and want to move it elsewhere.

# Stash on the current branch (records branch in .git/dubstack/stash-log.json)
dub stash

# Pop most recent — refuses unless current branch matches the recorded branch
dub stash pop

# Checkout feat/other, then pop the stash there
dub stash pop --on feat/other

# Pop onto the current branch regardless of where the stash was created
dub stash pop --force

# Show recorded stashes with branch context
dub stash list

See dub stash docs for the full behavior, error matrix, and stash-log schema.

dub freeze / dub unfreeze

Records a frozen flag on a tracked branch and surfaces it (🔒 in dub log, an informational notice in dub doctor). dub restack, dub sync, and dub post-merge skip frozen branches until dub unfreeze clears the flag.

# freeze the current branch
dub freeze

# freeze a specific branch and its ancestors toward trunk
dub freeze feat/auth-login --downstack

# freeze a branch and all its descendants
dub freeze feat/auth-base --upstack

# clear the flag
dub unfreeze feat/auth-login

dub log marks frozen branches with 🔒 and dub doctor lists them as an informational notice. Freeze wins over destructive maintenance flags: if a branch is frozen, unfreeze it explicitly before using dub sync --force or any other branch-mutating maintenance.

dub undo / dub redo

Multi-level undo and redo backed by a 20-entry ring buffer at .git/dubstack/undo-log.json. Reversal coverage includes create, restack, move, reorder, absorb, unlink, rename, pop, modify, freeze/unfreeze, track/untrack, delete, sync, split, and submit (PR body restore only — PR retargets and pushes are not reverted).

# Undo the most recent mutating dub command
dub undo

# Roll back the last N operations
dub undo --steps 3

# Show what's on the ring (newest first)
dub undo --list

# Wipe both undo and redo logs
dub undo --clear

# Replay the most recently undone operation
dub redo

A new mutating command clears the redo log; until then dub undodub redo cycle freely. If part of an undo can't fully succeed (a branch was force-pushed, GitHub rejected a PR body update, etc.) DubStack undoes what it can and prints ⚠ … warnings with manual recovery hints.

dub completion <shell> and dub man

Generate shell completions and a man page from the live commander definitions.

# bash, zsh, fish — pipe into the location your shell loads completions from
dub completion bash > ~/.local/share/bash-completion/completions/dub
dub completion zsh > "${fpath[1]}/_dub"
dub completion fish > ~/.config/fish/completions/dub.fish

# roff man page — drop into any MANPATH location
mkdir -p ~/.local/share/man/man1
dub man > ~/.local/share/man/man1/dub.1
man dub

Completions cover top-level subcommands, nested subcommands and their flags (e.g. dub config ai-provider <Tab>), per-command flags, and local branch names for co/checkout, delete, track, and untrack. Branch-valued flags (--parent, --branch, --before, --after) also complete local branches. Regenerate after upgrading dub to pick up new commands and flags. Full docs: apps/docs/content/docs/guides/shell-integration.mdx.

dub skills

Install or remove packaged agent skills.

# install all bundled skills
dub skills add

# install one skill
dub skills add dubstack

# remove one skill
dub skills remove dub-flow

# preview without changing anything
dub skills add --dry-run
dub skills remove --dry-run

dub config ai-assistant [on|off]

Enable or disable the repo-local AI assistant flag.

# check current value
dub config ai-assistant

# enable for this repository
dub config ai-assistant on

# disable for this repository
dub config ai-assistant off

dub config ai-defaults <create|submit|flow> [on|off]

Manage repo-local defaults for AI-assisted authoring.

# inspect current value
dub config ai-defaults create

# enable AI by default
dub config ai-defaults create on
dub config ai-defaults submit on
dub config ai-defaults flow on

dub config submit-default [auto|draft|publish]

Manage repo-local defaults for the submit PR lifecycle.

# inspect current value
dub config submit-default

# create new submit PRs as drafts by default
dub config submit-default draft

# publish existing draft PRs by default
dub config submit-default publish

# create drafts when `.github/workflows/` contains workflow files, otherwise create ready PRs
dub config submit-default auto

dub config ai-provider [auto|gemini|anthropic|gateway|bedrock|openai|ollama]

Manage the repo-local AI provider selection.

# inspect current provider
dub config ai-provider

# pin this repository to Bedrock
dub config ai-provider bedrock

# pin this repository to Anthropic
dub config ai-provider anthropic

# pin this repository to OpenAI
dub config ai-provider openai

# pin this repository to Ollama
dub config ai-provider ollama

# return to backward-compatible auto selection
dub config ai-provider auto

dub config ai-prompts [auto|on|off]

Manage AI choices inside interactive sync/restack/post-merge prompts.

# inspect current prompt mode
dub config ai-prompts

# show AI choices whenever the repo AI assistant is enabled
dub config ai-prompts auto

# hide AI choices in interactive prompts
dub config ai-prompts off

dub config ai-prompts-auto-accept [off|high]

Manage whether prompt recommendations can skip the confirmation prompt.

# inspect current auto-accept behavior
dub config ai-prompts-auto-accept

# apply high-confidence prompt recommendations immediately
dub config ai-prompts-auto-accept high

# always confirm recommendations before applying
dub config ai-prompts-auto-accept off

dub config ai-model [model] --provider <provider>

Manage repo-local model overrides by provider.

# inspect current OpenAI override
dub config ai-model --provider openai

# set a repo-local override
dub config ai-model "gpt-5.5" --provider openai

# set a repo-local Ollama override
dub config ai-model "qwen2.5-coder" --provider ollama

# set a repo-local Anthropic override
dub config ai-model "claude-sonnet-4-20250514" --provider anthropic

# clear the repo-local override
dub config ai-model --provider openai --clear

dub ai ask <prompt...>

Ask DubStack's AI assistant using streaming output (streamText).

dub ai ask "Summarize what this stack is changing"

dub ai ask automatically includes a context packet (current branch/stack signals, git status, doctor summary, and recent Dub command history) so it can give better recovery guidance. In TTY mode, response text streams live while status/tool activity lines are rendered separately for readability.

To inspect your repository, dub ai ask can invoke a constrained shell tool limited to a strict allow-list of safe, read-only commands (for example git status, dub doctor, dub ready) when command output is needed. The assistant cannot execute arbitrary shell commands; requests outside this allow-list are rejected, and additional safety checks block destructive command patterns.

Provider/model selection:

  • Repo config from dub config ai-provider ... wins when set to gemini, anthropic, gateway, bedrock, openai, or ollama.
  • Repo-local model overrides from dub config ai-model ... win for that provider when present.
  • In auto mode, DubStack uses Gemini, then Anthropic, then AI Gateway, then Bedrock, then OpenAI. Ollama is used in auto mode only when DUBSTACK_OLLAMA_BASE_URL or DUBSTACK_OLLAMA_MODEL is set.
  • Gemini uses DUBSTACK_GEMINI_API_KEY with optional DUBSTACK_GEMINI_MODEL override.
  • Anthropic uses DUBSTACK_ANTHROPIC_API_KEY with optional DUBSTACK_ANTHROPIC_MODEL override.
  • AI Gateway uses DUBSTACK_AI_GATEWAY_API_KEY with optional DUBSTACK_AI_GATEWAY_MODEL override.
  • Bedrock uses DUBSTACK_BEDROCK_AWS_REGION, DUBSTACK_BEDROCK_MODEL, and optional DUBSTACK_BEDROCK_AWS_PROFILE.
  • OpenAI uses DUBSTACK_OPENAI_API_KEY with optional DUBSTACK_OPENAI_MODEL override.
  • Ollama uses DUBSTACK_OLLAMA_BASE_URL (default http://localhost:11434) with optional DUBSTACK_OLLAMA_MODEL override. It checks <base>/api/tags before sending prompts, then uses the OpenAI-compatible <base>/v1 endpoint. For LM Studio, set DUBSTACK_OLLAMA_BASE_URL to the server's /v1 endpoint.
  • Bedrock support uses AWS credential-chain auth only. DubStack does not manage AWS secret key environment variables.

Local Ollama and LM Studio models can be useful for privacy-sensitive repositories, but they are typically lower-quality than frontier hosted models. Expect weaker results for conflict resolution, split proposals, and generated PR/commit metadata unless you run a strong local model.

Thinking is enabled by default for Gemini 3 Flash.

Template support:

  • PR templates: .github/pull_request_template.md, .github/PULL_REQUEST_TEMPLATE.md, .github/PULL_REQUEST_TEMPLATE/*.md, docs/pull_request_template.md, pull_request_template.md
  • commit templates: configured with git config commit.template <path>

When templates are present, DubStack uses them as the formatting contract for AI-generated commit messages and PR descriptions.

AI Evals

DubStack uses Evalite for local AI quality checks around generated metadata.

# run the curated dub flow metadata suite
pnpm evals

# rerun on file changes while iterating on prompts/scorers
pnpm evals:watch

# export the latest local report
pnpm evals:export

The first suite lives at packages/cli/evals/dub-flow-metadata.eval.ts and evaluates the pure generateFlowMetadata(...) helper used by dub flow. It mixes deterministic contract checks with an AI judge scorer so prompt changes are measured against staged diff fidelity, template preservation, and reviewer usefulness.

dub ai setup

Run the guided setup flow for Gemini, Anthropic, AI Gateway, Amazon Bedrock, OpenAI, or Ollama.

dub ai setup

The setup wizard helps you:

  • choose the repo-local provider
  • choose a curated model or enter a custom model ID
  • write global provider defaults into your shell profile
  • optionally store a repo-local model override

When the wizard writes env vars, DubStack loads them into the current dub process and prints the exact command to run in your shell to activate them immediately.

dub ai env

Write DubStack AI provider model/endpoint settings into your shell profile (macOS/Linux shells).

API keys are not set through dub ai env. Passing a secret as a CLI flag leaks it into your shell history and the OS process list. Set keys one of two ways:

  • Interactive: dub ai setup — prompts for the key with masked input that never enters your shell history.
  • Non-interactive / CI: export the env var directly, e.g. export DUBSTACK_OPENAI_API_KEY="<your-key>" (via your shell profile or a secrets manager).

DubStack reads keys from DUBSTACK_GEMINI_API_KEY, DUBSTACK_ANTHROPIC_API_KEY, DUBSTACK_AI_GATEWAY_API_KEY, and DUBSTACK_OPENAI_API_KEY.

# write Ollama endpoint
dub ai env --ollama-base-url "http://localhost:11434"

# write Gemini model override
dub ai env --gemini-model "gemini-2.5-pro-preview"

# write Anthropic model override
dub ai env --anthropic-model "claude-sonnet-4-20250514"

# write Gateway model override
dub ai env --gateway-model "google/gemini-2.5-pro"

# write OpenAI model override
dub ai env --openai-model "gpt-5.5"

# write Ollama model override
dub ai env --ollama-model "qwen2.5-coder"

# write Bedrock profile + region + model
dub ai env \
  --bedrock-profile "bw-sso" \
  --bedrock-region "us-west-2" \
  --bedrock-model "us.anthropic.claude-sonnet-4-6"

# target a specific profile file explicitly
dub ai env --gemini-model "gemini-3-flash-preview" --profile ~/.zshrc

Supported automatic profile detection:

  • zsh~/.zshrc
  • bash~/.bashrc (or ~/.bash_profile fallback)

After writing exports, DubStack prints the exact activation command to run in your shell so the new values take effect immediately in your terminal session.

dub history

Inspect recent Dub command history used for troubleshooting context.

# show last 20 entries
dub history

# show more
dub history --limit 50

# machine-readable output
dub history --json

Programmatic use (--json)

Every read-only command supports --json for scripts, MCP, and IDE integrations. Each payload carries a top-level schemaVersion: 1 and a stable shape; failures are emitted as { schemaVersion, error: { message, recovery } } with a non-zero exit code. Covered commands: log, info, branch info, status, doctor, history, parent, children, trunk, merge-check, ready. See the Programmatic use guide for the full schema reference.

dub mcp (Model Context Protocol)

Expose DubStack to MCP-aware agents (Claude Code, Cursor, etc.) so they can drive the stack without shelling out to free-form commands.

claude mcp add dubstack dub mcp

Mutating tools are gated by repo-local mode:

dub config mcp-mode read-only    # disable mutating tools entirely
dub config mcp-mode interactive  # terminal confirmation (default)
dub config mcp-mode trusted      # allow mutating tools without prompts

Every MCP tool invocation — success, refusal, or failure — is appended to dub history with redacted args and a args_sha256 fingerprint. See the MCP server guide for the tool list and security model.

Multi-trunk repositories

Repositories with multiple long-lived trunks (e.g. main plus a release branch) can register additional trunks. DubStack records which trunk each stack tracks and the default trunk used by dub create at the root.

dub trunk list                  # show configured trunks
dub trunk add release/24.04     # register an additional trunk
dub trunk set-default release/24.04
dub trunk remove release/24.04

dub doctor surfaces orphaned trunks (branches that lost their tracked trunk after a rename or deletion) and walks you through reattachment.

Storage backend (SQLite)

DubStack state defaults to .git/dubstack/state.json. Repositories with very large stacks can opt into a SQLite backend for faster reads.

dub config storage-backend           # show
dub config storage-backend sqlite    # switch backend (does not migrate data)
dub migrate storage --to sqlite      # copy state.json → SQLite
dub migrate storage --to json        # copy SQLite → state.json

Terminal theming

dub config theme            # show
dub config theme auto       # auto-detect light/dark from COLORFGBG (default)
dub config theme dark
dub config theme light
dub config theme none       # equivalent to --no-color globally

--no-color on any invocation overrides the configured theme for that run. Affects log, status, sync, and any other colorized output.

Typical Workflows

Add review feedback to a middle branch

# jump to branch needing edits
dub co feat/auth-login

# edit + amend + restack descendants
dub m -a -m "fix: address feedback"

# resubmit stack
dub ss

Sync after trunk moves

git checkout main
git pull
dub sync
# optional restack in one command
dub sync --restack

Merge stacks safely (bottom-up)

# merge next safe PR in stack order
dub merge-next

# run again for the next layer
dub merge-next

If the trunk branch uses GitHub's native merge queue, dub merge-next detects that branch protection and defaults to queue mode. Queue mode uses gh pr merge --auto --squash, skips local post-merge maintenance because the merge has not happened yet, and prints the follow-up dub sync command to run after GitHub processes the queue. Use --queue to require queue mode or --no-queue to force the direct merge path.

If you merged manually, normalize state and retarget remaining PRs:

dub post-merge

Recover from restack conflict

dub restack
# resolve conflicts
git add <resolved-files>
dub restack --continue

Troubleshooting

Problem What to do
gh CLI not found Install GitHub CLI: https://cli.github.com
Not authenticated with GitHub Run gh auth login
Branch not part of stack Create via dub create or run from tracked branch
Restack conflict Resolve files, git add, dub restack --continue
Rebase/restack interrupted Use dub continue to resume, dub abort to cancel
Branch not tracked Run dub track <branch> --parent <parent>
Need metadata-only removal Use dub untrack (or --downstack)
Need stack-aware branch deletion Use dub delete with --upstack / --downstack
Sync skipped branch Re-run with --interactive or --force as appropriate
Wrong operation during create/restack/move Use dub undo (multi-level; dub redo to replay)
PR merge blocked by order or GitHub conflict Run dub merge-check --pr <number> to verify stack order and remote mergeability
Manual merge left stack inconsistent Run dub post-merge

Stale Branch Recovery

When submit or sync gets blocked by stale tracked branches:

# 1) Inspect current health
dub doctor

# 2) Preview stale branch metadata
dub prune

# 3) Remove stale metadata if confirmed
dub prune --apply

# 4) Re-run pre-submit checks
dub ready

# 5) Submit current branch + ancestors
dub submit

State Files

DubStack stores local state in your repo:

.git/dubstack/
├── state.json
├── undo-log.json
├── redo-log.json
└── restack-progress.json

Nothing is pushed to your remote from these files.

Development

pnpm install
pnpm test
pnpm typecheck
pnpm checks
pnpm checks:fix
pnpm build

License

MIT

About

Resources

License

Contributing

Stars

Watchers

Forks

Packages

 
 
 

Contributors