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.
- package/CHANGELOG.md +4 -0
- package/README.md +2 -0
- package/extensions/lib/checkout.test.ts +59 -0
- package/extensions/lib/checkout.ts +57 -0
- package/extensions/lib/gauntlet-settings-loader.test.ts +32 -0
- package/extensions/lib/gauntlet-settings-loader.ts +11 -7
- package/extensions/lib/phase-tracker-helpers.test.ts +17 -0
- package/extensions/lib/phase-tracker-helpers.ts +16 -17
- package/extensions/lib/telemetry-paths.test.ts +10 -0
- package/extensions/lib/telemetry-paths.ts +9 -5
- package/extensions/phase-tracker.test.ts +75 -23
- package/extensions/phase-tracker.ts +20 -29
- package/extensions/telemetry.test.ts +51 -10
- package/extensions/telemetry.ts +57 -41
- package/extensions/verify-before-ship.test.ts +16 -0
- package/extensions/verify-before-ship.ts +4 -4
- package/package.json +1 -1
- package/skills/brainstorming/SKILL.md +7 -5
- package/skills/finishing-a-development-branch/SKILL.md +51 -88
- package/skills/gauntlet-resume/SKILL.md +1 -3
- package/skills/gauntlet-resume/reference/brief-contract.md +1 -1
- package/skills/roasting-the-spec/SKILL.md +1 -1
- package/skills/subagent-driven-development/SKILL.md +18 -15
- package/skills/using-git-worktrees/SKILL.md +46 -39
- package/skills/verification-before-completion/reference/conformance-check.md +6 -6
- package/skills/verification-before-completion/reference/settings-precedence.md +8 -6
- package/skills/writing-plans/SKILL.md +5 -3
- package/skills/writing-plans/reference/plan-contract.md +1 -1
|
@@ -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
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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 `
|
|
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
|
-
|
|
269
|
-
|
|
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
|
-
|
|
242
|
+
Removal precedes branch deletion in both options; `git branch -d`/`-D` fails while the worktree still references the branch.
|
|
275
243
|
|
|
276
|
-
|
|
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
|
-
**
|
|
313
|
-
- **Problem:**
|
|
314
|
-
- **Fix:**
|
|
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
|
|
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
|
-
-
|
|
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
|
-
- `
|
|
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 `
|
|
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
|
-
|
|
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
|
|
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
|
-
-
|
|
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
|
|
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.**
|
|
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
|
|
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
|
|
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`
|
|
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
|
|
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
|
|
24
|
-
|
|
25
|
-
|
|
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):**
|
|
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
|
-
|
|
38
|
-
|
|
39
|
-
|
|
37
|
+
```bash
|
|
38
|
+
WORKTREE=$(dirname "$(cat "$GIT_DIR/gitdir")")
|
|
39
|
+
```
|
|
40
40
|
|
|
41
|
-
|
|
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>`.
|
|
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
|
-
|
|
81
|
+
### 2b. Create - gitignore the home first
|
|
84
82
|
|
|
85
|
-
|
|
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
|
|
91
|
-
|
|
92
|
-
if
|
|
93
|
-
|
|
94
|
-
|
|
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
|
-
|
|
97
|
-
cd ".worktrees/$BRANCH_NAME"
|
|
97
|
+
WORKTREE="$ROOT/.worktrees/$BRANCH"
|
|
98
98
|
```
|
|
99
99
|
|
|
100
|
-
|
|
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
|
-
|
|
106
|
-
|
|
107
|
-
elif [ -f
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
[ -f
|
|
111
|
-
[ -f
|
|
112
|
-
[ -f
|
|
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)
|
|
126
|
-
- **Already in a worktree (Step 0):**
|
|
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
|
|
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
|