yāti (याति) — Sanskrit for "travels" or "goes forth." In the Rigveda, it describes the journeying of gods between realms. yāti lets you travel between worktrees seamlessly, each one a self-contained world.
It is a git worktree manager with tmux integration. Creates and manages isolated worktrees for feature branches, each in its own tmux session. For when you want to vibe code multiple branches of the same repository simultaneously but still keep your hand in the code using your regular tmux workflows.
Heavily inspired by opencode-worktree, but agent agnostic.
git clone git@github.com:jacobhm98/yati.git
cd yati
cargo install --path .yati create feature-branchThis will:
- Create a new git worktree at
~/.yati/<project>/feature-branch - Create a new branch
feature-branch(or use an existing one) - Copy any configured files into the worktree
- Run any
post_createhooks - Open a new tmux session named
<project>/feature-branch
Switch to an existing worktree:
yati activate project/feature-branchor, if ran from project root
yati activate feature-branchThis will:
- Check that a worktree exists at
~/.yati/<project>/feature-branch - If a tmux session already exists, switch to it
- If the session was lost (e.g., after a reboot), run
post_createhooks and create a new tmux session - Run
post_activatehooks (runs on every activate, whether the session existed or was recreated)
From inside a yati-managed worktree:
yati deactivateThis leaves the current session without destroying it. If you switched from another tmux session, you'll be returned there. If you attached from a bare terminal, you'll be detached from tmux. The session stays alive for later reactivation with yati activate.
From inside a yati-managed worktree:
yati teardownThis runs pre_teardown hooks, removes the worktree, deletes the branch, and kills the tmux session. If you came from another session you'll be switched back; otherwise you'll be returned to your original terminal.
Use --force to remove even with uncommitted changes:
yati teardown --forceyati listShows all yati-managed worktrees across all projects.
yati supports dynamic shell completions for subcommands, flags, worktree targets, and branch names. Run the appropriate setup for your shell once:
echo 'source (COMPLETE=fish yati | psub)' >> ~/.config/fish/completions/yati.fishecho 'source <(COMPLETE=bash yati)' >> ~/.bashrcecho 'source <(COMPLETE=zsh yati)' >> ~/.zshrcAfter restarting your shell (or sourcing the file), yati <TAB> will complete subcommands, yati activate <TAB> will complete with existing worktree targets, and yati create <TAB> will complete with git branch names.
Create a yati.toml in your repository root:
# Files or directories to copy from the main worktree into new worktrees
copy_files = [".env", "node_modules"]
# Patterns to exclude when copying
exclude = ["*.log"]
# Commands to run after creating a worktree.
# Plain strings run synchronously before the tmux session is created.
# Use { command = "...", async = true } to run in a background tmux window.
post_create = [
"echo setting up",
{ command = "npm install", async = true },
]
# Commands to run every time a worktree is activated (including after creation)
post_activate = ["docker compose up -d"]
# Commands to run before tearing down a worktree
pre_teardown = ["docker compose down"]
# Tmux windows to create in the session.
# The first window replaces the default window; additional entries create new windows.
[tmux]
windows = [
{ name = "editor", command = "nvim" },
{ name = "server", command = "npm run dev" },
{ name = "claude --continue" },
]