Worktree Placement
Every agent git-paw launches works in its own git worktree — an
independent checkout of a branch that shares the repository’s object store.
worktree_placement controls where git-paw creates that directory.
Child vs sibling
There are two layouts:
| Placement | Worktree path | When it applies |
|---|---|---|
child | <repo>/.git-paw/worktrees/<branch-slug>/ | New repos (git paw init writes it) |
sibling | ../<project>-<branch-slug>/ | The default when worktree_placement is absent |
Sibling is the original (v0.7.0) layout: worktrees are created in the
repository’s parent directory, beside the repo. Three agents on
my-project produce ../my-project-feat-a/, ../my-project-feat-b/, and
../my-project-fix-c/ — scattered across the parent folder.
Child keeps worktrees inside the repository, under
.git-paw/worktrees/. The same three agents produce
.git-paw/worktrees/feat-a/, .git-paw/worktrees/feat-b/, and
.git-paw/worktrees/fix-c/. This matches how tools like Claude Code keep
worktrees within the project tree.
The child-layout slug comes from the branch name alone — / becomes - and
characters outside [A-Za-z0-9._-] are stripped — so feat/auth-flow →
.git-paw/worktrees/feat-auth-flow/ and fix/issue#42 →
.git-paw/worktrees/fix-issue42/. The project name is not prepended because
the directory already lives under that project’s .git-paw/worktrees/.
Why the contained layout
The motivation for child is a project-scoped permission model. An agent
CLI (or an MCP client, or a sandbox profile) scoped to the repository can
read and write .git-paw/worktrees/ with a single grant. A sibling worktree
lives outside the repository the tool is scoped to, so it either falls
outside the grant or forces a broader, less precise one. Containing the
worktrees lets one grant for .git-paw/worktrees/ cover every agent.
Because child worktrees live inside the repo tree, they must be ignored so
git never tries to stage them. git paw init adds .git-paw/worktrees/ to
.gitignore for you. If you switch an existing repo to child by editing
the config manually, add that entry yourself. Git itself handles the nested
.git correctly — a linked worktree carries its own .git file pointing
back at the main repository.
Placement decides what an agent CLI can find
The same containment affects what an agent’s CLI can read, not just what a
grant can cover. A worktree is populated from a commit, so anything the
repository gitignores — an agent CLI’s command and skill definitions at the
repository root, .claude/ among them — is simply absent from it. A sibling
worktree lives outside the repository, so those uncommitted definitions are
invisible: an agent told to run a workflow command finds nothing and quietly
improvises one instead. A child worktree sits under the repository root, so
the CLI’s upward search through ancestor directories still reaches them.
Committing the definitions fixes it under either layout. git paw doctor
reports which applies: its spec-workflow check
warns when the command a spec-driven launch instructs
cannot be reached from where your worktrees are placed.
Existing sessions are never moved
Placement only governs new worktree creation. git-paw records the
concrete, absolute path of each worktree in the session it created, and
resume, status, and purge all operate on that recorded path — they never
re-derive it from the current worktree_placement. The consequences:
- A session created under
siblingkeeps resuming and purging from its sibling path even if you later flip the config tochild. - A session created under
childkeeps using its.git-paw/worktrees/...path. - Flipping the config mid-project leaves a mixed layout (old worktrees stay put, new ones follow the new setting). Each worktree is still torn down correctly because the recorded path is the single source of truth at teardown time. git-paw does not migrate existing worktrees.
This makes the upgrade to v0.8.0 a no-op for existing repositories: with no
worktree_placement field, the effective placement is sibling, byte-for-byte
identical to v0.7.0. Re-running git paw init backfills the field — see
below.
Setting it
Set it per-repo in .git-paw/config.toml or globally in
~/.config/git-paw/config.toml (repo wins on conflict):
worktree_placement = "child" # or "sibling"
See the Configuration reference for the full field description and merging rules.
git paw init backfills the field
Re-running git paw init in an already-initialised repo backfills every missing
top-level default key, worktree_placement = "child" among them. If the repo
already has worktrees under the sibling layout, init prints a warning naming
them, states that it did not move them, and tells you how to keep the old
layout. Nothing is moved, deleted, or re-registered — the choice is yours:
- Set
worktree_placement = "sibling"to pin the previous layout. Init never touches an explicitly-set value, so the pin holds on every later run. - Or leave the backfilled
"child": existing worktrees keep resuming from their recorded sibling paths, and only new ones land under.git-paw/worktrees/.