Worktree Naming and Layout Conventions for Agent Fleets

Predictable naming and layout let orchestrators route and clean up parallel agent work reliably.

Cover illustration for “Worktree Naming and Layout Conventions for Agent Fleets”
Written by
Ren MatsuyamaStaff Writer, Worktree and Orchestration
Published
October 10, 2026
Reading time
10 min read

Consistent worktree naming and directory layout are the connective tissue of an agent fleet. Without them, an orchestrator cannot spin up, route, or clean up agents predictably, and the advantage of running work in parallel collapses into an administrative mess that someone has to clean up by hand.

Why naming and layout conventions become load-bearing when agents run in parallel

A single Git checkout was never built to host more than one active line of work at a time, and the failure modes that follow from forcing it to are concrete and predictable. One HEAD per checkout means two agents fighting over which branch is checked out at any given moment. A shared index means concurrent git add operations corrupt staging, because both agents are writing to the same file at once. A shared working directory means one agent's uncommitted edits get overwritten by another's mid-task, silently, with no warning from Git that anything happened. These failures are properties of the data structure itself: a checkout has one working directory, one index, and one HEAD, full stop on what Git's model allows. Sharing history once keeps it cheap even as tasks multiply. Working files, the cheap part, get duplicated per task. That architecture resolves collisions at the file-system level, but it introduces a new dependency: an orchestrator now has to track which directory belongs to which task, which branch lives where, and which of a dozen or a hundred worktrees is safe to touch. That tracking only works if names are predictable. Once agents run in parallel, naming is no longer a style preference, it is the mechanism an orchestrator uses to route work and the mechanism a cleanup script uses to know what to delete.

The three-layer naming contract: branch, directory, and container folder

Reliable fleet behavior depends on three layers of naming agreeing with each other: the branch name, the worktree directory name, and the container folder that holds every agent worktree. When any one of these drifts from the other two, orchestrators misroute tasks and cleanup scripts fail silently, often without an error that anyone notices until the disk fills up or a task goes missing. Branch naming should be task-scoped, prefixed, and filterable. Directory naming has to be derived from that same task slug. One well-documented convention places every worktree at .trees/<task-id> on a branch named agent/<task-id>, cut from origin/develop, so the directory and the branch always agree because both come from the same sanitized string. Encoding that rule once in a shared function means no script and no agent can produce a name that breaks the contract. The container folder, finally, is the single parent directory, typically .trees/ or .worktrees/, that holds every one of these. The container name should stay stable across a team's projects: changing it between repos breaks scripts that assume a fixed path, and changing it mid-project leaves orphaned directories that cleanup tooling has no way to find.

Sibling vs. nested container layout

Where that container folder lives relative to the main checkout is a separate decision from how things inside it are named, and neither sibling nor nested layout is safe in every setting. Each carries a failure mode that stays invisible until a team hits it, so the right choice depends more on repo depth and operational discipline than on taste. The sibling pattern, historically dominant, places the main checkout at ~/code/myproject/ and worktrees alongside it at ~/code/myproject-feature-a/, ~/code/myproject-feature-b/, a flat structure that reads clearly in any file browser. The documented objection to this layout is that it puts agent working directories outside the repo boundary. The nested alternative keeps everything inside the repo's visible perimeter, placing worktrees under .claude/worktrees/<name> inside the repo root, with that directory gitignored. Nesting has its own failure mode, and it is not theoretical. A third pattern is emerging alongside these two as agent topologies grow more hierarchical: orchestrators spawning sub-agents that spawn workers, with directory nesting built to mirror that parentage. At least one active open-source project introduced a pull request, as of October 2026, that nests handoff and sub-task worktrees under their parent agent's worktree while keeping top-level "attempt" runs flat. That detail ties the layout decision directly to the shape of the orchestration itself: the directory tree becomes a physical map of who spawned whom.

Branch-to-worktree mapping and the rules that keep them in sync

A branch and its worktree directory start to drift apart the moment someone creates one without deriving it from the same slug as the other, so the pattern that prevents drift is a single creation script, something like wt-create.sh <task-id> base: you give it one task ID, and it derives both the branch name (agent/<slug>) and the directory path (.trees/<slug>) from that same sanitized slug in one operation. There is no step in that process where a human could name them differently, because there is only one input. A script built this way typically also resolves the base ref (defaulting to something like origin/develop), makes sure the container folder is gitignored, enables git rerere so repeated conflict resolutions carry over across parallel merges, copies .env.local into the new worktree, and assigns a dev port automatically. That last piece extends the naming discipline beyond Git into runtime configuration, fixing the port and env values a worktree uses so agents never collide on either. A utility function hashes the branch name into a stable port somewhere in the 3100 to 9998 range and writes it into the worktree's own .env.local. Worktrees do not isolate everything, though, and the convention has to account for what is still shared. Agents working in separate worktrees still share the host machine, its credentials, and any external services; databases, provider quotas, and most environment variables are not isolated by default. The mitigation is giving each worktree its own .env.local, with its own port and, where the task calls for it, its own database name, making per-worktree environment naming a required extension of the directory convention. If multiple agents solve the same problem in parallel for comparison, that ensemble work needs its own naming tier. Branches in that case follow a pattern like attempt-<task>-<n>, a separate namespace that keeps ensemble runs from polluting the main agent/* branch list and from being mistaken by cleanup scripts for ordinary in-flight work.

Lifecycle labeling: how a worktree's name tracks its state from creation to cleanup

A naming scheme that only encodes what task a worktree belongs to leaves an orchestrator blind to its state: whether it's active, stale, or safe to remove. Lifecycle labeling has to be part of the convention from the outset. Lock state is the first layer of that signal. Scripts like wt-lock.sh <task-id> reason and wt-unlock.sh <task-id>, wrapping git worktree lock and git worktree unlock, make lock state readable in the same status list as path, branch, and short HEAD, so any agent or human can see who holds a worktree before touching a file inside it. A well-built creation script locks a worktree by default the moment it's set up, and unlocking is an explicit step rather than something that happens automatically on exit. Visibility runs through a single list command. A wt-list.sh script prunes stale metadata first, then prints one row per worktree: path, branch, lock state, short HEAD. An orchestrator needs that much, and no more, to route a new task without opening individual directories to check. Git won't warn you when two branches edit the same file, so at runtime you rely on the list command plus discipline about keeping agents in non-overlapping file domains, since Git enforces none of it on its own. Cleanup should be tied to commit state as a worktree ages. Claude Code's native worktree management applies exactly this rule on exit: a worktree with no changes and an unnamed session gets auto-removed, while a clean but named worktree, or any worktree carrying changes or commits, triggers a prompt asking whether to keep or remove it. That rule needs no elapsed-time heuristic and leaves no ambiguity about what happens to any given worktree. Teams running their own scheduled cleanup should apply the same logic: remove a worktree only when its branch is fully merged, never by age alone, since a worktree that's three days old and untouched might still hold the only copy of uncommitted work. Stale metadata is its own hazard inside this system. If a worktree directory gets deleted without running git worktree remove, Git keeps metadata pointing at a path that no longer exists, and any list or status script needs to call git worktree prune first, before it reports anything, or it will list worktrees that are already gone.

Using CLAUDE.md and AGENTS.md to pair scope enforcement with directory identity

A worktree directory and its task-specific instruction file work as a matched pair. The directory name declares what the agent is doing, and the instruction file inside it enforces that scope, so a naming convention that leaves out the instruction-file half of the pairing is only doing half the job. The creation script is the right place to generate or copy that instruction file, a CLAUDE.md or AGENTS.md scoped to the task at hand, so it exists in the worktree before the agent ever starts working. Tight scope constraints written into that file reduce the odds that an agent reaches outside its assigned task and edits files it has no business touching, functioning as the worktree-level counterpart to the branch-protection rules a team applies later at merge time. Drift between these instruction files across a pipeline is a documented failure mode, not a hypothetical one. The fix is to version the instruction-file convention itself and keep it consistent across every tool in the pipeline, rather than leaving each agent to interpret the convention on its own.

Where the single-root worktree model breaks

Everything laid out so far holds cleanly inside a single Git repository, and you need to be precise about where that boundary sits. The naming and layout conventions built around one repo root break down once a workspace spans multiple Git roots, a situation that occurs routinely in enterprise monorepos and in nested multi-git governance layouts. In those nested arrangements, where product directories are themselves gitignored inner checkouts, a single agent conversation may need to touch documentation in an outer repo alongside a backend worktree and a frontend worktree at the same time. If you force that work through the single-root worktree model, it fragments agent context and chat history across boundaries that don't match how the work is actually organized. Creating a worktree from a single outer root is the wrong level of abstraction here: naming conventions built for one repo root produce paths that either collide or stop meaning anything once they're applied across several roots at once. The path-length truncation bug described earlier is most likely to surface in exactly these enterprise-scale, deeply nested layouts, where a shared parent path, a repo name, and a slug prefix combine to push past the roughly 200-character threshold that triggers the bug. The practical response is to favor shorter task slugs and shallower container paths in these settings, or to fall back to a sibling layout in repos where the base path is already long before a worktree ever gets added to it. Topology compounds the problem as a fleet grows. A flat supervisor-worker structure doesn't scale past roughly ten agents, because the orchestrator's own context window fills up with status updates from too many workers at once, which is what pushes teams toward tree-shaped agent hierarchies where directory nesting tracks agent parentage directly. None of this invalidates the three-layer naming contract or the sibling-versus-nested trade-off described earlier. It sharpens the domain those conventions apply to: a single repo, a bounded fleet size, and a layout chosen deliberately.

A reference layout and naming checklist for a working fleet

The conventions above are only useful if they're applied consistently across the whole lifecycle of a worktree, from creation through runtime visibility, environment isolation, scope enforcement, and cleanup, since a checklist covering all five stages does more for a working fleet than any single convention taken in isolation. On branch naming, the standard is agent/<task-id> as the default prefix, with attempt-<task-id>-<n> reserved for ensemble runs, branches named after the task rather than the agent or session, and git branch --list 'agent/*' returning all and only the branches that belong to agent work. On directory naming, the rule is to derive the directory slug from the same sanitized task ID as the branch rather than naming the two independently, sanitizing to the character set a-z0-9._-, lowercasing throughout, and converting slashes to hyphens so a branch-shaped name never produces a path-separator error when a worktree gets created. On the container folder, a single team-stable name, .trees/ or .worktrees/, should be chosen and added to .gitignore with one line, and in large repos using a nested layout, total path length deserves active monitoring, with a fallback to sibling layout if the base path is already deep before any worktree gets added. On environment isolation, .env.local should be copied into each worktree at creation time, a deterministic port derived from the branch name should be assigned automatically, and dependencies should install per worktree through a setup script checked into the repo, so every worktree bootstraps the same way regardless of who or what created it. On scope enforcement, a task-specific CLAUDE.md or AGENTS.md should be dropped into each worktree at creation time, with the instruction-file convention itself versioned so that different tools in the same pipeline don't drift into conflicting expectations about where artifacts belong. On lifecycle and cleanup, worktrees should be locked on creation, with path, branch, lock state, and short HEAD listed before any new task gets routed, removal decided by commit state (no changes means auto-remove, changes present means a prompt) rather than by how much time has passed, and git worktree prune run before any list or status operation so ghost metadata never gets reported as a live worktree.

Ren Matsuyama

Staff Writer, Worktree and Orchestration

Ren began their career writing developer documentation for a Tokyo-based SaaS company before relocating and transitioning into long-form technical reporting around 2018. They focus on worktree orchestration patterns — how work is decomposed, routed, and reconciled across agent graphs — and frequently report on emerging coordination protocols.