| name | git-worktree |
| description | Create/enter an isolated feature worktree and bootstrap-or-surface its environment (setup), and remove/prune it (teardown). Use when starting isolated agentic work (e.g. autonomous execute) or wrapping it up (finish). |
Git Worktree
Two operations on a git worktree: setup (create + enter + make it runnable) and teardown (remove + prune). execute (autonomous mode) calls setup; finish calls teardown.
A worktree is an isolated checkout of the same repo on its own branch, so an agent can work without disturbing the main tree. The trap is that a fresh worktree is code-only: it has no node_modules, no .env, no build cache — running tests in it before it's set up gives false failures. So setup is not just git worktree add; it must make the tree actually runnable, or stop and say it can't.
Setup
-
Create + enter the worktree.
MAIN=$(git rev-parse --show-toplevel)
WT="$MAIN/.worktrees/<branch>"
git worktree add "$WT" -b "<branch>" "<base>"
touch "$(git -C "$WT" rev-parse --git-dir)/council-worktree"
cd "$WT"
Name the base ref — omitting it silently branches from whatever HEAD happens to be. Put the marker in the worktree's git-metadata dir (.git/worktrees/<name>/council-worktree), never as a file in the working tree — an untracked marker in the tree would make git worktree remove (which refuses a dirty tree without --force) fail on the marker itself. The .worktrees/ path plus this metadata marker are how teardown recognises the worktree as ours.
-
Bootstrap or surface the environment. A fresh tree has none of the untracked, gitignored build state the project needs.
Detect the project's setup and run it — for example:
- JS/TS: the lockfile-appropriate install (
npm ci / pnpm install / yarn).
- Python: create/sync the venv (
uv sync, poetry install, pip install -e .).
- copy any gitignored env the project relies on (
.env, local config) from the main tree $MAIN (captured in step 1) if present.
If the setup can't be determined — no recognisable manifest, or an env file you can't safely reproduce — STOP and surface it: set up the env at <path> before autonomous runs (name what's missing). Never run tests in a half-built tree and call the result a failure; an unbootstrapped tree is a setup gap, not a code defect.
Teardown
The caller passes the target worktree path (WT) — captured from the caller's own state before it changes directory. Do not rediscover the target from the current directory here: a caller that has already cd'd to the main root (e.g. finish, for merge safety) would otherwise look at the wrong tree and conclude there's nothing to remove, leaking the worktree.
-
Provenance check — only remove a worktree this workflow created. Given WT:
WT isn't in git worktree list → nothing to remove. Done.
WT is the main checkout itself (its git -C "$WT" rev-parse --git-dir equals git -C "$WT" rev-parse --git-common-dir, i.e. not a linked worktree) → nothing to remove. Done.
WT is under .worktrees//worktrees/ and its git-metadata marker exists ([ -f "$(git -C "$WT" rev-parse --git-dir)/council-worktree" ]) → ours; remove it. (Require the marker — path convention alone could match a worktree someone else created under the same dir.)
- Otherwise → externally managed; leave it in place.
-
Remove + prune — from the main root, never from inside the worktree:
MAIN_ROOT=$(git -C "$(git rev-parse --git-common-dir)/.." rev-parse --show-toplevel)
cd "$MAIN_ROOT"
git worktree remove "$WT"
git worktree prune