wt config
Manage user & project configs. Includes shell integration, hooks, and saved state.
Examples
Install shell integration (required for directory switching):
wt config shell install
Create user config file with documented examples:
wt config create
Create project config file (.config/wt.toml) for hooks:
wt config create --project
Show current configuration and file locations:
wt config showConfiguration files
| File | Location | Contains | Committed & shared |
|---|---|---|---|
| User config | ~/.config/worktrunk/config.toml | Worktree path template, LLM commit configs, etc | ✗ |
| Project config | .config/wt.toml | Project hooks, dev server URL | ✓ |
Organizations can also deploy a system-wide config file for shared defaults — run wt config show for the platform-specific location.
User config — personal preferences:
# ~/.config/worktrunk/config.toml
worktree-path = ".worktrees/{{ branch | sanitize }}"
[commit.generation]
command = "CLAUDECODE= MAX_THINKING_TOKENS=0 claude -p --no-session-persistence --model=haiku --tools='' --disable-slash-commands --setting-sources='' --system-prompt=''"
Project config — shared team settings:
# .config/wt.toml
[post-create]
deps = "npm ci"
[pre-merge]
test = "npm test"
User Configuration
Create with wt config create.
Location:
- macOS/Linux:
~/.config/worktrunk/config.toml(or$XDG_CONFIG_HOMEif set) - Windows:
%APPDATA%\worktrunk\config.toml
Worktree path template
Controls where new worktrees are created.
Variables:
{{ repo_path }}— absolute path to the repository (e.g.,/Users/me/code/myproject){{ repo }}— repository directory name (e.g.,myproject){{ branch }}— raw branch name (e.g.,feature/auth){{ branch | sanitize }}— filesystem-safe:/and\become-(e.g.,feature-auth){{ branch | sanitize_db }}— database-safe: lowercase, underscores, hash suffix (e.g.,feature_auth_x7k)
Examples for repo at ~/code/myproject, branch feature/auth:
# Default — sibling directory
# Creates: ~/code/myproject.feature-auth
# worktree-path = "{{ repo_path }}/../{{ repo }}.{{ branch | sanitize }}"
# Inside the repository
# Creates: ~/code/myproject/.worktrees/feature-auth
worktree-path = "{{ repo_path }}/.worktrees/{{ branch | sanitize }}"
# Centralized worktrees directory
# Creates: ~/worktrees/myproject/feature-auth
worktree-path = "~/worktrees/{{ repo }}/{{ branch | sanitize }}"
~ expands to the home directory. Relative paths are relative to the repository root.
LLM commit messages
Generate commit messages automatically during merge. Requires an external CLI tool.
Claude Code
# [commit.generation]
# command = "CLAUDECODE= MAX_THINKING_TOKENS=0 claude -p --no-session-persistence --model=haiku --tools='' --disable-slash-commands --setting-sources='' --system-prompt=''"Codex
# [commit.generation]
# command = "codex exec -m gpt-5.1-codex-mini -c model_reasoning_effort='low' -c system_prompt='' --sandbox=read-only --json - | jq -sr '[.[] | select(.item.type? == \"agent_message\")] | last.item.text'"opencode
# [commit.generation]
# command = "opencode run -m anthropic/claude-haiku-4.5 --variant fast"llm
# [commit.generation]
# command = "llm -m claude-haiku-4.5"aichat
# [commit.generation]
# command = "aichat -m claude:claude-haiku-4.5"
See LLM commits docs for setup and Custom prompt templates for template customization.
Command config
List
Persistent flag values for wt list. Override on command line as needed.
[list]
summary = false # Enable LLM branch summaries (requires [commit.generation])
full = false # Show CI, main…± diffstat, and LLM summaries (--full)
branches = false # Include branches without worktrees (--branches)
remotes = false # Include remote-only branches (--remotes)
task-timeout-ms = 0 # Kill individual git commands after N ms; 0 disables
timeout-ms = 0 # Wall-clock budget for the entire collect phase; 0 disablesCommit
Shared by wt step commit, wt step squash, and wt merge.
[commit]
stage = "all" # What to stage before commit: "all", "tracked", or "none"Merge
Most flags are on by default. Set to false to change default behavior.
[merge]
squash = true # Squash commits into one (--no-squash to preserve history)
commit = true # Commit uncommitted changes first (--no-commit to skip)
rebase = true # Rebase onto target before merge (--no-rebase to skip)
remove = true # Remove worktree after merge (--no-remove to keep)
verify = true # Run project hooks (--no-verify to skip)
no-ff = false # Create a merge commit even when fast-forward is possible (--no-ff)Switch
[switch]
no-cd = true # Skip directory change after switching (--cd to override)
[switch.picker]
# Pager command for diff preview (overrides git's core.pager)
# pager = "delta --paging=never"
# Wall-clock budget (ms) for picker data collection (default: 500)
# Tasks still running when the budget expires are abandoned; 0 disables
# timeout-ms = 500Aliases
Command templates that run with wt step <name>. See wt step aliases for usage and flags.
[aliases]
greet = "echo Hello from {{ branch }}"
url = "echo http://localhost:{{ branch | hash_port }}"
Aliases defined here apply to all projects. For project-specific aliases, use the project config [aliases] section instead.
User project-specific settings
For context:
- Project config settings are shared with teammates.
- User configs generally apply to all projects.
- User configs also has a
[projects]table which holds project-specific settings for the user, such as worktree layout and setting overrides. That's what this section covers.
Entries are keyed by project identifier (e.g., github.com/user/repo).
Setting overrides
Override global user config for a specific project. Scalar values (like worktree-path) replace the global value. Hooks append — both global and per-project hooks run. Aliases merge — per-project aliases override global aliases on name collision.
[projects."github.com/user/repo"]
worktree-path = ".worktrees/{{ branch | sanitize }}"
list.full = true
merge.squash = false
post-create.env = "cp .env.example .env"
aliases.deploy = "make deploy BRANCH={{ branch }}"Custom prompt templates
Templates use minijinja syntax.
Commit template
Available variables:
{{ git_diff }},{{ git_diff_stat }}— diff content{{ branch }},{{ repo }}— context{{ recent_commits }}— recent commit messages
Default template:
[commit.generation]
template = """
Write a commit message for the staged changes below.
<format>
- Subject line under 50 chars
- For material changes, add a blank line then a body paragraph explaining the change
- Output only the commit message, no quotes or code blocks
</format>
<style>
- Imperative mood: "Add feature" not "Added feature"
- Match recent commit style (conventional commits if used)
- Describe the change, not the intent or benefit
</style>
<diffstat>
{{ git_diff_stat }}
</diffstat>
<diff>
{{ git_diff }}
</diff>
<context>
Branch: {{ branch }}
{% if recent_commits %}<recent_commits>
{% for commit in recent_commits %}- {{ commit }}
{% endfor %}</recent_commits>{% endif %}
</context>
"""
Squash template
Available variables (in addition to commit template variables):
{{ commits }}— list of commits being squashed{{ target_branch }}— merge target branch
Default template:
[commit.generation]
squash-template = """
Combine these commits into a single commit message.
<format>
- Subject line under 50 chars
- For material changes, add a blank line then a body paragraph explaining the change
- Output only the commit message, no quotes or code blocks
</format>
<style>
- Imperative mood: "Add feature" not "Added feature"
- Match the style of commits being squashed (conventional commits if used)
- Describe the change, not the intent or benefit
</style>
<commits branch="{{ branch }}" target="{{ target_branch }}">
{% for commit in commits %}- {{ commit }}
{% endfor %}</commits>
<diffstat>
{{ git_diff_stat }}
</diffstat>
<diff>
{{ git_diff }}
</diff>
"""
Project Configuration
Project config (.config/wt.toml) defines lifecycle hooks and project-specific settings. This file is checked into version control and shared with the team. Create with wt config create --project.
See wt hook for hook types, execution order, template variables, and examples.
Non-hook settings
# .config/wt.toml
# URL column in wt list (dimmed when port not listening)
[list]
url = "http://localhost:{{ branch | hash_port }}"
# Override CI platform detection for self-hosted instances
[ci]
platform = "github" # or "gitlab"
# Command aliases (run with wt step <name>)
[aliases]
deploy = "make deploy BRANCH={{ branch }}"
test = "cargo test"Shell Integration
Worktrunk needs shell integration to change directories when switching worktrees. Install with:
wt config shell install
For manual setup, see wt config shell init --help.
Without shell integration, wt switch prints the target directory but cannot cd into it.
First-run prompts
On first run without shell integration, Worktrunk offers to install it. Similarly, on first commit without LLM configuration, it offers to configure a detected tool (claude, codex). Declining sets skip-shell-integration-prompt or skip-commit-generation-prompt automatically.
Other
Environment variables
All user config options can be overridden with environment variables using the WORKTRUNK_ prefix.
Naming convention
Config keys use kebab-case (worktree-path), while env vars use SCREAMING_SNAKE_CASE (WORKTRUNK_WORKTREE_PATH). The conversion happens automatically.
For nested config sections, use double underscores to separate levels:
| Config | Environment Variable |
|---|---|
worktree-path | WORKTRUNK_WORKTREE_PATH |
commit.generation.command | WORKTRUNK_COMMIT__GENERATION__COMMAND |
commit.stage | WORKTRUNK_COMMIT__STAGE |
Note the single underscore after WORKTRUNK and double underscores between nested keys.
Example: CI/testing override
Override the LLM command in CI to use a mock:
WORKTRUNK_COMMIT__GENERATION__COMMAND="echo 'test: automated commit'" wt mergeOther environment variables
| Variable | Purpose |
|---|---|
WORKTRUNK_BIN | Override binary path for shell wrappers (useful for testing dev builds) |
WORKTRUNK_CONFIG_PATH | Override user config file location |
WORKTRUNK_SYSTEM_CONFIG_PATH | Override system config file location |
XDG_CONFIG_DIRS | Colon-separated system config directories (default: /etc/xdg) |
WORKTRUNK_DIRECTIVE_FILE | Internal: set by shell wrappers to enable directory changes |
WORKTRUNK_SHELL | Internal: set by shell wrappers to indicate shell type (e.g., powershell) |
WORKTRUNK_MAX_CONCURRENT_COMMANDS | Max parallel git commands (default: 32). Lower if hitting file descriptor limits. |
NO_COLOR | Disable colored output (standard) |
CLICOLOR_FORCE | Force colored output even when not a TTY |
Command reference
wt config - Manage user & project configs
Includes shell integration, hooks, and saved state.
Usage: wt config [OPTIONS] <COMMAND>
Commands:
shell Shell integration setup
create Create configuration file
show Show configuration files & locations
update Update deprecated config settings
state Manage internal data and cache
Options:
-h, --help
Print help (see a summary with '-h')
Global Options:
-C <path>
Working directory for this command
--config <path>
User config file path
-v, --verbose...
Verbose output (-v: hooks, templates; -vv: debug report)
Subcommands
wt config show
Show configuration files & locations.
Shows location and contents of user config (~/.config/worktrunk/config.toml)
and project config (.config/wt.toml). Also shows system config if present.
If a config file doesn't exist, shows defaults that would be used.
Full diagnostics
Use --full to run diagnostic checks:
wt config show --full
This tests:
- CI tool status — Whether
gh(GitHub) orglab(GitLab) is installed and authenticated - Commit generation — Whether the LLM command can generate commit messages
- Version check — Whether a newer version is available on GitHub
Command reference
wt config show - Show configuration files & locations
Usage: wt config show [OPTIONS]
Options:
--full
Run diagnostic checks (CI tools, commit generation, version)
-h, --help
Print help (see a summary with '-h')
Global Options:
-C <path>
Working directory for this command
--config <path>
User config file path
-v, --verbose...
Verbose output (-v: hooks, templates; -vv: debug report)
wt config state
Manage internal data and cache.
State is stored in .git/ (config entries and log files), separate from configuration files.
Use wt config show to view file-based configuration.
Keys
- default-branch: The repository's default branch (
main,master, etc.) - previous-branch: Previous branch for
wt switch - - ci-status: CI/PR status for a branch (passed, running, failed, conflicts, no-ci, error)
- marker: Custom status marker for a branch (shown in
wt list) - logs: Background operation logs
Examples
Get the default branch:
wt config state default-branch
Set the default branch manually:
wt config state default-branch set main
Set a marker for current branch:
wt config state marker set "🚧 WIP"
Clear all CI status cache:
wt config state ci-status clear --all
Show all stored state:
wt config state get
Clear all stored state:
wt config state clearCommand reference
wt config state - Manage internal data and cache
Usage: wt config state [OPTIONS] <COMMAND>
Commands:
default-branch Default branch detection and override
previous-branch Previous branch (for wt switch -)
ci-status CI status cache
marker Branch markers
logs Background operation logs
hints One-time hints shown in this repo
get Get all stored state
clear Clear all stored state
Options:
-h, --help
Print help (see a summary with '-h')
Global Options:
-C <path>
Working directory for this command
--config <path>
User config file path
-v, --verbose...
Verbose output (-v: hooks, templates; -vv: debug report)
wt config state default-branch
Default branch detection and override.
Useful in scripts to avoid hardcoding main or master:
git rebase $(wt config state default-branch)
Without a subcommand, runs get. Use set to override, or clear then get to re-detect.
Detection
Worktrunk detects the default branch automatically:
- Worktrunk cache — Checks
git config worktrunk.default-branch(single command) - Git cache — Detects primary remote and checks its HEAD (e.g.,
origin/HEAD) - Remote query — If not cached, queries
git ls-remote(100ms–2s) - Local inference — If no remote, infers from local branches
Once detected, the result is cached in worktrunk.default-branch for fast access.
The local inference fallback uses these heuristics in order:
- If only one local branch exists, uses it
- For bare repos or empty repos, checks
symbolic-ref HEAD - Checks
git config init.defaultBranch - Looks for common names:
main,master,develop,trunk
Command reference
wt config state default-branch - Default branch detection and override
Usage: wt config state default-branch [OPTIONS] [COMMAND]
Commands:
get Get the default branch
set Set the default branch
clear Clear the default branch cache
Options:
-h, --help
Print help (see a summary with '-h')
Global Options:
-C <path>
Working directory for this command
--config <path>
User config file path
-v, --verbose...
Verbose output (-v: hooks, templates; -vv: debug report)
wt config state ci-status
CI status cache.
Caches GitHub/GitLab CI status for display in wt list.
Requires gh (GitHub) or glab (GitLab) CLI, authenticated. Platform auto-detects from remote URL; override with ci.platform = "github" in .config/wt.toml for self-hosted instances.
Checks open PRs/MRs first, then branch pipelines for branches with upstream. Local-only branches (no remote tracking) show blank.
Results cache for 30-60 seconds. Indicators dim when local changes haven't been pushed.
Status values
| Status | Meaning |
|---|---|
passed | All checks passed |
running | Checks in progress |
failed | Checks failed |
conflicts | PR has merge conflicts |
no-ci | No checks configured |
error | Fetch error (rate limit, network, auth) |
See wt list CI status for display symbols and colors.
Without a subcommand, runs get for the current branch. Use clear to reset cache for a branch or clear --all to reset all.
Command reference
wt config state ci-status - CI status cache
Usage: wt config state ci-status [OPTIONS] [COMMAND]
Commands:
get Get CI status for a branch
clear Clear CI status cache
Options:
-h, --help
Print help (see a summary with '-h')
Global Options:
-C <path>
Working directory for this command
--config <path>
User config file path
-v, --verbose...
Verbose output (-v: hooks, templates; -vv: debug report)
wt config state marker
Branch markers.
Custom status text or emoji shown in the wt list Status column.
Display
Markers appear at the start of the Status column:
Branch Status Path
main ^ ~/code/myproject
feature 🚧↑ ~/code/myproject.feature
bugfix 🤖!↑⇡ ~/code/myproject.bugfixUse cases
- Work status —
🚧WIP,✅ready for review,🔥urgent - Agent tracking — The Claude Code plugin sets markers automatically
- Notes — Any short text:
"blocked","needs tests"
Storage
Stored in git config as worktrunk.state.<branch>.marker. Set directly with:
git config worktrunk.state.feature.marker '{"marker":"🚧","set_at":0}'
Without a subcommand, runs get for the current branch. For --branch, use get --branch=NAME.
Command reference
wt config state marker - Branch markers
Usage: wt config state marker [OPTIONS] [COMMAND]
Commands:
get Get marker for a branch
set Set marker for a branch
clear Clear marker for a branch
Options:
-h, --help
Print help (see a summary with '-h')
Global Options:
-C <path>
Working directory for this command
--config <path>
User config file path
-v, --verbose...
Verbose output (-v: hooks, templates; -vv: debug report)
wt config state logs
Background operation logs.
View and manage logs from background operations.
What's logged
Two kinds of logs live in .git/wt-logs/:
Command log (commands.jsonl)
All hook executions and LLM commands are recorded automatically — one JSON object per line with timestamp, command, exit code, and duration. Rotates to commands.jsonl.old at 1MB (~2MB total).
Hook output logs
| Operation | Log file |
|---|---|
| post-start hooks | {branch}-{source}-post-start-{name}.log |
| Background removal | {branch}-remove.log |
Source is user or project depending on where the hook is defined.
Location
All logs are stored in .git/wt-logs/ (in the main worktree's git directory).
Behavior
- Overwrites — Same operation on same branch overwrites previous log
- Persists — Logs from deleted branches remain until manually cleared
- Shared — All worktrees write to the same log directory
Examples
List all log files:
wt config state logs get
Query the command log:
tail -5 .git/wt-logs/commands.jsonl | jq .
View a specific hook log:
cat "$(git rev-parse --git-dir)/wt-logs/feature-project-post-start-build.log"
Clear all logs:
wt config state logs clearCommand reference
wt config state logs - Background operation logs
Usage: wt config state logs [OPTIONS] [COMMAND]
Commands:
get Get log file paths
clear Clear background operation logs
Options:
-h, --help
Print help (see a summary with '-h')
Global Options:
-C <path>
Working directory for this command
--config <path>
User config file path
-v, --verbose...
Verbose output (-v: hooks, templates; -vv: debug report)