wt skill bundle
wt wraps git worktree with opinionated defaults: worktrees are created as
siblings of the main repo (<repo>.worktrees/<name>/), branches get memorable
random adjective-noun names, and a shell wrapper makes cd-into-worktree from a
menu actually work. Built for parallel work where each branch — or each agent
session — gets its own checkout.
When to use
- Reach for
wtwhen you need multiple branches checked out at once — parallel edits, reviews, or agent sessions — without stash/switch churn on a single working tree. - Not for plain branch switching in one working tree: if you don’t need a
second checkout on disk,
git switchis simpler.wtadds a directory per branch; that is the whole point, and the cost.
Capabilities map
One line per subcommand (run wt <cmd> --help for flags):
create [branch](aliasnew) — new-branch worktree with a random name.--checkout <branch>puts it on an existing branch instead;--base <ref>sets a new branch’s start-point;-n/--nameoverrides the random name;--reusereuses an existing named worktree;--no-initskips the init script.list(aliasls) — table of worktrees (name, branch, path).--statusadds dirty/unpushed indicators;--jsonemits machine records;--path <name>prints one absolute path.open [name|path]— launch a worktree/dir in a detected app (editor, terminal, file manager) via the app menu. No arg opens the current context (worktree root / repo root / cwd).-a/--app <name>skips the menu;defaultpicks the auto-detected app.--list [--json]prints the app registry instead.go [name]— select a worktree: no arg → selection menu; a name → direct. By default navigates (cd) there;--open <prompt|default|skip|app>launches the selection instead (go owns the worktree menu, open owns the app menu; this flag composes them). Requires a git repo.delete [names...](aliasrm) — remove worktrees with optional branch cleanup.--all/-aremoves every worktree;-s/--stashstashes uncommitted changes first;--branch <true|false|auto>and--no-remotecontrol branch deletion.init— run the worktree init script for the current worktree/main repo.shell-init <shell>— print the shell wrapper function (zshorbash) forevalin your profile; a missing/unsupported shell is a usage error (exit 2).update— self-update the binary via Homebrew.
Composition patterns
- Shell-wrapper eval flow. A child process cannot
cdits parent shell, sowtprints shell code that the user evals:eval "$(wt shell-init zsh)"(orbash) installs a function wrapping the binary. That function powers the “Open here” menu option inwt openand the navigation inwt go. Without it, those fall back to printing a path for the caller tocd. - Launcher contract (
WT_CD_FILE/WT_WRAPPER).wt openis the toolkit’s canonical directory launcher — external callers (e.g.hop) delegate to it as a subprocess. “Open here” andwt goshare one shell-cd contract: whenWT_CD_FILEis set they write the resolved directory path there (mode 0600, truncate-on-write), and they always print the bare path as the last stdout line (cd "$(command wt …)"works without the wrapper); the caller applies thecditself. SetWT_WRAPPER=1to signal you handle thecdand suppress the “wrapper not loaded” hint. A non-zero exit means do not trustWT_CD_FILE’s contents. Seedocs/specs/launcher-contract.md. - Init protocol (
WORKTREE_INIT_SCRIPT). Each new worktree runs an init script — defaultfab sync, override viaWORKTREE_INIT_SCRIPT. A value with a space is a command invocation (first word looked up on PATH); a value without spaces is a file path resolved from the repo root and run viabash. It runs with the new worktree as its working directory; its output goes to stderr. Seedocs/specs/init-protocol.md. - Machine surface.
wt list --jsonis the structured composition surface (e.g. whathopreads);wt createprints the worktree path as its last stdout line.
Output & exit-code contracts
- stdout is data, stderr is human copy. Machine results (the created worktree
path,
list --json,list --path, thegotarget path) go to stdout; all progress, prompts, warnings, and errors go to stderr. Init-script output is diagnostic and streams to stderr. Sop=$(wt create ...)captures the path clean. - Errors are structured
Error: <what>/Why: <why>/Fix: <fix>on stderr, emitted viaExitWithError. - Typed exit codes (from
internal/worktree/errors.go) let scripts branch:0success ·1general error ·2invalid args / incompatible flags3git error (or not a git repo) ·4name-generation retries exhausted5byobu-tab error ·6tmux-window error7init script ran but exited non-zero (worktree is kept, not rolled back)130SIGINT duringwt create(partial state rolled back)
- Scriptable on demand. Interactive commands take
--non-interactivefor deterministic, prompt-free behavior; output degrades gracefully when stdout is not a TTY.NO_COLORdisables color.
Gotchas
- Worktrees live beside the repo, not inside it — at
<repo>.worktrees/<name>/, a sibling directory. They are not created under the main working tree. - Random names by default. New worktrees get an adjective-noun name (e.g.
lively-otter) unless you pass-n/--name. - The
createpositional is new-branch-only. Naming a branch that already exists (locally or on the remote) is an error (exit 2) pointing you at--checkout <branch>— the explicit opt-in for existing branches.--reusetakes precedence over--base. - Init failure keeps the worktree. If the init script exits non-zero,
wtexits7(not1) and leaves the worktree in place with a retry hint (cd <path> && wt init) — the git operations already succeeded. It does not roll back. (Two non-failures still exit 0: a missing init command/file, and — for the defaultfab synconly — a repo that is not fab-managed.) wt opencan’tcdwithout the shell wrapper. That is a Unix constraint; installeval "$(wt shell-init zsh)"(orbash) to make “Open here” andwt gochange your shell’s directory.- Deleting a worktree externally leaves git bookkeeping. If you
rm -rfa worktree, rungit worktree prunein the main repo to clean up.