Skip to content

Changelog

All notable changes to wtm are documented here. The format follows Keep a Changelog and wtm adheres to Semantic Versioning; how to write an entry is in docs/dev/changelog.md.

For scripts and agents: wtm events follows every repository and reports job crashes, wtm env stops printing secrets, wtm prune stays fast on repositories with many branches, and usage errors exit 2.

  • wtm events --all follows every repository wtm knows from any directory, ignoring an inherited GIT_DIR; integrations should pass it instead of running from outside a repository. → Every repository at once
  • wtm env --addressing ports|names moves the main checkout's addresses onto names, or back to ports, on its own. → The main checkout
  • wtm events reports jobs starting, crashing, exiting and stopping (job.*), shared services naming the worktrees that hold them, and its snapshot lists each worktree's jobs; same schema v: 1. → Jobs
  • wtm env prints only the values wtm writes, in text and JSON ("redacted": true for the others), and masks URL passwords, also in env_ports; --show-values prints everything. → A .env is out of date
  • wtm env main keeps the addressing its .env spells: reconciling its keys no longer moves it onto named URLs; pass --addressing names for that. → The main checkout
  • wtm prune reads only the branches that have a worktree, on git and on GitHub, so its time no longer grows with the repository's branches; it no longer refreshes the other remote-tracking refs. → Stacked pull requests
  • wtm env asks whether to keep or switch the worktree's isolation (the main checkout: its addressing), keeping it by default; the recap's verbatim action is gone. → Isolation
  • --output json without --yes on a command that could ask (create, checkout, sync, clean, env…) exits 2, a usage error, instead of 1: a script branching on 1 should read 2. → Exit codes
  • wtm prune and wtm tree --with-prs find a worktree's pull request however many newer ones the repository has, instead of only among the 100 newest. → Stacked pull requests
  • wtm env main no longer writes [[env]] namespaces into the main checkout (wt_main, acme-main), and puts back the template's value where an earlier run did. → Shared services
  • Usage errors exit 2 instead of 1: flags that cannot be combined (clean/prune --keep-data --drop-data, run up --exclusive --parallel, sync --push --no-push…), --all with a name, and wtm checkout <not a number>, now refused before the config is read. → Exit codes
  • wtm run list in a terminal opens its picker again instead of printing Aborted. straight away.
  • wtm env's resolver shows a kept conflict as your value alone, instead of an arrow from your value to itself.
  • wtm prune --dry-run --output json reports "dry_run": true when there is nothing to prune.

A fix release for wtm create and run.toml, with a shorter isolation question.

  • wtm create <branch>... with several names skips the branches step, as a single name does, and opens the wizard on the source branch.
  • wtm create and wtm checkout ask the isolation question in one line, the detail is in the guide. → Isolation
  • run.toml: a link to a .env that config.toml does not configure is ignored with a warning, and no longer stops the other .env values from being written. → run.toml
  • wtm create keeps the names you are typing when the branch fetch finishes, and a refreshed branch or worktree picker keeps its highlighted row.

wtm opens up to other tools with a live event stream, and works on several worktrees at once.

  • wtm events streams every worktree change as it happens, as JSON Lines for editors, terminal plugins and agents. → Event stream
  • wtm create and wtm clean take several worktrees in one run: wtm create feat/a feat/b. → Recipes
  • wtm exec runs one command in several worktrees in parallel, each with its own ports: wtm exec --all -- pnpm test. → Recipes
  • wtm create --output json and wtm clean --output json answer with an envelope: read .results[0]. → Migrating to 0.29
  • Exit code 21 for any command run outside a git repository (was 1). → Migrating to 0.29
  • Exit code 19 for an interactive cancellation (was 0), so wtm create x && wtm go x stops there. → Migrating to 0.29
  • wtm events outside a repository follows every repository wtm has been used in. → Every repository at once
  • worktree.provisioned and worktree.deprovisioned events tell when a worktree's hooks have run, and whether they passed.
  • WTM_CORRELATION_ID tags the events a command publishes, so a tool recognises its own. → Integrations
  • wtm version --output json reports the version of each machine contract, for integrations to check compatibility.
  • Locked worktrees (git worktree lock) are refused by clean and prune unless --force, and marked in list and tree.
  • wtm ui creates and deletes several worktrees at once, and picks up changes made elsewhere immediately.
  • wtm env --check exits 18 on drift, ready for CI.
  • wtm checkout and wtm extract ask the same questions as create and always show a recap before acting.
  • wtm env reports a count per file and only the keys left to handle; warnings go to stderr.
  • Invalid flag values and branch names git would reject are refused upfront with exit 2, before anything is created.
  • wtm relocate --to rewrites base_path even when no worktree has to move.
  • wtm create and wtm checkout reject an unknown --env-from before creating a half-provisioned worktree.
  • A branch can no longer be its own parent (create b --from b).
  • wtm extract no longer ignores --from and --ff when the target is picked in the wizard.

Each worktree runs its own services on its own ports; read the migration guide if you used wtm run, wtm switch or script wtm.

  • The run module: per-worktree services and tasks grouped in profiles; wtm run init writes the config, wtm run up starts the stack. → Jobs and profiles
  • Per-worktree isolation: shifted ports (3000 → 3010) rewritten in .env, and its own COMPOSE_PROJECT_NAME; wtm env settles them. → Isolation
  • Named URLs per job and worktree (http://web.feat-login.acme.localhost:11080), on port 80 on macOS with wtm run proxy install. → Addressing
  • wtm switch is removed: use wtm go then wtm run up. → Migrating to 0.28
  • --non-interactive is removed: use --yes. → Migrating to 0.28
  • Hooks run through /bin/sh -c with placeholders already quoted: drop your own quotes around {{worktree}}. → Migrating to 0.28
  • run commands take the worktree as argument and the job or profile as a flag, and their JSON changes shape: update scripts. → Migrating to 0.28
  • run down --all stays in the current repository, run import replaces instead of merging, and run.toml is validated more strictly. → Migrating to 0.28
  • Shared services: one postgres for the repository, one database per worktree, dropped on clean. → Shared services
  • run up stops before a migration touches data the worktree does not own.
  • wtm run up feat-a feat-b runs several worktrees at once, and wtm ui shows and drives the services.
  • Output is more consistent: a ┃ bar marks wtm's blocks, hooks sum up in one line, and --quiet works everywhere.
  • The wtm shell function returns the command's exit code (open a new shell after upgrading).
  • wtm init no longer installs every workspace package separately.
  • Rewriting a .env value keeps its quotes, comment and line endings.

A child worktree no longer pushes to its parent's branch.

  • wtm create from a parent only on origin no longer makes it the child's upstream, so git push targets the child's branch.
  • wtm prune --gone no longer offers to remove a never-pushed child whose parent's remote branch was deleted.
  • Not retroactive: in an older child whose upstream names another branch, run git branch --unset-upstream, then git push -u origin HEAD.

Self-update with wtm upgrade, and wtm fast-forward.

  • wtm upgrade updates wtm the way it was installed, checksum verified; --check shows what is available, --version pins a release.
  • Update notice: wtm mentions a newer version at the end of a command, without slowing it.
  • wtm fast-forward moves a branch to origin/<branch> and refuses a diverged one (use wtm sync); also in the dashboard.
  • wtm ui help overlay reads like a reference: four sections, sized to the screen, scrollable.
  • wtm sync interactive shows its recap instead of an empty picker.

The wtm ui detail panel no longer flickers.

  • wtm ui reloads the detail panel when the selection or its branch changes, and on r, instead of every three seconds.

A full-screen dashboard, wtm ui, to drive worktrees.

  • wtm ui: a full-screen dashboard running create, clean, reparent, prune and sync, with keyboard, mouse and help on ?.
  • wtm ui Tree tab shows the stacked branches and reparents from the dashboard.
  • wtm ui detail panel shows the last commit, working tree state, children, .env drift, removal blockers and the PR with its CI checks.
  • wtm ui tells a failing gh apart from "no PR", and opens the PR in the browser with p.
  • wtm list and wtm resolve mark the current worktree ● active.
  • ui.animations = false in the global config turns off dashboard animations.
  • New colour palette for every command's output, still respecting NO_COLOR.
  • wtm sync keeps the parent step visible and refreshes parents the cascade does not cover.
  • README no longer documents an agent key that made every command fail.

create, checkout and extract reuse an existing local branch.

  • wtm create <existing-branch> --yes and wtm extract --to <existing-branch> --yes require --from <parent>: wtm cannot guess the parent.
  • wtm checkout <PR> reuses an existing local branch instead of asking for wtm clean, and offers to fast-forward it.
  • wtm create <existing-branch> and wtm extract --to <existing-branch> reuse the branch, announced in the recap.
  • JSON of create and checkout reports whether the branch existed and how it stands against origin.
  • A branch checked out in another worktree exits 10 with a wtm go <branch> hint; --if-not-exists returns that worktree.

wtm extract handles untracked files properly.

  • wtm extract --files accepts a directory and takes every change below it.
  • wtm extract removes directories left empty in the source.
  • wtm extract --on-conflict resolve also covers untracked files already in the target; identical content is no longer a conflict.
  • wtm extract lists each file of a new directory separately, so --files newmod/x.go works.
  • wtm extract handles paths with spaces or non-ASCII characters, and staged renames.

wtm env detects and resolves .env drift between worktrees.

  • wtm env [branch] detects and resolves a worktree's .env conflicts, following the strategy chosen at creation.

on_clean hooks, generalized .env detection and harmonized output.

  • .env config moves from copy_files to [[env.file]] entries, with no automatic migration: run wtm init --only env or edit config.toml.
  • [hooks] on_clean runs before clean/prune remove a worktree (e.g. docker compose down); a failure aborts unless continue_on_error.
  • wtm init --clean-command and --skip-clean configure on_clean non-interactively.
  • sudo rm -rf fallback: an interactive run offers it when git worktree remove hits root-owned files, never on a dangerous path.
  • .env detection recognises .env.dist, .env.sample and other templates, and flags .env.local as local.
  • The example strategy copies the detected template instead of hard-coding .env.example.
  • Output conventions are harmonized across commands; wtm sync shows a spinner while pushing.

An opt-in run module and one --yes/--force model across commands.

  • wtm run init sets up run.toml from detected docker-compose files and package scripts, without overwriting existing jobs.
  • --yes and --force are separate: --yes answers every question with a flag or a safe default, --force only lifts safety refusals.
  • --output json requires --yes on every mutating command, and a missing required selection errors naming its flag: pass both.
  • The run module is opt-in: wtm init no longer configures services (--skip-services, --only services removed); use wtm run init.
  • origin divergence badges (origin ↑a ↓b) in list, tree, pickers and JSON, read without fetching; r refreshes.
  • --ff fast-forwards a source that is only behind, also on create --from and extract.
  • wtm extract [source] picks the source first, so you can extract from anywhere.
  • wtm reparent moves several worktrees onto one new parent in a single pass.
  • Wizards keep every confirmation inside, with a breadcrumb and Back; clean, relocate and sync each run as one wizard.
  • wtm agents install updates an already installed skill.
  • wtm init points out pre-existing worktrees and suggests wtm relocate.
  • wtm prune reads merged/closed from the GitHub PR state instead of local commits; a branch without a PR is never tagged.
  • wtm clean and wtm relocate without a terminal or --yes error out instead of starting a wizard.
  • wtm clean --reparent-children is honoured in the wizard.

wtm prune cleans up finished work in one pass, and every command speaks JSON.

  • wtm prune removes every worktree whose work is done, reparenting surviving children onto their grandparent.
  • --merged, --closed and --gone narrow prune to branches with no commit ahead, a merged or closed PR, or a deleted remote.
  • wtm prune needs --force for a dirty, unpushed or open-PR worktree, and never touches main or the base branch.
  • wtm prune --dry-run previews without changing anything.
  • wtm sync --keep-conflict leaves a conflicting rebase in progress for manual resolution instead of aborting it.
  • wtm sync detects a rebase already in progress and blocks its descendants.
  • --output json is available on every command, with a stable payload.
  • wtm --help groups commands into sections.
  • Command reference under docs/ is generated from the CLI.
  • wtm sync captures conflicting files before aborting, and finds the branch of a worktree stuck mid-rebase.

Branch pickers show remote branches and divergence, and multi-select lists can be filtered.

  • wtm create --from origin/x creates a worktree from a remote branch you never checked out.
  • wtm reparent --to origin/x reparents onto a remote branch.
  • Branch pickers list origin branches too, and tag drifted local ones with ↑2 ↓5; r fetches again.
  • wtm create offers to fast-forward a source branch behind origin/, and warns when it has diverged.
  • Multi-select lists filter on /; a toggles all filtered items.
  • Worktree lists are redesigned: aligned badges, a tinted selected row, a status glyph.
  • create, extract and checkout ask before the parent strategy copies .env from the main worktree.

A stacked-branch workflow: see the tree, reparent a branch, and sync only what you pick.

  • wtm sync no longer syncs everything by default: pass branch names, pick them interactively, or use --all.
  • wtm tree shows the forest of worktrees, flagging a child that needs a rebase with ⚠ needs sync.
  • wtm tree --with-prs adds PR state; --output mermaid prints a flowchart to paste into a PR.
  • wtm reparent <branch> --to <parent> changes a worktree's parent; the rebase happens on the next wtm sync.
  • wtm clean offers to reparent the children it would orphan onto the grandparent, or --reparent-children.
  • wtm sync without arguments opens a multi-select picker.
  • wtm sync always refreshes the base first, and exits 11 on an unknown branch.
  • Output has the same spacing and loader across commands; no spinner or \r reaches a pipe.
  • A fast task's first output is no longer lost.

wtm checkout replaces the pr group.

  • wtm pr checkout is now wtm checkout: update scripts and aliases.
  • wtm pr list is removed: use wtm list --with-prs or the checkout wizard.
  • wtm checkout [number] creates a worktree from a pull request; without a number, a wizard lists open PRs.
  • --review, --mine, --from and --env-from filter PRs and preset the wizard's answers.

Worktree commands move to the top level.

  • wtm wt is removed: wtm wt list becomes wtm list, and so on; update scripts and re-run eval "$(wtm shell-init)".
  • A detached job's output is no longer truncated when its process exits.

wt relocate gathers worktrees under base_path, and unused configuration is removed.

  • wtm pr create is removed: use gh pr create.
  • [agents], [integrations], [github] and the global agent key are refused: delete them or re-run wtm init.
  • wtm wt relocate moves scattered worktrees under base_path and adopts external ones, with a preview; --to and --output json for scripts.
  • The default-agent setting: the agent key, the --agent flag and its init step.
  • [github] auto_draft, unused since pr create was removed.

wt sync rebases the whole chain of worktrees in one command.

  • wtm wt sync rebases every worktree onto its refreshed parent in topological order, replaying only its own commits, locally.
  • wtm wt sync shows a recap, then offers one --force-with-lease push of the rebased branches.
  • --dry-run, --base, --push, --no-push and --yes on wt sync.
  • wtm wt sync --output json reports a status per branch and exits non-zero on a conflict or error.
  • wtm wt sync reports a failing git command as an error instead of up_to_date.

Worktree lists show up instantly while PRs stream in.

  • wtm wt list --with-prs includes PRs in non-interactive and JSON output.
  • wt list, wt go and wt switch show worktrees immediately, PR badges filling in as they arrive.
  • wt list no longer fetches PRs by default in non-interactive output.

wtm init reworked: skip sections, re-initialise one with --only, edit on_create hooks.

  • wtm init lets you skip env, hooks or services, written commented out; --skip-env, --skip-hooks, --skip-services do it non-interactively.
  • wtm init --only <section> re-initialises one section without touching the others.
  • wtm init edits on_create hooks as a list: add, edit, remove, reorder.
  • The install command and monorepo packages steps of wtm init: use the on_create hook editor.

wt extract moves uncommitted changes between worktrees.

  • wtm wt extract moves part of the current worktree's uncommitted changes to a new or existing worktree; --keep copies them instead.
  • wtm wt extract leaves the source untouched unless the whole extraction applied.
  • --on-conflict abort (default) changes nothing and exits 15; resolve writes conflict markers in the target.

wtm can be driven by agents, and detached services stream their startup logs.

  • Outside an initialised repository, commands exit 12 instead of 0: adjust scripts relying on a silent success.
  • wtm pr create exits 13 when a PR already exists, instead of 0.
  • wtm init --non-interactive bootstraps a project from flags, then detection, then defaults.
  • wtm pr create --yes pushes an unpushed branch and skips prompts.
  • wtm wt create --if-not-exists succeeds when the worktree already exists.
  • Exit codes per failure: 10 worktree exists, 11 branch not found, 12 config not found, 13 PR exists, 14 job not declared.
  • wtm run up streams a detached service's startup output instead of a spinner.
  • wt clean, run stop and run down succeed as no-ops when there is nothing to remove or stop.
  • wtm pr create --output json no longer stops silently on an unpushed branch.

run up and run start launch and tail in one step, and profiles run jobs in your order.

  • wtm run up / run start start jobs and stream their output straight away.
  • run profile add / edit order a profile's jobs, followed at run time.
  • A failed task aborts the rest of the profile and shows its logs.
  • The wt go / wt switch picker loads faster and shows a callout when gh is missing.

An interactive wt list, run.toml export/import and commands to edit jobs and profiles.

  • Config and metadata move from .wtm/ to <git-common-dir>/wtm/: move existing files or re-run wtm init.
  • wtm run list --output json uses lowercase keys (job, name, kind).
  • The shell wrapper changed: re-run eval "$(wtm shell-init)".
  • wtm wt list is interactive, with an Open PR action and a hint when gh is missing.
  • Removing the current worktree sends the shell back to the base repository.
  • wtm init offers package.json scripts, workspaces included, as jobs.
  • wtm run export / run import move run.toml in and out as JSON.
  • wtm run job and wtm run profile add|rm|edit|list manage run.toml by wizard or flags.
  • wtm config show and wtm config edit reach the config without digging into the git directory.
  • Setting a default profile unsets the previous one instead of failing.

Config files are decoded strictly and come with JSON Schemas for IDE autocomplete.

  • JSON Schemas for run.toml and both config.toml are written next to them, for autocomplete in Taplo-based editors.
  • wtm schema dump refreshes the schemas on disk after an upgrade.
  • Unknown keys in a config file are rejected instead of ignored.

The terminal is restored after detaching from a job's logs.

  • wtm run logs on a job with a TUI (turbo, vite, vim) no longer leaves the terminal broken on exit.

Stopping a job stops its whole process tree.

  • wtm run stop / run down stop the job's whole process group, with SIGKILL after 5 s if SIGTERM is ignored.

Services and one-shot tasks are unified as jobs in run.toml.

  • .wtm/services.toml is replaced by .wtm/run.toml, with [[job]] and [[profile]]: rewrite your file.
  • wtm svc is renamed wtm run: update scripts and aliases.
  • The wt switch shell wrapper calls wtm run up: regenerate it with wtm shell-init.
  • kind = "task" declares a one-shot command (migration, seed) that streams live and must succeed before the profile continues.
  • run.toml is validated before anything runs.
  • wtm init writes detected docker-compose files as detached services.

More output polish.

  • The wt go / wt switch picker keeps its colours through the shell wrapper.

Output polish.

  • svc up, svc ps, pr create and wtm init: consistent padding and spacing.
  • The wt go / wt switch picker keeps its highlight and badges through the shell wrapper.

wtm can be driven by LLM agents.

  • --output json on the wt, pr and svc commands, with human text on stderr.
  • wtm svc list lists declared services and profiles, with actions on a terminal.
  • wtm svc ps lists running services, with stop, logs and restart actions.
  • wtm agents install installs a using-wtm skill into the .claude/ or .cursor/ directories it finds.
  • wtm init detects docker-compose files and scaffolds matching services.
  • wtm svc down --all stops every service of every worktree.
  • wt switch without an argument shows the wt list picker.
  • wtm svc down without --all only touches the current worktree.
  • A service with a stop command no longer reports ✓ started when docker compose up -d fails.
  • svc down, wt clean and svc up --exclusive no longer stop other worktrees' services.

Pickers and shell navigation work through the shell wrapper.

  • The wt go / wt switch picker is visible through the shell wrapper.
  • "Go to worktree" from pr list and wt list navigates instead of asking for shell integration.
  • The shell wrapper lets any subcommand change the directory.

New pickers and wizards, wt switch, and focus removed in favour of services.

  • wtm wt focus and active-worktree tracking are removed: use svc up / svc down.
  • on_focus / on_blur hooks are removed: keep on_create, and let services run Docker.
  • The dashboard is hidden while it is reworked: wtm alone shows help.
  • wtm wt switch [branch] goes to a worktree and runs svc up.
  • svc up offers to stop services running in other worktrees; --exclusive stops them, --parallel skips the question.
  • wt clean stops a worktree's services before deleting it.
  • Pickers and wizards filter on /, show a breadcrumb and go back with Esc.
  • The pr list picker offers to go to or check out the PR's worktree; wt list shows badges.
  • Output: one style and indent for every message and error.
  • docker compose up -d services are tracked and stopped properly.
  • svc commands read services.toml from the main worktree when run from another.
  • The docker-compose and hook steps of the wtm init wizard.

GitHub access goes through the gh CLI.

  • wtm auth login|status|logout are removed: install gh and run gh auth login.
  • WTM_GITHUB_TOKEN is no longer read: use GH_TOKEN.
  • pr commands and the dashboard's PR panel use gh.

GitHub integration and pull-request commands.

  • Worktree commands move under wtm wt and service commands under wtm svc: update scripts and aliases.
  • wtm auth login signs in to GitHub with the device flow, with auth status and auth logout.
  • wtm pr list lists pull requests, with --mine and --review, also in the dashboard.
  • wtm pr create creates a PR from the current branch through a wizard.
  • wtm pr checkout creates a worktree from an existing PR.
  • wtm svc start / stop act on single services, up / down on profiles.
  • The dashboard splits worktrees and PRs, and multiplexes logs.
  • Dashboard focus handling.

Services run in a background daemon, each in its own terminal.

  • Project config moves from .wtm.toml to .wtm/config.toml: move the file.
  • wtm up starts a profile's services from .wtm/services.toml in a background daemon, scoped to the worktree.
  • wtm down stops them; wtm logs attaches to a service's terminal.
  • The dashboard starts, stops and attaches to the selected worktree's services.

A fix for the dashboard launched from the shell.

  • The dashboard opens through the shell wrapper.

An interactive dashboard.

  • wtm without arguments opens a full-screen dashboard of every worktree.
  • The dashboard shows each worktree's status and details, and creates, cleans, focuses and navigates to worktrees.
  • Focusing from the dashboard streams hook output live.
  • wtm new asks for the branch name when none is given.
  • Hook errors in the dashboard no longer corrupt the screen.

Fixes for commands run from a child worktree.

  • Commands run from a child worktree find the project config.
  • Blur hooks no longer fail when the previous worktree's directory is gone.
  • The shell wrapper returns to the main worktree after cleaning the current one.

Initial release.

  • wtm init sets up global and project configuration (.wtm.toml) through a wizard.
  • wtm new [branch] creates a worktree with env provisioning, metadata and hooks.
  • wtm ls lists worktrees with their git status.
  • wtm go [branch] moves to a worktree through shell integration.
  • wtm focus [branch] switches the active worktree and runs on_blur / on_focus hooks.
  • wtm clean [branch] removes a worktree, refusing when it is dirty, unpushed or has an open PR.
  • wtm shell-init generates the shell wrapper for zsh, bash and fish.
  • Env strategies example, main and parent, and hooks with template variables.
  • Detection of the base branch, env files, package manager, Docker Compose and pnpm workspaces.
  • Install with Homebrew (brew install LucasPcq/tap/wtm), release binaries or go install.