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 ongh).dub status --json— structured JSON withschemaVersion: 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 withoutghinstalled 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 5For 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 30oh-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>(aliascheckout),dub delete <Tab>,dub track <Tab>,dub untrack <Tab>. (dub upanddub downtake a numeric step count, not a branch.) - Branch names for branch-valued flags:
--parent,--branch,--before,--after. - File paths for
--by-fileand for commands that take positional file arguments. - Per-command flags read directly from the
dubbinary'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 dubThe 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