Your agent created the worktree. Now it does not run.
Every parallel-agent workflow ends at the same wall. The agent creates a
worktree, starts working, and the first command fails: no .env, no
node_modules, and a dev server that wants the port another worktree is
already using.
This is not a bug in any of those tools. git worktree add checks out
tracked files, and everything that makes a checkout runnable is
untracked on purpose. The difference from the usual version of this
problem is who created the checkout: you did not. Your agent did, so
the advice that starts with “when you create the worktree” does not
apply.
What the tools give you, and where each stops
.worktreeinclude (Claude Code) copies gitignored files into the new
worktree. It is the smallest possible fix and it works for secrets that
are identical everywhere. It cannot derive anything: every worktree
gets the same file, so the same PORT=3000 and the same
DATABASE_URL. Copy a port into three worktrees and two of them will not
start.
The WorktreeCreate hook (Claude Code, shipped since the feature
request that collected 29 reactions) does run your script when the agent
makes a worktree. It is the real answer, with one consequence the
feature request thread flagged immediately: your hook is expected to
create the worktree itself and print the path. You are not adding
setup to Claude’s worktree handling; you are replacing it.
That is fine if you have something that already knows how to create a worktree properly. It is a lot to write from scratch.
Nothing at all is what you get from every other path: a teammate’s
git worktree add, another agent tool, claude-squad (whose own issue
for this is still open), or the worktree you made by hand last Tuesday.
Measured: what an agent-created worktree is missing
Three worktrees, created the way an agent creates them:
$ git worktree add ../wts/fix-login -b fix-login
$ git worktree add ../wts/add-search -b add-search
$ git worktree add ../wts/refactor-api -b refactor-api
fix-login: .env MISSING
add-search: .env MISSING
refactor-api: .env MISSING
Copying .env into each would fix the first failure and create the next
one, because all three would then hold PORT=3000.
Adopting what already exists
pwt adopt registers a checkout that someone else created: it allocates
a port, writes the metadata, and runs the project’s setup() hook with
$PWT_PORT bound. From inside the worktree:
$ pwt adopt
Adopting worktree: agent-feature
Branch: agent-feature
Port: 4001
✓ Metadata saved
Running Pwtfile (setup)...
✓ Copied: .env
✓ Pwtfile (setup) completed
$ cat .env
PORT=4001
API_KEY=abc
The copy came from the hook; the 4001 did not. The setup rewrote it from the port pwt had just allocated, which is the difference between copying config and deriving it.
For the pile that accumulated while you were not looking, --all takes
the whole directory:
$ pwt adopt --all
Adopting: add-search
Adopting: fix-login
Adopting: refactor-api
Adopted: 3 Skipped (already registered): 0 Failed: 0
fix-login -> PORT=3002
add-search -> PORT=3001
refactor-api -> PORT=3003
Three worktrees, three ports, one command, and the ones already registered are skipped rather than redone.
If you do want the hook
The hook receives a JSON object on stdin (base_path,
worktree_path, worktree_name) and owns the creation: exit 0 and git
is never called, exit non-zero and the whole thing rolls back. So the
script creates the checkout where the agent asked for it, and hands the
rest to adopt:
#!/usr/bin/env bash
# .claude/hooks/worktree-create.sh
input=$(cat)
base=$(jq -r .base_path <<<"$input")
wt=$(jq -r .worktree_path <<<"$input")
git -C "$base" worktree add "$wt" -b "$(basename "$wt")" >&2 || exit 1
pwt --no-input adopt "$wt" >&2 || exit 1 # port, metadata, setup()
exit 0
{ "hooks": { "WorktreeCreate": [ { "matcher": "*", "hooks": [
{ "type": "command", "command": ".claude/hooks/worktree-create.sh" } ] } ] } }
Two details that are easy to get wrong. Everything the script prints on
stdout is parsed as structured output, so send progress to stderr.
And --no-input closes stdin and sets PWT_AGENT=1, so a setup step
that would have asked a question fails instead of hanging a session
nobody is watching.
Note where the worktree lives: the agent picks the path, often inside
.claude/worktrees/, and adopt records that real path rather than
insisting on the project’s own directory. Verified: adopting a checkout
outside worktrees_dir allocates the port and runs setup() normally.
Worth being honest about the split: the hook covers the worktrees that
agent creates. adopt covers all the others, and there are always
others. They are not alternatives; the hook is the front door and
adopt is the one you use for everything that came in through a window.
The rule underneath
A worktree is not ready because it exists. It is ready when the values that must differ per worktree have been derived rather than copied: the port, the database name, whatever your stack keys on. Which tool created the directory is an implementation detail, and any workflow that only works when you created it will break the first time an agent gets there first.
brew install jonasporto/pwt/pwt, then pwt adopt inside the worktree
your agent already made
(reference). What
setup() should do with the port, the database and the dependency store
is its own post.
You do not have to memorize any of this.
pwt skillprints the agent-facing guide to pwt; tell your agent the outcome you want and point it there, and it works out the mechanism and verifies it in a throwaway worktree.If the worktree already exists when you arrive,
pwt adoptis the command: it registers the checkout, allocates its port and runs the project’s setup hook, without recreating anything. Reference: pwt adopt.