WT Config
Use this skill to produce a project-specific wt config recommendation. Do not answer as a generic config manual. Do not list every possible field unless it is relevant to the current repo. Do not start work, coordinate agents, land branches, or clean worktrees.
This skill is not the wt setup CLI. wt setup prepares one user/machine
integration such as shell lines and agent hooks. wt init prepares one repo:
config, a usable <repo-root>/.wt/ personal storage path (real directory or
directory symlink), and the clone-local /.wt ignore line. config
recommends and diagnoses repo config.
Core Job
Given a repo, inspect the actual project and recommend the smallest useful active config for that project.
The recommendation must answer:
- what should go into the active config;
- which file should own it;
- what should stay out and why;
- what is already configured effectively;
- which local tools are missing for recommended commands;
- which env template substitutions, if any, should be active;
- what commands validate the result.
Ask questions only for choices that cannot be inferred from repo facts and would change the config.
Inspect First
Run these before giving a concrete recommendation:
git rev-parse --path-format=absolute --show-toplevel
find . "$(git rev-parse --path-format=absolute --show-toplevel 2>/dev/null)/.wt" -maxdepth 3 \
-name '.wt.toml' -o -name 'config.toml' -o -name 'profile.toml' 2>/dev/null
wt config show
wt doctor
rg --files | rg '(^|/)(Cargo.toml|Cargo.lock|package.json|pnpm-lock.yaml|yarn.lock|bun.lockb?|pyproject.toml|uv.lock|composer.json|Gemfile|Makefile|justfile|Justfile|deny.toml|rust-toolchain.toml|\.github/workflows/.*\.ya?ml)$'
If this is the wt repo itself, also read README.md, docs/consistency.md,
and docs/north-star.md before recommending user-facing model changes. Treat
docs/consistency.md as the source of truth for the wt setup / wt init /
personal storage boundary.
Read the relevant manifests, project docs, and CI workflows. Check local availability for tools that existing config or recommended commands depend on: agent CLIs, cmux, provider CLIs, test/lint/audit tools, browsers, secret bootstrap tools, and editors.
For env/secret bootstrap, inspect only file names and command availability.
Never read or print secret file contents such as .env.
Decide Ownership
Choose the file by ownership, not convenience:
<repo-root>/.wt/config/local.toml: personal repo config, local paths, local agent commands, private runtime details, personal defaults..wt.toml: project integration config contributors should share.<repo-root>/.wt/config/profiles/<name>/profile.toml: named runtime profile only when reusable structured profile config is worth the extra file.
Do not put .wt or linked-worktree .wt -> <main-repo>/.wt symlinks in
[worktree].link. That path is wt personal-storage infrastructure, not user
config intent.
Do not silently move settings between shared/private ownership. If existing config is mature, recommend a minimal patch rather than normalizing it into one ideal shape.
Recommend Active Config
Recommend active TOML, not a commented tutorial file. Include only settings that the project needs or the user explicitly chose.
Default recommendation rules:
- Keep
[workspace]when the user benefits from repeatable cmux tabs. - Add
[setup]only when the repo has a real per-worktree install/sync step. - Add
[setup.env]or[setup.env_files]only for non-secret, worktree-specific values rendered into env files that already exist after[worktree]copy/link materialization. Env substitution runs after copy/link and before deps, so deps cannot create the target file for the same setup run. - Add
[issues]only when provider issue workflows are used. - Add
[site],[workspace.browser], andworkspace.post_deps_tabsonly for app/web repos with a local server or URL. - Add
[workspace.browser.chrome_devtools]only with[workspace.browser] mode = "chrome_devtools"when the repo benefits from workspace-isolated debugging Chrome. Forclaude/codexagents, that mode also auto-wires chrome-devtools MCP to the workspace Chrome without editing global or tracked agent config. - If existing config uses a legacy top-level chrome_devtools sibling, recommend
moving it under
[workspace.browser.chrome_devtools]; do not present the legacy form as active TOML. - Add
[editor]only when a concrete editor command is useful for wt-managed TOML editing. - Add
[worktree]only for real path/copy/link/context needs.copyandlinkboth accept string entries for same-name materialization and{ from, to }entries for rename materialization. Usecopy = [{ from = "...", to = "..." }]for renamed copies andlink = [{ from = "...", to = "..." }]for renamed symlinks. AI-assisted branch/workspace naming is opt-in via the[worktree.naming]table: omitting the table entirely disables the feature (worktree_naming::generatereturns the non-AI fallback), so when the repo wants AI naming at all, include at least a minimal[worktree.naming]section — the command/prompt/branch defaults fill in once the table exists. Add the optional fields only when the repo needs a custom naming command; it renders as its own sub-section inwt config show. - Add
[workflow]only when future workflow PR/landing policy should differ from built-in defaults.wt config showalways materializes[workflow](pull_request, landing) even at defaults, so its presence in the effective output is not evidence the user configured it. Exception: these fields merge by Option replacement, so a default-looking value (pull_request = "none",landing = "manual") in a higher-precedence layer can be an explicit override of an inherited policy — keep it when resetting inheriteddraft/readyorautoback to the built-ins is the intent. - Add
[review]only when the codex_base policy should differ from the built-in default (none). Like[workflow],wt config showalways materializes[review].codex_base, so anonevalue there is the default, not intent — unless an owner file declares it:codex_basealso merges by Option replacement, so an explicit[review] codex_base = "none"in a higher-precedence layer is the only way to override an inheritedadvisory/requiredpolicy. Keep that explicitnone; do not strip it as "just the default". - Add
[task_list.columns.<name>](run,next,dur,task,branch,source,origin_status,size, each withhidden/width) only when the user wants to hide or resize a task-browser column from its built-in layout. - Keep simple agent defaults inline under
[profile.agent]; use named profiles only when prompt/scaffold/profile reuse is worth the structure. Note the surface flip: you author agent settings under[profile.agent](or a named profile's[agent]), butwt config showmerges the profile and renders the result as a top-level[agent]block (cli, args, command, ready, submit, timeout, send_after, plus[agent.prompt]). When diagnosing the effective output, look for[agent], not[profile.agent]. - Do not add active
[workspace].colorswhen it only restates built-in defaults. - Do not add cargo-audit, cargo-deny, browsers, or provider helpers to active config if the tool is not installed, unless the user explicitly wants a config that assumes it will be installed.
- Do not add framework-habit setup commands just because they are common. Only
recommend commands proven by project docs, manifests, CI, existing config, or
the user's stated workflow. For example, do not add
php artisan storage:link --forceto a Laravel project unless this repo uses it. - Prefer per-worktree
.envcopy only in personal config when.envexists and the repo needs local env state. If docs mention a secret bootstrap tool but the tool is missing, recommend.envcopy over a failing bootstrap command. - Do not use env templates as secret bootstrap or file creation. Missing env
targets are skipped; pair
[setup.env]with.envcopy/link when needed, or omit it and explain the no-op risk. - For
[editor], recommend exactly one active command. Useful concrete choices includevim {{path}},code {{path}},phpstorm {{path}}, orpstorm {{path}}, depending on what the user chose and what is installed. - Compact examples are allowed when they clarify a real project choice, but they must be project-shaped alternatives, not a general config manual.
For a web repo that should launch an isolated debugging Chrome, use the nested browser shape:
[workspace.browser]
mode = "chrome_devtools"
url = "{{site_url}}"
[workspace.browser.chrome_devtools]
port = 9222
user_data_dir = "{{worktree_parent}}/.chrome-devtools/{{worktree_name}}"
Env Template Shape
The implementation module is env_template, but the active config surface is
[setup.env] and [setup.env_files."relative/path"]. Never recommend an
env_template TOML field or section.
Use root [setup.env] only for <worktree>/.env. Use
[setup.env_files."path"] for nested or suffix env files such as
frontend/.env.development or backend/.env; root [setup.env] does not
discover or update those files.
Values are templates rendered from setup vars, commonly {{site_url}},
{{api_url}}, {{vite_port}}, {{api_port}}, {{branch_slug}},
{{worktree_path}}, {{worktree_name}}, {{issue_title}}, and
{{wt_agent_id}}. {{site_name}} exists only when a site is configured;
Chrome debug vars exist only when Chrome DevTools browser setup is active.
Leave unknown variables visible in the recommendation instead of inventing
values.
Use shared .wt.toml for non-secret repo conventions the whole team should
share, such as local callback URLs. Use personal
<repo-root>/.wt/config/local.toml for .env copying, local-only env file
paths, machine-specific values, or anything that would reveal private runtime
details. Never include actual secret values in active TOML examples or
responses.
Project-shaped example:
[worktree]
copy = [".env"]
[setup.env]
APP_URL = "{{site_url}}"
[setup.env_files."frontend/.env.development"]
VITE_API_TARGET = "{{api_url}}"
Explain Omissions
For every relevant section that could plausibly be expected, say whether to keep, add, change, or omit it.
Cover these when relevant:
[workspace][setup][setup.env][setup.env_files][issues][site][workspace.browser][workspace.browser.chrome_devtools][editor][worktree][worktree.naming][workflow][review][task_list.columns.*][profile.agent](renders as effective[agent])- named profiles
[workflow] and [review] always appear in wt config show even at their
built-in defaults, so frame them as "default materialized" unless an owner file
actually declares the field — a declared default-looking value (pull_request = "none", landing = "manual", codex_base = "none") can be an explicit
Option-replacement override of an inherited policy, not noise.
[task_list.columns.*] and [worktree.naming] only appear when the user
declared them; note that omitting [worktree.naming] disables AI naming
entirely, so its absence is itself a meaningful state.
The omission rationale should be practical, for example: "CLI repo, no dev server", "tool missing locally", "built-in default already covers this", or "shared config would leak a personal path".
For [workspace.browser.chrome_devtools], omit it when browser mode is
none/system or ordinary browser open is enough; keep or add it only for
mode = "chrome_devtools" isolated Chrome debugging.
Diagnose Existing Setup Against Intent
Before recommending changes, reconcile three views: what files declare, what
wt config show actually resolves, and what the user intends. Many setups fail
silently because the resolved effective config diverges from the written intent.
The canonical merge rules per section (REPLACE / extend / dedupe / append /
wholesale-section behavior) live in
docs/consistency.md → Config Merge Semantics.
Cite that table when explaining why a value disappeared or duplicated; do not
restate the matrix here.
Run this triangulation pass:
- Read every config file that exists.
.wt.toml,<repo-root>/.wt/config/local.toml, and every<repo-root>/.wt/config/profiles/*/profile.toml. Also list<repo-root>/.wt/config/profiles/*/scaffold/andprompts/to see what the profile expects to inject. - Read the user's intent. What did the user just paste, ask for, or describe? If unclear, ask one targeted question — do not guess.
- Run
wt config showand compare. The effective output is the source of truth for what wt will actually apply. Diff it against the user's intent.
For every divergence, propose a concrete fix. Common divergences to check explicitly:
- Profile dormancy.
<repo-root>/.wt/config/profiles/<name>/exists (withprofile.toml,scaffold/, orprompts/) butwt config showshows nocopy = [{ from = ".../scaffold", to = "." }]entry for that scaffold and no prompts fromprofile.toml/prompts/*.md. Cause:.wt.toml/local.tomlis missing[profile] name = "<name>", and no command passes--profile <name>. Fix: add[profile] name = "<name>"to the owner file, or remove the profile directory if it is unused. - Named profile + inline
[profile.agent.*]collision. When[profile]has bothname = "<name>"and inline settings like[profile.agent.prompt],wt config showfails with a hard parse error (schema validation rejects the combination). Fix: pick one — dropnameto use inline, or move the inline prompts into the named profile'sprompts/*.md(or its ownprofile.toml's[agent.prompt]) and delete the inline block. - Scaffold drift.
[profile] name = "<name>"is set andwt config showshows thecopy = [{ from = ".../scaffold", to = "." }]scaffold entry, butscaffold/is empty or missing the files the user expects. Fix: populate<repo-root>/.wt/config/profiles/<name>/scaffold/with the actual files the worktree should receive, then re-runwt config show. - Prompt file vs inline collision.
profile.tomldefines[agent.prompt].<mode>and the same profile hasprompts/<mode>.md. Behavior: file wins, stderr emitswarning: [agent.prompt].<mode> from profile.toml is overridden by .../prompts/<mode>.md. Fix: pick one source for the replace prompt. If the user wants both ("inline as base, file as override"), the warning is informational and no fix is needed — that pattern is supported.prompts/<mode>.append.mdis not a conflict; it layers on top of either source. - Env template no-op or wrong target.
wt config showshows[setup.env], but the worktree will not have.envafter copy/link materialization, or the intended file is nested/suffixed such asfrontend/.env.development. Cause:[setup.env]only updates root.envand skips missing targets. Fix: add personal[worktree] copy = [".env"],copy = [{ from = "...", to = ".env" }], or a suitablelink = [{ from = "...", to = ".env" }], move nested keys under[setup.env_files."path"], or remove the env template if no target file should exist. - Materialized default mistaken for intent.
[workflow],[review], and active[site]/[workspace.browser]/[agent]sections render their built-in defaults inwt config showeven when no file sets them. Before claiming a value is "configured," confirm an owner file actually declares it; otherwise report it as the default that wt materializes. - Effective ≠ files in another way. Any setting the user clearly intended
(a prompt, a tab, a command) is absent from
wt config show. Trace which file owns it and why the merge dropped it (wrong section, wrong owner file, shadowed by profile, etc.).
If divergence is detected, lead the response with the divergence and the fix, not with a generic recommendation.
Response Shape
Use this order:
- Observed facts: project type, CI checks, detected commands, existing effective config, available/missing tools.
- Divergences between files, intent, and
wt config show— with concrete fixes (skip this item only when there is no existing setup). - Recommended owner file.
- Recommended active TOML.
- Keep/add/omit rationale.
- Unresolved choices or compact project-shaped alternatives, only if needed.
- Validation commands.
Keep the answer concrete. Prefer a short active config block over a long field catalog.
Validation
After recommending or editing config, validate through the public interface:
wt config show
wt doctor
If the recommendation includes named profiles, also run:
wt config show --profile <name>
wt config show | grep -E 'copy =|link =|\[agent' # named profile actually merged into effective?
If this skill file or wt init behavior changes inside the wt repo, validate
with:
~/dotfiles/install.sh skills plan
cargo run --quiet -- init --help
cargo run --quiet -- doctor
cargo test init