pi-gauntlet 5.2.2 → 5.3.0

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 CHANGED
@@ -1,5 +1,13 @@
1
1
  # Changelog
2
2
 
3
+ ## v5.3.0 - 2026-09-04
4
+
5
+ - `chase-bug`: the real-bug verdict menu gains a fourth row, "Implement hotfix now", for small, evidenced, urgent fixes - a middle ceremony tier between the trivial carve-out and the full gauntlet. It hands off to the new companion `skills/chase-bug/hotfix.md`: dedicated `hotfix/<slug>` worktree, one implementer (TDD), one code review as the last mutation gate, an advisory conformance pass, then an unpushed squash commit on the default branch with guaranteed worktree/branch cleanup (or a PR when the pick says "as a PR"). Three safety invariants (no schema/persistence change, no public-contract change, one-commit rollback) gate the row's availability; three judgment predicates steer `[recommended]`. Triage itself stays read-only; the row is reachable only through the verdict menu. Zero changes to finishing, SDD, verification, extensions, or ci.mjs. Spec: `doc/specs/2026-09-03-chase-bug-hotfix.md`.
6
+
7
+ ## v5.2.3 - 2026-09-01
8
+
9
+ - Isolated `subagent` dispatch examples now mint an OS-temp report directory and use absolute `output:` paths, preventing reports from being captured in and deleted with throwaway worktrees. The parallel-dispatch Output capture guidance now distinguishes that isolated failure mode from non-isolated shared-working-tree commit/overwrite risk. Fixes #23. Spec: `doc/specs/2026-09-01-gh-23-absolute-report-paths.md`.
10
+
3
11
  ## v5.2.2 - 2026-09-01
4
12
 
5
13
  - `linear` skill: the once-per-session `linearis issues usage` sweep no longer requires authentication. `usage` prints local help and makes no API call, so gating it on `auth status` skipped the cheap staleness check exactly when the agent was already degraded; it now runs whenever the binary is present. Also drops a dead "or the MCP path is in use" skip clause - the sweep sits inside the present-binary branch, and MCP is the fallback only when the binary is missing. Prose only, no code or config surface. Follow-up to #22; spec `doc/specs/2026-09-01-gh-22-linear-cli-verification.md` amended to match.
package/README.md CHANGED
@@ -35,7 +35,7 @@ pi-gauntlet's only hard dependency is pi-cohort - every gate that dispatches a r
35
35
 
36
36
  Concretely, one change through the gauntlet:
37
37
 
38
- 0. *(Optional)* Before there's even a spec, `/skill:shape-ticket` can create or repair a single tracker issue - shaping a raw ask into a Context/Problem/Idea/Acceptance Criteria ticket, gated by an AC integrity check, a cheap council roast, and one human-confirmed write that may include one optional gated Reporter-note comment. A failed roast is retried once, then surfaced inline at the gate if it fails again. It's a tool, not a phase: no worktree, no plan/phase tracker, runs from any repo state. It never activates on its own (`disable-model-invocation: true`) - invoke it explicitly. Similarly, `/skill:chase-bug` triages a raw bug report into an evidenced verdict - and can hand off to shape-ticket or brainstorming - before any spec exists.
38
+ 0. *(Optional)* Before there's even a spec, `/skill:shape-ticket` can create or repair a single tracker issue - shaping a raw ask into a Context/Problem/Idea/Acceptance Criteria ticket, gated by an AC integrity check, a cheap council roast, and one human-confirmed write that may include one optional gated Reporter-note comment. A failed roast is retried once, then surfaced inline at the gate if it fails again. It's a tool, not a phase: no worktree, no plan/phase tracker, runs from any repo state. It never activates on its own (`disable-model-invocation: true`) - invoke it explicitly. Similarly, `/skill:chase-bug` triages a raw bug report into an evidenced verdict - and can hand off to shape-ticket, brainstorming, or a bounded hotfix - before any spec exists.
39
39
  1. You describe the change. **`brainstorming`** sets up an isolated worktree, explores the codebase, and turns your description into a written spec. A multi-model critique runs on it automatically. If the spec replaces a known prior spec, brainstorming marks the predecessor with a `> **Superseded by:**` banner under its title (default format, syntax overridable via `.pi/gauntlet-overrides.md`; event-driven only — gauntlet never sweeps historical specs). **You read and approve the spec - human gate 1.** No implementation code exists yet.
40
40
  2. **`writing-plans`** decomposes the approved spec into atomic, independently-verifiable tasks, grouped into parallel waves where they don't touch the same files.
41
41
  3. **`subagent-driven-development`** executes the plan one task at a time, each in a fresh subagent, behind spec-compliance review then code-quality review. TDD-locked: red, green, refactor.
@@ -69,7 +69,7 @@ Everything between gate 1 and gate 2 - task breakdown, implementation, both revi
69
69
 
70
70
  pi-gauntlet ships three kinds of pieces, layered on top of pi-cohort's dispatch:
71
71
 
72
- - **17 skills** - the workflow logic. Thirteen activate automatically when pi sees the matching kind of task, and each one gates the next: `brainstorming`, `writing-plans`, `roasting-the-spec`, `test-driven-development`, `subagent-driven-development`, `dispatching-parallel-agents`, `verification-before-completion`, `requesting-code-review`, `receiving-code-review`, `using-git-worktrees`, `finishing-a-development-branch`, `writing-skills`, `linear` (reads/searches/comments on/manages Linear tickets via the `linearis` CLI; owns all linearis mechanics and the `## Issue tracker` overrides schema; tracker-facing skills route to it). Four more are explicit-invocation-only (`disable-model-invocation: true`): `shape-ticket` creates or repairs one tracker issue per run against a Context/Problem/Idea/Acceptance-Criteria template, gated by an AC integrity check, a cheap council roast, and a single human-confirmed write - run it with `/skill:shape-ticket`. `gatekeep-pr` is consent-gated pre-merge verification of a PR against its issue - read-only gathering, verification evidence resolved CI-first (green checks on the exact assessed head count as evidence; the project's verification command runs only as fallback), a rubric-based review, then a deterministic authorship-aware menu with stable finding IDs (P#/L#/C#/F#) and numbered pre-composed courses (fixes execute as a single parallel-safe wave: one gate run, one re-review, one push); nothing mutates (fixes, pushes, reviews, merges) until you pick a row - run it with `/skill:gatekeep-pr <pr>`. `check-delivery` is a post-merge detective control: proves an issue actually shipped (default-branch landing, delivery target, per-AC evidence) before its tracker status advances; it never writes a terminal status - run it with `/skill:check-delivery <ref>`. `chase-bug` is human-only bug triage: read-only root-cause discovery to an evidenced verdict menu (real bug -> ticket/brainstorm/respond; five negative verdicts), then a gated response to the reporter for addressable origins (GitHub issue / tracker ticket) and a rendered verdict summary otherwise - it never fixes during triage - run it with `/skill:chase-bug`.
72
+ - **17 skills** - the workflow logic. Thirteen activate automatically when pi sees the matching kind of task, and each one gates the next: `brainstorming`, `writing-plans`, `roasting-the-spec`, `test-driven-development`, `subagent-driven-development`, `dispatching-parallel-agents`, `verification-before-completion`, `requesting-code-review`, `receiving-code-review`, `using-git-worktrees`, `finishing-a-development-branch`, `writing-skills`, `linear` (reads/searches/comments on/manages Linear tickets via the `linearis` CLI; owns all linearis mechanics and the `## Issue tracker` overrides schema; tracker-facing skills route to it). Four more are explicit-invocation-only (`disable-model-invocation: true`): `shape-ticket` creates or repairs one tracker issue per run against a Context/Problem/Idea/Acceptance-Criteria template, gated by an AC integrity check, a cheap council roast, and a single human-confirmed write - run it with `/skill:shape-ticket`. `gatekeep-pr` is consent-gated pre-merge verification of a PR against its issue - read-only gathering, verification evidence resolved CI-first (green checks on the exact assessed head count as evidence; the project's verification command runs only as fallback), a rubric-based review, then a deterministic authorship-aware menu with stable finding IDs (P#/L#/C#/F#) and numbered pre-composed courses (fixes execute as a single parallel-safe wave: one gate run, one re-review, one push); nothing mutates (fixes, pushes, reviews, merges) until you pick a row - run it with `/skill:gatekeep-pr <pr>`. `check-delivery` is a post-merge detective control: proves an issue actually shipped (default-branch landing, delivery target, per-AC evidence) before its tracker status advances; it never writes a terminal status - run it with `/skill:check-delivery <ref>`. `chase-bug` is human-only bug triage: read-only root-cause discovery to an evidenced verdict menu (real bug -> ticket/brainstorm/hotfix/respond; five negative verdicts), then a gated response to the reporter for addressable origins (GitHub issue / tracker ticket) and a rendered verdict summary otherwise - it never fixes during triage; the hotfix row hands off to `skills/chase-bug/hotfix.md` after the menu - run it with `/skill:chase-bug`.
73
73
  - **7 subagent personas** - the specialized child agents the skills dispatch via pi-cohort: `implementer`, `code-reviewer`, `spec-reviewer`, `conformance-reviewer`, `spec-summarizer`, `spec-council-member`, `spec-council-synthesizer`. See [doc/personas.md](./doc/personas.md) for what each one does and why its permissions are scoped the way they are.
74
74
  - **3 runtime extensions** - the enforcement layer. `plan-tracker` and `phase-tracker` are tools skills call to track progress (with a TUI widget); `verify-before-ship` is a hook that warns if you push or open a PR without a passing test run since your last edit; a phase-tracker flow guard reminds on implement-phase commits missing spec/code review. phase-tracker also registers plan_check, a deterministic plan linter (8 mechanical plan-vs-spec checks) whose pass stamp gates implement-start inside a gauntlet flow. See [doc/configuration.md](./doc/configuration.md) for the settings each one reads.
75
75
 
@@ -89,7 +89,7 @@ pi-gauntlet is **opinionated**: every non-trivial change is *meant* to ride this
89
89
 
90
90
  **Use it** for any change with more than one moving part: a feature, a refactor across files, anything where "what did we actually agree to build" matters by the time it's done.
91
91
 
92
- **Don't use it** for a one-line fix, a typo, or a throwaway spike you're going to discard. The gates have real overhead - a spec, a plan, a conformance check - and that overhead isn't worth paying for a change trivial enough to just make.
92
+ **Don't use it** for a one-line fix, a typo, or a throwaway spike you're going to discard. The gates have real overhead - a spec, a plan, a conformance check - and that overhead isn't worth paying for a change trivial enough to just make. Between that carve-out and the full pipeline sits one middle tier: `chase-bug`'s hotfix row - a small, evidenced, urgent fix landed as an unpushed squash, entered only through the triage verdict menu.
93
93
 
94
94
  ## Requirements
95
95
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pi-gauntlet",
3
- "version": "5.2.2",
3
+ "version": "5.3.0",
4
4
  "description": "Opinionated, gated workflow skills, subagent personas, and runtime extensions for the pi coding agent.",
5
5
  "author": "Jacek Juraszek",
6
6
  "type": "module",
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: chase-bug
3
- description: Use when a human hands you a bug report to triage - a Slack paste, tracker ticket, GitHub issue, or described symptom - and the goal is an evidenced verdict (real bug, not-a-bug, cannot reproduce, already fixed or reported), not a fix.
3
+ description: Use when a human hands you a bug report to triage - a Slack paste, tracker ticket, GitHub issue, or described symptom - and the goal is an evidenced verdict (real bug, not-a-bug, cannot reproduce, already fixed or reported); triage itself never fixes - a real-bug verdict may hand off to a bounded hotfix after the menu.
4
4
  disable-model-invocation: true
5
5
  ---
6
6
 
@@ -8,13 +8,16 @@ disable-model-invocation: true
8
8
 
9
9
  ## Overview
10
10
 
11
- Triage a bug report to an evidenced verdict, never a fix.
11
+ Triage a bug report to an evidenced verdict. Triage never
12
+ fixes; a real-bug verdict may hand off to a bounded hotfix (hotfix.md) after
13
+ the menu.
12
14
 
13
15
  ## Boundaries
14
16
 
15
17
  - Reads: anything - code, history, tracker, origin text.
16
18
  - Writes: `$TMPDIR` scratch only (repro captures, notes), plus at most one gated push to the
17
- origin's response channel at the very end.
19
+ origin's response channel at the very end; after a valid hotfix pick: the hotfix
20
+ worktree and one default-branch squash commit, per hotfix.md.
18
21
  - Does NOT: touch tracked files; touch tracker state (never closes, relabels, or
19
22
  reassigns an existing issue).
20
23
  - The zero-mutation invariant below mechanically enforces tracked-file immutability
@@ -25,7 +28,8 @@ Triage a bug report to an evidenced verdict, never a fix.
25
28
 
26
29
  ## Hard constraint
27
30
 
28
- **No verdict without evidenced root cause; no fix, ever.** (write surface: see
31
+ **No verdict without evidenced root cause; no fix during
32
+ triage. After a valid hotfix pick, writes follow hotfix.md.** (write surface: see
29
33
  Boundaries; enforcement: see the zero-mutation invariant below.)
30
34
 
31
35
  The invariant is baseline-relative, checked at three points. Never revert
@@ -41,17 +45,24 @@ pre-existing work - only ever revert damage this skill caused.
41
45
  rendering the summary). Re-run the same command and confirm it still matches
42
46
  the baseline.
43
47
 
48
+ **Handoff check** (hotfix row only). Immediately before handing off to
49
+ `hotfix.md`, run the same command on the primary checkout and require it to
50
+ match the baseline. Checkpoint 3 still runs at skill end, on the primary
51
+ checkout: a landed squash
52
+ commit and a restored branch leave tracked porcelain clean, so the invariant
53
+ holds literally on both exits.
54
+
44
55
  ## When to Use
45
56
 
46
57
  - A human pastes a bug report (Slack message, tracker ticket, GitHub issue, plain
47
58
  description of broken behavior) and wants to know whether it is real.
48
59
  - The ask is "is this a bug" / "can we reproduce this" / "what's causing this",
49
60
  not "fix this".
61
+ - An evidenced, urgent "fix this" request also enters
62
+ here - triage stops at the menu, where the hotfix row is offered.
50
63
 
51
64
  ## When NOT to Use
52
65
 
53
- - The report already has an evidenced root cause and the ask is to implement a
54
- fix - exit into `/skill:brainstorming` directly.
55
66
  - The item is an already-shaped ticket ready for implementation, not a report
56
67
  needing triage.
57
68
 
@@ -153,33 +164,64 @@ Render **only the matching action set** - never merge real-bug and negative-verd
153
164
  menus into one list. The human may **overrule the verdict in prose** - that is a
154
165
  change request, not a menu row.
155
166
 
156
- **Real bug** - three actions (all rendered unless noted), exactly one tagged
157
- `[recommended]`:
167
+ **Real bug** - four actions (all rendered unless noted), exactly one tagged
168
+ `[recommended]`. Untracked origin:
158
169
 
159
170
  ```
160
- 1. [ ] File a ticket - one /skill:shape-ticket create-mode invocation, seeded
161
- with this evidence.
171
+ 1. [ ] File a ticket - /skill:shape-ticket, seeded with this evidence.
162
172
  2. [ ] Brainstorm now - /skill:brainstorming with this evidence as the seed.
163
- Handoff happens AFTER gate 2 (step 5).
173
+ 3. [ ] Implement hotfix now - follow hotfix.md; add "as a PR" for a PR.
174
+ 4. [ ] Respond to reporter only.
175
+ ```
176
+
177
+ Tracker/GitHub origin (ticket row omitted as today, renumbered):
178
+
179
+ ```
180
+ 1. [ ] Brainstorm now - /skill:brainstorming with this evidence as the seed.
181
+ 2. [ ] Implement hotfix now - follow hotfix.md; add "as a PR" for a PR.
164
182
  3. [ ] Respond to reporter only.
165
183
  ```
166
184
 
167
- For unaddressable origins, action 3 reads `Finish with rendered summary`
168
- instead of "Respond to reporter only", and action 2's handoff happens after
169
- the rendered summary instead of gate 2. Exactly one rendered action still
170
- carries `[recommended]`.
185
+ Unaddressable variants adjust the last row's label exactly as today. Exactly
186
+ one `[recommended]` preserved. The eligibility line renders under the menu:
187
+ `eligible` or `not eligible: <predicate>`, from the predicate evaluation below.
171
188
 
172
- If the origin is itself a tracker/GitHub ticket, it's already tracked: omit
173
- action 1 and renumber the remaining two as 1 (Brainstorm now) and 2 (Respond
174
- to reporter only). Exactly one rendered action still carries `[recommended]`.
189
+ For unaddressable origins, the last action reads `Finish with rendered summary`
190
+ instead of "Respond to reporter only", and the Brainstorm handoff happens after
191
+ the rendered summary instead of gate 2.
175
192
 
176
- Heuristic for the `[recommended]` tag: pressing (user-facing break, data loss,
177
- security) or trivially fixable -> recommend brainstorm now; real but deferrable
178
- -> recommend file a ticket; blocked on another party (needs reporter input,
179
- upstream fix, another team) -> recommend respond-only (rendered as "Finish with
180
- rendered summary" for unaddressable origins). Root cause found but the
181
- fix cost is unclear still stays a **real-bug** verdict - state the uncertainty
182
- plainly in the fault story, do not downgrade the verdict to hedge on cost.
193
+ **Predicates and row availability.** Evaluate the six predicates in
194
+ `hotfix.md` once, here, from the root cause - a prediction of the fix shape
195
+ (read-only judgment). A failed safety invariant (1-3) renders the row as
196
+ `Implement hotfix now - unavailable: <invariant>`: never pickable, never
197
+ `[recommended]`; a pick of it is a change request. Judgment predicates (4-6)
198
+ only steer `[recommended]` and the eligibility line.
199
+
200
+ Heuristic for the `[recommended]` tag - rows top-down, first match wins:
201
+
202
+ | Situation | `[recommended]` |
203
+ |---|---|
204
+ | Pressing or trivially fixable, all predicates pass | Hotfix now |
205
+ | Pressing, any predicate fails | Brainstorm now |
206
+ | Trivially fixable, any predicate fails | Brainstorm now |
207
+ | Real but deferrable | File a ticket (tracker-origin: respond-only) |
208
+ | Blocked on another party | Respond-only |
209
+
210
+ Respond-only renders as "Finish with rendered summary" for unaddressable
211
+ origins. Root cause found but the fix cost is unclear still stays a
212
+ **real-bug** verdict - state the uncertainty plainly in the fault story, do
213
+ not downgrade the verdict to hedge on cost.
214
+
215
+ **Hotfix handoff.** On a hotfix pick, write the handoff record to
216
+ `$TMPDIR/hotfix-<slug>.md`: `delivery-mode` (`squash`, or `pr` when the pick
217
+ says "as a PR"); the evidence pack (fault story; trigger, observed, and
218
+ expected values from Phase 1; repro command; `file:line`; falsification
219
+ result); `slug` (kebab-case, from the symptom); origin type and response
220
+ target (step 1); the predicate evaluation. Run the handoff check (see the
221
+ zero-mutation invariant), then follow `hotfix.md`, which reads only this
222
+ record. On a hotfix abort, `hotfix.md` runs its baseline re-check and this
223
+ menu re-renders - the same gate, re-fired: with the hotfix row when the abort
224
+ created nothing, without it otherwise.
183
225
 
184
226
  **Negative verdicts** - exactly five, each with its own named citation source:
185
227
 
@@ -236,6 +278,10 @@ any handoff:
236
278
  response citing the new ticket link -> gate 2 -> done.
237
279
  - Brainstorm now chosen -> draft the response first ("confirmed, investigating
238
280
  now - fix to follow") -> gate 2 -> **then** hand off to `/skill:brainstorming`.
281
+ - Hotfix now chosen -> hand off to `hotfix.md` first; on completion, draft the
282
+ response citing `fixed in <SHA>` or the PR link -> gate 2 (`send it`) -> done.
283
+ Gate 2 fires once. On abort, `hotfix.md` returns to the step-4 menu; step 5
284
+ then runs for the new pick, the draft citing the abort reason.
239
285
  - Respond-only, or any negative verdict -> draft -> gate 2 -> done.
240
286
 
241
287
  **Draft template:**
@@ -298,6 +344,9 @@ action renders the verdict as a **summary to the human**, then the skill ends
298
344
  link.
299
345
  - Brainstorm now chosen -> render the summary -> **then** hand off to
300
346
  `/skill:brainstorming`.
347
+ - Hotfix now chosen -> hand off to `hotfix.md`; on completion render the
348
+ summary citing `fixed in <SHA>` or the PR link -> done. On abort, return to
349
+ the step-4 menu.
301
350
  - Finish with rendered summary chosen -> render the summary -> done.
302
351
 
303
352
  **Summary template** (same four fields as the draft - the difference is
@@ -319,7 +368,7 @@ rendered is out of skill scope - the skill has ended.
319
368
 
320
369
  | Verdict | Citation source | Response next-step |
321
370
  |---|---|---|
322
- | Real bug | Falsification test run + passed | Ticket link, fix branch, or ack |
371
+ | Real bug | Falsification test run + passed | Ticket link, squash SHA, fix branch, or ack |
323
372
  | `not-a-bug` | Contract satisfied (spec/schema/API doc) | Explain the contract |
324
373
  | `intended-behavior` | Decision record (design doc/ADR/commit) | Point to the decision |
325
374
  | `cannot-replicate` | Phase 1 repro attempts, missing input named | Ask reporter for missing input; offer discovery ticket |
@@ -337,11 +386,14 @@ falls through to the 404 handler.
337
386
  Proof: `curl /widgets/` -> 404 | src/router.ts:88 | expected match, got none
338
387
 
339
388
  1. [ ] File a ticket - /skill:shape-ticket, seeded with the above.
340
- 2. [x] Brainstorm now - user-facing 404 on a common URL shape. [recommended]
341
- 3. [ ] Respond to reporter only.
389
+ 2. [ ] Brainstorm now - /skill:brainstorming with the above as the seed.
390
+ 3. [x] Implement hotfix now - follow hotfix.md; add "as a PR" for a PR. [recommended]
391
+ 4. [ ] Respond to reporter only.
392
+
393
+ eligible - all predicates pass
342
394
  ```
343
395
 
344
- (The example assumes an addressable origin - action 3's label is the addressable one.)
396
+ (The example assumes an addressable origin - action 4's label is the addressable one.)
345
397
 
346
398
  **Negative-verdict example** (citation-source contrast):
347
399
 
@@ -361,7 +413,7 @@ nested resources" (the decision that made it so).
361
413
 
362
414
  | Excuse | Reality |
363
415
  |---|---|
364
- | "Trivial fix, faster to just do it" | Fixing during triage is the one thing this skill forbids - hand it to the human at the menu, always |
416
+ | "Trivial fix, faster to just do it" | Fixing during triage is forbidden - the hotfix row after the menu is the sanctioned path |
365
417
  | "Root cause is obvious, skip falsification" | Obvious and evidenced are different things - run the test or report it blocked |
366
418
  | "Reporter is waiting, skip the gate" | The gate is what makes the response trustworthy - urgency is not a bypass |
367
419
  | "I already know there's no prior report" | A guess isn't a search - use the ladder or declare it unreachable |
@@ -0,0 +1,198 @@
1
+ # Hotfix (chase-bug supplementary)
2
+
3
+ Consumed only by `SKILL.md` in this directory, at the real-bug menu handoff. Input:
4
+ the handoff record at `$TMPDIR/hotfix-<slug>.md` - read nothing else about the bug.
5
+ Automatic end to end: the menu pick was the consent. The only human gate left is
6
+ chase-bug's `send it`, reached in step 10 below.
7
+
8
+ ## Boundaries
9
+
10
+ - Reads: anything.
11
+ - Writes: the hotfix worktree; exactly one squash commit on `<default>`, made in the
12
+ primary checkout with a clean index, `<orig-branch>` restored after; `$TMPDIR`.
13
+ - Does NOT: run tests or create files in the primary checkout; push without an
14
+ explicit request; touch tracker state; commit on the source checkout during setup;
15
+ touch pre-existing dirt or any resource this run did not create.
16
+
17
+ ## Ownership
18
+
19
+ Two flags, `created-worktree` and `created-branch`, set only when `git worktree add`
20
+ succeeds (it creates both). Every destructive command below is gated on its flag.
21
+
22
+ ## Procedure
23
+
24
+ 1. **Read the record; print the eligibility line.** Reprint the menu-time
25
+ evaluation verbatim: `eligible` or `not eligible: <predicate>`. Never
26
+ re-derive, never block.
27
+ 2. **Resolve before mutating.** `SCOPED_TEST_COMMANDS`: the gauntlet overrides
28
+ file's verification section (`## verification-before-completion`, or a section
29
+ matching the verification topic), else `AGENTS.md` or the project's documented
30
+ test command. The full project test target is acceptable. Add the record's repro
31
+ command when present. No exact command -> abort (pre-land). Draft the implementer
32
+ task text from the record; not writable -> abort (pre-land). Nothing exists yet.
33
+ 3. **Worktree.** From the primary checkout:
34
+
35
+ ```bash
36
+ PRIMARY_ROOT=$(git rev-parse --show-toplevel)
37
+ DEFAULT=$(git symbolic-ref --short refs/remotes/origin/HEAD) && DEFAULT=${DEFAULT#origin/}
38
+ BASE_SHA=$(git rev-parse "$DEFAULT")
39
+ ORIG_BRANCH=$(git branch --show-current)
40
+ git status --porcelain > "$TMPDIR/hotfix-<slug>.baseline"
41
+ ```
42
+
43
+ Abort (pre-land, nothing created) when: `git rev-parse --git-dir` differs from
44
+ `git rev-parse --git-common-dir` (inside a linked worktree); `DEFAULT` empty
45
+ (never guess a squash target); `ORIG_BRANCH` empty (detached HEAD); `git status
46
+ --porcelain --untracked-files=no` non-empty; `git check-ignore -q .worktrees/`
47
+ fails (never commit on the source checkout); `git show-ref --verify -q
48
+ refs/heads/hotfix/<slug>` succeeds or `.worktrees/hotfix/<slug>` exists (never
49
+ reuse, never force); `git worktree add` itself failing (creation failure).
50
+
51
+ ```bash
52
+ git worktree add ".worktrees/hotfix/<slug>" -b "hotfix/<slug>" "$DEFAULT"
53
+ ```
54
+
55
+ Success sets both flags. Run the project's dependency install inside the
56
+ worktree. Every dispatch below: `cwd` = the worktree path, the record path in the
57
+ task text, `output:` (when used) an absolute `$TMPDIR` path.
58
+ 4. **Implement.** One `implementer`, fork context:
59
+
60
+ > Read `$TMPDIR/hotfix-<slug>.md`; the evidence pack is also inlined here:
61
+ > <evidence pack>. The evidence pack replaces plan and spec; do
62
+ > not report BLOCKED for a missing plan. TDD: write the regression test, run it,
63
+ > confirm it fails, then the minimal fix (dependency-bump fallback: the repro
64
+ > re-run is the regression evidence). SCOPED_TEST_COMMANDS: <commands>. Commit on
65
+ > `hotfix/<slug>` before reporting. End with the SDD status line verbatim.
66
+
67
+ `DONE` -> step 5. `DONE_WITH_CONCERNS` -> step 5 unless a concern names a safety
68
+ invariant -> abort. `NEEDS_CONTEXT` or `BLOCKED` -> abort. A regression command
69
+ named in the report joins `SCOPED_TEST_COMMANDS` only if it uses the resolved
70
+ command's runner.
71
+ 5. **Test.** Run `SCOPED_TEST_COMMANDS` in the worktree. Red -> one implementer
72
+ retry -> red -> abort.
73
+ 6. **Verify (advisory).** One fresh `conformance-reviewer`. Its entire origin, in
74
+ the task text, located as `prompt`:
75
+
76
+ > R1: the trigger `<trigger>` now yields `<expected>` (was `<observed>`).
77
+ > R2: regression evidence exists (test or repro re-run).
78
+ > R3: the diff stays inside the envelope: files implementing the mechanism at
79
+ > the recorded `file:line`, the regression test, and (dependency exception)
80
+ > manifest + lockfile.
81
+
82
+ Parent filter: only rows located as `prompt` count; a row sourced from a spec
83
+ file or ticket is not-a-gap. Real gaps -> one implementer round -> re-run step
84
+ 5 -> no second audit; unfixable -> abort. Dispatch failure or malformed output
85
+ -> note it, continue.
86
+ 7. **Review - last mutation gate.** One fresh `code-reviewer` over
87
+ `<base-sha>..HEAD` in the worktree. Task text: the record path,
88
+ `SCOPED_TEST_COMMANDS`, invariants 1-3 and predicates 4-6 as named review items
89
+ (a predicate miss is Moderate unless it trips an invariant). `SHIP` -> step 8.
90
+ `FIX_FIRST` -> one implementer round fixing every Critical and Moderate ->
91
+ re-run step 5 -> one re-review; `SHIP` -> step 8, else abort. `REJECT` or any
92
+ invariant violation -> abort, no round. Dispatch failure or malformed output ->
93
+ one redispatch, then abort.
94
+ 8. **Finish.** Branch on the record's `delivery-mode`: `squash` -> squash path;
95
+ `pr` -> PR path. Every command from `PRIMARY_ROOT`. Squash path, by state:
96
+
97
+ ```bash
98
+ cd "$PRIMARY_ROOT"
99
+ [ -z "$(git status --porcelain --untracked-files=no)" ] || land_abort
100
+ [ "$(git rev-parse "$DEFAULT")" = "$BASE_SHA" ] || land_abort # base moved: never touch <default>
101
+ git checkout "$DEFAULT" || land_abort # pre-squash ends here
102
+ git merge --squash "hotfix/<slug>" || { git reset --hard "$BASE_SHA"; land_abort; }
103
+ git diff --cached --quiet && { git reset --hard "$BASE_SHA"; land_abort; } # empty squash
104
+ git commit -m "fix: <slug>" -m "<fault story>" || { git reset --hard "$BASE_SHA"; land_abort; }
105
+ [ "$(git rev-parse HEAD^{tree})" = "$(git rev-parse "hotfix/<slug>^{tree}")" ] \
106
+ || { git reset --hard "$BASE_SHA"; land_abort; } # proven; never reset after this line
107
+ SHA=$(git rev-parse HEAD)
108
+ [ "$ORIG_BRANCH" = "$DEFAULT" ] || git checkout "$ORIG_BRANCH" # failure: report, commit stays
109
+ git worktree remove --force ".worktrees/hotfix/<slug>" && git worktree prune \
110
+ && git branch -D "hotfix/<slug>" # failure: keep commit, report residual
111
+ ```
112
+
113
+ `git branch -D` is forced by construction: a squash commit never has the branch
114
+ tip as ancestor, so `-d` always refuses; the proven tree is the loss guard. The
115
+ commit stays **unpushed**. Report: `$SHA`; revert line `git checkout <default>
116
+ && git reset --hard <base-sha>` (unpushed) or `git revert <sha>` (after any
117
+ push); `git status --porcelain` diff against the baseline (expected none); a
118
+ push nudge.
119
+
120
+ PR path, cwd = the worktree: `git push -u origin hotfix/<slug>` - failure ->
121
+ report branch + worktree path, no URL, preserve. `gh pr create --base <default>
122
+ --head hotfix/<slug>` - `gh` missing or failing after one retry -> report the
123
+ pushed branch and compare URL. Worktree and branch preserved; print the closing
124
+ line.
125
+ 9. **Cleanup evidence.** Squash exit and pre-land aborts: `git worktree list`
126
+ without the hotfix entry; `git branch --list hotfix/<slug>` empty; porcelain
127
+ delta vs baseline none. PR exit and land-stage aborts: both present, plus
128
+ `git worktree remove --force .worktrees/hotfix/<slug> && git branch -D hotfix/<slug>`.
129
+ 10. **Response.** chase-bug step 5 rules apply unchanged: addressable -> draft
130
+ citing `fixed in <SHA>` or the PR link -> `send it`; unaddressable -> summary.
131
+ Abort never reaches this step - it returns to the menu.
132
+
133
+ ## Eligibility predicates
134
+
135
+ Evaluated once by `SKILL.md` at menu time from the root cause; re-checked against
136
+ the diff in step 7.
137
+
138
+ Safety invariants (row availability):
139
+
140
+ 1. No schema, migration, or persistence change.
141
+ 2. No public API, contract, or config-shape change.
142
+ 3. Rollback is reverting one commit - no data or state side effects.
143
+
144
+ Judgment predicates (`[recommended]` only; Moderate review items):
145
+
146
+ 4. Existing code only - new files limited to the regression test.
147
+ 5. Dependencies unchanged, one exception: a patch/minor bump whose upstream issue or
148
+ changelog names the symptom, diff = manifest + lockfile, no call-site change.
149
+ Replacement, major/breaking upgrade, new dependency -> fails.
150
+ 6. Regression evidence writable in the existing harness (bump fallback: the repro).
151
+
152
+ ## Abort
153
+
154
+ Both classes end with the baseline re-check, then chase-bug step 4 re-renders.
155
+
156
+ **Pre-land** (steps 2-7): unresolvable commands or task text; setup precondition
157
+ unmet; `NEEDS_CONTEXT`/`BLOCKED` or a concern naming an invariant; red after retry;
158
+ unfixable conformance gap; review `REJECT`, invariant violation, or a non-`SHIP`
159
+ re-review.
160
+
161
+ ```bash
162
+ [ "$created_worktree" = 1 ] && git worktree remove --force ".worktrees/hotfix/<slug>"
163
+ git worktree prune
164
+ [ "$created_branch" = 1 ] && git branch -D "hotfix/<slug>"
165
+ ```
166
+
167
+ Nothing else is touched. The re-rendered menu keeps the hotfix row when neither
168
+ flag was set, omits it otherwise.
169
+
170
+ **Land-stage** (step 8 before *proven*, after review `SHIP`): base moved, checkout failure, empty
171
+ squash, merge/commit failure, tree mismatch. `git reset --hard <base-sha>` only when
172
+ this run moved `<default>` (squash-applied or later) and `<default>` is checked
173
+ out (the step 8 lines do
174
+ exactly that); on base moved `<default>` is never touched and both SHAs are
175
+ reported. Restore `<orig-branch>`. Preserve worktree and branch (reviewed work).
176
+ Report path, tip SHA, closing line. The menu re-renders without the hotfix row.
177
+
178
+ **Baseline re-check**: `git status --porcelain --untracked-files=no` matches the
179
+ triage baseline; full porcelain delta reported; `<default>` == `<base-sha>` asserted
180
+ only when this run touched `<default>`. Pre-existing dirt is never touched.
181
+
182
+ ## Harness fallback
183
+
184
+ No `subagent` tool and no personas (the Claude Code marketplace ships `agents: []`):
185
+ run the duties inline, same order. Write the failing regression test, confirm red,
186
+ minimal fix, confirm green, commit on `hotfix/<slug>`. Self-review the diff against
187
+ the record, invariants 1-3, predicates 4-6. Run `SCOPED_TEST_COMMANDS`. Apply the
188
+ abort classes as written. Finish and report per steps 8-9.
189
+
190
+ ## Red Flags - STOP
191
+
192
+ - Any mutation before every step 3 precondition passes
193
+ - Reusing or force-replacing an existing `hotfix/<slug>` branch or path
194
+ - `git reset --hard` after *proven*, on `<orig-branch>`, or inside the worktree
195
+ - Re-running tests in the primary checkout
196
+ - Merging onto a moved base
197
+ - Landing a diff the last review did not see
198
+ - Pushing without an explicit request
@@ -183,7 +183,11 @@ Parallel dispatch rides on the `subagent` tool (the pi-cohort package). Mechanic
183
183
  - **Filesystem isolation** — `worktree: true` runs each task in its own git worktree so concurrent edits can't collide. Requires clean git state; each task's diff returns separately for you to integrate. Omit it for read-only investigations.
184
184
  - **Worktree base / `cwd`** — under `worktree: true` the base commit is `HEAD` resolved from the **top-level `cwd`**, which defaults to the orchestrator's process cwd. When you orchestrate from inside a git worktree, pass that worktree's absolute path as the top-level `cwd`, or children branch from the wrong checkout. Don't set per-task `cwd` with `worktree: true` — it must equal the shared cwd or the run errors.
185
185
  - **Agent choice** — `worker` is the pi-cohort builtin generalist. Use a persona (`implementer`, `code-reviewer`) when you want its system prompt and tool profile. Persona frontmatter (tools, thinking, context) is fixed; only `model`, `task`, `output`, `reads`, `progress`, `skill` are callable per task.
186
- - **Output capture** `output: "<file>"` writes a task's summary to a file instead of inline; add `outputMode: "file-only"` for large results.
186
+ - **Output capture** - `output: "<file>"` writes a task's summary to a file instead of inline; add `outputMode: "file-only"` for large results. When a batch uses `worktree: true`, each `output:` path must be absolute and outside every isolated checkout; a relative report is captured as helper work and then deleted with the checkout. In a non-isolated batch, a relative report lands in the shared working tree and risks being committed or overwritten by a later task.
187
+
188
+ ```bash
189
+ REPORT_DIR=$(mktemp -d)
190
+ ```
187
191
 
188
192
  ```ts
189
193
  subagent({
@@ -191,9 +195,9 @@ subagent({
191
195
  worktree: true, // isolate edits; omit for read-only investigations
192
196
  concurrency: 3,
193
197
  tasks: [
194
- { agent: "worker", task: "Fix + explain failures in src/a.test.ts", output: "a.md" },
195
- { agent: "worker", task: "Fix + explain failures in src/b.test.ts", output: "b.md" },
196
- { agent: "worker", task: "Fix + explain failures in src/c.test.ts", output: "c.md" },
198
+ { agent: "worker", task: "Fix + explain failures in src/a.test.ts", output: "<REPORT_DIR>/a.md" },
199
+ { agent: "worker", task: "Fix + explain failures in src/b.test.ts", output: "<REPORT_DIR>/b.md" },
200
+ { agent: "worker", task: "Fix + explain failures in src/c.test.ts", output: "<REPORT_DIR>/c.md" },
197
201
  ],
198
202
  })
199
203
  ```
@@ -185,6 +185,10 @@ Auto-selected at handoff by `writing-plans` (any wave with ≥2 tasks) when the
185
185
 
186
186
  **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.)
187
187
 
188
+ ```bash
189
+ REPORT_DIR=$(mktemp -d)
190
+ ```
191
+
188
192
  ```ts
189
193
  subagent({
190
194
  context: "fresh",
@@ -193,8 +197,8 @@ subagent({
193
197
  concurrency: 4, // default; cap = wave size
194
198
  tasks: [
195
199
  // do NOT set per-task cwd under worktree:true — it must equal the top-level cwd or the run errors
196
- { agent: "implementer", task: "<task text + owned files + SCOPED_TEST_COMMANDS + status protocol>", output: "wave1-task1.md" },
197
- { agent: "implementer", task: "<task text + owned files + SCOPED_TEST_COMMANDS + status protocol>", output: "wave1-task2.md" },
200
+ { agent: "implementer", task: "<task text + owned files + SCOPED_TEST_COMMANDS + status protocol>", output: "<REPORT_DIR>/wave1-task1.md" },
201
+ { agent: "implementer", task: "<task text + owned files + SCOPED_TEST_COMMANDS + status protocol>", output: "<REPORT_DIR>/wave1-task2.md" },
198
202
  ],
199
203
  })
200
204
  ```