DubStack
Guides

Shell Integration

Wire `dub status` into your shell prompt, tmux status line, or editor status bar.

dub status prints a compact one-liner describing the current branch, its PR state, CI rollup, and any stack drift. With --json it emits a stable, versioned snapshot designed for shell prompts and editor integrations.

The contract

  • dub status — human-readable one-liner (cache-first; never blocks on gh).
  • dub status --json — structured JSON with schemaVersion: 1.
  • dub status --live — bypass the 30s overview cache and refresh PR/CI data.
  • dub status --no-pr — skip the PR fetch entirely (great for prompts on machines without gh installed or authenticated).

The cache-only default is the fast path: when the stack overview cache is fresh, dub status returns immediately without ever calling gh. On a cold cache the command returns cached: false with a minimal local-only snapshot rather than blocking on a network round-trip — your prompt stays snappy.

JSON shape

{
  "schemaVersion": 1,
  "cached": true,
  "currentBranch": "feat/api",
  "operation": "none",
  "branch": {
    "tracked": true,
    "stackId": "stack-1",
    "root": "main",
    "parent": "main",
    "children": ["feat/api-tests"]
  },
  "pr": {
    "state": "OPEN",
    "baseRefName": "main",
    "number": 123,
    "title": "feat: add API",
    "isDraft": false,
    "ciRollup": "SUCCESS",
    "reviewDecision": null
  },
  "drift": { "healthy": true, "issues": [] }
}

Consumers should pin on schemaVersion. Future breaking changes will bump the version; additive fields will stay on version 1.

Starship

Add a custom dubstack module to ~/.config/starship.toml:

[custom.dubstack]
command = "dub status --no-pr"
when = "git rev-parse --is-inside-work-tree"
shell = ["bash", "--noprofile", "--norc"]
format = "[$output]($style) "
style = "bold cyan"

For a richer prompt with PR + CI status, drop --no-pr (still cache-first):

[custom.dubstack]
command = "dub status"
when = "git rev-parse --is-inside-work-tree"
shell = ["bash", "--noprofile", "--norc"]
format = "[$output]($style) "
style = "bold cyan"

tmux

Show the current stack status in the right status bar. Add to ~/.tmux.conf:

set -g status-right '#(cd #{pane_current_path} && dub status --no-pr 2>/dev/null) | %H:%M '
set -g status-interval 5

For PR/CI awareness, drop --no-pr and bump the interval to match the 30s cache TTL:

set -g status-right '#(cd #{pane_current_path} && dub status 2>/dev/null) | %H:%M '
set -g status-interval 30

oh-my-zsh

Drop this snippet into a custom plugin (e.g. ~/.oh-my-zsh/custom/plugins/dubstack/dubstack.plugin.zsh):

function dubstack_prompt_info() {
  command -v dub >/dev/null 2>&1 || return
  git rev-parse --is-inside-work-tree >/dev/null 2>&1 || return
  local status_line
  status_line="$(dub status --no-pr 2>/dev/null)" || return
  [[ -n "$status_line" ]] && echo " %F{cyan}${status_line}%f"
}

PROMPT="${PROMPT}\$(dubstack_prompt_info)"

Enable the plugin in ~/.zshrc:

plugins=(... dubstack)

Shell completions

dub completion <shell> writes a completion script to stdout. Pipe it into the location your shell loads completions from:

# bash
dub completion bash > ~/.local/share/bash-completion/completions/dub

# zsh — write to a user-owned directory you put on $fpath before compinit
mkdir -p ~/.zsh/completions
dub completion zsh > ~/.zsh/completions/_dub
# then ensure these two lines are in ~/.zshrc before any `compinit` call:
#   fpath=(~/.zsh/completions $fpath)
#   autoload -Uz compinit && compinit

# fish
dub completion fish > ~/.config/fish/completions/dub.fish

${fpath[1]} on most systems points at a root-owned directory like /usr/local/share/zsh/site-functions. Writing there works for system-wide installs (with sudo), but the user-owned path above is the recommended default.

The generated script completes:

  • Top-level subcommands (dub <Tab>).
  • Nested subcommands and their flags (e.g. dub config ai-provider <Tab>, dub trunk add <Tab>).
  • Local branch names for branch-arg commands: dub co <Tab> (alias checkout), dub delete <Tab>, dub track <Tab>, dub untrack <Tab>. (dub up and dub down take a numeric step count, not a branch.)
  • Branch names for branch-valued flags: --parent, --branch, --before, --after.
  • File paths for --by-file and for commands that take positional file arguments.
  • Per-command flags read directly from the dub binary's commander metadata, so completions stay in sync with the CLI version installed in $PATH.

Regenerate the script after upgrading dub so new flags and commands show up.

Man page

dub man emits a roff-formatted man page to stdout. Redirect it into any directory on your MANPATH:

mkdir -p ~/.local/share/man/man1
dub man > ~/.local/share/man/man1/dub.1
man dub

The page is generated from the same commander.js definitions that power dub --help, so every subcommand and option is documented automatically.

Distributors can bundle the man page alongside the binary — for example, the Homebrew formula installs dub.1 into share/man/man1/.

Refreshing the cache

Most shell integrations should rely on the default (cache-first) behavior — the overview cache is refreshed automatically by dub log, dub co, and dub status --live. If you want PR/CI freshness on every prompt, run --live from a background process and let the cached result feed your prompt:

(dub status --live >/dev/null 2>&1 &) ; dub status

On this page