Worktree
Set up worktree-per-feature discipline for a project where several AI sessions (or humans + agents) work concurrently and collide in one checkout. Writes a thin `worktree:` config block that the plugin's CONSUMED main-checkout hook reads (no rendered per-project hook copy), plus a project-specific worktree lifecycle skill — calibrated by interview (which repo, what's exempt, how a fresh worktree gets configured) and PROVEN by a live smoke worktree before handoff. Invoke /dotclaude:worktree when parallel sessions are real or planned.From its SKILL.md
npx -y skills add vindm/dotclaude --skill worktreeAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
3 things to look at
- reads credentialsReads from 1 credential source: `.env*`.
- 1 stars1 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
- runs commandsInstructs the agent to run 8 commands, including `git rev-parse --show-toplevel 2>/dev/null` and 7 more.
SKILL.md
11.1 KB, ~2.7k tokens by cl100k_base, as published. Nobody here has run it
/dotclaude:worktree — parallel-session isolation kit
You are setting up worktree-per-feature discipline: every substantive edit to
the policed repo happens in a dedicated git worktree, enforced by a blocking
PreToolUse hook. Read ../../principles/worktree-discipline.md FIRST — it
carries the doctrine and the five hard-won lessons this flow encodes; this
file is the procedure.
The hook is CONSUMED, not rendered. The plugin ships one debugged
check-main-checkout-edit.sh (in hooks/scripts/, wired always-on) that reads
a worktree: block from the project's dotclaude.yml and NO-OPs when there is
none. So this flow does NOT copy a hook into the project — it writes the config
the consumed hook reads. No per-project hook copy, no drift, and a project
tunes its policing in one data file.
The deliverable is not files — it is a proven install: the worktree:
config the consumed hook reads correctly, a smoke worktree that built the
project for real, and an explicit restart + live-fire handoff.
Phase 1 — Read the project's concurrency shape
Before any question:
-
Repo topology — is the project root the repo, or does the policed repo sit below it?
git rev-parse --show-toplevel 2>/dev/null for d in */; do git -C "$d" rev-parse --show-toplevel 2>/dev/null; done git worktree list 2>/dev/nullMultiple sibling repos → ask which one(s) carry the collision risk (usually the one being actively developed, not read-only references/snapshots).
-
Parallel-session evidence — lock files (
.session_lock,*.lockat repo root), CLAUDE.md sections about session coordination, git history mentions of collisions/clobbered work, scheduled/background agents. This calibrates urgency and whether a lease protocol already exists to narrow. -
Git-ignored per-machine files (lesson 2 — the fresh-worktree breakers):
git -C <repo> status --ignored --porcelain | grep '^!!'Filter to files/dirs the build actually needs:
.env*,config/*pointers,node_modules, credential stores. For each, note the likely recipe: copy a committed*.exampletemplate / symlink from main / regenerate / skip. -
Markdown-as-code signal (lesson 1): does the repo carry markdown the system executes —
policies/,workflows/, prompt libraries, agent instructions,.claude/kits? If yes, those paths must NOT be exempt. -
Verify command — how the project proves itself (from
package.jsonscripts, Makefile, CI config, README): the build/test/render command the smoke run (Phase 5) will execute, and the close-protocol gates.
Phase 2 — Interview
Open interview.md (same directory). 4-5 questions, adaptive — skip what
Phase 1 answered. Non-skippable even when scan feels conclusive: W2 (exempt
list / markdown-as-code) — it is a judgment call only the user can make.
Phase 3 — Read the principle
../../principles/worktree-discipline.md — in particular the
universal/project-specific split (what the worktree: config carries vs what
you author) and the five lessons (each maps to a concrete step below).
Phase 4 — Author the config + the lifecycle skill
Config (write the worktree: block to dotclaude.yml)
The consumed hook reads these keys; you do NOT render or wire a hook. Write (or
merge) a worktree: block into the project root's dotclaude.yml:
worktree:
policedRepo: <repo path relative to the project root; "." when root IS the repo>
namePrefix: <repo>-wt- # unless the user prefers otherwise
exempt: # main-checkout paths that stay freely editable
- "docs/*"
- "README.md"
- "LICENSE*"
setup: # fresh-worktree recipe, shown in the block message
- "cp config/instance.example.yaml <wt>/config/instance.yaml"
skillPath: .claude/skills/worktree/SKILL.md
exempt— the interviewed list, matched against the repo-relative path (*spans directory separators). NEVER include*.mdunless the user explicitly confirmed no markdown is executed (markdown-as-code, lesson 1).setup— the per-machine-files recipe (lesson 2), one line each;<wt>stands for the worktree dir in the block message.- The stray-worktree guard (lesson 5) and the escape hatch are built into the consumed hook — no per-project authoring.
- Merge into an existing
dotclaude.yml(from another elicitation) — never clobber theartifacts:/fileSize:keys.
Skill (in .claude-staging/skills/worktree/SKILL.md)
The project's lifecycle skill — author it (this one is project-specific by nature). Sections, each filled with THIS project's real commands:
- Create + configure:
git -C <repo> worktree add ../<prefix><slug> -b feat/<slug>+ the setup recipe (one line per per-machine file, real paths). Then (lesson 5) author a capture + assert step: pull the worktree's ABSOLUTE path fromgit -C <repo> worktree list --porcelaininto a variable, assert it (test -d "$WT/<build-marker>"), and tell the agent to use that literal path for every later write — never recompose../<prefix><slug>by eye. Include the path-discipline note:../resolves against the-C <repo>dir (not the shell cwd), write tools need an absolute path, and the harness resets cwd between tool calls. - Verify: the project's verify command + expected output.
- Close: the project's gates → commit (with any project-specific
pre-commit review the repo's conventions demand) → merge etiquette →
git worktree remove→ branch cleanup. Include the derived-artifacts "drop the noise" step with the EXACT paths Phase 5's smoke run recorded. - Escape hatch: the
allow-main-editsconvention, ask-first. - Shared resources lease (only if Phase 1/interview surfaced out-of-repo shared state): the narrowed lock protocol from the principle doc.
No wiring step
The consumed hook is wired once in the plugin's hooks/hooks.json (always-on,
NO-OP without a worktree: block). Do NOT add a local hook to the project's
.claude/settings.json — a project-level hook copy is exactly the drift this
model removes. The worktree: block written in Phase 4 is the entire opt-in.
CLAUDE.md section
A short "Session coordination" section for the project's CLAUDE.md: the rule, the hook path, the exempt list, the escape hatch, the lifecycle skill pointer, and — if a lease protocol survives — its narrowed scope (out-of-repo shared resources + the merge window ONLY).
Phase 5 — Prove it live (mandatory, before presenting)
- Live-fire the consumed hook against the written config: feed it a few
synthetic tool inputs and confirm the verdicts.
A wrong verdict means theH="$CLAUDE_PLUGIN_ROOT/hooks/scripts/check-main-checkout-edit.sh" fire() { echo "{\"tool_input\":{\"file_path\":\"$1\"}}" | bash "$H"; echo "exit=$?"; } fire "<policed-repo>/<a source file>" # expect exit 2 (block) fire "<a markdown-as-code file>" # expect exit 2 if the project has any fire "<an exempt path>" # expect exit 0 fire "<a real worktree>/<a file>" # expect exit 0worktree:block is off (wrongpolicedRepo, a bad exempt glob) — fix the config, not a hook. The hook's own logic is tested in the plugin; this proves THIS project's config drives it correctly. - Smoke worktree (lesson 3): create a real worktree per the lifecycle
skill, run the setup recipe, run the project's verify command inside it.
- Record EVERY file
git statusshows dirty afterwards — these are the project's derived artifacts; write their exact paths into the lifecycle skill's "drop the noise" close step. - Re-run the Phase 5.1 live-fire with the smoke worktree's path (the worktree-allowed case → expect exit 0).
- Tear down per the close protocol (
worktree removemust succeed WITHOUT--force).
- Record EVERY file
- If the verify command fails in the worktree but works in main — a per-machine file is missing from the setup recipe. Fix the recipe, not the worktree; re-run.
Phase 6 — Present + handoff
Present per dotclaude staging convention (inventory, highlight reasoning, what
was skipped and why). After approval, move .claude-staging/ → .claude/,
merge the worktree: block into dotclaude.yml, commit. (No settings-fragment
merge — the hook is plugin-wired and reads the config.)
Then the two lines every install ends with (lesson 4):
"Hooks register at session start — the block is NOT active in this session or in already-open ones. Restart, then live-fire: ask for a trivial edit to
<a policed file>and confirm the hook blocks with the worktree instructions. Until each parallel session restarts, it remains unpoliced."
Non-negotiable rules for this flow
- Never blanket-exempt
*.mdby default. The markdown-as-code question (W2) is mandatory. Projects whose markdown is the program (policies, prompts, agent kits) need those paths POLICED; a docs-are-free default silently unguards their behavioral layer. - The hook is consumed, never copied. The plugin ships one debugged
check-main-checkout-edit.sh(nearest-existing-dir walk, worktree detection, other-repo pass-through, stray-worktree guard) that reads theworktree:block. Write config, not a hook — never author a local hook copy or a.claude/settings.jsonhook entry; that project-level copy is exactly the drift this model kills. If the hook needs logic it lacks, that's a dotclaude PR, not a local fork. - Prove the config drives the hook. The hook's own logic is tested in the
plugin; this install's job is to live-fire the consumed hook against THIS
project's
worktree:block (Phase 5.1). A green block / allow / exempt / worktree set is the proof the config is right. - The smoke run is not optional. Derived-artifact dirt and missing per-machine files are only discoverable by actually building in a fresh worktree. An install presented without a smoke run has unknown failure modes scheduled for the user's first real feature.
- Opt-in only. Never wire this into plugin-level always-on hooks; never install it uninvited on a project with no concurrency signal — for a solo single-session project, recommend AGAINST installing (say so explicitly in the applicability decision).
- Worktrees + lease, not worktrees instead of lease. If out-of-repo shared resources exist (data snapshots, device pools, the merge window), ship the narrowed lease protocol alongside; if a broad lock protocol already exists, narrow it rather than deleting it.
What ships with it: 1 file
3.4 KB alongside SKILL.md
- interview.md3.4 KB