{"id":35411371,"url":"https://github.com/chmouel/lazyworktree","last_synced_at":"2026-02-13T15:09:01.978Z","repository":{"id":331972024,"uuid":"1124227816","full_name":"chmouel/lazyworktree","owner":"chmouel","description":"Easy Git worktree management for the terminal.","archived":false,"fork":false,"pushed_at":"2026-01-22T06:36:30.000Z","size":4759,"stargazers_count":65,"open_issues_count":1,"forks_count":2,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-01-22T12:40:09.548Z","etag":null,"topics":["bubbletea","charmbracelet","git","golang","lazy","lazygit","terminal","tmux","tui","worktree-manager","worktrees","zellij"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/chmouel.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":"AGENTS.md","dco":null,"cla":null}},"created_at":"2025-12-28T15:54:23.000Z","updated_at":"2026-01-22T08:11:45.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/chmouel/lazyworktree","commit_stats":null,"previous_names":["chmouel/lazyworktree"],"tags_count":42,"template":false,"template_full_name":null,"purl":"pkg:github/chmouel/lazyworktree","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/chmouel%2Flazyworktree","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/chmouel%2Flazyworktree/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/chmouel%2Flazyworktree/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/chmouel%2Flazyworktree/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/chmouel","download_url":"https://codeload.github.com/chmouel/lazyworktree/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/chmouel%2Flazyworktree/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28736509,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-24T19:23:36.361Z","status":"ssl_error","status_checked_at":"2026-01-24T19:23:28.966Z","response_time":89,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["bubbletea","charmbracelet","git","golang","lazy","lazygit","terminal","tmux","tui","worktree-manager","worktrees","zellij"],"created_at":"2026-01-02T14:10:28.568Z","updated_at":"2026-02-13T15:09:01.947Z","avatar_url":"https://github.com/chmouel.png","language":"Go","funding_links":[],"categories":["Go","TUI"],"sub_categories":[],"readme":"![Go](https://img.shields.io/badge/go-1.25%2B-blue) ![Coverage](https://img.shields.io/badge/Coverage-57.5%25-yellow)\n\n# LazyWorktree - Easy Git worktree management for the terminal\n\n\u003cimg align=\"right\" width=\"180\" height=\"180\" alt=\"lw-logo\" src=\"https://github.com/user-attachments/assets/77b63679-40b8-494c-a62d-19ccc39ac38e\" /\u003e\n\nLazyWorktree is a TUI for Git worktrees. It provides a keyboard-driven workflow\nfor creating, inspecting, and navigating worktrees within a repository.\n\nBuilt with [BubbleTea](https://github.com/charmbracelet/bubbletea), it focuses on fast iteration, clear state visibility, and tight Git tooling integration.\n\n## Screenshot\n\n![lazyworktree screenshot](https://github.com/user-attachments/assets/229a4d6d-f26f-4b85-b909-fc28b9c524c2)\n\n_See other [Screenshots below](#screenshots)_\n\n## Features\n\n* Worktree management: create, rename, remove, absorb, and prune merged worktrees.\n* Powerful creation options:\n  * From current branch, optionally with uncommitted changes.\n  * Checkout existing branch or create a new branch from it.\n  * From GitHub/GitLab issue with automatic branch naming.\n  * From open GitHub/GitLab PR or MR.\n* VIM style keybinding and a VSCode-like command palette (and as configurable\nas emacs!).\n* View CI logs from GitHub Actions.\n* Display linked PR/MR, CI status, and checks.\n* Stage, unstage, commit, edit, and diff files.\n* View diffs in a pager with optional delta integration.\n* Manage per-worktree tmux or zellij sessions.\n* Cherry-pick commits between worktrees.\n* Command palette with MRU-based navigation.\n* Custom commands: define keybindings, tmux/zellij layouts, and per-repo workflows.\n* Init/terminate hooks via `.wt` files with TOFU security.\n* Shell integration: jump into worktrees and return to the last-used one.\n* Automatic branch naming via scripts (e.g., LLM tools).\n\n## Getting Started\n\n* Install lazyworktree using one of the methods below\n* Navigate to a Git repository in your terminal\n* Run lazyworktree to launch the TUI\n* Press ? to view the interactive help screen\n\n## Requirements\n\n* **Git**: 2.31+\n* **Forge CLI**: `gh` or `glab` for PR/MR status\n\n**Optional:**\n\n* Nerd Font: Icons default to Nerd Font glyphs.\n\n\u003e [!IMPORTANT]\n\u003e If you see weird characters when starting lazyworktree, set `icon_set: text` or install a font patched with Nerd Font.\n\n* delta: Syntax-highlighted diffs (recommended)\n* lazygit: Full TUI git control\n* tmux / zellij: Session management\n\n**Build-time only:**\n\n* Go 1.25+\n\n## Installation\n\n### Pre-built Binaries\n\nPre-built binaries are available in the [Releases](https://github.com/chmouel/lazyworktree/releases).\n\n### 🍺 Homebrew (macOS)\n\n```shell\nbrew tap chmouel/lazyworktree https://github.com/chmouel/lazyworktree\nbrew install lazyworktree --cask\n```\n\n#### macOS Gatekeeper\n\nIf macOS shows \"Apple could not verify lazyworktree\":\n\n**Option 1:** System Settings \u003e Privacy \u0026 Security \u003e \"Open Anyway\"\n\n**Option 2:** Remove quarantine attribute:\n\n```bash\nxattr -d com.apple.quarantine /opt/homebrew/bin/lazyworktree\n```\n\n### [Arch](https://aur.archlinux.org/packages/lazyworktree-bin)\n\n```shell\nyay -S lazyworktree-bin\n```\n\n### From Source\n\nDirect installation:\n\n```bash\ngo install github.com/chmouel/lazyworktree/cmd/lazyworktree@latest\n```\n\nVia cloning and building:\n\n```bash\ngit clone https://github.com/chmouel/lazyworktree.git\ncd lazyworktree\ngo build -o lazyworktree ./cmd/lazyworktree\n```\n\n## Shell Integration\n\nShell helpers change directory to the selected worktree on exit. Optional but recommended.\n\nZsh helpers are in `shell/functions.zsh`. See [./shell/README.md](./shell/README.md) for details.\n\n## Key Bindings\n\n| Key | Action |\n| --- | --- |\n| `Enter` | Jump to worktree (exit and cd) |\n| `j`, `k` | Move selection up/down in lists and menus |\n| `c` | Create new worktree (from branch, commit, PR/MR, or issue) |\n| `i` | Annotate selected worktree (multiline note with optional pinned flag) |\n| `m` | Rename selected worktree |\n| `D` | Delete selected worktree |\n| `d` | View diff in pager (worktree or commit, depending on pane) |\n| `A` | Absorb worktree into main |\n| `X` | Prune merged worktrees (refreshes PR data, checks merge status) |\n| `!` | Run arbitrary command in selected worktree (with command history) |\n| `v` | View CI checks (Enter opens in browser, Ctrl+v views logs in pager) |\n| `o` | Open PR/MR in browser (or root repo in editor if main branch with merged/closed/no PR) |\n| `ctrl+p`, `:` | Command palette |\n| `g` | Open LazyGit |\n| `r` | Refresh list (also refreshes PR/MR/CI for current worktree on GitHub/GitLab) |\n| `R` | Fetch all remotes |\n| `S` | Synchronise with upstream (pull + push, requires clean worktree) |\n| `P` | Push to upstream (prompts to set upstream if missing) |\n| `f` | Filter focused pane (worktrees, files, commits) |\n| `/` | Search focused pane (incremental) |\n| `alt+n`, `alt+p` | Move selection and fill filter input |\n| `↑`, `↓` | Move selection (filter active, no fill) |\n| `s` | Cycle sort mode (Path / Last Active / Last Switched) |\n| `Home` | Go to first item in focused pane |\n| `End` | Go to last item in focused pane |\n| `?` | Show help |\n| `q` | Quit |\n| `1` | Focus Worktree pane (toggle zoom if focused) |\n| `2` | Focus Status pane (toggle zoom if focused) |\n| `3` | Focus Log pane (toggle zoom if focused) |\n| `h`, `l` | Navigate left/right (h=worktree pane, l=cycle right panes) |\n| `Tab`, `]` | Cycle to next pane |\n| `[` | Cycle to previous pane |\n| `=` | Toggle zoom for focused pane (full screen) |\n\nIn the annotation editor (`i`): `Ctrl+S` saves, `Enter` adds a new line, `Tab` switches focus to the pinned checkbox, and `Esc` cancels.\n\n**Log Pane** (when focused on commit log):\n\n| Key | Action |\n| --- | --- |\n| `Enter` | Open commit file tree (browse files changed in commit) |\n| `d` | Show full commit diff in pager |\n| `C` | Cherry-pick commit to another worktree |\n| `j/k` | Navigate commits |\n| `ctrl+j` | Next commit and open file tree |\n| `/` | Search commit titles (incremental) |\n\n**Commit File Tree** (when viewing files in a commit):\n\n| Key | Action |\n| --- | --- |\n| `j/k` | Navigate files and directories |\n| `Enter` | Toggle directory collapse/expand, or show file diff |\n| `d` | Show full commit diff in pager |\n| `f` | Filter files by name |\n| `/` | Search files (incremental) |\n| `n/N` | Next/previous search match |\n| `ctrl+d`, `Space` | Half page down |\n| `ctrl+u` | Half page up |\n| `g`, `G` | Jump to top/bottom |\n| `q`, `Esc` | Return to commit log |\n\n**Status Pane** (when focused on status):\n\nDisplays changed files in a collapsible tree view, grouped by directory (similar to lazygit).\n\n| Key | Action |\n| --- | --- |\n| `j/k` | Navigate between files and directories |\n| `Enter` | Toggle directory expand/collapse, or show diff for files |\n| `e` | Open selected file in editor |\n| `d` | Show full diff of all files in pager |\n| `s` | Stage/unstage selected file or directory |\n| `D` | Delete selected file or directory (with confirmation) |\n| `c` | Commit staged changes |\n| `C` | Stage all changes and commit |\n| `g` | Open LazyGit |\n| `ctrl+←`, `ctrl+→` | Jump to previous/next folder |\n| `/` | Search file/directory names (incremental) |\n| `ctrl+d`, `Space` | Half page down |\n| `ctrl+u` | Half page up |\n| `PageUp`, `PageDown` | Half page up/down |\n\n**CI Status Pane** (when viewing CI checks):\n\n| Key | Action |\n|--- | --- |\n| `Enter` | Open CI job in browser |\n| `Ctrl+v` | View CI logs in pager |\n| `Ctrl+r` | Restart CI job (GitHub Actions only) |\n\n**Filter Mode:**\n\nApplies to focused pane (worktrees, files, commits). Active filter shows `[Esc] Clear` hint.\n\nSelection menus: press `f` to show the filter input; `Esc` returns to the list and keeps the current filter.\n\n* `alt+n`, `alt+p`: Navigate and update filter input\n* `↑`, `↓`, `ctrl+j`, `ctrl+k`: Navigate without changing input\n* `Enter`: Exit filter mode (filter remains)\n* `Esc`, `Ctrl+C`: Clear filter\n\n**Search Mode:**\n\n* Type to jump to the first matching item\n* `n`, `N`: Next / previous match\n* `Enter`: Close search\n* `Esc`, `Ctrl+C`: Clear search\n\n**Command History (`!`):**\n\nSaved per repository (100 max). Use `↑`/`↓` to navigate.\n\n**Command Palette Actions:**\n\n* **Select theme**: Change theme with live preview (see [Themes](#themes)).\n* **Create from current branch**: Copy current branch to a new worktree. Tick \"Include current file changes\" to carry over uncommitted changes. Uses `branch_name_script` if configured.\n\n### Mouse Controls\n\n* **Click**: Select and focus panes or items\n* **Scroll**: Navigate lists in any pane\n\n## Configuration\n\nDefault worktree location: `~/.local/share/worktrees/\u003corganization\u003e-\u003crepo_name\u003e`.\n\n### Global Configuration (YAML)\n\nReads `~/.config/lazyworktree/config.yaml`. Example (also in [config.example.yaml](./config.example.yaml)):\n\n```yaml\nworktree_dir: ~/.local/share/worktrees\nsort_mode: switched  # Options: \"path\", \"active\" (commit date), \"switched\" (last accessed)\nauto_refresh: true\nrefresh_interval: 10  # Seconds\ndisable_pr: false     # Disable all PR/MR fetching and display (default: false)\nicon_set: nerd-font-v3\nsearch_auto_select: false\nfuzzy_finder_input: false\npalette_mru: true         # Enable MRU (Most Recently Used) sorting for command palette\npalette_mru_limit: 5      # Number of recent commands to show (default: 5)\nmax_untracked_diffs: 10\nmax_diff_chars: 200000\nmax_name_length: 95       # Maximum length for worktree names in table display (0 disables truncation)\ntheme: \"\"       # Leave empty to auto-detect based on terminal background colour\n                # (defaults to \"rose-pine\" for dark, \"dracula-light\" for light).\n                # Options: see the Themes section below.\ngit_pager: delta\npager: \"less --use-color --wordwrap -qcR -P 'Press q to exit..'\"\neditor: nvim\ngit_pager_args:\n  - --syntax-theme\n  - Dracula\ntrust_mode: \"tofu\" # Options: \"tofu\" (default), \"never\", \"always\"\nmerge_method: \"rebase\" # Options: \"rebase\" (default), \"merge\"\nsession_prefix: \"wt-\" # Prefix for tmux/zellij session names (default: \"wt-\")\n# Branch name generation for issues\nissue_branch_name_template: \"issue-{number}-{title}\" # Placeholders: {number}, {title}, {generated}\n# Automatic branch name generation (see \"Automatically Generated Branch Names\")\nbranch_name_script: \"\" # Script to generate names from diff/issue content\ninit_commands:\n  - link_topsymlinks\nterminate_commands:\n  - echo \"Cleaning up $WORKTREE_NAME\"\ncustom_commands:\n  t:\n    command: make test\n    description: Run tests\n    show_help: true\n    wait: true\n# Custom worktree creation menu items\ncustom_create_menus:\n  - label: \"From JIRA ticket\"\n    description: \"Create from JIRA issue\"\n    command: \"jayrah browse 'SRVKP' --choose\"\n    interactive: true  # TUI-based commands need this to suspend lazyworktree\n    post_command: \"git commit --allow-empty -m 'Initial commit for ${WORKTREE_BRANCH}'\"\n    post_interactive: false  # Run post-command in background\n  - label: \"From clipboard\"\n    description: \"Use clipboard as branch name\"\n    command: \"pbpaste\"\n```\n\n### Configuration Precedence\n\nHighest to lowest priority:\n\n1. **CLI overrides** (`--config` flag)\n2. **Git local configuration** (`git config --local`)\n3. **Git global configuration** (`git config --global`)\n4. **YAML configuration file** (`~/.config/lazyworktree/config.yaml`)\n5. **Built-in defaults**\n\n### Git Configuration\n\nUse the `lw.` prefix:\n\n```bash\n# Set globally\ngit config --global lw.theme nord\ngit config --global lw.worktree_dir ~/.local/share/worktrees\n\n# Set per-repository\ngit config --local lw.theme dracula\ngit config --local lw.init_commands \"link_topsymlinks\"\ngit config --local lw.init_commands \"npm install\"  # Multi-values supported\n```\n\nTo view configured values:\n\n```bash\ngit config --global --get-regexp \"^lw\\.\"\ngit config --local --get-regexp \"^lw\\.\"\n```\n\n### Settings\n\n**Themes**\n\n* `theme`: colour theme (auto-detected: `dracula` dark, `dracula-light` light). See [Themes](#themes).\n* `lazyworktree --show-syntax-themes`: show delta syntax-theme defaults.\n* `lazyworktree --theme \u003cname\u003e`: select UI theme.\n\n**Worktree list and refresh**\n\n* `sort_mode`: `\"switched\"` (last accessed, default), `\"active\"` (commit date), or `\"path\"` (alphabetical).\n* `auto_refresh`: background refresh of git metadata (default: true).\n* `ci_auto_refresh`: periodically refresh CI status for GitHub repositories (default: false).\n* `refresh_interval`: refresh frequency in seconds (default: 10).\n* `icon_set`: choose icon set (\"nerd-font-v3\", \"text\").\n* `max_untracked_diffs`, `max_diff_chars`: limits for diff display (0 disables).\n* `max_name_length`: maximum display length for worktree names (default: 95, 0 disables truncation).\n\n**Search and palette**\n\n* `search_auto_select`: start with filter focused (or use `--search-auto-select`).\n* `fuzzy_finder_input`: show fuzzy suggestions in input dialogues.\n* `palette_mru`: enable MRU sorting in command palette (default: true). Control count with `palette_mru_limit` (default: 5).\n\n**Diff, pager, and editor**\n\n* `git_pager`: diff formatter (default: `delta`). Empty string disables formatting.\n* `git_pager_args`: arguments for git_pager. Auto-selects syntax theme for delta.\n* `git_pager_interactive`: set `true` for interactive viewers like `diffnav` or `tig`.\n* `git_pager_command_mode`: set `true` for command-based diff viewers like `lumen` that run their own git commands (e.g. `lumen diff`).\n* `pager`: pager for output display (default: `$PAGER`, fallback to `less`).\n* `ci_script_pager`: pager for CI logs with direct terminal control. Falls back to `pager`. Example to strip GitHub Actions timestamps:\n\n```yaml\nci_script_pager: |\n  sed -E '\n  s/.*[0-9]{4}-[0-9]{2}-[0-9]{2}T([0-9]{2}:[0-9]{2}:[0-9]{2})\\.[0-9]+Z[[:space:]]*/\\1 /;\n  t;\n  s/.*UNKNOWN STEP[[:space:]]+//' | \\\n   tee /tmp/.ci.${LW_CI_JOB_NAME_CLEAN}-${LW_CI_STARTED_AT}.md |\n  less --use-color -q --wordwrap -qcR -P 'Press q to exit..'\n```\n\nCI environment variables: `LW_CI_JOB_NAME`, `LW_CI_JOB_NAME_CLEAN`, `LW_CI_RUN_ID`, `LW_CI_STARTED_AT`.\n\n* `editor`: editor for Status pane `e` key (default: `$EDITOR`, fallback to `nvim`).\n\n**Worktree lifecycle**\n\n* `init_commands`, `terminate_commands`: run before repository `.wt` commands.\n\n**Sync and multiplexers**\n\n* `merge_method`: `\"rebase\"` (default) or `\"merge\"`. Controls Absorb and Sync (`S`) behaviour.\n* `session_prefix`: prefix for tmux/zellij sessions (default: `wt-`). Palette filters by this prefix.\n\n**Branch naming**\n\n* `branch_name_script`: script for automatic branch suggestions. See [Automatically generated branch names](#automatically-generated-branch-names).\n* `issue_branch_name_template`: template with placeholders `{number}`, `{title}`, `{generated}`.\n\n**Custom create menu**\n\n* `custom_create_menus`: add custom items to the creation menu (`c` key). Supports `interactive` and `post_command`.\n\n## Themes\n\nBuilt-in themes:\n\n| Theme | Notes | Best For |\n|-------|-------|----------|\n| **dracula** | Dark (#282A36) | Dark terminals, vibrant colours, default fallback |\n| **dracula-light** | White (#FFFFFF) | Light terminals, Dracula colours, default light theme |\n| **narna** | Charcoal (#0D1117) | Dark terminals, blue highlights |\n| **clean-light** | White (#FFFFFF) | Light terminals, cyan accent |\n| **catppuccin-latte** | Soft white (#EFF1F5) | Catppuccin Latte light palette |\n| **rose-pine-dawn** | Warm white (#FAF4ED) | Rosé Pine Dawn warm palette |\n| **one-light** | Light grey (#FAFAFA) | Atom One Light |\n| **everforest-light** | Beige (#F3EFDA) | Everforest nature light |\n| **solarized-dark** | Deep teal (#002B36) | Classic Solarized dark palette |\n| **solarized-light** | Cream (#FDF6E3) | Classic Solarized light palette |\n| **gruvbox-dark** | Dark grey (#282828) | Gruvbox dark, warm accents |\n| **gruvbox-light** | Sand (#FBF1C7) | Gruvbox light, earthy tones |\n| **nord** | Midnight blue (#2E3440) | Nord calm cyan accents |\n| **monokai** | Olive black (#272822) | Monokai bright neon accents |\n| **catppuccin-mocha** | Mocha (#1E1E2E) | Catppuccin Mocha pastels |\n| **modern** | Zinc (#18181B) | Sleek modern dark theme with violet accents |\n| **tokyo-night** | Storm (#24283B) | Tokyo Night Storm with blue highlights |\n| **one-dark** | Dark (#282C34) | Atom One Dark classic palette |\n| **rose-pine** | Midnight (#191724) | Rosé Pine dark and moody |\n| **ayu-mirage** | Mirage (#212733) | Ayu Mirage modern look |\n| **everforest-dark** | Dark (#2D353B) | Everforest nature dark |\n| **kanagawa** | Wave (#1F1F28) | Kanagawa Wave inspired by Japanese art |\n\nSet in config: `theme: dracula`\n\n### Custom Themes\n\nDefine custom themes that inherit from built-in themes or define new colour schemes.\n\n**Inherit from built-in:**\n\n```yaml\ncustom_themes:\n  my-dark:\n    base: dracula\n    accent: \"#FF6B9D\"\n    text_fg: \"#E8E8E8\"\n\n  my-light:\n    base: dracula-light\n    accent: \"#0066CC\"\n```\n\n**Defining a complete theme (all 11 colour fields required):**\n\n```yaml\ncustom_themes:\n  completely-custom:\n    accent: \"#00FF00\"\n    accent_fg: \"#000000\"\n    accent_dim: \"#2A2A2A\"\n    border: \"#3A3A3A\"\n    border_dim: \"#2A2A2A\"\n    muted_fg: \"#888888\"\n    text_fg: \"#FFFFFF\"\n    success_fg: \"#00FF00\"\n    warn_fg: \"#FFFF00\"\n    error_fg: \"#FF0000\"\n    cyan: \"#00FFFF\"\n```\n\n**Inherit from other custom themes:**\n\n```yaml\ncustom_themes:\n  base-custom:\n    base: dracula\n    accent: \"#FF0000\"\n  derived:\n    base: base-custom\n    accent: \"#00FF00\"\n```\n\n**Colour fields:** `accent`, `accent_fg`, `accent_dim`, `border`, `border_dim`, `muted_fg`, `text_fg`, `success_fg`, `warn_fg`, `error_fg`, `cyan`.\n\nValues must be hex (`#RRGGBB` or `#RGB`). With `base`, only override what you need. Without `base`, all 11 fields are required. Custom themes appear alongside built-in themes.\n\n## CI Status Display\n\nShows CI check statuses for worktrees with associated PR/MR:\n\n* `✓` Green - Passed | `✗` Red - Failed | `●` Yellow - Pending | `○` Grey - Skipped | `⊘` Grey - Cancelled\n\nStatus is fetched lazily and cached for 30 seconds. Press `p` to refresh.\n\n## Custom Commands\n\nDefine keybindings in config. Commands run interactively (TUI suspends) and appear in the palette. Use `show_output` to pipe through pager.\n\nDefaults: `t` = tmux, `Z` = zellij. Override via `custom_commands.t` or `custom_commands.Z`. Palette lists sessions matching `session_prefix` (default: `wt-`).\n\n### Configuration Format\n\n```yaml\ncustom_commands:\n  e:\n    command: nvim\n    description: Editor\n    show_help: true\n  s:\n    command: zsh\n    description: Shell\n    show_help: true\n  T: # Run tests and wait for keypress\n    command: make test\n    description: Run tests\n    show_help: false\n    wait: true\n  o: # Show output in the pager\n    command: git status -sb\n    description: Status\n    show_help: true\n    show_output: true\n  c: # Open Claude CLI in a new terminal tab (Kitty, WezTerm, or iTerm)\n    command: claude\n    description: Claude Code\n    new_tab: true\n    show_help: true\n  t: # Open a tmux session with multiple windows\n    description: Tmux\n    show_help: true\n    tmux: # If you specify zellij instead of tmux this would manage zellij sessions\n      session_name: \"wt:$WORKTREE_NAME\"\n      attach: true\n      on_exists: switch\n      windows:\n        - name: claude\n          command: claude\n        - name: shell\n          command: zsh\n        - name: lazygit\n          command: lazygit\n```\n\n### Field Reference\n\n| Field | Type | Default | Description |\n|-------|------|---------|-------------|\n| `command` | string | **required** | Command to execute |\n| `description` | string | `\"\"` | Shown in help and palette |\n| `show_help` | bool | `false` | Show in help screen (`?`) and footer |\n| `wait` | bool | `false` | Wait for keypress after completion |\n| `show_output` | bool | `false` | Show stdout/stderr in pager (ignores `wait`) |\n| `new_tab` | bool | `false` | Launch in new terminal tab (Kitty with remote control enabled, WezTerm, or iTerm) |\n| `tmux` | object | `null` | Configure tmux session |\n| `zellij` | object | `null` | Configure zellij session |\n\n#### tmux fields\n\n| Field | Type | Default | Description |\n|-------|------|---------|-------------|\n| `session_name` | string | `wt:$WORKTREE_NAME` | Session name (env vars supported, special chars replaced) |\n| `attach` | bool | `true` | Attach immediately; if false, show modal with instructions |\n| `on_exists` | string | `switch` | Behaviour if session exists: `switch`, `attach`, `kill`, `new` |\n| `windows` | list | `[ { name: \"shell\" } ]` | Window definitions for the session |\n\nIf `windows` is empty, creates a single `shell` window.\n\n#### tmux window fields\n\n| Field | Type | Default | Description |\n|-------|------|---------|-------------|\n| `name` | string | `window-N` | Window name (supports env vars) |\n| `command` | string | `\"\"` | Command to run in the window (empty uses your default shell) |\n| `cwd` | string | `$WORKTREE_PATH` | Working directory for the window (supports env vars) |\n\n#### zellij fields\n\n| Field | Type | Default | Description |\n|-------|------|---------|-------------|\n| `session_name` | string | `wt:$WORKTREE_NAME` | Session name (env vars supported, special chars replaced) |\n| `attach` | bool | `true` | Attach immediately; if false, show modal with instructions |\n| `on_exists` | string | `switch` | Behaviour if session exists: `switch`, `attach`, `kill`, `new` |\n| `windows` | list | `[ { name: \"shell\" } ]` | Tab definitions for the session |\n\nIf `windows` is empty, creates a single `shell` tab. Session names with `/`, `\\`, `:` are replaced with `-`.\n\n#### zellij window fields\n\n| Field | Type | Default | Description |\n|-------|------|---------|-------------|\n| `name` | string | `window-N` | Tab name (supports env vars) |\n| `command` | string | `\"\"` | Command to run in the tab (empty uses your default shell) |\n| `cwd` | string | `$WORKTREE_PATH` | Working directory for the tab (supports env vars) |\n\n### Environment Variables\n\nAvailable: `WORKTREE_BRANCH`, `MAIN_WORKTREE_PATH`, `WORKTREE_PATH`, `WORKTREE_NAME`, `REPO_NAME`.\n\n### Supported Key Formats\n\nSingle keys (`e`, `s`), modifiers (`ctrl+e`, `alt+t`), special keys (`enter`, `esc`, `tab`, `space`).\n\n**Examples:**\n\n```yaml\ncustom_commands:\n  \"ctrl+e\":\n    command: nvim\n    description: Open editor with Ctrl+E\n  \"alt+t\":\n    command: make test\n    description: Run tests with Alt+T\n    wait: true\n```\n\n### Key Precedence\n\nCustom commands override built-in keys.\n\n## Custom Initialisation and Termination\n\nCreate a `.wt` file in your repository to run commands when creating/removing worktrees. Format inspired by [wt](https://github.com/taecontrol/wt).\n\n### Example `.wt` configuration\n\n```yaml\ninit_commands:\n    - link_topsymlinks\n    - cp $MAIN_WORKTREE_PATH/.env $WORKTREE_PATH/.env\n    - npm install\n    - code .\n\nterminate_commands:\n    - echo \"Cleaning up $WORKTREE_NAME\"\n```\n\nEnvironment variables: `WORKTREE_BRANCH`, `MAIN_WORKTREE_PATH`, `WORKTREE_PATH`, `WORKTREE_NAME`.\n\n### Security: Trust on First Use (TOFU)\n\nSince `.wt` files execute arbitrary commands, lazyworktree uses TOFU. On first encounter or modification, select **Trust**, **Block**, or **Cancel**. Hashes stored in `~/.local/share/lazyworktree/trusted.json`.\n\nConfigure `trust_mode`: `tofu` (default, prompt), `never` (skip all), `always` (no prompts).\n\n### Special Commands\n\n* `link_topsymlinks`: Built-in command that symlinks untracked/ignored root files, editor configs (`.vscode`, `.idea`, `.cursor`, `.claude/settings.local.json`), creates `tmp/`, and runs `direnv allow` if `.envrc` exists.\n\n## Branch Naming Conventions\n\nSpecial characters are converted to hyphens for Git compatibility. Leading/trailing hyphens are removed, consecutive hyphens collapsed. Length capped at 50 (manual) or 100 (auto) characters.\n\n| Input | Converted |\n|-------|-----------|\n| `feature.new` | `feature-new` |\n| `bug fix here` | `bug-fix-here` |\n| `feature:test` | `feature-test` |\n\n## Automatically Generated Branch Names\n\nConfigure `branch_name_script` to generate names via tools like [aichat](https://github.com/sigoden/aichat/) or [claude code](https://claude.com/product/claude-code). Issues output to `{generated}` placeholder; diffs output complete names. PR creation always uses the PR branch name.\n\n\u003e [!NOTE]\n\u003e Smaller, faster models suffice for branch names.\n\n### Configuration\n\n```yaml\n# For issues: generate a title (available via {generated} placeholder)\nbranch_name_script: \"aichat -m gemini:gemini-2.5-flash-lite 'Generate a short title for this issue. Output only the title (like feat-session-manager), nothing else.'\"\n\n# For diffs: generate a complete branch name\n# branch_name_script: \"aichat -m gemini:gemini-2.5-flash-lite 'Generate a short git branch name (no spaces, use hyphens) for this diff. Output only the branch name, nothing else.'\"\n```\n\n### Template Placeholders\n\n* `{number}` - Issue number\n* `{title}` - Original sanitised title\n* `{generated}` - Generated title (falls back to `{title}`)\n\n**Examples:**\n\n| Template | Result (Issue #2: \"Add AI session management\") | Generated: `feat-ai-session-manager` |\n|----------|------------------------------------------------|--------------------------------------|\n| `issue-{number}-{title}` | `issue-2-add-ai-session-management` | Not used |\n| `issue-{number}-{generated}` | `issue-2-feat-ai-session-manager` | Used |\n\nIf script fails, `{generated}` falls back to `{title}`.\n\n### Script Requirements\n\nReceives content on stdin, outputs branch name on stdout (first line). Timeout: 30s.\n\n### Environment Variables\n\n`LAZYWORKTREE_TYPE` (issue/diff), `LAZYWORKTREE_NUMBER`, `LAZYWORKTREE_TEMPLATE`, `LAZYWORKTREE_SUGGESTED_NAME`.\n\n**Example:**\n\n```yaml\n# Different prompts for different types\nbranch_name_script: |\n  if [ \"$LAZYWORKTREE_TYPE\" = \"diff\" ]; then\n    aichat -m gemini:gemini-2.5-flash-lite 'Generate a complete branch name for this diff'\n  else\n    aichat -m gemini:gemini-2.5-flash-lite 'Generate a short title (no issue- prefix) for this issue'\n  fi\n\n# Use issue number in the prompt\nbranch_name_script: |\n  aichat -m gemini:gemini-2.5-flash-lite \"Generate a title for issue #$LAZYWORKTREE_NUMBER. Output only the title.\"\n```\n\n## CLI Usage\n\n### Config overrides\n\n```bash\nlazyworktree --worktree-dir ~/worktrees\n\n# Override config values via command line\nlazyworktree --config lw.theme=nord --config lw.sort_mode=active\n```\n\nCreate, delete, and list worktrees from the command line. Legacy aliases `wt-create` and `wt-delete` still work.\n\n### Listing Worktrees\n\n```bash\nlazyworktree list              # Table output (default)\nlazyworktree list --pristine   # Paths only (scripting)\nlazyworktree list --json       # JSON output\nlazyworktree ls                # Alias\n```\n\nNote: `--pristine` and `--json` are mutually exclusive.\n\n### Creating Worktrees\n\n```bash\nlazyworktree create                          # Auto-generated from current branch\nlazyworktree create my-feature               # Explicit name\nlazyworktree create my-feature --with-change # With uncommitted changes\nlazyworktree create --from-branch main my-feature\nlazyworktree create --from-pr 123\nlazyworktree create --from-issue 42          # From issue (base: current branch)\nlazyworktree create --from-issue 42 --from-branch main  # From issue with explicit base\nlazyworktree create -I                       # Interactively select issue (fzf or list)\nlazyworktree create -I --from-branch main    # Interactive issue with explicit base\nlazyworktree create -P                       # Interactively select PR (fzf or list)\nlazyworktree create --from-pr 123 --no-workspace        # Branch only, no worktree\nlazyworktree create --from-issue 42 --no-workspace      # Branch only, no worktree\nlazyworktree create -I --no-workspace                    # Interactively select issue, branch only\nlazyworktree create -P --no-workspace        # Interactively select PR, branch only\n```\n\nPR creation always uses the PR branch name. If that branch is already checked out in another worktree, creation fails and you must reuse that worktree.\n\nFor complete CLI documentation, see `man lazyworktree` or `lazyworktree --help`.\n\n### Deleting Worktrees\n\n```bash\nlazyworktree delete                # Delete worktree and branch\nlazyworktree delete --no-branch    # Delete worktree only\n```\n\n## Screenshots\n\n### Light Theme (dracula-light theme)\n\n\u003cimg width=\"3730\" height=\"2484\" alt=\"image\" src=\"https://github.com/user-attachments/assets/ab19a23a-852c-46c3-a6f4-a27d8519f89a\" /\u003e\n\n### Command Palette (nord)\n\n\u003cimg width=\"3730\" height=\"2484\" alt=\"image\" src=\"https://github.com/user-attachments/assets/8a722eea-5d00-47b2-8e59-6019cfd6336f\" /\u003e\n\n### Github Actions Logs viewer (rose-pine)\n\n\u003cimg width=\"3730\" height=\"2484\" alt=\"image\" src=\"./.github/screenshots/ci-runs.png\" /\u003e\n\n### Branch creation (tokyo-night)\n\n\u003cimg width=\"3730\" height=\"2484\" alt=\"image\" src=\"https://github.com/user-attachments/assets/92888a4f-c3aa-4b39-b78b-d3c62897b69a\" /\u003e\n\n### Files in commit view (kanagawa)\n\n\u003cimg width=\"3730\" height=\"2484\" alt=\"image\" src=\"https://github.com/user-attachments/assets/735458b2-a3a9-451c-ac51-b43452d5e421\" /\u003e\n\n### Create a branch from a Issue (clean-light)\n\n\u003chttps://github.com/user-attachments/assets/a733b95f-cd11-48a9-be58-810866aff1a2\u003e\n\n## How does it compare?\n\nSee [COMPARISON.md](./COMPARISON.md) for a detailed comparison with other worktree managers.\n\n## Trivia\n\nOriginally a Python [Textual](https://textual.textualize.io/) app, migrated to Go ([BubbleTea](https://github.com/charmbracelet/bubbletea)) for faster startup. Python version: \u003chttps://github.com/chmouel/lazyworktree/tree/python\u003e\n\n## Copyright\n\n[Apache-2.0](./LICENSE)\n\n## Authors\n\n### Chmouel Boudjnah\n\n* 🐘 Fediverse - \u003c[@chmouel@chmouel.com](https://fosstodon.org/@chmouel)\u003e\n* 🐦 Twitter - \u003c[@chmouel](https://twitter.com/chmouel)\u003e\n* 📝 Blog  - \u003c[https://blog.chmouel.com](https://blog.chmouel.com)\u003e\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fchmouel%2Flazyworktree","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fchmouel%2Flazyworktree","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fchmouel%2Flazyworktree/lists"}