A git worktree is the most underrated feature in git. It lets you check out more than one branch of the same repo in more than one directory, all sharing a single .git. You can have main building in one folder, a feature branch open in your editor in another, and a hotfix compiling in a third — at the same time, with no stashing.
Nobody uses them because the CLI is friction. This post fixes that.
The problem
Your reviewer asked you to tweak PR #1234 "quickly." Meanwhile, you're elbow-deep in a different feature branch. Without worktrees, you stash, switch, fix, push, switch back, pop. Six commands, ten minutes of context damage.
With worktrees, you just open a new folder. The CLI you'd actually type is:
git fetch origin pull/1234/head:pr-1234
git worktree add ../myrepo-pr-1234 pr-1234
cd ../myrepo-pr-1234
pnpm install
code .
That's five commands. Every time. For every PR. You stop doing it after a week.
The agent fix
An AI agent with shell access turns the above into one sentence:
Start a worktree for PR 1234, install deps, and open it in my editor.
If you're using Froots, you highlight that sentence and press ⌘⇧R. The routine compiler asks Clem (the "Maker" agent) to execute. Ten seconds later you have a new Cursor window open in a fresh folder with node_modules already populated.
Here's how to set that up.
Step 1 — Give Clem shell access
In Froots, open Settings → Agents → Clem → Tools. Make sure shell is enabled. Set trust to Balanced (the default). This means Clem can run shell commands but will prompt you the first time for potentially destructive ones — rm, git worktree remove --force, etc.
If you want zero prompts (you trust Clem fully in your dev environment), set trust to Yolo. I recommend Balanced — you want to notice when Clem is about to --force something.
Step 2 — Teach Clem your conventions
Every repo is a snowflake. Clem will guess the right commands, but you'll get better results by writing conventions down. In your repo, create .froots/clem.md:
# Clem conventions for this repo
- Package manager: pnpm (not npm, not yarn)
- Install: `pnpm install --frozen-lockfile`
- Worktree parent dir: `~/work/<repo-name>-<branch-slug>/`
- After worktree creation: open in Cursor (`cursor .`)
- After worktree creation: copy `.env.local` from main checkout
- Port allocation: pick a free port >3000; set PORT env var
- After closing: run `git worktree remove --force <path>` + `git branch -D <branch>`
Clem reads that file whenever it's working in this repo. Shared conventions for a team go in a file you can commit; personal preferences go in ~/.froots/clem.md.
Step 3 — The actual routines
You'll want four of these. Build them once, use them forever. Each is one sentence in the compiler.
Start a worktree for an issue
When I say "worktree for #{issue}", fetch the branch, create a worktree at
~/work/<repo>-<branch>/, copy.env.localover, runpnpm install, pick an unused port, and open the folder in Cursor.
Compiled graph:
Input (issue number)
→ Shell: git fetch origin issue/#{issue}:issue-#{issue}
→ Shell: git worktree add ~/work/<repo>-issue-#{issue} issue-#{issue}
→ Shell: cp .env.local ~/work/.../.env.local
→ Shell: cd ~/work/...; pnpm install --frozen-lockfile
→ Agent: Clem (pick unused port >3000, write to .env)
→ Shell: cursor ~/work/<repo>-issue-#{issue}
→ Notify: slack #dev "started worktree for #{issue}"
Start a worktree for a PR
When I say "worktree for PR {number}", fetch the PR ref, create a worktree, install deps, and open it in Cursor.
Same graph, substitutes pull/#{n}/head:pr-#{n} for the fetch step.
List active worktrees
When I say "show my worktrees", run
git worktree listin every repo under~/work/, format the result as a table, and announce it in the editor.
This one's handy on Monday mornings. Clem scans your ~/work/ tree and produces:
repo branch path
---------------- -------------------- ------------------------------
froots issue-847 ~/work/froots-issue-847
froots pr-1234 ~/work/froots-pr-1234
nimbus feat/tachyon ~/work/nimbus-feat-tachyon
Clean up stale worktrees
On the first weekday of the month, find all worktrees whose branch has been merged to main, and offer to remove them.
This one's a cron routine. Clem runs it Monday at 10am, gathers candidates, and pings you in the inbox with a "remove these four?" message. You pick the ones to delete; Clem runs git worktree remove and git branch -D. Your ~/work/ stays clean without you ever thinking about it.
The full routine, hand-written
If you're not on Froots yet but want the same thing on your current stack, here's the equivalent shell function. Add it to your .zshrc:
wt() {
local issue=$1
local repo=$(basename "$(git rev-parse --show-toplevel)")
local target="$HOME/work/${repo}-issue-${issue}"
git fetch origin "issue/${issue}:issue-${issue}"
git worktree add "${target}" "issue-${issue}"
cp .env.local "${target}/.env.local" 2>/dev/null || true
(cd "${target}" && pnpm install --frozen-lockfile)
cursor "${target}"
}
wt 1234 now does most of what the Froots routine does — minus the Slack ping, the port allocation, the branch metadata awareness. It's fine. But once you've tried the agent version, going back to shell feels like typing emails in Notepad.
Why this matters for AI-assisted dev
Worktrees are, secretly, the ideal unit of work for an AI coding agent. Claude / Cursor / whatever-you-use can happily work on ~/work/myrepo-issue-1234/ in parallel with you editing ~/work/myrepo-main/. No merge conflicts, no stash dance, no "which branch am I on again." When you want the agent to review a PR, you give it the worktree path. When it's done, you remove the worktree.
You get Codespaces-style isolation without Codespaces.
Troubleshooting
"fatal: 'pr-1234' is already checked out" — you already have a worktree for that ref. git worktree list to find it. Remove with git worktree remove <path>.
Agent can't find .env.local — your .env.local is .gitignored (good) but Clem is trying to read it from the new worktree (bad, it doesn't exist there yet). Fix: make sure the copy step runs before pnpm install. The order matters.
Cursor opens, Node complains about missing module — you installed deps in the worktree but node_modules is a symlink pointing at ../myrepo/node_modules. Rerun with pnpm install --no-optional or add node_modules/ to your worktree's .gitignore. Some package managers (pnpm) are fine; others (yarn classic) aren't.
Recap
Worktrees are good. Worktrees with one-sentence ergonomics are better. An agent that understands your repo conventions, runs the commands, allocates the port, opens the editor, and pings your team is the whole package.
If you want this set up in your workspace in under fifteen minutes, Froots's routine compiler is the shortest path. If you already have an agent runtime you like (Hermes, OpenCode, Aider, your own), the same patterns port — the sentences are the IP, not the runtime.