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 show

Configuration files

FileLocationContainsCommitted & shared
User config~/.config/worktrunk/config.tomlWorktree path template, LLM commit configs, etc
Project config.config/wt.tomlProject 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:

Worktree path template

Controls where new worktrees are created.

Variables:

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 disables

Commit

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 = 500

Aliases

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:

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:

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):

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:

ConfigEnvironment Variable
worktree-pathWORKTRUNK_WORKTREE_PATH
commit.generation.commandWORKTRUNK_COMMIT__GENERATION__COMMAND
commit.stageWORKTRUNK_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 merge

Other environment variables

VariablePurpose
WORKTRUNK_BINOverride binary path for shell wrappers (useful for testing dev builds)
WORKTRUNK_CONFIG_PATHOverride user config file location
WORKTRUNK_SYSTEM_CONFIG_PATHOverride system config file location
XDG_CONFIG_DIRSColon-separated system config directories (default: /etc/xdg)
WORKTRUNK_DIRECTIVE_FILEInternal: set by shell wrappers to enable directory changes
WORKTRUNK_SHELLInternal: set by shell wrappers to indicate shell type (e.g., powershell)
WORKTRUNK_MAX_CONCURRENT_COMMANDSMax parallel git commands (default: 32). Lower if hitting file descriptor limits.
NO_COLORDisable colored output (standard)
CLICOLOR_FORCEForce 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:

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

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 clear

Command 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:

  1. Worktrunk cache — Checks git config worktrunk.default-branch (single command)
  2. Git cache — Detects primary remote and checks its HEAD (e.g., origin/HEAD)
  3. Remote query — If not cached, queries git ls-remote (100ms–2s)
  4. 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:

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

StatusMeaning
passedAll checks passed
runningChecks in progress
failedChecks failed
conflictsPR has merge conflicts
no-ciNo checks configured
errorFetch 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.bugfix

Use cases

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

OperationLog 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

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 clear

Command 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)