1 unstable release
| 0.1.3 | Feb 1, 2026 |
|---|
#325 in GUI
200KB
5K
SLoC
twig
A tmux session manager with git worktree support, inspired by tmuxinator.
Built to scratch my own itch. Terminal UI built with Ratatui.
When you are juggling features, fixes, and reviews, git worktree lets you keep multiple branches checked out side by side. Twig ties each worktree to a tmux session and provides a snappy TUI so you can spin up a clean, focused workspace per branch in seconds.
Need to review a teammate's PR? In the tree view (twig tree list), enter #123 as the branch
name and twig will use gh to fetch the PR head (including forks), create a local pr-123
branch, and spin up a worktree. Requires GitHub CLI (gh) authentication.
Requirements
tmuxgit
Installation
We recommend using mise to install.
Via mise
mise use -g cargo:https://github.com/andersonkrs/twig
This compiles twig from source and installs it globally.
From source (for development)
git clone https://github.com/andersonkrs/twig.git ~/Work/twig
cd ~/Work/twig
# Install all tools (rust, lefthook) + git hooks
mise install
# Build
cargo build --release
# Symlink to PATH
ln -s ~/Work/twig/target/release/twig ~/.local/bin/twig
Usage
twig start [project] # Start/attach to session (interactive if no arg)
twig list # List all projects/worktrees
twig list --focus-current # Focus current TWIG_PROJECT/TWIG_WORKTREE
twig new [name|repo_url] # Create new project (accepts name or git URL)
twig edit [project] # Open config in $EDITOR
twig delete [project] # Delete project config
twig stop [project] # Kill tmux session
# Debug tmux control-mode I/O
Use `--verbose` (or `TWIG_DEBUG=1`) to enable verbose tmux control output on stderr.
twig --verbose window new [project] [name]
# Run a command in a window/pane
twig run --project=dotfiles --window=6 --pane=1 -- whoami
# Run a command in a worktree session
twig run --project=dotfiles --tree=feature-x --window=1 -- btop
# Worktree commands
twig tree create [project] [branch] # Create worktree + session
twig tree list [project] # List worktrees
twig tree delete [project] [branch] # Delete worktree + kill session
When creating a project with a git URL, twig extracts the project name automatically:
twig new git@github.com:user/myproject.git # Creates project "myproject"
Aliases: ls for list, s for start, n for new, e for edit, rm for delete, t for tree
Configuration
Global Config
Location: ~/.config/twig/config.yml
# Base path for worktrees (default: ~/Work/.trees)
# Worktrees are created at: {worktree_base}/{project}/{branch}
worktree_base: ~/Work/.trees
# Projects directory (default: ~/.config/twig/projects)
projects_dir: ~/.config/twig/projects
Project Config
Location: ~/.config/twig/projects/<name>.yml
name: myproject
root: ~/Work/myproject
# Optional: git repo URL (https or ssh)
# If root doesn't exist, twig will clone this repo on first start
repo: git@github.com:user/myproject.git
windows:
# Simple window with command
- git: lazygit
# Empty shell window
- shell:
# Window with multiple panes
- editor:
panes:
- nvim
# Window with layout and multiple panes
- servers:
layout: main-vertical # main-vertical, main-horizontal, even-vertical, even-horizontal, tiled
panes:
- rails server
- bin/sidekiq
# Optional: worktree configuration
worktree:
# Files/folders to copy from parent project to worktree
copy:
- .env
- .env.local
- config/master.key
# Files/folders to symlink from parent project to worktree
# Only supported on Unix
symlink:
- .env
# Commands to run after worktree creation
post_create:
- bundle install
- yarn install
- rails db:migrate
# Note: post_create runs inside a temporary setup window in the worktree session
# so your shell init and environment (mise/rbenv/etc) are applied.
Example Configs
Rails project:
name: myapp
root: ~/Work/myapp
windows:
- editor:
panes:
- nvim
- shell:
- rails:
layout: main-vertical
panes:
- rails server
- bin/sidekiq
- console: rails console
- git: lazygit
worktree:
copy:
- .env
- .env.local
- config/master.key
- config/credentials.yml.enc
symlink:
- .env
post_create:
- bundle install
- yarn install
- bin/rails db:prepare
Simple project:
name: dotfiles
root: ~/.dotfiles
windows:
- editor:
panes:
- nvim
- shell:
- shell:
- git: lazygit
How It Works
Twig is a thin Rust layer that turns YAML configs into tmux control-mode commands and manages git worktrees when requested. The CLI orchestrates config loading, git worktree creation, and tmux session construction; the TUI only renders state and triggers CLI actions.
YAML config
|
v
CLI (twig) ---> git worktree ops (optional)
|
v
tmux control mode -> tmux server -> sessions/windows/panes
User input (TUI)
|
v
CLI commands -> tmux control mode
Tmux control protocol docs: https://man7.org/linux/man-pages/man1/tmux.1.html#CONTROL_MODE
Sessions
When you run twig start <project>:
- Checks if session already exists → attaches if so
- Creates new tmux session with configured windows/panes
- Runs commands in each pane
- Attaches to the session (or switches if already in tmux)
Worktrees
When you run twig tree create <project> <branch>:
- Creates git worktree at
{worktree_base}/{project}/{branch} - Creates the branch if it doesn't exist
- Copies and symlinks configured files from parent project
- Runs post-create commands
- Starts a tmux session named
{project}__{branch}
Session naming: myproject__feature-auth (double underscore separator)
Worktree path: ~/Work/.trees/myproject/feature-auth
When you run twig tree delete <project> <branch>:
- Kills the tmux session if running
- Removes the git worktree
Tmux Popup Session Picker
You can replace the tmux session picker with a popup that calls twig ls --focus-current.
This uses the TWIG_PROJECT and TWIG_WORKTREE environment variables to focus the cursor
on the current project/worktree when available.
Add a key binding to your ~/.tmux.conf:
# Twig popup
unbind s
bind-key s display-popup -E -w 80% -h 60% "twig ls --focus-current"
If you want the popup to always open from anywhere (not just inside a twig session), it will still work but will fall back to the first project when the env vars are not set.
Releases
- Releases are managed by release-plz using conventional commits to determine the bump.
- A release PR is created/updated on every push to
main. - Merge the release PR to tag and publish a GitHub release; binaries are uploaded for linux x86_64 and macOS universal2.
- You can re-run release checks by triggering the "Release Plz" workflow manually.
Development
# Install dependencies + git hooks
mise install
# Build
cargo build --release
Formatting and linting are automatically run by lefthook on pre-commit.
License
MIT
Dependencies
~9–22MB
~259K SLoC