git worktree + Kitty or tmux for one or multiple repos.
- I work in Kitty + neovim. Terminal is my IDE. I like to use
git worktreeto isolate work across features and PRs. - More than often, I need to work across multiple repos for one feature (e.g.
backend+frontend). - Inspired by workmux, but I needed multi-repo support.
-
Looks like vibe coded? : Yes. Good vibes only.
-
Do you even use this? : Yes, daily.
brew tap alienxp03/tap
brew install wktreego install github.com/alienxp03/wktree/cmd/wktree@latestwktree initCreates .wktree.yaml in the current directory. wktree searches from cwd up to the Git root and uses the nearest config.
worktree_dir: ~/worktree
terminal:
session_name: "${repo}/${branch}"
workspace_mode: single
workspaces:
- name: backend
files:
copy:
- .env.backend
symlink:
- .tool-versions
hooks:
post_create:
- direnv allow
panes:
- command: nvim
focus: true
- commands:
- pnpm install
- pnpm run dev
split: horizontal
- command: codex
split: verticalworktree_dir: ~/worktree
workspace_mode: all
defaults:
files:
copy:
- .env
symlink:
- AGENTS.override.md
workspaces:
- name: backend
files:
copy:
- .env.backend
hooks:
post_create:
- direnv allow
randomize_ports:
- file: .env.local
vars:
- PORT
- APP_PORT
set_env:
- file: .env.local
vars:
API_URL: "http://localhost:${backend:.env.local:PORT}/api"
open:
- "http://localhost:${backend:.env.local:PORT}/api"
panes:
- command: nvim
focus: true
- commands:
- pnpm install
- pnpm run dev
split: horizontal
- name: frontend
repo: ~/workspace/frontend
files:
copy:
- .env.frontend
hooks:
post_create:
- pnpm install
panes:
- command: nvim
focus: true
- command: pnpm run dev
split: horizontalUse selected to target only named workspaces by default. The workspace order still comes from workspaces; --workspaces overrides this selection and targets all configured workspaces.
workspace_mode: selected
default_workspaces:
- backend
- worker
workspaces:
- name: backend
- name: frontend
repo: ~/workspace/frontend
- name: worker
repo: ~/workspace/worker| Key | Description |
|---|---|
worktree_dir |
Where worktrees are stored. Default ~/workspace/worktrees. |
terminal.provider |
Terminal provider: kitty (default) or tmux. Set provider: tmux to opt in to tmux layouts. |
terminal.mode |
Tmux-only: window (default) creates a window in the current session; session creates a tmux session. |
terminal.session_name |
Layout/session name template. Supports ${owner}, ${repo}, ${branch}, ${dir}, and ${dir:N}. Default ${repo}/${branch}. |
integrations.zoxide |
When true, adds every selected worktree path to zoxide during new and switch. |
workspace_mode |
single uses the first workspace, all uses every workspace, and selected uses default_workspaces. --workspaces always targets all configured workspaces. |
default_workspaces |
Workspace names targeted by default when workspace_mode is selected. |
defaults |
Shared config applied to every workspace before workspace-level config. |
workspaces |
Ordered list of workspaces. |
${dir} is the directory containing .wktree.yaml; ${dir:1} is its parent, ${dir:2} is the next parent, and so on.
| Key | Description |
|---|---|
name |
Workspace identifier. Used for tmux window / Kitty tab names and env variable names. |
repo |
Path to the Git repo. Omit to use the directory containing .wktree.yaml. |
files.copy |
Copy files into the new worktree (isolated per worktree). |
files.symlink |
Symlink files from the source repo (shared across worktrees). |
hooks.post_create |
Commands to run after worktree creation, before the terminal layout opens. |
randomize_ports |
Replaces named env vars with available localhost ports. |
set_env |
Sets env variables with template references like ${workspace:file:VAR}. |
open |
Opens URLs after setup completes. Uses the same template references as set_env. |
panes |
Terminal panes/windows. Each has command or commands, optional split (horizontal/vertical), percentage, and focus. Each new pane splits the immediately preceding pane. Kitty maps horizontal to vsplit, vertical to hsplit, and percentage to bias; Kitty rejects tmux-only size and zoom. |
When a workspace is created or switched, wktree writes .wktree.env with one variable per workspace:
export WKTREE_BACKEND_DIR='/Users/stan/worktree/org/backend/feature-example'
export WKTREE_FRONTEND_DIR='/Users/stan/worktree/org/frontend/feature-example'Pane commands and post_create hooks source this file before running. PR worktrees also include WKTREE_PR_NUMBER, WKTREE_PR_URL, WKTREE_PR_HEAD_REF, and WKTREE_PR_HEAD_SHA.
wktree init Create starter config
wktree doctor Check repo, config, and configured terminal provider
wktree list List worktrees
wktree list --pr List worktrees with PR info
wktree cleanup Remove merged worktree branches after confirmation
wktree cleanup --dry-run Preview merged worktree branch cleanup
wktree new <branch> Create branch + worktree + terminal layout
wktree new --from <ref> <branch> Create from a specific ref
wktree new --workspaces <branch> Create across all workspaces
wktree switch <branch> Open existing worktree in the configured terminal
wktree switch --pr <number|url> Open a GitHub PR locally
wktree close <branch> Close terminal layout (keeps worktree)
wktree remove <branch> Close layout + remove worktree + delete branch
wktree remove --pr <number|url> Remove by GitHub PR head branch
Common flags: --dry-run to preview, --force to override safety checks, --workspaces to target all configured workspaces (including those excluded by default_workspaces).
When removing across all workspaces, --force skips workspaces where the local branch is already gone.
Use wktree cleanup --yes to skip the confirmation prompt after reviewing the cleanup behavior.
Worktree paths follow <worktree_dir>/<owner>/<repo>/<branch>. For GitHub remotes, owner and repo come from the remote URL.
wktree switch <branch> reuses an existing worktree at that path even if you changed the checked-out branch inside it after creation.
Kitty is the default and requires no provider setting:
terminal:
session_name: "${repo}/${branch}"Kitty creates one generated session per branch, with each workspace as a tab and each configured pane as a Kitty window. Run wktree inside Kitty, or set KITTY_LISTEN_ON to a Kitty remote-control socket. Existing generated sessions are focused instead of duplicated. Session files are stored under the user cache directory; no Kitty dotfiles or socket paths are modified.
Opt in to tmux explicitly:
terminal:
provider: tmux
mode: window
session_name: "${repo}/${branch}"To make worktrees available to zoxide-backed project pickers such as Cmd+Shift+O:
integrations:
zoxide: trueThis runs zoxide add -- <workspace-path>... after setup on both new and switch.
Completion-only:
eval "$(wktree completion zsh)" # or bashmake build # build to dist/
make install # install to ~/.local/bin/wktree
make lint test # lint and testtmux window mode requires running inside tmux— start tmux first or useterminal.mode: session.- Kitty remote-control errors — run inside Kitty, or configure Kitty remote control and pass its socket through
KITTY_LISTEN_ON. gh is required for --pr— install and authenticate the GitHub CLI.branch is not merged— merge first, check whether the local branch has commits beyond the merged PR head, or use--force. For merged GitHub PRs,wktreemay fetch the PR head ref to verify local branches that do not have the merged PR commit locally yet.wktree doctor— run this first when something looks wrong.