worktrunk · diff
v0.48.0 to git:20260919.abe4774
67 added, 219 removed. Audit A to A.
---
name: worktrunk
- description: Guidance for Worktrunk (the `wt` CLI) — git worktree management, hooks, and config. Load when editing .config/wt.toml or ~/.config/worktrunk/config.toml; adding, modifying, or debugging hooks (post-merge, post-start, pre-commit, pre-merge, post-switch, etc.); configuring commit message generation or command aliases; or troubleshooting wt behavior. Also answers general worktrunk/wt questions.
- version: 0.48.0
+ description: Guidance for Worktrunk (the `wt` CLI) — git worktree management, hooks, and config. Load when working out which worktree a `wt` command will act on, or reaching for the global `-C <path>` to target one; editing .config/wt.toml or ~/.config/worktrunk/config.toml; adding, modifying, or debugging hooks (post-merge, post-start, pre-commit, pre-merge, post-switch, etc.); configuring commit message generation or command aliases; or troubleshooting wt behavior. Also answers general worktrunk/wt questions.
license: MIT OR Apache-2.0
- compatibility: Requires worktrunk CLI (https://worktrunk.dev)
+ compatibility: Requires the `wt` CLI (https://worktrunk.dev)
---
# Worktrunk
Help users work with Worktrunk, a CLI tool for managing git worktrees.
- ## Available Documentation
+ ## Available documentation
Reference files are synced from [worktrunk.dev](https://worktrunk.dev) documentation:
- **reference/config.md**: User and project configuration (LLM, hooks, command defaults)
- **reference/hook.md**: Hook types, timing, and execution order
- **reference/switch.md**, **merge.md**, **list.md**, etc.: Command documentation
+ - **reference/extending.md**: Aliases, multi-step pipelines, custom subcommands, and template-expansion gotchas (two-pass `{% raw %}` deferral, for-each recipes)
- **reference/llm-commits.md**: LLM commit message generation
- - **reference/tips-patterns.md**: Language-specific tips and patterns
+ - **reference/tips-patterns.md**: Practical recipes — aliases, per-branch variables, dev server per worktree, parallel agent patterns
- **reference/shell-integration.md**: Shell integration debugging
- **reference/troubleshooting.md**: Troubleshooting for LLM and hooks (Claude-specific)
For command-specific options, run `wt <command> --help`. For configuration, follow the workflows below.
- ## Two Types of Configuration
-
- Worktrunk uses two separate config files with different scopes and behaviors:
-
- ### User Config (`~/.config/worktrunk/config.toml`)
- - **Scope**: Personal preferences for the individual developer
- - **Location**: `~/.config/worktrunk/config.toml` (never checked into git)
- - **Contains**: LLM integration, worktree path templates, command settings, user hooks, approved commands
- - **Permission model**: Always propose changes and get consent before editing
- - **See**: `reference/config.md` for detailed guidance
-
- ### Project Config (`.config/wt.toml`)
- - **Scope**: Team-wide automation shared by all developers
- - **Location**: `<repo>/.config/wt.toml` (checked into git)
- - **Contains**: Hooks for worktree lifecycle (pre-start, pre-merge, etc.)
- - **Permission model**: Proactive (create directly, changes are reversible via git)
- - **See**: `reference/hook.md` for detailed guidance
-
- ## Determining Which Config to Use
-
- When a user asks for configuration help, determine which type based on:
-
- **User config indicators**:
- - "set up LLM" or "configure commit generation"
- - "change where worktrees are created"
- - "customize commit message templates"
- - Affects only their environment
-
- **Project config indicators**:
- - "set up hooks for this project"
- - "automate npm install"
- - "run tests before merge"
- - Affects the entire team
-
- **Both configs may be needed**: For example, setting up commit message generation requires user config, but automating quality checks requires project config.
-
- ## Core Workflows
-
- ### Setting Up Commit Message Generation (User Config)
-
- Most common request. See `reference/llm-commits.md` for supported tools and exact command syntax.
-
- 1. **Detect available tools**
- ```bash
- which claude codex llm aichat 2>/dev/null
- ```
-
- 2. **If none installed, recommend Claude Code** (already available in Claude Code sessions)
-
- 3. **Propose config change** — Get the exact command from `reference/llm-commits.md`
- ```toml
- [commit.generation]
- command = "..." # see reference/llm-commits.md for tool-specific commands
- ```
- Ask: "Should I add this to your config?"
-
- 4. **After approval, apply**
- - Check if config exists: `wt config show`
- - If not, guide through `wt config create`
- - Read, modify, write preserving structure
-
- 5. **Suggest testing**
- ```bash
- wt step commit --show-prompt | head # verify prompt builds
- wt merge # in a repo with uncommitted changes
- ```
-
- ### Setting Up Project Hooks (Project Config)
-
- Common request for workflow automation. Follow discovery process:
-
- 1. **Detect project type**
- ```bash
- ls package.json Cargo.toml pyproject.toml
- ```
-
- 2. **Identify available commands**
- - For npm: Read `package.json` scripts
- - For Rust: Common cargo commands
- - For Python: Check pyproject.toml
-
- 3. **Design appropriate hooks** (7 hook types available)
- - Dependencies (fast, must complete) → `pre-start`
- - Tests/linting (must pass) → `pre-commit` or `pre-merge`
- - Long builds, dev servers → `post-start`
- - Terminal/IDE updates → `post-switch`
- - Deployment → `post-merge`
- - Cleanup tasks → `pre-remove`
+ ## Which worktree a command acts on
- 4. **Validate commands work**
- ```bash
- npm run lint # verify exists
- which cargo # verify tool exists
- ```
+ `wt` finds the *repository* from the working directory, and the *worktree* from the command's own arguments. Two rules cover every case:
- 5. **Create `.config/wt.toml`**
- ```toml
- # Install dependencies when creating worktrees
- pre-start = "npm install"
+ 1. **A command that names a branch already names its worktree.** Worktrees are addressed by branch name, so `wt switch <branch>`, `wt remove <branch>`, `wt step diff --branch <branch>`, and `wt config state marker set --branch <branch>` act on that branch's worktree no matter which worktree you run them from. Every such argument also accepts the worktree's own path, for the cases a branch cannot name — a second checkout of the same branch, or a detached worktree (which `marker` still rejects, since it keys state by branch name).
+ 2. **`-C <path>` moves the working directory, not the worktree selection.** Reach for it when the repository lookup is what's wrong: a *different* repository; a command that acts on the current worktree and takes no branch argument (`wt merge`, `wt step rebase|squash|push` — their `[TARGET]` is the merge target, not a worktree); or a caller whose working directory isn't inside a repository at all, such as an agent hook the host pins elsewhere.
- # Validate code quality before committing
- [pre-commit]
- lint = "npm run lint"
- typecheck = "npm run typecheck"
+ Layering `-C` on top of a branch argument names the same worktree twice. From inside the `alpha` worktree of a repo that also has `beta`:
- # Run tests before merging
- pre-merge = "npm test"
- ```
+ ```bash
+ wt step diff --branch beta # ✓ the branch argument selects the worktree
+ wt -C ../repo.beta step diff --branch beta # ✗ says beta twice
- 6. **Add comments explaining choices**
+ wt switch --create beta # ✓ --base already defaults to the default branch
+ wt -C ../repo switch --create beta # ✗ -C adds nothing; you are already in that repo
+ ```
- 7. **Suggest testing**
- ```bash
- wt switch --create test-hooks
- ```
+ ## Two types of configuration
- **See `reference/hook.md` for complete details.**
+ Worktrunk uses two config files with different scopes and permission models:
- ### Adding Hooks to Existing Config
+ **User config** (`~/.config/worktrunk/config.toml`, never checked into git) holds personal preferences: LLM integration, worktree path templates, command settings, user hooks. Treat it conservatively — propose changes and get consent before editing, never install tools on the user's behalf, and preserve the file's existing structure and comments. See `reference/config.md`.
- When users want to add automation to an existing project:
+ **Project config** (`<repo>/.config/wt.toml`, checked into git) holds team-wide automation: hooks for the worktree lifecycle (pre-start, pre-merge, etc.). Edit proactively — changes are versioned and reversible via git. Comment why each hook exists, and warn the user before adding destructive commands (`rm -rf`, `DROP TABLE`), network fetches piped to shells, or `sudo`. See `reference/hook.md`.
- 1. **Read existing config**: `cat .config/wt.toml`
+ Some requests span both: commit-message generation is user config, while the team's quality checks are project config.
- 2. **Determine hook type** - When should this run?
- - Creating worktree (blocking) → `pre-start`
- - Creating worktree (background) → `post-start`
- - Every switch → `post-switch`
- - Before committing → `pre-commit`
- - Before merging → `pre-merge`
- - After merging → `post-merge`
- - Before removal → `pre-remove`
+ ## Core workflows
- 3. **Handle format conversion if needed**
+ ### Setting up commit message generation (user config)
- Single command to named table:
- ```toml
- # Before
- pre-start = "npm install"
+ Detect which tools are installed (`which claude codex llm aichat`); if none, recommend Claude Code. Take the exact command for the chosen tool from `reference/llm-commits.md`, propose the `[commit.generation]` change, and apply it after approval (`wt config create` first if no config exists). To verify, `wt step commit --dry-run` renders the prompt, runs the LLM, and prints the message without committing.
- # After (adding db:migrate)
- [pre-start]
- install = "npm install"
- migrate = "npm run db:migrate"
- ```
+ ### Configuring project hooks
- 4. **Preserve existing structure and comments**
+ Pick the hook type by when the command should run and whether it may block — `reference/hook.md` maps all ten (5 events × pre/post) to their timing and typical uses.
- ### Validation Before Adding Commands
+ Derive the commands from the project itself (`package.json` scripts, `Cargo.toml`, `pyproject.toml`) and verify they run before adding them.
- Before adding hooks, validate:
+ When a new hook must wait for an existing one, convert the entry to a pipeline; independent commands in a named table run concurrently:
- ```bash
- # Verify command exists
- which npm
- which cargo
+ ```toml
+ # Pipeline: install completes before migrate starts
+ [[pre-start]]
+ install = "npm install"
- # For npm, verify script exists
- npm run lint --dry-run
+ [[pre-start]]
+ migrate = "npm run db:migrate"
- # For shell commands, check syntax
- bash -n -c "if [ true ]; then echo ok; fi"
+ # Concurrent: independent commands in one table
+ [pre-start]
+ install = "npm install"
+ env = "cp .env.example .env"
```
- **Dangerous patterns** — Warn users before creating hooks with:
- - Destructive commands: `rm -rf`, `DROP TABLE`
- - External dependencies: `curl http://...`
- - Privilege escalation: `sudo`
-
- ## Permission Models
-
- ### User Config: Conservative
- - **Never edit without consent** - Always show proposed change and wait for approval
- - **Never install tools** - Provide commands for users to run themselves
- - **Preserve structure** - Keep existing comments and organization
- - **Validate first** - Ensure TOML is valid before writing
-
- ### Project Config: Proactive
- - **Create directly** - Changes are versioned, easily reversible
- - **Validate commands** - Check commands exist before adding
- - **Explain choices** - Add comments documenting why hooks exist
- - **Warn on danger** - Flag destructive operations before adding
+ Test with `wt switch --create test-hooks`.
- ## Common Tasks Reference
+ ## Common tasks reference
- ### User Config Tasks
+ ### User config tasks
- Set up commit message generation → `reference/llm-commits.md`
- Customize worktree paths → `reference/config.md#worktree-path-template`
- - Custom commit templates → `reference/llm-commits.md#templates`
- - Configure command defaults → `reference/config.md#command-settings`
+ - Custom commit templates → `reference/llm-commits.md#prompt-templates`
+ - Configure command defaults → `reference/config.md#command-config`
- Set up personal hooks → `reference/config.md#user-hooks`
- ### Project Config Tasks
+ ### Project config tasks
- Set up hooks for new project → `reference/hook.md`
- - Add hook to existing config → `reference/hook.md#configuration`
+ - Add hook to existing config → `reference/hook.md#hook-forms`
- Use template variables → `reference/hook.md#template-variables`
- Add dev server URL to list → `reference/config.md#dev-server-url`
- ## Key Commands
+ ### Aliases & multi-worktree tasks
+ - Create a `wt` alias → `reference/extending.md#aliases`
+ - Run a command in every worktree → `reference/step.md#wt-step-for-each`
+ - Rebase every worktree (up-style) → `reference/extending.md#recipe-rebase-every-worktree-onto-its-upstream`
+ - Pass a template to a nested `wt` command → `reference/extending.md#nesting-templates`
+ ## Key commands
+
```bash
# View all configuration
wt config show
- # Create initial user config
+ # Create initial user config (LLM/commit setup: see reference/llm-commits.md)
wt config create
- # LLM setup guide
+ # Full config reference (subcommands, templates, env vars)
wt config --help
```
- ## Loading Additional Documentation
-
- Load **reference files** for detailed configuration, hook specifications, and troubleshooting.
-
- Find specific sections with grep:
- ```bash
- grep -A 20 "## Setup" reference/llm-commits.md
- grep -A 30 "### pre-start" reference/hook.md
- grep -A 20 "## Warning Messages" reference/shell-integration.md
- ```
+ ## Hook approvals in non-interactive sessions
- ## Hook Approvals in Non-Interactive Sessions
+ Worktrunk never runs a project's hooks or aliases until the user has explicitly approved them. The commands in `.config/wt.toml` are arbitrary shell code shipped in a repository the user may have just cloned, so on first run Worktrunk shows each command and waits for the user to approve it — an untrusted `.config/wt.toml` cannot silently execute anything. Approvals are stored per-project in `~/.config/worktrunk/approvals.toml` and re-prompted whenever a command template changes, so a hook can't be swapped for a different command after it was approved.
- Project hooks and project aliases prompt for approval on first run, so an untrusted `.config/wt.toml` can't silently execute arbitrary commands. Agents running `wt merge`, `wt switch`, or other commands that trigger hooks will hit an error like:
+ Agents running `wt merge`, `wt switch`, or other commands that trigger hooks will hit an error like:
```
▲ cargo-difftest needs approval to execute 1 command:
○ post-merge install:
cargo install --path .
✗ Cannot prompt for approval in non-interactive environment
- ↳ To skip prompts in CI/CD, add --yes; to pre-approve commands, run wt config approvals add
+ ↳ To skip prompts in CI/CD, add --yes; to pre-approve commands, run wt config approvals add --yes
```
- Two resolutions exist — pick based on who the agent is running for:
-
- - **`wt config approvals add`** — interactive prompt that stores approvals to `~/.config/worktrunk/approvals.toml`. Run once per project; persists across invocations until the command template changes or the project moves. This is the right choice when the human owns the trust decision.
- - **`--yes`** / `-y` — bypasses approval for a single invocation. Appropriate for CI/CD where hook contents are controlled by the pipeline itself.
-
- **When invoked as an agent, stop and escalate to the user** — pre-approval is a security decision about whether this project's hooks should be trusted to run arbitrary commands on their machine. Tell the user to run `wt config approvals add` (or review and re-run with `--yes` if they accept the CI-style one-shot bypass). Don't reach for `--yes` on the user's behalf just to unblock the command.
+ The resolution is for the user to make the trust decision themselves:
- ## Advanced: Agent Handoffs
+ - **`wt config approvals add`** — interactive prompt where the user reviews each command before it is stored to `~/.config/worktrunk/approvals.toml`. Run once per project; the approval persists across invocations until the command template changes or the project moves. This is the path to recommend — the user reviews and consents to exactly the commands that will run.
- When the user requests spawning a worktree with an agent in a background session ("spawn a worktree for...", "hand off to another agent"), use the appropriate pattern for their terminal multiplexer. Substitute `<agent-cli>` with the CLI you are running as: `claude` for Claude Code, `'opencode run'` for OpenCode.
+ **When invoked as an agent, stop and escalate to the user.** Approving a project's hooks is a security decision about whether this repository should be trusted to run arbitrary commands on the user's machine — that decision belongs to the user, not the agent. Tell the user to run `wt config approvals add` and let them review the commands. Do not reach for either `--yes` on the user's behalf: on the blocked command it skips the gate for that invocation, and `wt config approvals add --yes` records every command the project declares with nobody reading them. Both exist for CI/CD pipelines and containers that already control their own hook contents; neither is a shortcut for an interactive agent to silence an approval prompt.
- **tmux** (check `$TMUX` env var):
- ```bash
- tmux new-session -d -s <branch-name> "wt switch --create <branch-name> -x <agent-cli> -- '<task description>'"
- ```
+ ## Advanced: agent handoffs
- **Zellij** (check `$ZELLIJ` env var):
- ```bash
- zellij run -- wt switch --create <branch-name> -x <agent-cli> -- '<task description>'
- ```
+ When the user requests spawning a worktree with an agent in a background session ("spawn a worktree for...", "hand off to another agent"), use the tmux or Zellij command from `reference/tips-patterns.md#agent-handoffs` with the CLI you are running as in place of `claude`, following that section's note on where a subcommand such as OpenCode's `run` goes.
**Requirements** (all must be true):
- User explicitly requests spawning/handoff
- - User is in a supported multiplexer (tmux or Zellij)
+ - User is in a supported multiplexer (check `$TMUX` / `$ZELLIJ`)
- The user's project instructions (`CLAUDE.md` or `AGENTS.md`) or an explicit prompt authorize this pattern
**Do not use this pattern** for normal worktree operations.
- Example (tmux, Claude Code):
- ```bash
- tmux new-session -d -s fix-auth-bug "wt switch --create fix-auth-bug -x claude -- \
- 'The login session expires after 5 minutes. Find the session timeout config and extend it to 24 hours.'"
- ```
-
- Example (Zellij, OpenCode):
- ```bash
- zellij run -- wt switch --create fix-auth-bug -x 'opencode run' -- \
- 'The login session expires after 5 minutes. Find the session timeout config and extend it to 24 hours.'
- ```
-
### Parallel sub-Agents (single Claude Code session)
- To spawn multiple sub-Agents that each work in their own worktree from one Claude Code session — no terminal multiplexer, no human in the other pane — pre-create each worktree from the parent and pass the path into the sub-Agent prompt:
+ To spawn multiple sub-Agents that each work in their own worktree from one Claude Code session — no terminal multiplexer, no human in the other pane — pre-start each worktree from the parent and pass the path into the sub-Agent prompt:
```bash
wt switch --create <branch> --no-cd --no-hooks
```
Then call the `Agent` tool **without** `isolation: "worktree"`, naming the path in the prompt:
```
- You are working in `/abs/path/to/worktrunk.<branch>` on branch `<branch>`.
+ You are working in `/abs/path/to/myproject.<branch>` on branch `<branch>`.
All edits must stay in that worktree.
```
`--no-cd` skips the shell-integration cd script the parent can't consume; `--no-hooks` is appropriate when each sub-Agent will run its own build/test step (e.g. `cargo run -- hook pre-merge --yes`) and you don't need post-start setup repeated per worktree.
- **Do not** use `Agent { isolation: "worktree" }` for this. Claude Code passes its internal agent ID as `name` to the `WorktreeCreate` hook, so `wt` creates the worktree as `worktrunk.agent-<id>` on a throwaway branch. If the sub-Agent then creates a feature branch on top, you end up with non-canonical paths, orphan branches, and post-start hooks fired against the wrong branch. Pre-creating with `wt switch --create` keeps path, branch, and hook target aligned.
+ **Do not** use `Agent { isolation: "worktree" }` for this. Claude Code passes its internal agent ID as `name` to the `WorktreeCreate` hook, so `wt` creates the worktree as `myproject.agent-<id>` on a throwaway branch. If the sub-Agent then creates a feature branch on top, you end up with non-canonical paths, orphan branches, and post-start hooks fired against the wrong branch. Pre-creating with `wt switch --create` keeps path, branch, and hook target aligned.