wt

July 22, 2026 · View on GitHub

Part of the shll toolkit — see all projects there.

Latest release Downloads Stars

A small CLI that wraps git worktree with opinionated defaults: worktrees are created as siblings of the main repo (<repo>.worktrees/<name>/), names are memorable random adjective-noun pairs, and a shell wrapper makes cd-into-worktree from a menu actually work. Designed for the parallel-edit workflow where each branch (or each AI session) gets its own checkout.

Install

curl -fsSL https://shll.ai/install | sh -s -- wt

Installs wt (plus the shll meta-CLI) via Homebrew, handling tap trust automatically. To install the entire shll toolkit instead:

curl -fsSL https://shll.ai/install | sh

Why wt?

  • Sibling layout, not clutter — worktrees go in <repo>.worktrees/<name>/, never inside the main repo.
  • Memorable names — random adjective-noun pairs (lively-otter, bold-fox) instead of feature-1, feature-2.
  • Real cd from a menu — the shell wrapper lets wt open actually change your shell's directory (something a plain binary can't do).
  • Per-worktree init — each new worktree runs an init script (default fab sync, override via WORKTREE_INIT_SCRIPT) so it's ready to use immediately.

Other ways to install

Manual (requires Go and just):

git clone https://github.com/sahil87/wt
cd wt
just local-install   # builds bin/wt and copies to ~/.local/bin/wt

For the "Open here" menu option to actually cd your current shell, add the wrapper to your shell profile:

eval "$(wt shell-init zsh)"     # in ~/.zshrc
eval "$(wt shell-init bash)"    # in ~/.bashrc

💡 Have other shll tools? shll shell-install handles all of their shell integrations and autocompletions at once.

For the full install guide — every path, the shell wrapper, and cross-tool setup — see the install guide.

Usage

A typical first session:

$ wt create
Created: ../wt.worktrees/lively-otter
  Branch: lively-otter (from main)

$ wt list
Worktrees for: wt
Location: /Users/you/code/wt.worktrees

  Name          Branch         Path
* (main)        main           wt/
  lively-otter  lively-otter   wt.worktrees/lively-otter/

$ wt open lively-otter        # menu → "Open here" cd's your shell
$ wt delete lively-otter      # removes worktree (and optionally the branch)

Command reference

CommandSummary
wt create [branch] (alias wt new)Create a worktree on a new branch (random name, or the named positional). Key flags: --checkout <branch> (existing branch), --base <ref>, --reuse, --name/-n, --non-interactive.
wt list (alias wt ls)List all worktrees with name, branch, and path. Add --status for dirty/unpushed indicators; --path and --json for scripting.
wt open [name|path]Open a worktree — or any directory — in a detected app (editor, terminal, file manager). No arg opens the current context; --app/-a skips the app menu.
wt go [name]Pick a worktree (menu or by name) and cd there via the shell wrapper. --open launches the selection instead (menu with --open prompt).
wt delete [names...] (alias wt rm)Delete one or more worktrees with optional branch cleanup.
wt initRun the worktree init script (default fab sync, override via WORKTREE_INIT_SCRIPT).
wt shell-init <shell>Print a shell wrapper function (zsh or bash) for eval in your shell profile.
wt skillPrint the agent usage bundle — a static, one-page markdown briefing for an agent operating wt (offline, embedded, versioned with the binary).

Run wt <command> --help for inline flag details. For every flag and exit code, see the auto-generated command reference; for the --base start-point rules and the wt open launcher matrix, see the workflows guide.

wt create --base — branch start-point

--base <ref> controls the start-point when wt creates a new branch (maps to git worktree add -b <branch> <path> <start-point>). Behavior depends on whether the branch already exists:

Scenario--baseBehavior
New branch (doesn't exist locally or remotely)providedBranch created from --base ref
New branchomittedBranch created from HEAD (default)
Positional names an existing branch (local or remote)eitherError (exit 2): the positional only creates new branches — use --checkout <branch>
With --checkout <branch>providedError (exit 2): --base sets a new branch's start-point; --checkout targets an existing branch
Exploratory (no branch arg)providedExploratory branch created from --base ref
ExploratoryomittedBranch created from current HEAD (default)
With --reuse (worktree exists)provided--reuse takes precedence; --base has no effect
Invalid refprovidedError exit; no worktree or branch created

To put a worktree on an existing branch (local or remote), opt in explicitly with --checkout <branch> — e.g. wt create --checkout sockets-v2. A remote-only branch is fetched first; a branch that exists nowhere is an error pointing you back at the positional/--base form.

The ref is validated via git rev-parse --verify before worktree creation, so invalid refs produce a clear error rather than a partial failure.

wt open and wt go — launcher and selector

The two commands split along two axes — selection (which directory) and action (navigate vs. launch). Each menu lives in exactly one verb: wt go owns the "which worktree?" menu, wt open owns the "which app?" menu. Compose them with wt go --open:

InvocationWorktree menu?App menu?Result
wt goyesnocd to selection
wt go frosty-foxnonocd directly
wt go --open promptyesyeslaunch selection in chosen app
wt go --open codeyesnolaunch selection in VS Code
wt opennoyeslaunch current dir (worktree root / repo root / cwd)
wt open <name|path>noyeslaunch that dir
wt open --app codenonolaunch current dir in VS Code

wt open is the canonical directory launcher in the toolkit (hop delegates to it too): no arg opens the current context, a name resolves against this repo's worktrees (requires a git repo), and a path opens literally — git context doesn't matter. The app menu lists the apps wt detected on your machine (editors, terminals, file managers) plus an "Open here" option that cds your current shell into the target — that one needs the shell wrapper (see Gotchas).

Picking a worktree and launching it, with two worktrees on disk:

$ wt go --open prompt
Select worktree to open:
  1) main (main)
  2) lively-otter (feature/spinner) (default)
  3) bold-fox (fix/race-condition)
  0) Cancel

Choice [2]: 2
Open in:
  1) Open here
  2) VSCode (default)
  3) Cursor
  4) Ghostty
  5) Terminal.app
  6) Finder
  7) Copy path
  0) Cancel

Choice [2]:

Pick 1 to cd your shell into the worktree, 26 to launch it in a detected app, or 7 to copy the absolute path to your clipboard.

Gotchas

  • wt open can't cd without the shell wrapper. A child process can't change its parent shell's directory — that's a Unix constraint, not a wt bug. eval "$(wt shell-init zsh)" (or bash) installs a shell function that wraps the binary so the "Open here" menu option actually works.
  • The wt create positional never checks out an existing branch. Naming a branch that already exists (locally or on the remote) is an error (exit 2) — checkout of an existing branch is an explicit opt-in via --checkout <branch>. --reuse takes precedence over --base.
  • Worktrees survive cd into deleted directories. If you delete a worktree from outside (rm -rf), run git worktree prune in the main repo to clean up git's bookkeeping.