Tmux Integration

Willow includes native tmux support — a worktree picker popup, live Claude output preview, status bar widget, and automatic session management. If you use tmux, this replaces the need for any separate worktree-switching plugin.

Setup

ww tmux install

This prints the tmux.conf lines to add. Copy them into your ~/.tmux.conf:

bind w run-shell -b 'tmux display-popup -E -w 90% -h 80% "/path/to/willow tmux pick --session #S"'
set -g status-right '#(/path/to/willow tmux status-bar) %l:%M %a'
set -g status-interval 3

Then reload: tmux source ~/.tmux.conf

If "tmux": {"switcherPreview": false} is set before running ww tmux install, Willow prints a compact 70% by 70% popup binding instead:

bind w run-shell -b 'tmux display-popup -E -w 70% -h 70% "/path/to/willow tmux pick --session #S"'

Picker (prefix + w)

Press prefix + w to open the worktree picker in a popup.

The right panel shows a live preview of the tmux pane content (Claude Code output). Set "tmux": {"switcherPreview": false} in config to hide that panel, use the full popup for the fzf picker, and make ww tmux install emit the smaller popup binding.

Keybindings

KeyAction
EnterSwitch to worktree (creates tmux session if needed)
Ctrl-NCreate new worktree from typed query (also accepts PR URLs)
Ctrl-TCreate a detached worktree from the selected HEAD
Ctrl-UPromote the selected detached worktree to a branch
Ctrl-BCreate new worktree stacked on a base branch (opens branch picker)
Ctrl-EBrowse existing remote branches and create a worktree
Ctrl-PBrowse open PRs and create a worktree for the selected one
Ctrl-GDispatch: create worktree from query text as prompt, launch Claude Code
Ctrl-SSync stacked worktrees (selected branch's subtree, or all)
Ctrl-DDelete selected worktree and its tmux session
Ctrl-XDelete stale worktrees currently shown, skipping unsafe ones
EscClose picker

Dispatch

Type a prompt in the query field and press Ctrl-G to dispatch a Claude Code agent. This creates a worktree (branch auto-named from the prompt, e.g. dispatch--fix-the-login-bug), opens a tmux session, and launches claude with your prompt. You're switched to the session immediately.

PR picker

Press Ctrl-P to list open PRs via gh pr list. Each line shows the PR number, title, author, and branch. Select one to create a worktree (or switch to it if one already exists). Requires the GitHub CLI.

You can also paste a PR URL into the query field and press Ctrl-N for quick one-off access.

Detached worktrees

Press Ctrl-T to create a detached worktree from the currently selected row's HEAD. If the query field is empty, Willow generates a label like detached-a13f09c; if the query has text, that text becomes the worktree directory and tmux session name.

To keep the work, select the detached worktree, type a branch name, and press Ctrl-U. Explicitly named detached worktrees can still promote with an empty query and reuse their detached name. Generated detached worktrees require a branch name; promotion moves their tmux session and agent status to the promoted branch identity.

Renaming worktrees

Use ww rename <new-name> from the current worktree, or ww rename <worktree> <new-name> from anywhere, to rename a worktree. When a matching tmux session exists, Willow renames it from <repo>/<old-dir> to <repo>/<new-dir> so panes and running agents stay reachable under the new worktree name.

Rename refuses to overwrite an existing tmux session. If you use the shell integration while inside the renamed worktree, your shell moves to the new path and preserves the nested subdirectory when possible.

Existing branch picker

Press Ctrl-E to open a secondary picker showing all remote branches that don't already have worktrees. Willow opens this picker immediately from cached refs, then refreshes from origin in the background (unless defaults.fetch is disabled) so freshly pushed branches appear without blocking the initial render. Press Ctrl-R inside the branch picker to force a synchronous refresh.

Stale worktree cleanup

Worktrees whose exact current-head PR is merged show a dim [merged] tag, and worktrees whose configured upstream branch is gone show [gone]. Willow matches PRs by head branch, head SHA, and expected base branch, using stack parents as the base for stacked branches. The picker uses cached GitHub PR-state results on open so slow PR lookups don't block rendering. Stale rows and fully stale stack groups sort toward the bottom of the list. Clean them up one at a time with Ctrl-D, bulk-delete the safe subset currently shown with Ctrl-X (the active tmux session, dirty worktrees, stacked parents, and remote-gone branches with local-only commits are skipped), or use ww gc --prune.

Features

  • Fast startup — opens from local git/status files and cached GitHub PR-state results
  • Auto-navigate — opens with the cursor on your current session
  • Urgency sort — current session first, then WAIT, unread DONE, BUSY, read DONE, IDLE, then offline
  • Status colors — BUSY (green), WAIT (red), DONE (blue), IDLE (yellow)
  • Unread indicator marks completed sessions you haven't viewed
  • Merged indicator[merged] marks worktrees whose exact current-head PR is merged when gh data is available
  • Stack-aware ordering — stacked branches stay grouped together and inherit the most urgent item in the tree
  • Multi-Claude sub-rows — when a worktree has multiple active Claude sessions, each is shown as an indented sub-row with its own status and tool info
  • Embedded fzf — fzf is compiled into the willow binary, no external fzf dependency needed

Status bar widget

The status bar shows worktree and active agent counts:

🌳 5 🤖 3

It also tracks state transitions — when a Claude session goes from BUSY to any other state, it triggers an audio notification (macOS Glass.aiff by default).

Configuration

{
  "tmux": {
    "notification": true,           // enable/disable sound (default: true)
    "notifyCommand": "afplay /System/Library/Sounds/Glass.aiff"  // custom command
  }
}

Set "notification": false to disable sound.

Session layout

By default, willow tmux creates a single window with one pane for each worktree session. You can customize this with tmux.layout — a list of raw tmux subcommands that run after session creation. The -t (target session) and -c (working directory) flags are auto-injected when not present.

{
  "tmux": {
    "layout": [
      "split-window -h",
      "select-layout even-horizontal"
    ]
  }
}

Any tmux subcommand works: split-window, new-window, select-layout, resize-pane, etc.

Per-pane commands

Use tmux.panes to send different commands to specific panes after the layout is set up. The array index maps to the pane index — pane 0 is the initial pane created by new-session, pane 1 is created by the first split-window, and so on. Panes without a config entry (or with an empty command) receive no command.

{
  "tmux": {
    "layout": [
      "split-window -h",
      "select-layout even-horizontal"
    ],
    "panes": [
      { "command": "cd website" },
      { "command": "cd website" }
    ]
  }
}

This creates two side-by-side panes, each starting in the website/ subdirectory.

To run a command in only one pane, leave the others empty:

{
  "tmux": {
    "layout": ["split-window -h"],
    "panes": [
      {},
      { "command": "dev sync --only install_system_deps,install_python_deps" }
    ]
  }
}

The left pane (index 0) gets no startup command. The right pane (index 1) runs dev sync.

Outside tmux (during willow new), pane commands run sequentially in the foreground after setup hooks.

Shell integration

When inside tmux, ww sw automatically switches tmux sessions instead of just cd-ing. This works out of the box after running eval "$(willow shell-init)" — no additional setup needed.

Contextww sw behavior
Outside tmuxfzf picker → cd to worktree
Inside tmuxfzf picker → create/switch tmux session

Commands reference

ww tmux pick

Interactive worktree picker. Designed to run inside a tmux popup.

ww tmux pick              # all repos
ww tmux pick -r myrepo    # filter to one repo

ww tmux list

Print formatted picker lines for diagnostics and picker integrations.

ww tmux status-bar

Output tmux status-right widget string. Called every status-interval seconds.

ww tmux install

Print the tmux.conf lines to add for willow integration.