wtm

Worktrees isolate code. wtm isolates the runtime.

for teams and their agents

Every branch gets its own worktree, ports, Docker Compose project, database and URL, so ten Claude Code agents can run their apps on one laptop.

git worktree add ../feat-login feat/loginPreparing worktree (checking out 'feat/login')git worktree add ../feat-search feat/searchPreparing worktree (checking out 'feat/search')cd ../feat-login && pnpm dev ✓ ready on http://localhost:3000cd ../feat-search && pnpm dev Error: listen EADDRINUSE: address already in use :::3000pnpm db:migrate Error: Environment variable not found: DATABASE_URL.docker compose up -d postgres Conflict. The container name "/acme-postgres-1" is already in use
wtm create feat/login feat/search --yes┃ ✓ feat/login┃ ../acme.trees/feat-login┃ ✓ feat/search┃ ../acme.trees/feat-search┃┃ 2 createdwtm run up feat/login feat/search -d --yes┃ ✓ api started · feat/login · http://api.feat-login.acme.localhost┃ ✓ api started · feat/search · http://api.feat-search.acme.localhost┃ ✓ web started · feat/login · http://web.feat-login.acme.localhost┃ ✓ web started · feat/search · http://web.feat-search.acme.localhost
brew install LucasPcq/tap/wtm
go install github.com/LucasPcq/wtm@latest
Download a release for macOS or Linux →

Agents: read llms.txt, then wtm agents install.

fig. 1 — what wtm writes in each worktree

git worktree gives each branch a directory. wtm gives it the rest.

The same repository, three worktrees. wtm rewrites the ports and addresses in each one's .env files when it creates it, and hands every job the worktree's identity when it runs it. Pick a worktree, or create one.

apps/web/.envwtm create
# main: 3000PORT=3010# main: http://localhost:4000API_URL=http://api.feat-login.acme.localhost
apps/api/.envwtm create
# main: 4000PORT=4010# main: postgresql://app:app@localhost:5432/appDATABASE_URL=postgresql://app:app@localhost:5432/app_feat-login
environment of every jobwtm run up
WTM_BRANCH=feat/loginWTM_WORKTREE=feat-loginWTM_ORDINAL=1WTM_PORT_OFFSET=10COMPOSE_PROJECT_NAME=acme-feat-login

wtm --help

Create, run, watch, sync, follow.

Five commands cover the day. Every terminal on this page replays what wtm printed in a sandbox repository called acme, trimmed to fit.

wtm create

Worktrees, ready to work in

Several branches in one command. Each worktree gets its .env files copied and your on_create hooks run (pnpm install…). wtm clean refuses anything uncommitted or unpushed.

~/code/acme
wtm create feat/login feat/search fix/header --yes┃ › feat/login (1/3)┃ › feat/search (2/3)┃ › fix/header (3/3)┃┃ ✓ feat/login┃ ../acme.trees/feat-login┃ ✓ feat/search┃ ../acme.trees/feat-search┃ ✓ fix/header┃ ../acme.trees/fix-header┃┃ 3 created
wtm run up

A whole stack per worktree

Declare your jobs once in run.toml; wtm run init writes it from your Compose files and package scripts. Each worktree runs it on its own ports, Compose project and database, behind its own *.localhost URL (on port 80 once wtm run proxy install redirects it).

How wtm run works →

~/code/acme
wtm run up feat/login feat/search -d --yes┃ Profile dev · 2 worktrees┃┃ ✓ api started · feat/search · http://api.feat-search.acme.localhost┃ ✓ api started · feat/login · http://api.feat-login.acme.localhost┃ ✓ web started · feat/search · http://web.feat-search.acme.localhost┃ ✓ web started · feat/login · http://web.feat-login.acme.localhostwtm run ps┃ NAME STATUS ADDRESS WORKTREE┃ api running http://api.feat-login.acme.localhost feat/login┃ web running http://web.feat-login.acme.localhost feat/login┃ api running http://api.feat-search.acme.localhost feat/search┃ web running http://web.feat-search.acme.localhost feat/search
wtm ui

One screen for all of it

Every worktree, the branch tree and the running services, updated live as worktrees come and go from any shell or agent. Pull request status shows up when gh is connected.

wtm ui
wtm acme · base main · ● main v0.29.2 Worktrees Tree Services + New worktree ⋯ Actions 5 worktrees ━━━━━━━━━━━━━─────────────────────────────────────────────────────────────────────────────────────╭────────────────────────────────────────╮╭──────────────────────────────────────────────────────╮│ Worktrees ││ DETAIL LOGS ││ ││ ━━━━━━━━━━────────────────────────────────────────── ││ ▌ main clean ││ ││ ▌ parent · ● you are here ▶ 2 running ││ main ● you are here ││ ││ ──────────────────────────────────────────────────── ││ feat/login clean ││ ││ from main · base ↑1 ▶ 2 running ││ clean · active just now ││ ││ ││ feat/search clean ││ RUN 2 up ││ from main ▶ 2 running ││ ││ ││ ● web http://web.main.acme.localhost 15s ││ fix/header clean ││ ● api http://api.main.acme.localhost 15s ││ from main ││ ││ ││ ││ feat/login-ui clean ││ ││ from feat/login · base ↑2 ││ ││ ││ ││ ││ │╰────────────────────────────────────────╯╰──────────────────────────────────────────────────────╯ ↑↓ select · n new · m actions · a bulk · tab view · o output · ? help · q quit
wtm sync

Stacked branches, rebased in order

Branch off a branch. When main moves, wtm sync rebases the whole chain, parents before children, and aborts cleanly on a conflict.

~/code/acme
wtm tree┃ main┃ ├─ feat/login base ↑1 ⚠ needs sync┃ │ └─ feat/login-ui base ↑1┃ ├─ feat/search ⚠ needs sync┃ └─ fix/header ⚠ needs syncwtm sync --all --yes┃ ✓ feat/login rebased onto main 1 commits┃ ✓ feat/search rebased onto main 0 commits┃ ✓ fix/header rebased onto main 0 commits┃ ✓ feat/login-ui rebased onto feat/login 1 commits┃┃ 4 branch(es) ready to push (force-with-lease).
wtm events

Every change, as it happens

Whoever makes it, a shell, an agent or wtm ui: worktrees created and removed, hooks that failed, jobs that started or crashed with their last lines. --output json turns it into JSON Lines for an orchestrator to read, no polling.

The event stream →

~/code/acme
wtm events┃ = 1 worktree · /code/acme┃ = watching for changes┃ ✓ created agent/checkout /code/acme.trees/agent-checkout┃ ~ updated agent/checkout ordinal=1┃ ✓ provisioned agent/checkout┃ ✓ started api in agent/checkout http://api.agent-checkout.acme.localhost┃ ✓ started web in agent/checkout http://web.agent-checkout.acme.localhost┃ ✗ web crashed in agent/checkout (exit 1)┃ Error: Cannot find module './routes/checkout'┃ ~ stopped api in agent/checkout┃ ✓ removed agent/search

wtm agents install

Built for Claude Code to drive.

wtm ships a skill that teaches Claude Code its commands and their unattended forms. Four issues, four agents, four running stacks, one laptop.

Recipe: agents in parallel
orchestrator
wtm agents install # once: the skill for Claude Codeagents="agent/checkout agent/search agent/oauth agent/billing"wtm create $agents --yes --output json > /dev/nullwtm run up $agents -d --yes --output json | jq -r '.[].jobs[].url'http://api.agent-checkout.acme.localhosthttp://web.agent-checkout.acme.localhosthttp://api.agent-search.acme.localhosthttp://web.agent-search.acme.localhost…
--yes
Every command runs unattended. A missing choice is an error naming its flag, never a prompt the agent cannot answer.
--output json
A document to read instead of text to parse, with published JSON schemas.
exit codes
Stable and documented: 10 the worktree exists, 11 no such branch, 16 no run.toml…
wtm events
Every worktree and job change as JSON Lines, for the agent or whatever orchestrates it.

git worktree add

Same git underneath. Everything around it handled.

Taskgit worktreewtm
New worktreean empty checkout.env copied, hooks run, ports shifted
Two branches runningsame ports, containers and databaseown ports, Compose project, database and URL
Stacked branchesrebase each one by hand, in orderwtm sync rebases the chain
Many worktreesone command eachwtm create a b c, wtm exec --all
Agents and toolsparse porcelain output--output json, --yes, a skill, an event stream

git tag --list 'v*'

42 releases since April 2026.

Shipped in the open, every week, each with its changelog and a migration note when something moves.

  1. v0.29.2For 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.
  2. v0.29.1A fix release for wtm create and run.toml, with a shorter isolation question.
  3. v0.29.0wtm opens up to other tools with a live event stream, and works on several worktrees at once.

MIT licensedmacOS, Linux, Windows through WSL2Homebrew, Go, binariesFull changelog

wtm tree

From isolated stacks to orchestrated agents.

What ships next, drawn the way wtm draws branches.

main  ✓ shipped  worktrees, isolated stacks, stacked branches, wtm ui, wtm events
├─ next/orchestration  ● in progress
│  └─ one agent per issue: spawned, tracked and cleaned up by wtm
└─ explore/claude-api
   ├─ write run.toml from an analysis of the repository
   ├─ resolve rebase conflicts while wtm sync walks a stack
   └─ describe a stack of pull requests

git log --reverse | head -1

Built inside a monorepo that runs a dozen services.

Lucas PicqueFounder · @LucasPcq · contact@wtm.sh

I work at a startup on a monorepo of two apps, each with a frontend, a backend and a back office, over Docker with several databases. Once AI agents could take several tasks at once, every task needed its own running stack, for me to check the work and for the agent to check it itself.

It started as shell scripts to create a worktree, copy its .env and run the hooks. The tools I tried stopped at the worktree. So I built wtm, and today the whole team runs part or all of the monorepo in several worktrees at once with it.