LLM Commit Messages
Worktrunk generates commit messages by building a templated prompt and piping it to an external command. This integrates with wt merge, wt step commit, and wt step squash.
Any command that reads a prompt from stdin and outputs a commit message works. Add to ~/.config/worktrunk/config.toml:
Claude Code
Section titled “Claude Code”[commit.generation]command = "MAX_THINKING_TOKENS=0 claude -p --no-session-persistence --model=haiku --tools='' --safe-mode --setting-sources='user' --system-prompt=''"--no-session-persistence prevents the commit conversation from polluting claude --continue. --safe-mode keeps the run hermetic — no hooks, plugins, MCP, skills, or CLAUDE.md — while leaving authentication working normally, so setups that authenticate via apiKeyHelper (not just OAuth or ANTHROPIC_API_KEY) still get a key. --setting-sources='user' scopes settings to your user config so a project .claude/settings.json can’t override auth. The remaining flags disable tools, system prompt, and thinking for fast text-only output. --safe-mode requires Claude Code ≥ 2.1.169. See Claude Code docs for installation.
[commit.generation]command = "codex exec -m gpt-5.6-luna -c model_reasoning_effort='low' -c system_prompt='' --sandbox=read-only --json - | jq -sr '[.[] | select(.item.type? == \"agent_message\")] | last.item.text'"Uses the fast, low-cost variant of the current Codex model family with low reasoning effort and an empty system prompt for faster output. Requires jq for JSON parsing. See Codex CLI docs.
Other tools
Section titled “Other tools”# opencode — use a fast model variantcommand = "opencode run -m anthropic/claude-haiku-4.5 --variant fast"
# llmcommand = "llm -m claude-haiku-4.5"
# aichatcommand = "aichat -m claude:claude-haiku-4.5"These examples assume a feature worktree with changes to commit.
wt merge
Section titled “wt merge”Squashes all changes (uncommitted + existing commits) into one commit with an LLM-generated message, then merges to the default branch:
wt merge◎ Squashing 3 commits into a single commit (5 files, +16)...◎ Generating squash commit message... feat(auth): Implement JWT authentication system Add comprehensive JWT token handling including validation, refresh logic, and authentication tests.✓ Squashed @ a1b2c3d◎ Merging 1 commit to main @ a1b2c3d (no rebase needed) * a1b2c3d feat(auth): Implement JWT authentication system auth.rs | 2 ++ auth_test.rs | 2 ++ integration_test.rs | 6 ++++++ jwt.rs | 3 +++ jwt_test.rs | 3 +++ 5 files changed, 16 insertions(+)✓ Merged to main (1 commit, 5 files, +16)◎ Removing feature worktree & branch in background (same commit as main, _)○ Switched to worktree for main @ ~/repowt step commit
Section titled “wt step commit”Stages and commits with LLM-generated message:
wt step commit◎ Generating commit message and committing changes... (2 files, +26) feat(validation): add input validation utilities✓ Committed changes @ a1b2c3dwt step squash
Section titled “wt step squash”Squashes branch commits into one with LLM-generated message:
wt step squash◎ Squashing 3 commits into a single commit (5 files, +16)...◎ Generating squash commit message... feat(auth): Implement JWT authentication system Add comprehensive JWT token handling including validation, refresh logic, and authentication tests.✓ Squashed @ a1b2c3dSee wt merge and wt step for full documentation.
Branch summaries
Section titled “Branch summaries”With summary = true and a [commit.generation] command configured, Worktrunk generates LLM branch summaries — one-line descriptions of each branch’s changes since the default branch.
Summaries appear in:
wt switchinteractive picker — preview tab 5wt list --full— the Summary column (seewt list)
Enable in user config:
[list]summary = trueSummaries are cached and regenerated only when the diff changes.
Prompt templates
Section titled “Prompt templates”Worktrunk uses minijinja templates (Jinja2-like syntax) to build prompts.
Custom templates
Section titled “Custom templates”Override the defaults with inline templates:
[commit.generation]command = "llm -m claude-haiku-4.5"
template = """Write a commit message for this diff. One line, under 50 chars.
Branch: {{ branch }}Diff:{{ git_diff }}"""
squash-template = """Combine these {{ commit_details | length }} commits into one message:{% for c in commit_details %}- {{ c.subject }}{% endfor %}
Diff:{{ git_diff }}"""Template variables
Section titled “Template variables”| Variable | Description |
|---|---|
{{ git_diff }} | The diff (staged changes or combined diff for squash) |
{{ git_diff_stat }} | Diff statistics (files changed, insertions, deletions) |
{{ branch }} | Current branch name |
{{ repo }} | Repository name |
{{ recent_commits }} | Recent commit subjects (for style reference) |
{{ commit_details }} | Commits being squashed (squash template only); each renders as its subject and exposes .subject / .body |
{{ target_branch }} | Merge target branch (squash template only) |
{{ user_guidance }} | Rendered user template-append fragment (see below) |
{{ project_guidance }} | Rendered project template-append fragment (see below) |
Template syntax
Section titled “Template syntax”Templates use minijinja, which supports:
- Variables:
{{ branch }},{{ repo | upper }} - Filters:
{{ commit_details | length }},{{ repo | upper }} - Conditionals:
{% if recent_commits %}...{% endif %} - Loops:
{% for c in commit_details %}{{ c.subject }}{% endfor %} - Loop variables:
{{ loop.index }},{{ loop.length }} - Whitespace control:
{%- ... -%}strips surrounding whitespace
See wt config create --help for the full default templates.
Appending to the prompt
Section titled “Appending to the prompt”template-append adds to the commit and squash prompts instead of replacing them. It lives in both user config (personal preferences) and project config (.config/wt.toml, shared so every teammate’s LLM sees the same style guide). Each fragment is itself a minijinja template — Worktrunk renders it with the same variables as the main template ({{ branch }}, {{ git_diff }}, …), then appends the result after <style>. The user fragment renders into a <user-guidance> block and the project fragment into a <project-guidance> block, so the LLM can tell personal preference from shared convention:
[commit.generation]template-append = """- Use conventional commits (feat:, fix:, docs:, …)- Reference the related issue ID in the body"""When both the user and project set template-append, the <user-guidance> block comes first, then <project-guidance>.
The user fragment needs no approval — it’s the developer’s own config. For the project fragment, the first time the rendered text is sent to the LLM, Worktrunk shows the raw fragment in an approval prompt — the same one-shot gate as project-defined hooks. Subsequent commits don’t re-prompt unless the fragment changes. Declining is non-fatal: the LLM runs with just the user fragment (if any).
Custom user templates that don’t reference {{ user_guidance }} / {{ project_guidance }} opt out of the appended blocks — the rendered values are injected only where the template places them.
Fallback behavior
Section titled “Fallback behavior”When no LLM is configured, worktrunk generates deterministic messages based on changed filenames (e.g., “Changes to auth.rs & config.rs”).
