pi-gauntlet 5.9.0 → 5.9.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,7 @@
1
1
  ---
2
2
  name: finishing-a-development-branch
3
3
  description: Use when implementation is complete, all tests pass, and you need to decide how to integrate the work - guides completion of development work by presenting structured options for merge, PR, or cleanup
4
+ argument-hint: "<worktree-path>"
4
5
  ---
5
6
 
6
7
  # Finishing a Development Branch
@@ -11,9 +12,21 @@ Guide completion of development work by presenting clear options and handling ch
11
12
 
12
13
  **Core principle:** Verify tests → Detect environment → Surface closure → Present options → Execute choice → Clean up.
13
14
 
15
+ ## Input
16
+
17
+ `<worktree-path>` - the absolute path of the worktree to finish, from the `using-git-worktrees` report or the handoff brief. Before anything else - before the announcement and before `phase_tracker` start - if it is missing, stop with "finishing needs the worktree path: /skill:finishing-a-development-branch <worktree-path>" and do nothing else. Derive the primary checkout once:
18
+
19
+ ```bash
20
+ WORKTREE=<worktree-path>
21
+ PRIMARY=$(dirname "$(git -C "$WORKTREE" rev-parse --path-format=absolute --git-common-dir)")
22
+ FEATURE=$(git -C "$WORKTREE" branch --show-current)
23
+ ```
24
+
25
+ The process cwd never changes; every command targets `$WORKTREE` or `$PRIMARY` explicitly.
26
+
14
27
  **Announce at start:** "I'm using the finishing-a-development-branch skill to complete this work."
15
28
 
16
- At start, call `phase_tracker({ action: "start", phase: "ship" })`.
29
+ Then call `phase_tracker({ action: "start", phase: "ship" })`.
17
30
 
18
31
  ## The Process
19
32
 
@@ -21,11 +34,11 @@ At start, call `phase_tracker({ action: "start", phase: "ship" })`.
21
34
 
22
35
  **Hard verification gate.** Tests/format/lint must pass before presenting any options — including Discard. The user's stated intent to throw the branch away does not change whether the diff is in a verifiable state; verifying first surfaces accidental damage to unrelated code before the branch is gone forever. No exceptions.
23
36
 
24
- Run the project's canonical verification target from inside the worktree. The exact command lives in the repo's `AGENTS.md` or service-level docs (look for "verification", "CI", or "test" sections). Typical patterns: `make ci`, `npm test`, `pytest`, `cargo test`, `bundle exec rspec`. Cross-cutting changes: run each affected service's target; don't skip any.
37
+ Run the project's canonical verification target in the worktree: `(cd "$WORKTREE" && <verification command>)`. The exact command lives in the repo's `AGENTS.md` or service-level docs (look for "verification", "CI", or "test" sections). Typical patterns: `make ci`, `npm test`, `pytest`, `cargo test`, `bundle exec rspec`. Cross-cutting changes: run each affected service's target; don't skip any.
25
38
 
26
39
  **Scoping caveat — pre-existing findings.** Some services carry lint findings unrelated to the diff. If verification fails on lines you didn't touch:
27
40
 
28
- 1. Confirm with `git diff <base>...HEAD --name-only` that the offending file isn't in your diff.
41
+ 1. Confirm with `git -C "$WORKTREE" diff <base>...HEAD --name-only` that the offending file isn't in your diff.
29
42
  2. Surface the pre-existing finding to the user as a separate issue — do **not** auto-fix it in this completion ("surface, don't auto-fix").
30
43
  3. Proceed only after the user acknowledges.
31
44
 
@@ -46,26 +59,13 @@ No documentation prompt here: Documentation impact is decided at spec time (`/sk
46
59
 
47
60
  ### Step 2: Detect Environment
48
61
 
49
- **Determine workspace state before presenting options:**
50
-
51
- ```bash
52
- GIT_DIR=$(cd "$(git rev-parse --git-dir)" 2>/dev/null && pwd -P)
53
- GIT_COMMON=$(cd "$(git rev-parse --git-common-dir)" 2>/dev/null && pwd -P)
54
- ```
55
-
56
- This determines which menu to show and how cleanup works:
57
-
58
- | State | Menu | Cleanup |
59
- |-------|------|---------|
60
- | `GIT_DIR == GIT_COMMON` (normal repo) | Standard 4 options | No worktree to clean up |
61
- | `GIT_DIR != GIT_COMMON`, named branch | Standard 4 options | Provenance-based (see Step 6) |
62
- | `GIT_DIR != GIT_COMMON`, detached HEAD | Reduced 3 options (no merge) | No cleanup (externally managed) |
62
+ Detached HEAD (`git -C "$WORKTREE" symbolic-ref -q HEAD` prints nothing) -> reduced 3-option menu (no merge), no cleanup. Otherwise the standard 4 options.
63
63
 
64
64
  ### Step 3: Determine Base Branch
65
65
 
66
66
  ```bash
67
67
  # Try common base branches
68
- git merge-base HEAD main 2>/dev/null || git merge-base HEAD master 2>/dev/null
68
+ git -C "$WORKTREE" merge-base HEAD main 2>/dev/null || git -C "$WORKTREE" merge-base HEAD master 2>/dev/null
69
69
  ```
70
70
 
71
71
  Or ask: "This branch split from main - is that correct?"
@@ -76,7 +76,7 @@ This is an **enforced disposition gate**, not a surface-only notice. The user is
76
76
 
77
77
  `verification-before-completion/reference/conformance-check.md` is **canonical** for the durable handoff schema, concern-decomposition rules, the single disposition-availability table, the `UNAUTHORIZED` question text, the `recommended: none` preflight, the freshness rule, and the concern-scoped fix projection. This step owns only **render, response, and execute-order** and consumes the rest by link - it does not restate the availability table, the `UNAUTHORIZED` question, or the preflight prose.
78
78
 
79
- **If no conformance check has run in this flow** (e.g. ad-hoc work that landed without an execution skill): say so, then dispatch a fresh-context `conformance-reviewer` against the origin (spec + verbatim prompt + full diff vs base) per that reference - it owns the audit-time input rule (stage/commit untracked deliverables before auditing). Closing the loop is cheap relative to shipping unverified intent. Route the raw reviewer verdict through the reference's canonical pipeline (gap/concern partition, auto-fix where eligible, concern decomposition, emission of a durable `## Closure / conformance` block), then consume that block through the branching below exactly as a carried handoff.
79
+ **If no conformance check has run in this flow** (e.g. ad-hoc work that landed without an execution skill): say so, then dispatch a fresh-context `conformance-reviewer` with `cwd: "<worktree-path>"` against the origin (spec + verbatim prompt + full diff vs base) per that reference - it owns the audit-time input rule (stage/commit untracked deliverables before auditing). Closing the loop is cheap relative to shipping unverified intent. Route the raw reviewer verdict through the reference's canonical pipeline (gap/concern partition, auto-fix where eligible, concern decomposition, emission of a durable `## Closure / conformance` block), then consume that block through the branching below exactly as a carried handoff.
80
80
 
81
81
  **Freshness precondition - before any verdict branch, including `CONFORMS`.** The durable block opens with a two-line sentinel: `status: CONFORMS (0 open)` or `status: GAPS (N open)`, then `audited-base: <full HEAD SHA at audit time>`. Read the sentinel, then apply the reference's freshness rule (its `## Closure / conformance` block is the single source): compare `audited-base` to the current working tree; any change, doubt, missing/mismatched sentinel, legacy terse row, or malformed structured reviewer block triggers a fresh audit and replacement of the closure block. Never infer `CONFORMS` from the absence of bullets. Only a clean, valid `status: CONFORMS (0 open)` handoff enters the zero-gap fast path.
82
82
 
@@ -165,32 +165,17 @@ Which option?
165
165
  #### Option 1: Squash-merge to base
166
166
 
167
167
  ```bash
168
- # Get main repo root for CWD safety
169
- MAIN_ROOT=$(git -C "$(git rev-parse --git-common-dir)/.." rev-parse --show-toplevel)
170
- cd "$MAIN_ROOT"
171
-
172
- # Squash-merge — collapses the feature branch into one commit on base
173
- git checkout <base-branch>
174
- git pull
175
- git merge --squash <feature-branch>
176
-
177
- # Plans are ephemeral — delete from the squash. Spec stays.
178
- git rm doc/plans/<plan-file>.md # or <service>/doc/plans/<plan-file>.md
179
-
180
- # Single commit covering spec + code + review fixes.
181
- git commit -m "<imperative summary> (ref <ticket-id>)"
182
-
183
- # Verify tests on merged result
184
- <Step 1 command for the service(s) touched>
168
+ git -C "$PRIMARY" checkout <base-branch>
169
+ git -C "$PRIMARY" pull
170
+ git -C "$PRIMARY" merge --squash "$FEATURE"
171
+ git -C "$PRIMARY" rm doc/plans/<plan-file>.md # or <service>/doc/plans/<plan-file>.md
172
+ git -C "$PRIMARY" commit -m "<imperative summary> (ref <ticket-id>)"
173
+ (cd "$PRIMARY" && <Step 1 command for the service(s) touched>)
185
174
  ```
186
175
 
187
176
  The post-squash re-verify is not optional — `git merge --squash` can surface conflict-resolution mistakes the worktree-side run couldn't catch.
188
177
 
189
- Then: Cleanup worktree (Step 6), then delete branch:
190
-
191
- ```bash
192
- git branch -d <feature-branch>
193
- ```
178
+ Cleanup worktree (Step 6), then, if Step 6 removed the worktree, `git -C "$PRIMARY" branch -D "$FEATURE"`.
194
179
 
195
180
  **No push. No PR.** The squashed commit stays local on `<base-branch>` unless the user explicitly asks to push.
196
181
 
@@ -199,22 +184,22 @@ git branch -d <feature-branch>
199
184
  ```bash
200
185
  # Plans are ephemeral - if one was committed on this branch, remove it before the PR diff is opened.
201
186
  PLAN_PATH=doc/plans/<plan-file>.md # or <service>/doc/plans/<plan-file>.md
202
- if git ls-files --error-unmatch "$PLAN_PATH" >/dev/null 2>&1; then
203
- git rm "$PLAN_PATH" && git commit -m "Remove ephemeral plan doc"
187
+ if git -C "$WORKTREE" ls-files --error-unmatch "$PLAN_PATH" >/dev/null 2>&1; then
188
+ git -C "$WORKTREE" rm "$PLAN_PATH" && git -C "$WORKTREE" commit -m "Remove ephemeral plan doc"
204
189
  fi
205
190
 
206
191
  # Push branch
207
- git push -u origin <feature-branch>
192
+ git -C "$WORKTREE" push -u origin "$FEATURE"
208
193
 
209
194
  # Create PR
210
- gh pr create --title "<title>" --body "$(cat <<'EOF'
195
+ (cd "$WORKTREE" && gh pr create --title "<title>" --body "$(cat <<'EOF'
211
196
  ## Summary
212
197
  <2-3 bullets of what changed>
213
198
 
214
199
  ## Test Plan
215
200
  - [ ] <verification steps>
216
201
  EOF
217
- )"
202
+ )")
218
203
  ```
219
204
 
220
205
  **Do NOT clean up worktree** — user needs it alive to iterate on PR feedback.
@@ -239,57 +224,35 @@ Type 'discard' to confirm.
239
224
 
240
225
  Wait for exact confirmation.
241
226
 
242
- If confirmed:
243
- ```bash
244
- MAIN_ROOT=$(git -C "$(git rev-parse --git-common-dir)/.." rev-parse --show-toplevel)
245
- cd "$MAIN_ROOT"
246
- ```
247
-
248
- Then: Cleanup worktree (Step 6), then force-delete branch:
249
- ```bash
250
- git branch -D <feature-branch>
251
- ```
227
+ If confirmed: Cleanup worktree (Step 6), then, if Step 6 removed the worktree, `git -C "$PRIMARY" branch -D "$FEATURE"`.
252
228
 
253
229
  ### Step 6: Cleanup Workspace
254
230
 
255
231
  **Only runs for Options 1 and 4.** Options 2 and 3 always preserve the worktree.
256
232
 
257
- ```bash
258
- GIT_DIR=$(cd "$(git rev-parse --git-dir)" 2>/dev/null && pwd -P)
259
- GIT_COMMON=$(cd "$(git rev-parse --git-common-dir)" 2>/dev/null && pwd -P)
260
- WORKTREE_PATH=$(git rev-parse --show-toplevel)
261
- ```
233
+ **If the worktree was created by a project-native script** (e.g. `script/worktree create`, `bin/worktree`): defer to its destroy command, run against the primary: `"$PRIMARY/script/worktree" destroy "${WORKTREE##*/}"`.
262
234
 
263
- **If `GIT_DIR == GIT_COMMON`:** Normal repo, no worktree to clean up. Done.
264
-
265
- **If the worktree was created by a project-native script (e.g., `script/worktree create`, `bin/worktree`):** defer to the matching destroy command. The script likely cleans up DBs, env files, or other side-effects that raw `git worktree remove` will miss.
235
+ **If `$WORKTREE` is under `$PRIMARY/.worktrees/` or `~/.worktrees/<project>/`:** gauntlet created it - we own cleanup:
266
236
 
267
237
  ```bash
268
- MAIN_ROOT=$(git -C "$(git rev-parse --git-common-dir)/.." rev-parse --show-toplevel)
269
- name="${WORKTREE_PATH##*-}"
270
- # Example: project-native wrapper. Substitute your project's destroy command.
271
- "$MAIN_ROOT/script/worktree" destroy "$name"
238
+ git -C "$PRIMARY" worktree remove "$WORKTREE"
239
+ git -C "$PRIMARY" worktree prune
272
240
  ```
273
241
 
274
- **If worktree path is under `.worktrees/` or `~/.worktrees/<project>/`:** Gauntlet created this worktree — we own cleanup.
242
+ Removal precedes branch deletion in both options; `git branch -d`/`-D` fails while the worktree still references the branch.
275
243
 
276
- ```bash
277
- MAIN_ROOT=$(git -C "$(git rev-parse --git-common-dir)/.." rev-parse --show-toplevel)
278
- cd "$MAIN_ROOT"
279
- git worktree remove "$WORKTREE_PATH"
280
- git worktree prune # Self-healing: clean up any stale registrations
281
- ```
282
-
283
- **Otherwise:** The host environment (harness) owns this workspace. Do NOT remove it. If your platform provides a workspace-exit tool, use it. Otherwise, leave the workspace in place.
244
+ **Otherwise:** the host environment owns this workspace. Do NOT remove it, and skip the branch deletion that follows - report that the host-owned worktree still holds `$FEATURE`.
284
245
 
285
246
  ## Quick Reference
286
247
 
287
248
  | Option | Merge | Push | Keep Worktree | Cleanup Branch | Plan-doc removal |
288
249
  |---|---|---|---|---|---|
289
- | 1. Squash-merge locally | yes (squash) | - | - | yes | yes (unconditional) |
250
+ | 1. Squash-merge locally | yes (squash) | - | - | yes (after Step 6 removal) | yes (unconditional) |
290
251
  | 2. Create PR | - | yes | yes | - | yes (guarded, before push) |
291
252
  | 3. Keep as-is | - | - | yes | - | - |
292
- | 4. Discard | - | - | - | yes (force) | - |
253
+ | 4. Discard | - | - | - | yes (force, after Step 6 removal) | - |
254
+
255
+ A host-owned worktree (Step 6 "Otherwise") keeps both the worktree and the branch.
293
256
 
294
257
  ## Common Mistakes
295
258
 
@@ -309,9 +272,9 @@ git worktree prune # Self-healing: clean up any stale registrations
309
272
  - **Problem:** `git branch -d` fails because worktree still references the branch
310
273
  - **Fix:** Merge first, remove worktree, then delete branch
311
274
 
312
- **Running git worktree remove from inside the worktree**
313
- - **Problem:** Command fails silently when CWD is inside the worktree being removed
314
- - **Fix:** Always `cd` to main repo root before `git worktree remove`
275
+ **Removing the worktree with the wrong `-C`**
276
+ - **Problem:** `git worktree remove` run against the worktree itself fails
277
+ - **Fix:** `git -C "$PRIMARY" worktree remove "$WORKTREE"`
315
278
 
316
279
  **Cleaning up harness-owned worktrees**
317
280
  - **Problem:** Removing a worktree the harness created causes phantom state
@@ -322,8 +285,8 @@ git worktree prune # Self-healing: clean up any stale registrations
322
285
  - **Fix:** Require typed "discard" confirmation
323
286
 
324
287
  **Skipping the plan-doc deletion in Options 1 and 2 (any path that lands on base)**
325
- - **Problem:** Plan docs are ephemeral and shouldn't land on `<base-branch>`. Forgetting `git rm doc/plans/<plan-file>.md` ships scaffolding to main.
326
- - **Fix:** The plan stays in the deleted branch's git history (`git log --all -- doc/plans/...`). Spec stays on `<base-branch>`; plan does not.
288
+ - **Problem:** Plan docs are ephemeral and shouldn't land on `<base-branch>`. Forgetting `git -C "$PRIMARY" rm doc/plans/<plan-file>.md` ships scaffolding to main.
289
+ - **Fix:** The plan stays in the deleted branch's git history (`git -C "$PRIMARY" log --all -- doc/plans/...`). Spec stays on `<base-branch>`; plan does not.
327
290
 
328
291
  ## Completion
329
292
 
@@ -344,18 +307,18 @@ Once the merge (and any deploy) has landed, `/skill:check-delivery <ticket-ref>`
344
307
  - Force-push without explicit request
345
308
  - Remove a worktree before confirming merge success
346
309
  - Clean up worktrees you didn't create (provenance check)
347
- - Run `git worktree remove` from inside the worktree
310
+ - Run any step without the `<worktree-path>` argument
348
311
  - Auto-proceed past an undispositioned carried-open gap
349
312
  - Skip the guarded plan-doc removal before push on Option 2 when a plan doc was committed
350
313
 
351
314
  **Always:**
352
315
  - Verify tests before offering options
353
- - Detect environment before presenting menu
316
+ - Derive `$PRIMARY` and `$FEATURE` from `<worktree-path>` before presenting the menu
354
317
  - Present exactly 4 options (or 3 for detached HEAD)
355
318
  - Get typed confirmation for Option 4
356
319
  - Clean up worktree for Options 1 & 4 only
357
- - `cd` to main repo root before worktree removal
358
- - Run `git worktree prune` after removal
320
+ - Target `$PRIMARY` with `git -C` for merge, worktree removal, and branch deletion
321
+ - Run `git -C "$PRIMARY" worktree prune` after removal
359
322
  - Surface the closure / conformance verdict as its own section before the options menu
360
323
 
361
324
  ## Project overrides
@@ -41,9 +41,7 @@ optional pasted text after the command line.
41
41
  | `<brief> <worktree>` | brief plus an explicit worktree override (required when the brief's worktree field is `no`/`unavailable`/not a git repo; must equal the brief's worktree after `realpath` otherwise) |
42
42
  | anything else | not a resume input - stop with "this is a new idea - run /skill:brainstorming" |
43
43
 
44
- `<primary>` is the checkout owning `.worktrees/`: `dirname $(git rev-parse --git-common-dir)`
45
- (not `--show-toplevel`, which returns the linked worktree when run inside one). A pasted
46
- brief that needs an override uses the file form. This skill never runs `git worktree add`.
44
+ `<primary>` is the checkout owning `.worktrees/`: `dirname "$(git rev-parse --path-format=absolute --git-common-dir)"` run in the session cwd - absolute from any primary subdirectory and from inside a linked worktree (`--show-toplevel` would return the linked worktree there). A bare `<name>` resolves as `<primary>/.worktrees/<name>`. A pasted brief that needs an override uses the file form. This skill never runs `git worktree add`.
47
45
 
48
46
  ## Entry checks
49
47
 
@@ -2,7 +2,7 @@
2
2
 
3
3
  Consumed only by `SKILL.md` in this directory. This file is the single concentration
4
4
  point for text coupled to pi-cohort's `/handoff` template (`doc/handoff-template.md`
5
- in pi-cohort; baseline inlined from its `prune-prompts` branch, commit `d737eb9`).
5
+ in pi-cohort; baseline inlined from its `prune-prompts` branch, commit `812de45`).
6
6
  Cohort drift is reconciled here and nowhere else.
7
7
 
8
8
  ## Brief grammar
@@ -54,7 +54,7 @@ mktemp -d # absolute path, e.g. /tmp/tmp.XXXXXX
54
54
 
55
55
  Dispatch one member per configured model, in parallel, each writing its critique into that dir. Do **not** read these files' findings content yourself — they are for the chair. The only permitted parent access is the mechanical structural probe below (existence plus header regex, no content ingestion, no adjudication).
56
56
 
57
- Capture the worktree path once (`git rev-parse --show-toplevel`, run from inside the worktree) and pass it as `cwd:` on every dispatch below — a child otherwise inherits pi's launch dir (the primary checkout), not the worktree.
57
+ Pass the worktree path (the value brainstorming carries from the `using-git-worktrees` Step 4 report) as `cwd:` on every dispatch below - a child otherwise inherits pi's launch dir (the primary checkout), not the worktree.
58
58
 
59
59
  ```
60
60
  subagent({
@@ -33,13 +33,13 @@ You are the **orchestrator**. You read the plan, dispatch, review the review, de
33
33
  - An escalated round fails (stop note per [Fix-Loop Rounds](#fix-loop-rounds))
34
34
  - A ⚠️ workflow warning fires
35
35
 
36
- Reaching the end of the plan is not a pause: continue through verification and invoke `/skill:finishing-a-development-branch` as defined in [After All Tasks](#after-all-tasks-complete).
36
+ Reaching the end of the plan is not a pause: continue through verification and invoke `/skill:finishing-a-development-branch <abs worktree path>` as defined in [After All Tasks](#after-all-tasks-complete).
37
37
 
38
38
  Periodic "should I continue?" prompts add latency without adding safety. The plan is the contract; execute it.
39
39
 
40
40
  ## Prerequisites
41
41
 
42
- - Running inside a dedicated worktree (the same one the spec and plan were authored in). If you're on `main` in the primary checkout, stop and invoke `/skill:using-git-worktrees` first — implementation never lands directly on `main`.
42
+ - The worktree path is known - from the `using-git-worktrees` Step 4 report in this session or the handoff brief's `worktree:` row - and is passed as the top-level dispatch `cwd`. If no worktree path exists, stop and invoke `/skill:using-git-worktrees` first - implementation never lands directly on `main`. The process cwd is the primary checkout; nothing here changes it.
43
43
  - Approved plan or clear task scope
44
44
  - `plan_tracker` list initialized at writing-plans handoff with the full wave-ordered task list. Consume and preserve it on continuation; only direct recovery with no tracker initializes the full plan list once, before dispatch, and never over an existing list.
45
45
 
@@ -128,6 +128,7 @@ Pi-subagents accepts a per-task `model` override. Use it.
128
128
  subagent({
129
129
  agent: "implementer",
130
130
  async: false,
131
+ cwd: "<abs worktree path>",
131
132
  task: "...",
132
133
  model: "anthropic/claude-haiku-4" // cheap tier
133
134
  })
@@ -137,23 +138,25 @@ When in doubt, default. Don't downgrade reviewers — false negatives are expens
137
138
 
138
139
  ## Dispatch
139
140
 
141
+ Every dispatch carries the worktree as top-level `cwd` - sequential mode included.
142
+
140
143
  ```ts
141
144
  // implementer
142
- subagent({ agent: "implementer", async: false, task: "<task text + context + SCOPED_TEST_COMMANDS + status protocol>" })
145
+ subagent({ agent: "implementer", async: false, cwd: "<abs worktree path>", task: "<task text + context + SCOPED_TEST_COMMANDS + status protocol>" })
143
146
 
144
147
  // escalated fix round (Fix-Loop Rounds): same fix payload, model from gauntlet_setting({ key: "escalationLoop" }).implModel
145
- subagent({ agent: "implementer", model: "<implModel>", context: "fresh", async: false, task: "<the just-dispatched fix payload + prior review report verbatim>" })
148
+ subagent({ agent: "implementer", model: "<implModel>", context: "fresh", async: false, cwd: "<abs worktree path>", task: "<the just-dispatched fix payload + prior review report verbatim>" })
146
149
 
147
150
  // spec compliance
148
- subagent({ agent: "spec-reviewer", async: false, task: "<task text + patch diff + absolute spec path + task's Spec: anchors + Tests: block + Test: paths>" })
151
+ subagent({ agent: "spec-reviewer", async: false, cwd: "<abs worktree path>", task: "<task text + patch diff + absolute spec path + task's Spec: anchors + Tests: block + Test: paths>" })
149
152
 
150
153
  // code quality
151
- subagent({ agent: "code-reviewer", async: false, task: "<diff range + SCOPED_TEST_COMMANDS (task commands; wave: union; whole-diff: none) + ask: production-ready?>" })
154
+ subagent({ agent: "code-reviewer", async: false, cwd: "<abs worktree path>", task: "<diff range + SCOPED_TEST_COMMANDS (task commands; wave: union; whole-diff: none) + ask: production-ready?>" })
152
155
 
153
156
  // closing-loop conformance (origin vs deliverable) — its OWN dispatch, never fused with code quality
154
157
  // model: call gauntlet_setting({ key: "closureReview" }) first; use the returned model (omit model: if undefined to inherit) and maxFixRounds
155
158
  // If gauntlet_setting is unavailable, stop and report - never fall back to a manual bash/JSON settings merge.
156
- subagent({ agent: "conformance-reviewer", async: false, model: /* gauntlet_setting({ key: "closureReview" }).model, else omit to inherit */, task: "<spec path + verbatim original prompt + full diff vs main; per conformance-check.md>" })
159
+ subagent({ agent: "conformance-reviewer", async: false, cwd: "<abs worktree path>", model: /* gauntlet_setting({ key: "closureReview" }).model, else omit to inherit */, task: "<spec path + verbatim original prompt + full diff vs main; per conformance-check.md>" })
157
160
  ```
158
161
 
159
162
  Prompt templates live alongside this SKILL.md:
@@ -182,10 +185,10 @@ Auto-selected at handoff by `writing-plans` (any wave with ≥2 tasks) when the
182
185
  1. **Independence check.** Parse the wave's tasks' `Files:` blocks; assert pairwise-disjoint (mechanical, mirroring `wave-file-disjointness`: `Test`/`Test` on one path is not overlap, `Test` vs another task's `Create`/`Modify` is, `Modify`/`Modify` is). Runtime-resource disjointness (DB/schema, port, fixture, external service, shared temp path) is not machine-checkable here — trust the plan's wave grouping, which `writing-plans`' D5 contract guarantees. Either kind of overlap → the wave is mis-grouped; run those tasks as sequential single-task waves and note it.
183
186
  2. **Start, then fan out.** Mark every wave index `in_progress` before one parallel foreground dispatch (shape below): `implementer` per task, `context: "fresh"`, `worktree: true`. Each returns a status + a patch.
184
187
  3. **Status + spec review per task.** Parse each `DONE`/`BLOCKED`/etc. (see [Implementer Status](#implementer-status)) **first**. Then **dispatch a `spec-reviewer` per accepted patch** (`DONE`, or a `DONE_WITH_CONCERNS` you proceeded with) in one parallel fan-out — `context: "fresh"`, `cwd: <this worktree>`, **no `worktree` flag** (read-only) — each passed its task text, the returned **patch diff**, the absolute spec path, and the task's `**Spec:**` anchors, plus its `**Tests:**` block and `- Test:` paths as contract — SR reads the anchored ranges itself (never inline excerpts; authority hierarchy in `./spec-reviewer-prompt.md`; anchor-less tasks are task-text-only). Review starts from the diff (its hunks carry `file:line`) and reads each touched file in full, and test execution is never the reviewer's job - in either mode (persona rule; the wave test gate in step 5 runs the wave's `SCOPED_TEST_COMMANDS`). Inline verdicts are fine at normal wave sizes; large waves use `output:` + `outputMode: "file-only"` to keep verdicts out of your context. **Re-dispatch by cause:** `BLOCKED`/`NEEDS_CONTEXT` per the [Implementer Status](#implementer-status) matrix; a **spec gap** re-dispatches the implementer (fresh, `worktree: true`) carrying the prior patch + the reviewer's findings, the new patch superseding the old at step 4. Loop until accepted + spec ✅, within [Fix-Loop Rounds](#fix-loop-rounds), same as sequential.
185
- 4. **Integrate.** `git apply` each task's patch sequentially onto HEAD. Apply fails = textual conflict → drop that task, finish the rest, re-run the dropped task sequentially on the updated HEAD.
186
- 5. **Test gate.** Run the wave's `SCOPED_TEST_COMMANDS` (union of its tasks' `Tests:` commands) on the integrated tree — the full verification set is the verify phase's job, run once. Failure = semantic conflict or bug → re-run the offending task sequentially, else fix per [When a Subagent Fails](#when-a-subagent-fails).
188
+ 4. **Integrate.** `git -C <worktree> apply` each task's patch sequentially onto HEAD. Apply fails = textual conflict → drop that task, finish the rest, re-run the dropped task sequentially on the updated HEAD.
189
+ 5. **Test gate.** Run the wave's `SCOPED_TEST_COMMANDS` (union of its tasks' `Tests:` commands) on the integrated tree as `(cd "<worktree>" && <command>)` for each command — the full verification set is the verify phase's job, run once. Failure = semantic conflict or bug → re-run the offending task sequentially, else fix per [When a Subagent Fails](#when-a-subagent-fails).
187
190
  6. **Quality review.** CR binds to the wave: exactly one **initial** code-review dispatch per code-touching wave, over the integrated wave diff - never per task within a wave, never batched across waves. Subsequent dispatches within the wave are re-reviews triggered only by findings, per Fix-Loop Rounds. Pass the wave's `SCOPED_TEST_COMMANDS`. Code-quality review on the integrated wave diff; loop fixes to ✅ within [Fix-Loop Rounds](#fix-loop-rounds), same as sequential. Skip for doc-only waves (SR-only per the commit precondition below).
188
- 7. **Commit and complete the wave.** After the gate passes and the wave commits, mark all of its existing indices `complete`. Leaves a clean tree; the next wave's children branch from this commit and so see the integrated work.
191
+ 7. **Commit and complete the wave.** After the gate passes, commit with `git -C <worktree> add ... && git -C <worktree> commit ...`, then mark all of its existing indices `complete`. Leaves a clean tree; the next wave's children branch from this commit and so see the integrated work.
189
192
 
190
193
  **Two-stage review is preserved:** spec review per task (pre-integration, dispatched `spec-reviewer` — not inline), quality review per wave (post-integration). A wave commit requires one spec-review verdict per accepted task, plus one code-review verdict on the integrated diff for waves that touch code. A doc-only wave (every task's `Files:` block documentation-only, per `writing-plans`' Wave Grouping) is SR-only — the CR gate does not apply.
191
194
 
@@ -193,7 +196,7 @@ Auto-selected at handoff by `writing-plans` (any wave with ≥2 tasks) when the
193
196
 
194
197
  **Caveat:** each task must be independently runnable and verifiable in a fresh worktree — no reliance on uncommitted local state. `pi-cohort` symlinks `node_modules`; repos needing other per-worktree setup must account for it.
195
198
 
196
- **Set `cwd` to your worktree — resilience-critical.** This whole workflow runs *inside* a worktree, but the `subagent` tool resolves the worktree base from the **top-level `cwd`**, which defaults to the orchestrator's process cwd — the *primary* checkout (usually `main`), not the worktree. Omit `cwd` and `worktree: true` branches every child from the primary checkout's HEAD: the children never see your spec, plan, or prior-wave commits, and integration runs against the wrong baseline. Pass the worktree's absolute path as the top-level `cwd`. Do **not** set per-task `cwd` under `worktree: true` — pi-cohort requires it to equal the shared cwd and errors otherwise. (Clean-tree is enforced here too — `resolveRepoState` rejects a dirty tree — which is why each wave commits before the next.)
199
+ **Set `cwd` to your worktree — resilience-critical.** The work lives in a worktree while the process stays in the primary checkout, and the `subagent` tool resolves the worktree base from the **top-level `cwd``, which defaults to the orchestrator's process cwd — the *primary* checkout (usually `main`), not the worktree. Omit `cwd` and `worktree: true` branches every child from the primary checkout's HEAD: the children never see your spec, plan, or prior-wave commits, and integration runs against the wrong baseline. Pass the worktree's absolute path as the top-level `cwd`. Do **not** set per-task `cwd` under `worktree: true` — pi-cohort requires it to equal the shared cwd and errors otherwise. (Clean-tree is enforced here too — `resolveRepoState` rejects a dirty tree — which is why each wave commits before the next.)
197
200
 
198
201
  ```bash
199
202
  REPORT_DIR=$(mktemp -d)
@@ -203,7 +206,7 @@ REPORT_DIR=$(mktemp -d)
203
206
  subagent({
204
207
  context: "fresh",
205
208
  async: false,
206
- cwd: "/abs/path/to/this/worktree", // REQUIRED: the worktree you're in, else children branch from main
209
+ cwd: "/abs/path/to/this/worktree", // REQUIRED: the worktree path, else children branch from main
207
210
  worktree: true, // each task in its own git worktree, branched from cwd's HEAD
208
211
  concurrency: 4, // default; cap = wave size
209
212
  tasks: [
@@ -234,11 +237,11 @@ For the fan-out + worktree + patch-integration + conflict mechanics, see `dispat
234
237
  ## After All Tasks Complete
235
238
 
236
239
  0. Call `phase_tracker({ action: "start", phase: "verify" })`. (The `implement` phase was started at execution start and auto-completes from `plan_tracker` once all tasks are done; this flow runs its own verify gate instead of `/skill:verification-before-completion`, so it must mark verify itself.)
237
- 1. **Parent full verification.** Run the complete plan-header `**Verification:**` command set foreground: tests plus every declared lint, type, format, and build check. A failure must be repaired and the full set rerun successfully before the next step. Before dispatching a verification repair, reopen (`in_progress`) every existing plan-task index whose `Files:` ownership includes its touched files; leave unowned cross-cutting repair work in the verification report. Those indices stay `in_progress` through the successful full rerun **and** step 2's whole-diff review accepting the repair — that acceptance is their completion point, not the passing rerun. Commit any verification-produced tracked changes; use the resulting `HEAD_SHA` in the review task and include the commands/results in its existing `DESCRIPTION`.
240
+ 1. **Parent full verification.** Run the complete plan-header `**Verification:**` command set foreground in the worktree via `(cd "<worktree>" && <command>)`: tests plus every declared lint, type, format, and build check. A failure must be repaired and the full set rerun successfully before the next step. Before dispatching a verification repair, reopen (`in_progress`) every existing plan-task index whose `Files:` ownership includes its touched files; leave unowned cross-cutting repair work in the verification report. Those indices stay `in_progress` through the successful full rerun **and** step 2's whole-diff review accepting the repair — that acceptance is their completion point, not the passing rerun. Commit any verification-produced tracked changes; use the resulting `HEAD_SHA` in the review task and include the commands/results in its existing `DESCRIPTION`.
238
241
  2. **Whole-diff code review.** Only after passing full verification, dispatch one foreground whole-diff `code-reviewer` per `/skill:requesting-code-review` against that committed HEAD, with `SCOPED_TEST_COMMANDS: none`; the reviewer does not repeat the full suite. Address Critical and Moderate findings. Before dispatching a review repair, reopen (`in_progress`) every existing plan-task index whose `Files:` ownership includes its touched files; leave unowned cross-cutting repair work in the review report. Mark each reopened index `complete` only once the repair is re-verified and the re-review accepts it — this is the same completion point step 1's reopened indices wait for, not an extra gate, and the gate order stays full verification -> whole-diff CR -> conformance. Any repair invalidates prior full verification, so rerun the full set successfully before the next gate.
239
242
  3. **Close the loop — conformance check.** The review in step 2 is plan-vs-code (single-step); it inherits any requirement the plan already dropped. Before marking verify complete, dispatch a fresh-context **`conformance-reviewer`** — its **own** dispatch, never fused into the step-2 review — to confront the deliverable (code **and** docs) against the *origin* — the spec **and** the original prompt — per `verification-before-completion/reference/conformance-check.md`. Pass the spec path, the verbatim original prompt, and the full diff. Follow that reference for the partition rule, concern decomposition, and fix-loop mechanics; do not reimplement them here. The fix loop reuses durable `Gn` gap indices as defined in conformance-check.md; it never calls `phase_tracker`. Call `phase_tracker({ action: "complete", phase: "verify" })` only when the reference says the handoff is durably complete: either a current `CONFORMS` result, or a current `## Closure / conformance` inventory whose carried-open concerns all come from valid deferred gaps, including `recommended: fix` gaps carried open because a declared precondition made the fix loop unavailable (`maxFixRounds: 0`, or no eligible named-branch worktree). A started positive-cap fix loop that blocks, fails, or exhausts its rounds with an open `fix` gap is escalation, not completion; on escalation, do not complete verify, stop and report.
240
243
  4. Summarize what was implemented (tasks completed, files changed, test counts, code-review verdict). Emit the `## Closure / conformance` block exactly as defined in `verification-before-completion/reference/conformance-check.md`: it must open with the two-line sentinel (`status: CONFORMS (0 open)` or `status: GAPS (N open)`, then `audited-base: <full HEAD SHA>`), then carry the exact durable concern schema by reference with no renamed or reformatted fields. `finishing-a-development-branch` Step 3.5 consumes that block verbatim.
241
- 5. **Proceed to finishing — no confirmation prompt.** Once verify is complete per step 3's criterion, invoke `/skill:finishing-a-development-branch` immediately. Its Step 4 menu (squash / PR / keep / discard) is the human gate; a separate "ready to finish?" prompt only stacks a second stop in front of it. Carried-open concerns are resolved there per concern via the `## Closure / conformance` block from step 4. Manual testing is a follow-up after the finishing choice (on `<base-branch>` after a squash-merge, or on the PR branch), never a reason to hold this gate.
244
+ 5. **Proceed to finishing — no confirmation prompt.** Once verify is complete per step 3's criterion, invoke `/skill:finishing-a-development-branch <abs worktree path>` immediately - the same absolute path every dispatch in this flow carried as `cwd`; finishing stops without it. Its Step 4 menu (squash / PR / keep / discard) is the human gate; a separate "ready to finish?" prompt only stacks a second stop in front of it. Carried-open concerns are resolved there per concern via the `## Closure / conformance` block from step 4. Manual testing is a follow-up after the finishing choice (on `<base-branch>` after a squash-merge, or on the PR branch), never a reason to hold this gate.
242
245
 
243
246
  ## Red Flags — STOP
244
247
 
@@ -260,7 +263,7 @@ For the fan-out + worktree + patch-integration + conflict mechanics, see `dispat
260
263
  - `/skill:using-git-worktrees` — set up isolation first (small changes can branch in place with user approval)
261
264
  - `/skill:writing-plans` — creates the plan this skill executes
262
265
  - `/skill:requesting-code-review` — review template for reviewer subagents
263
- - `/skill:finishing-a-development-branch` — invoked automatically once every gap is fixed (`CONFORMS`) or carried open
266
+ - `/skill:finishing-a-development-branch <abs worktree path>` — invoked automatically once every gap is fixed (`CONFORMS`) or carried open
264
267
 
265
268
  **Subagents follow by default:**
266
269
 
@@ -20,9 +20,9 @@ Git worktrees create isolated workspaces sharing the same repository, allowing w
20
20
  Before doing anything else, check whether you are **already** inside an isolated worktree. Creating a worktree inside another worktree, or inside a submodule, produces silent corruption.
21
21
 
22
22
  ```bash
23
- GIT_DIR=$(cd "$(git rev-parse --git-dir)" 2>/dev/null && pwd -P)
24
- GIT_COMMON=$(cd "$(git rev-parse --git-common-dir)" 2>/dev/null && pwd -P)
25
- BRANCH=$(git branch --show-current)
23
+ read -r GIT_DIR GIT_COMMON <<<"$(git rev-parse --path-format=absolute --git-dir --git-common-dir | tr '\n' ' ')"
24
+ ROOT=$(dirname "$(git rev-parse --path-format=absolute --git-common-dir)")
25
+ CURRENT_BRANCH=$(git branch --show-current)
26
26
  ```
27
27
 
28
28
  **Submodule guard:** `GIT_DIR != GIT_COMMON` is also true inside git submodules. Before concluding "already in a worktree," verify you are not in a submodule:
@@ -32,13 +32,15 @@ BRANCH=$(git branch --show-current)
32
32
  git rev-parse --show-superproject-working-tree 2>/dev/null
33
33
  ```
34
34
 
35
- **If `GIT_DIR != GIT_COMMON` (and not a submodule):** You are already in a linked worktree. Skip to Step 3 (Verify Clean Base). Do NOT create another worktree.
35
+ **If `GIT_DIR != GIT_COMMON` (and not a submodule):** The session already runs inside a linked worktree. Its `$GIT_DIR` is `<primary>/.git/worktrees/<name>`, and `$GIT_DIR/gitdir` contains `<worktree>/.git`, so derive its full path:
36
36
 
37
- Report with branch state:
38
- - On a branch: "Already in isolated workspace at `<path>` on branch `<name>`."
39
- - Detached HEAD: "Already in isolated workspace at `<path>` (detached HEAD, externally managed)."
37
+ ```bash
38
+ WORKTREE=$(dirname "$(cat "$GIT_DIR/gitdir")")
39
+ ```
40
40
 
41
- **If `GIT_DIR == GIT_COMMON` (or in a submodule):** You are in a normal repo checkout. Proceed to Step 1.
41
+ Use `$WORKTREE`, report it in the Step 4 shape (`Worktree ready at <that path>`), create nothing, and continue at Step 3 against that path.
42
+
43
+ **If `GIT_DIR == GIT_COMMON` (or in a submodule):** You are in the primary checkout. Proceed to Step 1.
42
44
 
43
45
  ## Step 1 — Announce, Don't Ask (skill-driven work defaults to a worktree)
44
46
 
@@ -74,56 +76,58 @@ Only when no native tool exists:
74
76
 
75
77
  ### 2a. Pick a location
76
78
 
77
- The canonical home is `<repo>/.worktrees/<branch>`. Resolve in this order:
78
-
79
- 1. **Project override** — a wrapper/script or a gauntlet overrides worktree path (see Project overrides) (`grep -i worktree README.md AGENTS.md .pi/settings.json .pi/gauntlet-overrides.md gauntlet-overrides.md doc/gauntlet-overrides.md`). Obey it.
80
- 2. **Default** — `<repo>/.worktrees/<branch>`. Create the directory if missing (Step 2b).
81
- 3. **No enclosing repo** — only when there's no repo to anchor `.worktrees/`, fall back to `~/.worktrees/<project>/<branch>`.
79
+ The canonical home is `<repo>/.worktrees/<branch>`. A project override or wrapper may define another path; otherwise use the canonical home. Do not ask local-vs-global or invent another path.
82
80
 
83
- Don't ask local-vs-global and don't invent other paths — `.worktrees/` is the default.
81
+ ### 2b. Create - gitignore the home first
84
82
 
85
- ### 2b. Create — gitignore the home first
86
-
87
- Run the Step 3 clean-base check in the source checkout *before* this sequence. `.worktrees/` must be gitignored before a worktree lands inside it. Fold the check into creation:
83
+ Run the Step 3 clean-base check in the source checkout before this sequence. `.worktrees/` must be gitignored before a worktree lands inside it.
88
84
 
89
85
  ```bash
90
- ROOT=$(git rev-parse --show-toplevel)
91
- cd "$ROOT"
92
- if ! git check-ignore -q .worktrees; then
93
- echo ".worktrees/" >> .gitignore
94
- git add .gitignore && git commit -m "Ignore .worktrees/" -- .gitignore
86
+ # ROOT is the primary checkout derived in Step 0.
87
+ BRANCH=<new feature branch name>
88
+ if git -C "$ROOT" worktree list --porcelain | grep -qx "worktree $ROOT/.worktrees/$BRANCH"; then
89
+ : # already exists - emit the Step 4 report, add nothing
90
+ else
91
+ if ! git -C "$ROOT" check-ignore -q .worktrees; then
92
+ echo ".worktrees/" >> "$ROOT/.gitignore"
93
+ git -C "$ROOT" add .gitignore && git -C "$ROOT" commit -m "Ignore .worktrees/" -- .gitignore
94
+ fi
95
+ git -C "$ROOT" worktree add "$ROOT/.worktrees/$BRANCH" -b "$BRANCH"
95
96
  fi
96
- git worktree add ".worktrees/$BRANCH_NAME" -b "$BRANCH_NAME"
97
- cd ".worktrees/$BRANCH_NAME"
97
+ WORKTREE="$ROOT/.worktrees/$BRANCH"
98
98
  ```
99
99
 
100
- For the outside-a-repo `~/.worktrees/<project>/` fallback, no .gitignore check applies.
100
+ The process cwd never changes. `$WORKTREE` is the value every later step carries; do not `cd` into it.
101
101
 
102
102
  ### 2c. Run project setup
103
103
 
104
104
  ```bash
105
- if [ -f pnpm-lock.yaml ]; then pnpm install
106
- elif [ -f yarn.lock ]; then yarn install
107
- elif [ -f package.json ]; then npm install
108
- fi
109
- [ -f Cargo.toml ] && cargo build
110
- [ -f pyproject.toml ] && uv sync
111
- [ -f Gemfile ] && bundle install
112
- [ -f go.mod ] && go mod download
105
+ (cd "$WORKTREE" && {
106
+ if [ -f pnpm-lock.yaml ]; then pnpm install
107
+ elif [ -f yarn.lock ]; then yarn install
108
+ elif [ -f package.json ]; then npm install
109
+ fi
110
+ [ -f Cargo.toml ] && cargo build
111
+ [ -f pyproject.toml ] && uv sync
112
+ [ -f Gemfile ] && bundle install
113
+ [ -f go.mod ] && go mod download
114
+ })
113
115
  ```
114
116
 
115
117
  ### 2d. Sandbox fallback
116
118
 
117
119
  If worktree creation fails on permissions (read-only filesystem, container sandbox without write to parent dirs): stop, announce the failure, and continue in the current directory on a feature branch.
118
120
 
121
+ Working in place is a degraded mode for this skill only; `/skill:finishing-a-development-branch` requires a worktree path and does not finish an in-place branch.
122
+
119
123
  ## Step 3 — Verify Clean Base
120
124
 
121
125
  The check: bare `git status --porcelain` — untracked files count as dirty. Never `--untracked-files=no` / `-uno`. Empty output means clean only when the command exits 0; a nonzero exit is an error to surface — stop; never treat a failed check as "clean".
122
126
 
123
127
  **When and where it runs:**
124
128
 
125
- - **Fresh creation (Steps 1a/2):** in the source checkout, **before** invoking the wrapper (Step 1a) or the `git worktree add` sequence (Step 2b) — pre-creation, the current directory *is* the source checkout, so no `$ROOT` plumbing or `git worktree list` derivation is needed. Those steps point here; this section defines the check.
126
- - **Already in a worktree (Step 0):** the same check against the current worktree, on arrival at this step.
129
+ - **Fresh creation (Steps 1a/2):** in the source checkout, **before** invoking the wrapper (Step 1a) or the `git worktree add` sequence (Step 2b), as `git -C "$ROOT" status --porcelain`.
130
+ - **Already in a worktree (Step 0):** on arrival at this step, as `git -C "$WORKTREE" status --porcelain`.
127
131
 
128
132
  **Clean** → proceed (create the worktree if not yet created, then Step 4).
129
133
 
@@ -142,6 +146,8 @@ Ready to implement <feature>
142
146
 
143
147
  When the user chose to proceed past a dirty source, the base line is `Base: <ref> (dirty - proceeded after ask)` instead. When the provenance check fired (fresh paths only), append its `Note: branching from <ref>, not <default>.` line after the base line. `<ref>` per path: fresh creation — the branch/commit the worktree was created from (the user-requested base when one was given); Step 0 — the current branch/HEAD of the existing worktree, with no provenance line.
144
148
 
149
+ Every later skill takes `<full-path>` as a value: dispatch `cwd: "<full-path>"`, `git -C <full-path> ...`, or `(cd "<full-path>" && <cmd>)` for other cwd-bound commands. Never change the process cwd.
150
+
145
151
  ## Detached HEAD
146
152
 
147
153
  If `git symbolic-ref -q HEAD` returns nothing, you're on a detached HEAD. Do not create a worktree from this state — first ask the user whether to branch from the current commit or from `main`.
@@ -151,8 +157,8 @@ If `git symbolic-ref -q HEAD` returns nothing, you're on a detached HEAD. Do not
151
157
  For longer-running work the base branch advances:
152
158
 
153
159
  ```bash
154
- git fetch origin
155
- git rebase origin/main # or merge if branch is shared
160
+ git -C "$WORKTREE" fetch origin
161
+ git -C "$WORKTREE" rebase origin/main # or merge if branch is shared
156
162
  ```
157
163
 
158
164
  Re-run tests after rebasing.
@@ -161,11 +167,11 @@ Re-run tests after rebasing.
161
167
 
162
168
  | Situation | Action |
163
169
  |---|---|
164
- | `GIT_DIR != GIT_COMMON` | Already in worktree — do NOT create another |
170
+ | `GIT_DIR != GIT_COMMON` | Already in worktree - report its path, create nothing |
171
+ | Worktree path already listed by `git worktree list` | Report it, create nothing |
165
172
  | `git rev-parse --show-superproject-working-tree` returns a path | Submodule — treat as normal repo |
166
173
  | Project-native wrapper exists | Use the wrapper (commonly `script/worktree create`) |
167
174
  | No native tool | Create `<repo>/.worktrees/<branch>` (gitignore `.worktrees/` first) |
168
- | No enclosing repo | Fall back to `~/.worktrees/<project>/<branch>` |
169
175
  | Detached HEAD | Ask before branching |
170
176
  | Sandbox/permission failure | Work in place on a feature branch |
171
177
  | Source checkout dirty | Report + ask |
@@ -173,6 +179,7 @@ Re-run tests after rebasing.
173
179
  ## Red Flags — STOP
174
180
 
175
181
  - About to run `git worktree add` from inside a worktree (`GIT_DIR != GIT_COMMON`)
182
+ - About to `cd` into the worktree (carry the path instead)
176
183
  - About to call `git worktree add` directly when the project ships a wrapper (use the wrapper)
177
184
  - Created a `.worktrees/` worktree without gitignoring `.worktrees/` first
178
185
  - Placed a worktree outside `.worktrees/` (or the project's configured path) for no reason