Git Worktrees For Agent Tasks
Use this workflow when you want an isolated checkout for a coding-agent task, parallel human work, or any change that should not touch the base checkout while it is in progress. Worktrees are recommended for independent agent tasks and parallel work, but they are not required for developers who intentionally choose to work in the current checkout.
Standard Flow
Section titled “Standard Flow”When the app or agent has native worktree support, let that app create the worktree. Root bun install and bun run prepare copy the tracked hook sources and automatic setup dispatcher into shared Git metadata, then register git worktree-auto-setup. The installed post-checkout hook calls that trusted dispatcher, while the app owns placement, lifecycle, apply/handoff behavior, and cleanup. The repo does not commit local automatic setup callbacks because the target branch could replace them before the trust gate runs.
| Tool | Worktree creator | Repo setup hook/config |
|---|---|---|
| WebStorm | Git New Worktree |
Installed post-checkout hook |
| JetBrains Air | Air Git Worktree task | Installed post-checkout hook |
| Codex App | Codex App Worktree/New worktree | Installed post-checkout hook |
| Cursor IDE | Cursor /worktree or Agents Window worktree |
Installed post-checkout hook |
| Cursor Cloud Agent | Cursor Cloud Agent environment | .cursor/environment.json |
| Claude Code | claude --worktree or EnterWorktree |
.worktreeinclude, then conditional setup |
| OpenCode | Existing checkout or manually created worktree | Conditional setup after manual creation |
Use the native flow for Air, Codex App, Cursor IDE, and Claude Code unless you intentionally need the repo-standard .worktrees/<task-slug> location. That keeps each app’s UI, cleanup, and handoff/apply behavior aligned with the worktree it created.
For WebStorm, choose an external location outside the currently open project directory. WebStorm opens the new worktree as a separate project, and the trusted installed Git hook completes setup before that project opens after root bun install or bun run prepare. If the dispatcher skips a non-dev or dirty checkout, review it before running bun run worktree:setup manually.
For standard independent work, select an up-to-date dev base in the native tool before it creates the worktree. When a tool bases worktrees on the current checkout instead of an explicit branch picker, switch/update that checkout to dev before starting the native worktree task. If the native tool cannot target dev, or you are unsure which base it will use, use bun run worktree:create <task-slug> instead so the helper fetches origin/dev.
Use this manual/CLI fallback only when no app-native worktree owner is available, or when a human explicitly wants a repo-local .worktrees/<task-slug> worktree:
bun run worktree:create <task-slug>cd .worktrees/<task-slug>The command fetches origin/dev, creates .worktrees/<task-slug> on worktree/<task-slug>, installs Bun dependencies with the frozen lockfile, and provisions local env files. Work in that branch, verify the changed surface, and open the PR against dev.
Automatic setup is fail-closed before any target package script runs. git worktree-auto-setup executes only when the new checkout is clean and its HEAD is contained in origin/dev, or after an explicit one-time trust decision. Other worktrees are still created, but setup is skipped with a review-and-run instruction. The dispatcher, active hook copies, and automatic callback ownership live outside the target checkout so a target branch cannot replace code that runs before the trust decision.
After reviewing a skipped checkout, explicitly trust that one setup run:
git worktree-auto-setup --trust-targetIf a human asks an assistant to stay in the current checkout or keep working on the current branch, that instruction wins. The other common exception is continuing an isolated experiment or initiative slice that already has its own worktree. In that case, stay in the existing worktree or pass an explicit base.
Base Branches
Section titled “Base Branches”dev is the default base for independent new tasks. Use --base only when the task intentionally belongs somewhere else:
bun run worktree:create research-nav -- --base=initiative/research-workspaceThat command creates the custom-base worktree but skips setup. After reviewing and intentionally trusting the base, either run bun run worktree:setup inside it or create it with the explicit trust decision:
bun run worktree:create research-nav -- --base=initiative/research-workspace --trust-worktree-codeThe script rejects --base=main unless --allow-main is also present. Use that only when a human explicitly says the task targets main.
Useful options:
bun run worktree:create auth-fix -- --branch=fix/auth-callbackbun run worktree:create auth-fix -- --path=../ai-auth-fixbun run worktree:create auth-fix -- --env-mode=symlinkbun run worktree:create auth-fix -- --skip-fetchUse --skip-fetch only for intentional offline/local-ref work. Otherwise the default fetch keeps new worktrees current with origin/dev.
Env Files And Local Artifacts
Section titled “Env Files And Local Artifacts”Worktrees do not inherit gitignored files, so this repo provisions env files and a small allowlist of setup-owned local dev artifacts explicitly.
Default env mode is copy:
bun run worktree:setupCopy mode copies .env.common, root .env, and app .env files from the main checkout when they do not already exist. Missing files are created from the tracked .env.example and .env.common.example files through scripts/envFiles.ts. Existing regular copy-mode worktree env files are not replaced, but setup still rewrites local service URLs and port vars in those files to the active worktree profile. Use --overwrite-env only when you intentionally want setup to replace existing worktree env files from the main checkout.
Setup also copies the ignored auth dev HTTPS cert/key from apps/dev-proxy/certs/ when those files already exist in the main checkout. It does not generate certificates or modify the host trust store; if the main checkout does not have the certs, use the local troubleshooting cert command there first.
Symlink mode is available when you intentionally want one shared live env file set:
bun run worktree:setup -- --env-mode=symlinkUse symlink mode only when edits in one worktree should immediately affect the main checkout and other symlinked worktrees. Neither mode commits env files; they remain gitignored.
Worktree Ports
Section titled “Worktree Ports”Linked worktrees get a generated, gitignored .worktree-ports.json so app servers can run beside another checkout without port conflicts. Setup verifies that Git ignores this file before writing it, and the file is intentionally not listed in .worktreeinclude, so port profiles do not show up in copied env files or PR diffs. The main checkout keeps the established ports:
| Surface | Main checkout |
|---|---|
| Auth | 3001 |
| Web | 3002 |
| Customer CMS | 3003 |
| Support Dev | 3004 |
| Leverage CMS | 3005 |
| Token Replacer | 3006 |
| API | 4111 |
The first linked worktree uses 4001-4006 plus API 5111, the second uses 5001-5006 plus API 6111, and so on. bun run worktree:setup assigns the first unused profile it can see from git worktree list.
Print the URLs for the current checkout at any time:
bun run worktree:portsThe root dev entrypoints print the same summary before starting servers. Use root commands such as bun run dev, bun run dev:support, and bun run dev:token-replacer from the worktree root so the profile is injected into Turbo and app scripts. Direct app-local commands still default to the main checkout ports unless you pass the matching *_PORT env vars yourself.
There are two intentional port-update layers. bun run worktree:setup rewrites copied env files so direct tools and app-local commands have compatible defaults, but .worktree-ports.json remains the runtime source of truth for root dev commands. The root wrappers read that file and inject the active port profile into Turbo/app processes, so bun run worktree:ports:apply can switch between unique and auth-default even if a copied env file is stale or missing one of the generated local URL vars.
Connector OAuth Testing
Section titled “Connector OAuth Testing”Some local connector OAuth apps only allow the default auth callback port. When you need that flow from a linked worktree, stop any running dev servers and apply the auth-default profile:
bun run worktree:ports:apply auth-defaultThis rewrites the gitignored .worktree-ports.json and existing copy-mode env files so only Auth moves back to http://localhost:3001; Web, API, CMS, Support Dev, and Token Replacer stay on the linked-worktree ports. The command refuses to run in the main checkout, refuses symlinked env files, and fails if target ports are already in use. Why: the main checkout already owns the default ports, symlinked env files would mutate the shared checkout, and occupied target ports would silently route OAuth callbacks to the wrong process. After OAuth testing, switch the worktree back:
bun run worktree:ports:apply uniqueFor provider apps such as Slack that require an ngrok HTTPS callback, keep the public auth URL and opted-in provider ids in apps/auth/.env or export them in the shell. Keep NGROK_AUTHTOKEN in apps/auth/.env, root .env, or your shell. Normal bun run dev preserves nonblank AUTH_PUBLIC_BASE_URL, AUTH_CONNECTOR_OAUTH_PUBLIC_BASE_URL_PROVIDER_IDS, DEV_WITH_NGROK, and NGROK_AUTHTOKEN values in both the main checkout and linked worktrees. Blank root env placeholders are ignored at process launch so the auth app env can provide the real values.
If DEV_WITH_NGROK=true, the normal dev stack starts the auth tunnel automatically. If you prefer to run the tunnel in a separate terminal, leave DEV_WITH_NGROK unset or false for the stack and run:
bun run dev:auth-ngrokThen start the normal stack in another terminal:
bun run devA single public ngrok URL can safely represent only one local auth server at a time. Before testing OAuth in a worktree, stop any other local auth stack or make sure the tunnel forwards to the worktree’s active auth port.
Shared Local Data
Section titled “Shared Local Data”Worktree setup isolates Git state and local app ports; it does not isolate databases or shared local services. Because env files are copied or symlinked from the main checkout, linked worktrees use the same configured MongoDB databases, Redis instance, Qdrant collections, OAuth users, sessions, connector records, and local credentials unless you intentionally edit that worktree’s .env files.
This is deliberate for normal agent work because existing local OAuth users and linked-account setup keep working in new worktrees. Treat runtime data as shared when running multiple agents: avoid destructive local data cleanup from one worktree while another worktree is using the same local services.
Parallel chat testing is expected to be common. Multiple agents may create chats in the same shared local database as long as they do not depend on a clean global chat list or mutate each other’s target conversations. Assume local web app logins, connector OAuth accounts, linked accounts, and connector records are shared across worktrees. Prefer distinct agent-browser session names and clearly named or scoped test chats when agents are verifying chat behavior at the same time. Do not run chat-data cleanup, seed resets, OAuth unlink/reconnect flows, or connector data resets from one worktree while another worktree is actively testing chat flows.
Deferred enhancement: add an explicit isolated data mode only if parallel destructive runtime work becomes common. That mode would need generated per-worktree MongoDB database names, Qdrant collection names, Redis channel or queue names, seed/init reruns, and a clear OAuth/local-user setup story. Do not make that the default until the setup cost and OAuth implications are intentionally accepted.
Tool Setup
Section titled “Tool Setup”The repo intentionally does not commit a local .mise.toml. Mise requires local project configs to be trusted, and an untrusted config can make a mise-shimmed bun fail before worktree:setup can run. Developers who use mise can install or pin Bun outside this checkout, or intentionally add and trust their own local mise config. Developers without mise do not need to install it; setup only requires a working bun on PATH.
Claude Code should use its native claude --worktree or EnterWorktree flow when available. The committed .worktreeinclude copies gitignored env files and setup-owned local dev artifacts into Claude-created worktrees and matches the targets owned by scripts/setupWorktree.ts. Run bun run worktree:setup -- --if-needed inside the Claude-created worktree when dependency install or port-profile provisioning is needed.
Do not add a committed Claude WorktreeCreate hook for normal Git worktree setup unless the team intentionally wants to replace Claude’s built-in worktree behavior. Claude’s hook takes over worktree creation entirely, so it is better reserved for a future custom placement or non-Git workflow.
JetBrains Air has a Git Worktree task run environment in its UI. Air-created linked worktrees receive automatic setup from the installed Git hook; the repo intentionally does not commit .air/worktree.json, because target-controlled callbacks run before the dispatcher can establish trust. Air bases that worktree on the branch currently open in the workspace. If you want the standard dev base, switch to an up-to-date dev branch before starting the Air task, or use bun run worktree:create <task-slug> instead for the helper-managed origin/dev flow.
The current Air docs do not document a .air/worktree.json setting for the worktree directory. Treat Air-created worktree placement as Air-managed. Use bun run worktree:create <task-slug> when you need the repo-standard .worktrees/<task-slug> location.
JetBrains Air is in public preview and its behavior can change quickly. Before relying on a new Air behavior, re-check the current JetBrains Air task run environments docs and update this page in the same change.
Codex App users should use Codex App Worktree/New worktree when they want Codex to manage the isolated checkout. The installed Git hook keeps normal clean dev-based Codex worktree setup automatic. As an idempotent fallback, a Local Environment setup script configured in Codex App settings outside the checkout may run:
git worktree-auto-setupDo not run bun run worktree:create first when you want the Codex App to own the worktree. Codex-managed worktrees default to $CODEX_HOME/worktrees; change the root through Settings > Worktrees when needed. The committed .codex environment keeps manual actions but intentionally has no automatic setup callback. Its app-generated empty setup declaration ([setup] with script = "") satisfies the current schema without executing repository-controlled code. Do not hand-author undocumented .codex files unless the app generated them and you have reviewed that they contain no secrets or local absolute paths. The committed .worktreeinclude already covers Codex-managed local worktrees that need ignored env files copied.
Cursor IDE native linked worktrees receive automatic setup from the installed Git hook. The repo intentionally does not commit .cursor/worktrees.json, because a target branch could replace that callback before the trust gate runs. Use Cursor’s /worktree command or Agents Window worktree flow instead of pre-creating .worktrees/<task-slug> when you want Cursor to manage apply, delete, and cleanup behavior.
Cursor Cloud Agents use the committed .cursor/environment.json. Cursor resolves that repo file before personal or team saved environments. The install command pins Bun to the repo’s packageManager version when needed, then runs:
bun run worktree:setup -- --skip-mise --if-neededCursor Cloud env files are created from examples unless a saved snapshot already has real files. Put secret values in Cursor Secrets, not in .cursor/environment.json or committed env files. The config exposes the normal local ports for review in Cursor’s cloud environment, but local linked worktrees should use bun run worktree:ports for their generated profile. Cursor does not auto-start the full stack; run bun run docker:up and bun run dev when the task needs runtime verification.
Other agents should use native worktree creation first when they provide it, then run git worktree-auto-setup when the installed alias is available. If the trust gate skips, review the checkout before running bun run worktree:setup -- --if-needed; the completion marker keeps either command idempotent.
OpenCode does not need committed repo automation for this workflow. It can discover the repo’s existing .agents/skills guidance from the worktree root, and OpenCode project tools or plugins can call bun run worktree:setup -- --if-needed if a future workflow needs a dedicated setup action. Until then, start OpenCode in an existing checkout or a manually created worktree, and use bun run worktree:create <task-slug> only as the manual fallback when no native worktree owner is available.
UI Apply And Handoff
Section titled “UI Apply And Handoff”Tool-managed worktree buttons should stay compatible with this setup because the worktree remains a normal Git checkout. Applying a task back to Local, checking out a task branch locally, or creating a branch from a worktree should move only the Git-tracked work the agent changed. Provisioned env files, node_modules, and other local setup output remain gitignored and should not appear in the applied diff or PR.
Use copy mode for UI-managed worktrees unless you intentionally want shared live env files. In symlink mode, editing an env file in the worktree edits the source env file immediately, outside the tool’s apply/handoff diff.
For JetBrains Air, use the Git Worktree environment’s Apply Locally or Checkout Branch Locally flow after review. Air-created worktree placement is Air-managed, while the installed Git hook owns conditional setup.
For Codex App, use Handoff when you want to move a thread between Local and Worktree. Codex-managed worktrees start detached by default; use Create branch here when the branch should live in the worktree. Git allows a branch to be checked out in only one worktree at a time, so use Handoff or remove/switch the worktree before checking the same branch out locally.
For Cursor IDE, use /apply-worktree or Cursor’s apply/delete UI instead of manually moving files out of Cursor-managed worktrees. Cursor-created worktree placement and cleanup are Cursor-managed, while the installed Git hook owns conditional setup.
For Claude Code, use Claude’s session/worktree controls after review. Claude-created worktrees may live under Claude-managed paths, so remove them through Claude’s prompts when available or with git worktree remove only after confirming the branch/worktree state.
For OpenCode, start it in the checkout you want it to edit. If the worktree was created manually, use the manual cleanup commands below when the task branch is merged or abandoned.
Manual Recovery
Section titled “Manual Recovery”If you create a worktree manually, run the setup script inside it:
git fetch origin devgit worktree add .worktrees/<task-slug> -b worktree/<task-slug> origin/devcd .worktrees/<task-slug>bun run worktree:setupStart the stack the same way as a normal checkout:
bun run docker:upbun run devIf another worktree is already running servers, check this worktree’s assigned URLs:
bun run worktree:portsWhen the branch is merged or abandoned, remove the worktree from the main checkout:
git worktree remove .worktrees/<task-slug>git worktree pruneDelete the local branch only when you no longer need it:
git branch -d worktree/<task-slug>Canonical Sources
Section titled “Canonical Sources”scripts/createWorktree.tsscripts/installGitHooks.tsscripts/automaticWorktreeSetup.mjsscripts/setupWorktree.ts.husky/post-checkoutscripts/worktreePorts.tsscripts/runWithWorktreePorts.tsscripts/envFiles.ts.cursor/environment.json.worktreeinclude.gitignoreAGENTS.mdapps/support-dev/src/content/docs/workflows/branching-and-initiative-work.md
Official Docs
Section titled “Official Docs”- Git worktree documentation
- Git post-checkout hook documentation
- WebStorm Git worktrees
- JetBrains Air quickstart
- JetBrains Air task run environments
- JetBrains Air multitasking
- JetBrains Air project instructions
- JetBrains Air MCP servers
- Claude Code worktrees
- Codex App worktrees
- Codex App local environments
- Cursor Worktrees
- Cursor Cloud Agents
- Cursor Cloud Agent setup
- Cursor environment schema
- OpenCode plugins
- OpenCode custom tools
- mise configuration
- Bun installation