pi-gauntlet 7.13.0 → 7.15.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,22 @@
1
1
  # Changelog
2
2
 
3
+ ## v7.15.0 - 2026-10-18
4
+
5
+ ### Changed
6
+
7
+ - **forge-skill covers repo-routed files and adds the No history rule.** The `description` names a file the repo's `AGENTS.md` or `CLAUDE.md` routes to the skill, so a consumer declares procedure files with one always-on bullet instead of an overrides key; `## Authoring rules` gains "No history": an added or changed line carries no date or narration of a rule's past, and a rule edited inside a history section moves to its topic section with the history section deleted in the same edit (#66).
8
+
9
+ ## v7.14.0 - 2026-10-17
10
+
11
+ ### Added
12
+
13
+ - **`## using-git-worktrees` keys.** The overrides file's `## using-git-worktrees` section accepts `- home: <path pattern>`, `- create: <command>`, and `- destroy: <command>`; `using-git-worktrees` creates there, `finishing-a-development-branch` Step 6 and `gatekeep-pr` cleanup remove only a worktree that matches `home:` and run `destroy:` when set. A section with none of the keys keeps the legacy behavior.
14
+ - **Configuration front door.** `README.md` "Project-specific overrides" lists every overrides-file heading with its reader, default, and extends/overrides relationship, plus the rules the file cannot change; "Configuring the gates" lists every `piGauntlet.*` key with its default. Every skill's `## Project overrides` paragraph points there.
15
+
16
+ ### Changed
17
+
18
+ - **gatekeep-pr `## PR gate` `worktree wrapper:` removed.** Worktree placement for the gate comes from `## using-git-worktrees`; a leftover key is named once and ignored.
19
+
3
20
  ## v7.13.0 - 2026-10-16
4
21
 
5
22
  ### Added
package/README.md CHANGED
@@ -179,7 +179,7 @@ On both harnesses, `gatekeep-pr` uses the same temporary continuation record
179
179
  and action-scoped consent protocol; Claude Code uses native file operations
180
180
  and a checklist when pi's tracker is absent. Native tool permissions still apply.
181
181
  `forge-skill` is the authoring skill for skills, personas, prompt templates,
182
- and slash commands under
182
+ slash commands, and files the repo routes to it under
183
183
  gauntlet's conventions (imperative voice, minimal diff, low conditionality,
184
184
  extraction over 500 lines); Claude Code namespaces plugin skills, so it lists
185
185
  as `/gauntlet:forge-skill` and coexists with the skill-authoring skill of
@@ -290,52 +290,86 @@ exact repo folder* in interactive Claude Code. Trusting a parent folder,
290
290
 
291
291
  ## Project-specific overrides
292
292
 
293
- The skills shipped here are generic on purpose - they describe *how* to TDD, brainstorm, debug, request review, etc., without naming your services, your CI command, or your worktree wrapper. When you need that level of detail, drop a file at `.pi/gauntlet-overrides.md` in your repo. Every active skill reads and applies `## conventions` whenever present in the selected file, without relevance filtering. Use this heading for repo-wide rules that bind more than one skill:
293
+ The gauntlet overrides file is the one place a repo tunes gauntlet's Markdown surface: skills read it as instructions, and `gauntlet-spec-index` reads `## Spec index`. Discovery checks `.pi/gauntlet-overrides.md`, `<repo root>/gauntlet-overrides.md`, then `<repo root>/doc/gauntlet-overrides.md`; first found wins, never merged (`<repo root>` is `git rev-parse --show-toplevel`, or the current directory outside a repo). `## conventions` applies to every skill without a relevance judgment; `## <skill-name>` applies to that skill's steps and wins over conflicting conventions. Missing or empty conventions adds no rules; a lower-priority file cannot supplement the selected file. A repo declares procedure files for `forge-skill` in its `AGENTS.md` (Claude Code: `CLAUDE.md`), not here, because the overrides file is read only after a skill loads - for example `Edits to projects/*/README.md follow /skill:forge-skill`.
294
+
295
+ ### What you can tweak
296
+
297
+ | Heading / key | Read by | Default (absent) | Extends or overrides | Effect |
298
+ |---|---|---|---|---|
299
+ | `## conventions` | every skill | no added rules | extends | repo-wide rules applied without a relevance judgment |
300
+ | `## <skill-name>` (e.g. `## writing-plans`) | that skill | no added rules | overrides the named step | replaces or extends the step it names |
301
+ | `## using-git-worktrees` `- home: <path pattern>` | using-git-worktrees, finishing-a-development-branch, gatekeep-pr | `<primary>/.worktrees/<name>` | overrides | where worktrees live; `<name>` is the branch (`/` -> `-`) or `pr-<N>`; the ownership test at cleanup |
302
+ | `## using-git-worktrees` `- create: <command>` | using-git-worktrees, gatekeep-pr | `git worktree add` at `home:` | overrides | creation command run from the primary; `<name>`, `<branch>` substituted, other `<token>`s resolved from context or asked once |
303
+ | `## using-git-worktrees` `- destroy: <command>` | finishing-a-development-branch, gatekeep-pr | `git worktree remove` + `prune` when the path matches `home:` | overrides | removal command run from the primary; a failure keeps the branch |
304
+ | `## cleanup` items `- <label>: <command or /skill:...>` | gatekeep-pr | git teardown and base sync only | extends | ordered post-gate steps with `<issue>`, `<pr>`, `<merge-sha>`; inherits `## PR gate` `timeout minutes:`; missing placeholders or unlanded-change steps are skipped with a reason; `/skill:` items keep their own gates |
305
+ | `## PR gate` keys (`verification command`, `timeout minutes`, `requires credentials`, `local verification`, `ci checks`, `issue fetch`, `merge policy`) | gatekeep-pr | per-key defaults in the block below | overrides | the gate's verification, evidence, and merge configuration |
306
+ | `## comms style` | gatekeep-pr | shipped wording rules | extends | tone and format of reports, menus, and external payloads |
307
+ | `## verification-before-completion` | verification-before-completion; gatekeep-pr (verification command only); chase-bug (hotfix verification) | repo test entrypoint discovery | overrides | the canonical verification target |
308
+ | `## Spec index` `- docs: <glob>` | `gauntlet-spec-index` bin | `**/doc/**/*.md`, `**/docs/**/*.md`, `README.md`, `AGENTS.md` | overrides | the docs corpus include list; quotes/backticks stripped, fixed exclusions still apply, no other keys read |
309
+ | `## Issue tracker` keys | shape-ticket, linear, chase-bug, check-delivery, brainstorming (`repo:` and tracker selection) | capability ladder / `git remote` | overrides | which tracker, repo, and commands ticket work uses |
310
+ | `## Capabilities` | shape-ticket | tool discovery | extends | tools, commands, env hosts available to ticket authoring |
311
+ | `## Ticket wording` | shape-ticket | the shipped wording contract | overrides | ticket self-containment rules |
312
+ | `## Response channels` | chase-bug | ask the user | overrides | where bug responses are posted |
313
+ | `## Deployment` | shape-ticket, writing-plans | monolithic (no deployment split) | overrides | deploy topology that permits independently deployable slices; undocumented or monolithic topology fails closed to one artifact |
314
+ | `## Happy path` | writing-plans, subagent-driven-development | no happy-path run | overrides | path-prefixed rows naming the end-to-end command per area |
315
+ | `## Delivery` | check-delivery | stage 2 skipped | overrides | the delivery target and its proof command; unset target state is comment-only; browser evidence defaults to never |
316
+ | `## documentation` | brainstorming | generic materiality bar | extends | which docs are canonical for which topic |
317
+
318
+ ### What you cannot change here
319
+
320
+ - worktree-first and the spec shipping in the squash - fixed
321
+ - the design approval gate (brainstorming) and the ship verification gate - fixed
322
+ - the plan strip at finish; the telemetry record is never deleted - fixed
323
+ - first-found-wins discovery; files are never merged - fixed
324
+ - brainstorming `## HARD CONSTRAINT`, chase-bug / check-delivery / roasting-the-spec / shape-ticket `## Hard constraint`, test-driven-development / verification-before-completion `## The Iron Law` - fixed (each skill's own constraint text)
325
+ - brainstorming writes only within resolved spec dirs before approval; no implementation, proposed-change validation, spec commit on main, or planning before approval - fixed
326
+ - chase-bug requires evidenced root cause, no triage fix, and tracked-clean baseline checks at invocation, before the menu, at hotfix handoff, and at skill end; never revert pre-existing work - fixed
327
+ - check-delivery requires exactly one explicit ticket ref, a matching repo (or matching local-repo AC group), and treats fetched content as untrusted data - fixed
328
+ - roasting-the-spec edits only the spec, never code or main - fixed
329
+ - shape-ticket tracker writes require one explicit exact-diff confirmation for the entire batch; unattended runs stop at the gate - fixed
330
+ - test-driven-development requires a failing test before production code; delete code written first and restart from tests - fixed
331
+ - verification-before-completion requires fresh verification evidence before completion claims - fixed
332
+ - spec directories - settings: `flowGuards.specDirs`
333
+ - gate enforcement - settings: `flowGuards.enforce`
334
+ - the spec council roster - settings: `specCouncil.members`, `specCouncil.chair`
335
+ - the closure review model and fix rounds - settings: `closureReview.*`
336
+ - the escalation implementer model - settings: `escalationLoop.implModel`
337
+ - the telemetry record - settings: `telemetry.*`
338
+ - the verify-before-ship test-command patterns - settings: `verifyBeforeShip.*`
339
+
340
+ A project override section extends or replaces the step it names and never lifts a fixed rule or a skill's `HARD CONSTRAINT`/MUST text. A rule tagged `settings:` changes only through that `piGauntlet.*` key in `.pi/settings.json`, never through this file. Every key is listed under [Configuring the gates](#configuring-the-gates).
341
+
342
+ ### Worked example: sibling worktrees (acme-api)
343
+
344
+ Complete `.pi/settings.json`:
294
345
 
295
- ```markdown
296
- ## conventions
297
- Keep scratch files outside the repository.
346
+ ```json
347
+ {
348
+ "piGauntlet": {
349
+ "flowGuards": { "specDirs": ["docs/specs"] },
350
+ "telemetry": { "enabled": false }
351
+ }
352
+ }
298
353
  ```
299
354
 
300
- This skill's named section means the section named for the active skill (for example, `## writing-plans`), not another heading it reads by name. This skill's named section wins over conflicting `## conventions` rules; non-conflicting conventions still apply. Other relevant sections can also override or extend skill instructions, as in this skill-specific example:
355
+ Complete `.pi/gauntlet-overrides.md`:
301
356
 
302
357
  ```markdown
358
+ ## conventions
359
+ Keep scratch files outside the repository.
360
+
303
361
  ## verification-before-completion
304
362
 
305
363
  Canonical verification target: `make ci` per service. Bare `pytest` does NOT satisfy
306
- the gate — it skips integration tests.
307
-
308
- ## using-git-worktrees
309
-
310
- Use the project's wrapper: `script/worktree create <name>`. It provisions an isolated
311
- database and copies `.env.local`. Never call `git worktree add` directly.
312
- ```
313
-
314
- A `## cleanup` section lists what gatekeep-pr runs after a PR is merged, approved, or found already merged or closed, in order, after the implied git teardown (worktree, local branch, base fast-forward):
364
+ the gate - it skips integration tests.
315
365
 
316
- ```markdown
317
- ## cleanup
318
- - close ticket: gh issue close <issue> --comment "Delivered in <pr>, merged <merge-sha>."
319
- - release: /skill:release
320
- ```
321
-
322
- Each item is `<label>: <command or /skill:... invocation>`. Placeholders `<issue>`, `<pr>`, and `<merge-sha>` are filled from the gate's digest; an item whose placeholder has no value is skipped with a reason, and items that need a landed change (`<merge-sha>`, `/skill:release`) are skipped when the PR was only approved or closed. A `/skill:` item keeps its own gates; anything else runs as a shell command in the primary checkout under the PR gate's `timeout minutes`.
323
-
324
- Beyond `## conventions` and skill-named sections, headings a skill reads by name are documented in their owning skills; other headings retain topic/workflow-convention matching. The override file is read by skill instructions and, for its `## Spec index` section only, by `gauntlet-spec-index`; the Pi runtime itself never reads it. Missing or empty `## conventions` adds no rules; a lower-priority file cannot supplement the selected file.
325
-
326
- **Discovery ladder:** skills check three locations, in order, and use the first one found - never merged: `.pi/gauntlet-overrides.md`, then `<repo root>/gauntlet-overrides.md`, then `<repo root>/doc/gauntlet-overrides.md` (`<repo root>` = `git rev-parse --show-toplevel`, or the current directory outside a repo). Pick one location per repo.
327
-
328
- **`## Spec index` section:** `gauntlet-spec-index --corpus docs` reads `- docs: <glob>` bullets under this heading as the docs include list, replacing the default (`**/doc/**/*.md`, `**/docs/**/*.md`, `README.md`, `AGENTS.md`). Backticks or quotes around the glob are stripped; no other key under the heading is read, and the fixed exclusions always apply. For example:
329
-
330
- ```markdown
331
366
  ## Spec index
332
367
  - docs: `**/doc/**/*.md`
333
368
  - docs: `handbook/**/*.md`
334
- ```
335
369
 
336
- **`## Issue tracker` section:** `shape-ticket` resolves tracker access through a capability ladder, and this is its first rung - it overrides the zero-config `gh` (GitHub) / `linearis` (Linear) defaults for any other tracker. Name the CLI's read, search, create, update, and post comment commands explicitly. For a Jira CLI, for example:
370
+ ## using-git-worktrees
371
+ - home: ../acme-api-worktrees/<name>
337
372
 
338
- ```markdown
339
373
  ## Issue tracker
340
374
 
341
375
  Use the `jira` CLI (authenticated via `jira login`), not `gh` or `linearis`.
@@ -345,9 +379,14 @@ Use the `jira` CLI (authenticated via `jira login`), not `gh` or `linearis`.
345
379
  - create: `jira issue create --project ABC --type Task --summary "<title>" --description "<body>"`
346
380
  - update: `jira issue edit ABC-123 --summary "<title>" --description "<body>"`
347
381
  - post comment (approved Reporter note/evidence): `jira issue comment ABC-123 --body "<text>"`
348
- ```
349
382
 
350
- Overlap checking uses only the selected tracker's documented search fields, workflow meanings, and supported mutations. Native Linear body-only recall remains unverified; returned descriptions do not prove body indexing. Disabled or unavailable trackers report discovery not performed and retain manual output. Missing comment support emits the approved text for manual posting and reports it as not performed. Overlap evidence is a gated comment exception even without Reporter-note overflow; when both are needed, they share the one-comment slot with labeled parts.
383
+ ## PR gate
384
+ - verification command: npm test
385
+
386
+ ## cleanup
387
+ - close ticket: jira issue move <issue> Done --comment "Delivered in <pr>, merged <merge-sha>."
388
+ - release: /skill:release
389
+ ```
351
390
 
352
391
  **`linear` setup:** preferred, not required - `linearis` installed and authenticated
353
392
  (or a Linear MCP server as a fallback when `linearis` is missing). Without either, the
@@ -364,17 +403,32 @@ tracker selection; free-form verb mappings keep working both without a `tracker:
364
403
  key (ladder rung 1, as today) and as the mechanics source when `tracker:` names an
365
404
  unknown value.
366
405
 
367
- **`## Deployment` section:** `shape-ticket` (split rule), `writing-plans` (scope check), and `brainstorming` (scope check) read deploy topology from this section: what ships together, what ships independently, and the mechanism. It is a fact to look up, never to infer - when the section is absent, or when it documents a monolithic topology (like the example below), the "separable release timing" split axis is unavailable and splits fail closed to one artifact.
406
+ ### Worked example: wrapper-managed worktrees (acme-mono)
368
407
 
369
- ```markdown
370
- ## Deployment
408
+ Complete `.pi/settings.json`:
371
409
 
372
- One deploy workflow ships the whole system at once - nothing ships independently.
410
+ ```json
411
+ {
412
+ "piGauntlet": {
413
+ "flowGuards": { "specDirs": ["doc/specs"] }
414
+ }
415
+ }
373
416
  ```
374
417
 
375
- **`## Happy path` section:** `writing-plans` selects the row whose `Paths` cover the plan's files and copies it into the plan header's `**Happy path:**` line; `subagent-driven-development` runs it once in the verify phase - after full verification and code review, before the conformance audit - and hands a bounded transcript to the conformance reviewer as runtime evidence. Optional: without the section, or with no matching row, nothing downstream changes.
418
+ Complete `.pi/gauntlet-overrides.md`:
376
419
 
377
420
  ```markdown
421
+ ## using-git-worktrees
422
+ - home: ../acme-mono-<name>
423
+ - create: script/worktree create <name> <subproject> --branch <branch>
424
+ - destroy: script/worktree destroy <name>
425
+
426
+ The wrapper symlinks build/ into the tree; never replace it with a directory.
427
+
428
+ ## Deployment
429
+
430
+ One deploy workflow ships the whole system at once - nothing ships independently.
431
+
378
432
  ## Happy path
379
433
 
380
434
  | Row | Paths | Command | Timeout |
@@ -382,39 +436,7 @@ One deploy workflow ships the whole system at once - nothing ships independently
382
436
  | dashboard | `dashboard/` | `script/e2e-dashboard` | 3m |
383
437
  | excavation | `excavation/` | `cd excavation && make e2e` | 2m |
384
438
  | cross-cutting | `dashboard/`, `excavation/`, `docker-compose.yml`, `Makefile` | `script/e2e-stack` | 5m |
385
- ```
386
439
 
387
- - `Row` is a free label; `cross-cutting` is reserved: it applies when the change matches two or more non-`cross-cutting` rows, or when a path is inside its own `Paths` and inside no other row's `Paths`, and it takes precedence over a single matched row (so root compose files, Makefiles, and lockfiles a stack run depends on select it on their own, while a change inside one project row alone selects that row).
388
- - `Paths` is a comma-separated list of repo-relative prefixes; a path is inside a row when it starts with one of them. Paths matching no row are ignored, both for selection and for the fix-loop re-run test.
389
- - `Command` is repo-relative and runs through `bash -c`, so `cd`, `&&`, and env assignments work. It must be self-contained and worktree-safe: boot what it needs, drive one flow, exit, trap `TERM`/`INT` to tear down (containers are not in the process group, so the script owns their teardown), and write only to gitignored paths or outside the worktree. Two worktrees may run it at the same time; pi-gauntlet does not serialize, and knows nothing about brokers, compose files, or ports.
390
- - `Timeout` is optional, grammar `\d+(s|m|h)`, default `10m`. The parent runs the command under `timeout -k 30s <Timeout>`: `TERM`, then `KILL` after 30s. A malformed cell falls back to the default and the plan header omits the suffix.
391
- - Exit code contract: `0` = passed; `75` (`EX_TEMPFAIL`) = environment unavailable, reported as `not run`; `126` = not executable, reported as `not run`; any other non-zero = failed. A timeout is failed, not `not run`. Residue left in the worktree is failed regardless of exit code.
392
- - Host dependency: GNU `timeout` (`timeout` or `gtimeout` on PATH); absent -> `not run - no timeout binary`.
393
-
394
- **`## Delivery` section:** `check-delivery` resolves its overrides through the same discovery ladder. Defaults are pessimistic where it matters: an unset `target state` keeps the write comment-only; unset `deploy watch`/`delivery target` skip stage 2 (reported, never silently passed); `browser evidence` defaults to never. `check-delivery` is single-ticket by design - sweep/reconciliation passes over many tickets stay consumer territory, invoking the skill once per ticket. The remaining slots have working defaults shown below:
395
-
396
- | Slot | Meaning | Default (unset) |
397
- |---|---|---|
398
- | `target state` | Non-terminal tracker state to advance to on success | none - comment only |
399
- | `deploy watch` | Workflow/command to await before the target check | none |
400
- | `delivery target` | URL / health endpoint / registry query / command + success predicate reflecting the shipped SHA (`<sha>` substituted) | none - stage 2 skipped, reported |
401
- | `timeout` | Upper bound on stage 2 (watch + target check) | 10 minutes when stage 2 runs at all |
402
- | `browser evidence` | When/how to capture UI evidence (requires a browser tool) | never |
403
- | `ref convention` | How commits/PRs reference tickets (e.g. `(ref ABC-123)`) | tracker-native forms (`#N`, `Fixes #N`, bare `ABC-123`) |
404
- | `AC location` | Where ACs live if not the ticket body | ticket body |
405
- | `synthesized AC gaps` | `block` or `soft` - whether an unmet synthesized AC produces a blocking `unexplained gap` or a non-blocking proposal | `soft` |
406
- | `descope edits` | `strikethrough` - on gate approval, strike ratified `proposed descope` AC lines in the ticket body | none - no body edits ever |
407
-
408
- Malformed slot values fail safe, with one warning per invocation naming the
409
- bad value: `synthesized AC gaps` treats anything other than `block`/`soft`
410
- as `soft`; `descope edits` treats anything other than `strikethrough` as
411
- unset (no body edits). `descope edits` also requires a resolved edit-body
412
- write verb: when the slot is active and the approval ratifies a `proposed
413
- descope` but no edit-body verb resolves, the whole batched write (body
414
- edit, evidence comment, status advance) degrades to manual - none
415
- auto-posted.
416
-
417
- ```markdown
418
440
  ## Delivery
419
441
  - target state: Ready
420
442
  - deploy watch: gh run watch --workflow deploy.yml (run for <sha>)
@@ -425,6 +447,10 @@ auto-posted.
425
447
  - descope edits: strikethrough
426
448
  ```
427
449
 
450
+ The Happy path table selects a row by repo-relative path prefix. `cross-cutting` takes precedence when multiple project rows match or only its own paths match. No matching row means no run. Commands run through `bash -c` and must be self-contained, worktree-safe, tear down on `TERM`/`INT`, and leave no residue. Timeout accepts `s`, `m`, or `h` (default `10m`, malformed values fall back); GNU `timeout` or `gtimeout` is required, with `TERM` then `KILL` after 30 seconds. Exit `0` passes; `75` or `126` reports not run; other nonzero exits, timeout, or residue fail.
451
+
452
+ Delivery is single-ticket. `timeout` defaults to 10 minutes when stage 2 runs, `ref convention` to tracker-native forms, `AC location` to the ticket body, `synthesized AC gaps` to `soft`, and `descope edits` to unset. Malformed synthesized-gap values fall back to `soft`; malformed descope values remain unset, with one warning. `descope edits: strikethrough` needs an edit-body verb and gate approval; without the verb, the entire batched write degrades to manual output.
453
+
428
454
  ## REVIEW.md convention
429
455
 
430
456
  `/skill:gatekeep-pr` (the pre-merge gate) reads an optional root-level `REVIEW.md` -
@@ -479,7 +505,6 @@ customization lives in three places, never in the wrapper itself:
479
505
  - requires credentials: false # optional; true => skill reports "not run" as missing evidence
480
506
  - local verification: always # optional; default (absent) = CI-first; "always" forces the local run even when exact-head CI is green
481
507
  - ci checks: <comma-separated check names> # optional; narrows which checks count as evidence; absent = all checks on the assessed head
482
- - worktree wrapper: <command> # optional
483
508
  - issue fetch: <command with <ref> placeholder> # optional, replaces gh issue view
484
509
  - merge policy: squash | merge-commit | rebase # optional; default squash
485
510
  ```
@@ -490,14 +515,32 @@ An existing `## verification-before-completion` overrides section is an accepted
490
515
  equivalent source for the verification command only; all other PR-gate keys
491
516
  still live under `## PR gate`. A `## comms style` section in the same overrides
492
517
  file extends gatekeep-pr's wording rules - the rendered report and menu, and every
493
- external payload (review bodies, replies, tracker comments, commit subjects) alike.
518
+ external payload (review bodies, replies, tracker comments, commit subjects) alike. Worktree placement for the gate is the `## using-git-worktrees` contract above.
494
519
 
495
520
  Anything a wrapper skill contains beyond trigger phrases is misplaced - move it to
496
521
  `REVIEW.md` or the overrides file instead.
497
522
 
498
523
  ## Configuring the gates
499
524
 
500
- The conformance gate's model, the spec council's roster, and the phase-tracker's flow guards are all configured per pi preset (or per repo, via `.pi/settings.json`). See [doc/configuration.md](./doc/configuration.md) for every setting, its default, and how repo-local config overrides a preset.
525
+ The conformance gate's model, the spec council's roster, and the phase-tracker's flow guards are all configured per pi preset (or per repo, via `.pi/settings.json`). Keys below are relative to `piGauntlet`.
526
+
527
+ | Key | Owner (extension) | Default | Effect |
528
+ |---|---|---|---|
529
+ | `specCouncil.members` | phase-tracker (`gauntlet_setting`), roasting-the-spec | `[]` (worker critique) | council models for the spec critique - [detail](./doc/configuration.md#spec-council) |
530
+ | `specCouncil.chair` | same | unset (inherits the main loop) | chair model - [detail](./doc/configuration.md#spec-council) |
531
+ | `closureReview.enforce` | phase-tracker | `true` | conformance gate on/off - [detail](./doc/configuration.md#conformance-gate-model) |
532
+ | `closureReview.model` | phase-tracker | unset (inherits) | conformance reviewer model - [detail](./doc/configuration.md#conformance-gate-model) |
533
+ | `closureReview.maxFixRounds` | phase-tracker | `3` | fix rounds before escalation - [detail](./doc/configuration.md#conformance-gate-model) |
534
+ | `escalationLoop.implModel` | phase-tracker | unset (main loop) | implementer model on escalation - [detail](./doc/configuration.md#escalation-loop) |
535
+ | `flowGuards.enforce` | phase-tracker | `true` | phase gates on/off - [detail](./doc/configuration.md#phase-tracker) |
536
+ | `flowGuards.specDirs` | phase-tracker, plan-tracker; telemetry and spec-index consumers | `["doc/specs", "docs/specs"]` | where specs and sibling plans live - [detail](./doc/configuration.md#phase-tracker) |
537
+ | `verifyBeforeShip.testCommands` | verify-before-ship | the `DEFAULT_TEST_COMMANDS` patterns in `extensions/lib/gauntlet-settings.ts` (make, npm, pnpm, yarn, pytest, rspec, cargo, go) | patterns that count as a test run - [detail](./doc/configuration.md#verify-before-ship) |
538
+ | `verifyBeforeShip.warningReference` | verify-before-ship | unset | pointer shown with the warning - [detail](./doc/configuration.md#verify-before-ship) |
539
+ | `telemetry.enabled` | telemetry | `true` | record each flow - [detail](./doc/configuration.md#telemetry) |
540
+ | `telemetry.dir` | telemetry | `.pi/gauntlet/telemetry` | record location - [detail](./doc/configuration.md#telemetry) |
541
+ | `telemetry.buckets` | telemetry | test / docs / config globs (`DEFAULT_TELEMETRY_BUCKETS`) | file classification - [detail](./doc/configuration.md#telemetry) |
542
+
543
+ For Markdown instructions rather than runtime settings, use [Project-specific overrides](#project-specific-overrides). Repo-local settings replace each configured second-level object wholesale; see the [deep reference](./doc/configuration.md).
501
544
 
502
545
  ## Relationship to the other repos
503
546
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pi-gauntlet",
3
- "version": "7.13.0",
3
+ "version": "7.15.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",
@@ -183,3 +183,5 @@ Redraw: keep the worktree and the approved spec file. `plan_tracker({ action: "c
183
183
  ## Project overrides
184
184
 
185
185
  If a gauntlet overrides file exists - checked in order: `.pi/gauntlet-overrides.md`, `<repo root>/gauntlet-overrides.md`, `<repo root>/doc/gauntlet-overrides.md`; first found wins - read it. Read and apply `## conventions` whenever present, without a relevance judgment. Give this skill's named section precedence over conflicting `## conventions` rules. Use other relevant sections - by name match, by topic (routing, verification, worktrees, etc.), or by workflow convention - to override or extend the instructions above. Project-local `AGENTS.md` is already in context — check it for project-specific routing tables, service paths, and verification commands.
186
+
187
+ The recognized headings, their readers, and the rules an override cannot change are listed in the [configuration front door](../../README.md#project-specific-overrides); an override extends or replaces the step it names and never lifts this skill's HARD CONSTRAINT or MUST text.
@@ -441,3 +441,5 @@ nested resources" (the decision that made it so).
441
441
  ## Project overrides
442
442
 
443
443
  If a gauntlet overrides file exists - checked in order: `.pi/gauntlet-overrides.md`, `<repo root>/gauntlet-overrides.md`, `<repo root>/doc/gauntlet-overrides.md`; first found wins - read it. Read and apply `## conventions` whenever present, without a relevance judgment. Give this skill's named section precedence over conflicting `## conventions` rules. Use other relevant sections - by name match, by topic (routing, verification, worktrees, etc.), or by workflow convention - to override or extend the instructions above. Project-local `AGENTS.md` is already in context - check it for project-specific routing tables, service paths, and verification commands. `## Response channels` and `## Issue tracker` are the named extension points for this skill.
444
+
445
+ The recognized headings, their readers, and the rules an override cannot change are listed in the [configuration front door](../../README.md#project-specific-overrides); an override extends or replaces the step it names and never lifts this skill's HARD CONSTRAINT or MUST text.
@@ -418,3 +418,5 @@ verification, worktrees, etc.), or by workflow convention - to override or
418
418
  extend the instructions above. Project-local `AGENTS.md` is already in
419
419
  context - check it for project-specific routing tables, service paths, and
420
420
  verification commands.
421
+
422
+ The recognized headings, their readers, and the rules an override cannot change are listed in the [configuration front door](../../README.md#project-specific-overrides); an override extends or replaces the step it names and never lifts this skill's HARD CONSTRAINT or MUST text.
@@ -219,3 +219,5 @@ After agents return:
219
219
  ## Project overrides
220
220
 
221
221
  If a gauntlet overrides file exists - checked in order: `.pi/gauntlet-overrides.md`, `<repo root>/gauntlet-overrides.md`, `<repo root>/doc/gauntlet-overrides.md`; first found wins - read it. Read and apply `## conventions` whenever present, without a relevance judgment. Give this skill's named section precedence over conflicting `## conventions` rules. Use other relevant sections - by name match, by topic (routing, verification, worktrees, etc.), or by workflow convention - to override or extend the instructions above. Project-local `AGENTS.md` is already in context — check it for project-specific routing tables, service paths, and verification commands.
222
+
223
+ The recognized headings, their readers, and the rules an override cannot change are listed in the [configuration front door](../../README.md#project-specific-overrides); an override extends or replaces the step it names and never lifts this skill's HARD CONSTRAINT or MUST text.
@@ -320,6 +320,18 @@ If confirmed: Cleanup worktree (Step 6), then, if Step 6 removed the worktree, `
320
320
 
321
321
  **Only runs for the Squash-merge and Discard options (3 and 5).** The PR, draft PR, and Keep options always preserve the worktree.
322
322
 
323
+ Read the gauntlet overrides file now (ladder in Project overrides) and its `## using-git-worktrees` section; nothing from creation time is carried - the file is the contract (keys written like `## cleanup` items: `using-git-worktrees/SKILL.md` Step 1a).
324
+
325
+ **Keyed contract** - the section has at least one of `- home:`, `- create:`, `- destroy:`:
326
+
327
+ 1. Resolve `home:` against `$PRIMARY` (absent -> `$PRIMARY/.worktrees/<name>`; an absolute value is used as-is). `<name>` must appear exactly once, inside one path segment that may carry a literal prefix or suffix; otherwise stop and name the line.
328
+ 2. Ownership match: canonicalize both sides (`realpath`) and compare `$WORKTREE` to the resolved pattern, treating the `<name>` segment as `<prefix>*<suffix>` where `*` matches the remainder of that one segment. The text `*` matched is `NAME` - the creation identifier (`jacek/fix-x` was created as `jacek-fix-x`; `home: ../acme-mono-<name>` recovers `fix-x` from `acme-mono-fix-x`). A pattern that cannot isolate one segment -> stop and report.
329
+ 3. Match and `destroy:` set -> run it from `$PRIMARY` with `<name>` -> `'NAME'` and `<branch>` -> `'$FEATURE'`, each value one single-quoted shell word (`'...'`, an embedded `'` escaped), any other `<token>` resolved from context or asked once, never executed raw. Non-zero exit -> print its output, keep the branch, end this step; never fall back to `git worktree remove --force`. On success, run no `git worktree remove` or `prune`; continue to `git -C "$PRIMARY" branch -D "$FEATURE"`.
330
+ 4. Match and no `destroy:` -> `git -C "$PRIMARY" worktree remove "$WORKTREE"` then `git -C "$PRIMARY" worktree prune`; after success, continue to `git -C "$PRIMARY" branch -D "$FEATURE"`.
331
+ 5. No match -> the host environment owns this workspace: remove nothing, skip the branch deletion that follows, report that the host-owned worktree still holds `$FEATURE`.
332
+
333
+ **Legacy path** - no overrides file, no section, or a keyless section:
334
+
323
335
  **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##*/}"`.
324
336
 
325
337
  **If `$WORKTREE` is under `$PRIMARY/.worktrees/` or `~/.worktrees/<project>/`:** gauntlet created it - we own cleanup:
@@ -343,7 +355,7 @@ Removal precedes branch deletion in both options; `git branch -d`/`-D` fails whi
343
355
  | 4. Keep as-is | - | - | yes | - | - |
344
356
  | 5. Discard | - | - | - | yes (force, after Step 6 removal) | - |
345
357
 
346
- A host-owned worktree (Step 6 "Otherwise") keeps both the worktree and the branch.
358
+ A host-owned worktree (Step 6: no `home:` match, or the legacy "Otherwise") keeps both the worktree and the branch.
347
359
 
348
360
  ## Common Mistakes
349
361
 
@@ -369,7 +381,7 @@ A host-owned worktree (Step 6 "Otherwise") keeps both the worktree and the branc
369
381
 
370
382
  **Cleaning up harness-owned worktrees**
371
383
  - **Problem:** Removing a worktree the harness created causes phantom state
372
- - **Fix:** Only clean up worktrees under `.worktrees/`, `~/.worktrees/<project>/`, or paths produced by a project-native worktree script
384
+ - **Fix:** Only clean up worktrees that match the `home:` pattern of `## using-git-worktrees`, or - on the legacy path - under `.worktrees/`, `~/.worktrees/<project>/`, or paths produced by a project-native worktree script
373
385
 
374
386
  **No confirmation for discard**
375
387
  - **Problem:** Accidentally delete work
@@ -402,6 +414,7 @@ Once the merge (and any deploy) has landed, `/skill:check-delivery <ticket-ref>`
402
414
  - Force-push without explicit request
403
415
  - Remove a worktree before confirming merge success
404
416
  - Clean up worktrees you didn't create (provenance check)
417
+ - Retry a failed `destroy:` with `git worktree remove --force`
405
418
  - Run any step without the `<worktree-path>` argument
406
419
  - Auto-proceed past an undispositioned carried-open gap
407
420
  - Skip the strip-and-seal block before the Option 3 squash or the Option 1/2 push
@@ -416,8 +429,11 @@ Once the merge (and any deploy) has landed, `/skill:check-delivery <ticket-ref>`
416
429
  - Clean up worktree for Options 3 & 5 (Squash-merge, Discard) only
417
430
  - Target `$PRIMARY` with `git -C` for merge, worktree removal, and branch deletion
418
431
  - Run `git -C "$PRIMARY" worktree prune` after removal
432
+ - Match `$WORKTREE` against the `home:` pattern of `## using-git-worktrees` before removing anything when the keyed contract is active
419
433
  - Surface the closure / conformance verdict as its own section before the options menu
420
434
 
421
435
  ## Project overrides
422
436
 
423
437
  If a gauntlet overrides file exists - checked in order: `.pi/gauntlet-overrides.md`, `<repo root>/gauntlet-overrides.md`, `<repo root>/doc/gauntlet-overrides.md`; first found wins - read it. Read and apply `## conventions` whenever present, without a relevance judgment. Give this skill's named section precedence over conflicting `## conventions` rules. Use other relevant sections - by name match, by topic (routing, verification, worktrees, etc.), or by workflow convention - to override or extend the instructions above. Project-local `AGENTS.md` is already in context — check it for project-specific routing tables, service paths, and verification commands.
438
+
439
+ The recognized headings, their readers, and the rules an override cannot change are listed in the [configuration front door](../../README.md#project-specific-overrides); an override extends or replaces the step it names and never lifts this skill's HARD CONSTRAINT or MUST text.
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: forge-skill
3
- description: Use when creating or editing a SKILL.md, a skill's reference file, an agent persona, a prompt template, or a slash command in pi or Claude Code - including one-line edits - or when such a file exceeds 500 lines, gains if/else branching, or drifts from imperative voice; the authoring skill for repos that follow gauntlet's conventions.
3
+ description: Use when creating or editing a SKILL.md, a skill's reference file, an agent persona, a prompt template, a slash command, or a file the repo's AGENTS.md or CLAUDE.md routes here, in pi or Claude Code - including one-line edits - or when such a file exceeds 500 lines, gains if/else branching, or drifts from imperative voice; the authoring skill for repos that follow gauntlet's conventions.
4
4
  ---
5
5
 
6
6
  # Forge Skill
@@ -35,6 +35,7 @@ These rules bind the lines an edit adds or changes. Leave other lines alone.
35
35
  - Imperative voice. Write instructions as commands. Never "should", "consider", "you may want to", "it is recommended".
36
36
  - Low conditionality. One path per step: branch only on a runtime fact the model can observe - a tool result, a file's presence, a settings value - never on the reader's judgment. Two branches is the ceiling; a third goes into a table, or for a skill a reference/ file.
37
37
  - Minimal diff. A rule change touches the sentence that owns the rule, not the section. Never restate a rule in a second place; link the owner.
38
+ - No history. An instruction file states current rules only: an added or changed line carries no date, no "previously"/"formerly"/"as of" clause, and no narration of a rule's past - that goes to the commit body, the ticket, or the spec; a one-clause operational reason stays, and a date that is itself a rule (a freeze window) stays. The one exception to Minimal diff and to "Leave other lines alone": an edit that changes a rule inside a changelog, a dated-entry list, or a "previously" section moves that section's surviving rules into the section that owns their topic and deletes the history section in the same edit; a history section the edit does not touch stays. Example: `2025-03-02: builds now use the release profile because debug ran out of memory` under `## History` becomes `Build with the release profile (debug runs out of memory)` under `## Deploy`, and `## History` is deleted.
38
39
  - Skills only: Oversized file. A change touching a file over 500 lines extracts the concern it touches - or the largest self-contained `##` section - into `reference/<topic>.md` in the same change, and leaves a one-line "read X now" pointer at the step that needs it.
39
40
  - Recipe over prohibition. A shape or quality problem gets a statement of what the output is; a discipline problem gets one explicit rule. Never a list of things to avoid.
40
41
  - No nuance clauses. "Unless it matters", "when appropriate", "if needed" reopen the decision; delete them or name the observable condition.
@@ -59,7 +60,7 @@ A persona is an `agents/<name>.md` file dispatched by name (pi-cohort `subagent(
59
60
  ## Edit procedure
60
61
 
61
62
  1. Read the whole file.
62
- 2. Locate and edit the sentence that owns the rule you are changing (see Minimal diff).
63
+ 2. Locate and edit the sentence that owns the rule you are changing (see Minimal diff; under No history, the history section it sits in).
63
64
  3. Read the changed lines back against `## Authoring rules`.
64
65
  4. Run wc -l; over 500 lines, a skill extracts per the oversized-file rule, a persona splits by job.
65
66
  5. Skill, pi: run /reload. Persona, pi: nothing. Claude Code: start a new session.
@@ -81,3 +82,5 @@ Run after adding a rule or rewording a discipline rule.
81
82
  ## Project overrides
82
83
 
83
84
  If a gauntlet overrides file exists - checked in order: `.pi/gauntlet-overrides.md`, `<repo root>/gauntlet-overrides.md`, `<repo root>/doc/gauntlet-overrides.md`; first found wins - read it. Read and apply `## conventions` whenever present, without a relevance judgment. Give this skill's named section precedence over conflicting `## conventions` rules. Use other relevant sections - by name match, by topic (routing, verification, worktrees, etc.), or by workflow convention - to override or extend the instructions above. Project-local `AGENTS.md` is already in context - check it for project-specific routing tables, service paths, and verification commands.
85
+
86
+ The recognized headings, their readers, and the rules an override cannot change are listed in the [configuration front door](../../README.md#project-specific-overrides); an override extends or replaces the step it names and never lifts this skill's HARD CONSTRAINT or MUST text.
@@ -76,3 +76,5 @@ These bind every rendered report, menu, and external payload (review bodies, rep
76
76
  ## Project overrides
77
77
 
78
78
  If a gauntlet overrides file exists - checked in order: `.pi/gauntlet-overrides.md`, `<repo root>/gauntlet-overrides.md`, `<repo root>/doc/gauntlet-overrides.md`; first found wins - read it. Read and apply `## conventions` whenever present, without a relevance judgment. Give this skill's named section precedence over conflicting `## conventions` rules. Use other relevant sections - by name match, by topic (routing, verification, worktrees, etc.), or by workflow convention - to override or extend the instructions above. Project-local `AGENTS.md` is already in context - check it for project-specific routing tables, service paths, and verification commands. `## PR gate` keys are read in step 2 (`reference/assessment.md`); `## comms style` extends the wording rules. `## cleanup` steps run on the `cleanup` pick (`reference/cleanup.md`).
79
+
80
+ The recognized headings, their readers, and the rules an override cannot change are listed in the [configuration front door](../../README.md#project-specific-overrides); an override extends or replaces the step it names and never lifts this skill's HARD CONSTRAINT or MUST text.
@@ -8,9 +8,11 @@ Read from SKILL.md step 2. Input: the step-1 digest. Output: a provisioned workt
8
8
  |---|---|---|---|
9
9
  | A worktree exists on the expected branch (`headRefName` for in-repo PRs, a fork-local `pr-<N>` branch for fork PRs), at any path | Reuse unconditionally; sync with `git fetch origin` + `git pull --ff-only` (the local branch tracks `origin/<headRefName>`) | Reuse unconditionally; the local `pr-<N>` branch has no upstream - sync with `git fetch origin pull/<N>/head` + `git merge --ff-only FETCH_HEAD` | STOP and surface on divergence, dirt, or local-only commits; never force, never create a duplicate |
10
10
  | The default path `.worktrees/pr-<N>` exists but holds a different branch | STOP and surface; never repurpose | STOP and surface; never repurpose | - |
11
- | Nothing exists (an overrides worktree wrapper can relocate it, following `using-git-worktrees` conventions, gitignore-first) | Create at `.worktrees/pr-<N>`; `git fetch origin` + `git worktree add .worktrees/pr-<N> <headRefName>`; verify post-checkout that HEAD == the digest's `headRefOid` | Create at `.worktrees/pr-<N>`; `git fetch origin pull/<N>/head:pr-<N>` first, then add on that local branch; verify post-checkout that HEAD == the digest's `headRefOid` | - |
11
+ | Nothing exists | `git fetch origin`, then create on `headRefName`: keyed contract -> `create:` when set with `<name>` = `pr-<N>`, `<branch>` = `headRefName`, never `-b`, else `git worktree add "<home>" <headRefName>`; no section or keyless -> `git worktree add .worktrees/pr-<N> <headRefName>`; verify post-checkout that HEAD == the digest's `headRefOid` | `git fetch origin pull/<N>/head:pr-<N>` first, then create on the local `pr-<N>` branch: keyed contract -> `create:` when set with `<name>` = `<branch>` = `pr-<N>`, else `git worktree add "<home>" pr-<N>`; no section or keyless -> `git worktree add .worktrees/pr-<N> pr-<N>`; verify post-checkout that HEAD == the digest's `headRefOid` | - |
12
12
 
13
- Record the digest's `worktree` block (`../verification-brief.md`): `path`, `branch` (the actual local branch - `headRefName`, `pr-<N>`, or whatever a wrapper created), `created` (true when this run created it), and `destroy` (the exact destroy invocation when a `worktree wrapper` created it, else null). `cleanup.md` reads it; `post-selection-loop.md` `### Teardown` points there.
13
+ **Keyed contract.** The merge-base overrides file's `## using-git-worktrees` section (read like `## PR gate`, `## Configuration` below) with at least one of `- home:`, `- create:`, `- destroy:` is the keyed contract; its grammar is `using-git-worktrees/SKILL.md` Step 1a. The worktree path is `home:` resolved against the primary with `<name>` -> `pr-<N>` (absent -> `.worktrees/pr-<N>`). `create:` runs from the primary with every resolved token one single-quoted shell word (`'...'`, an embedded `'` escaped; an unresolved `<token>` is never executed) and replaces only the add command above; the fetch, the unconditional reuse row, the divergence stops, and the HEAD check are unchanged. A `create:` that exits non-zero STOPs with the command's output; never fall back to `git worktree add`. A `create:` with a `<token>` the PR context cannot resolve (the one top-level directory the PR's files touch, for `<subproject>`) asks once. Before the built-in add (keyed with `home:` only, or the legacy `.worktrees/pr-<N>` fallback), gitignore the home's parent directory first when the resolved home is inside the primary, following `using-git-worktrees/SKILL.md` Step 2b; a sibling home needs no gitignore edit. After creation, `git worktree list --porcelain` must list the resolved path; otherwise STOP and surface the mismatch. A legacy `worktree wrapper:` line under `## PR gate` is named once in the report as unrecognized and ignored. No section or a keyless section: the legacy behavior above, including a wrapper `## Configuration` rung 3 discovers from `AGENTS.md`.
14
+
15
+ Record the digest's `worktree` block (`../verification-brief.md`): `path` (the worktree actually selected - the resolved `home:` when this run created it, a reused tree's real path otherwise), `branch` (the actual local branch - `headRefName`, `pr-<N>`, or whatever a wrapper created), `created` (true when this run created it), and `destroy` (under the keyed contract, `destroy:` substituted with the identifier the ownership match in `../../finishing-a-development-branch/SKILL.md` Step 6 recovers from `path`, null when there is no `destroy:` or no match; under the legacy path, the wrapper's exact destroy invocation when one created it, else null). `cleanup.md` reads it; `post-selection-loop.md` `### Teardown` points there.
14
16
 
15
17
  Then set the digest's `permissions.head_pushable` (`../verification-brief.md` Section A): `git -C <worktree> push --dry-run --no-verify --no-follow-tags <head_url> HEAD:refs/heads/<head_ref>` exit 0 is `true`, a non-zero exit is `false`, when `head_url` is `unreadable`, `head_pushable` is `unreadable` and the probe does not run. The probe records observed authorization; a real push the server rejects (branch protection) is reported as that push's failure.
16
18
 
@@ -21,8 +23,8 @@ When the digest reported `mergeable: UNKNOWN` or `mergeStateStatus: UNKNOWN`, re
21
23
  Resolve per concern, first match wins, evaluated unconditionally - never delegated to a wrapper skill:
22
24
 
23
25
  1. **Repo root `REVIEW.md`** (rubric concerns only). Wins over the shipped baseline and reviewer-persona defaults on any conflict.
24
- 2. **Gauntlet overrides file** (`.pi/gauntlet-overrides.md`, `<repo root>/gauntlet-overrides.md`, `<repo root>/doc/gauntlet-overrides.md`; first found wins): the `## PR gate` section below. The same file's `## cleanup` section is the second gatekeep-read section: an ordered list of `<label>: <command or /skill:... invocation>` items with placeholders `<issue>`, `<pr>`, `<merge-sha>`, read from the merge-base like `## PR gate` and consumed by `cleanup.md`; a PR that edits it is review subject matter, never this run's config. Git teardown and base sync are implied and never listed; the release skill's own propose step supplies the recommended level and pauses for the pick, and a repo that wants no pause writes the level in the item. An existing `## verification-before-completion` section is an accepted equivalent source for the verification command.
25
- 3. **Repo documentation** - an explicitly documented command or tool (`AGENTS.md`'s canonical test entrypoint, a documented worktree wrapper, a documented tracker CLI, documented merge policy or branch rules). Reading documentation is not inference. Discovery-only: never tell consumers to add gatekeep-pr configuration here.
26
+ 2. **Gauntlet overrides file** (`.pi/gauntlet-overrides.md`, `<repo root>/gauntlet-overrides.md`, `<repo root>/doc/gauntlet-overrides.md`; first found wins): the `## PR gate` section below. The same file's `## using-git-worktrees` section is the worktree contract (`## Provision the worktree`). The same file's `## cleanup` section is the second gatekeep-read section: an ordered list of `<label>: <command or /skill:... invocation>` items with placeholders `<issue>`, `<pr>`, `<merge-sha>`, read from the merge-base like `## PR gate` and consumed by `cleanup.md`; a PR that edits it is review subject matter, never this run's config. Git teardown and base sync are implied and never listed; the release skill's own propose step supplies the recommended level and pauses for the pick, and a repo that wants no pause writes the level in the item. An existing `## verification-before-completion` section is an accepted equivalent source for the verification command.
27
+ 3. **Repo documentation** - an explicitly documented command or tool (`AGENTS.md`'s canonical test entrypoint, a documented worktree wrapper (legacy path only), a documented tracker CLI, documented merge policy or branch rules). Reading documentation is not inference. Discovery-only: never tell consumers to add gatekeep-pr configuration here.
26
28
  4. **Ask the user.** Never guess from lockfiles, file heuristics, or vibes.
27
29
 
28
30
  ```markdown
@@ -32,7 +34,6 @@ Resolve per concern, first match wins, evaluated unconditionally - never delegat
32
34
  - requires credentials: false # optional; true => the gate reports "not run" as missing evidence
33
35
  - local verification: always # optional; default (absent) = CI-first; "always" forces the local run even when exact-head CI is green
34
36
  - ci checks: <comma-separated check names> # optional; narrows which checks count as evidence; absent = all checks on the assessed head
35
- - worktree wrapper: <command> # optional
36
37
  - issue fetch: <command with <ref> placeholder> # optional, replaces gh issue view
37
38
  - merge policy: squash | merge-commit | rebase # optional; default squash
38
39
  ```
@@ -6,8 +6,8 @@ Read from `decision-menu.md` when `cleanup` is picked on a terminal overlay. Inp
6
6
 
7
7
  Run the steps in order; a failing step prints its first error line and the loop continues; retry nothing.
8
8
 
9
- 1. **Worktree.** Eligible when `worktree.path` is not the primary, `git -C <worktree.path> status --porcelain --untracked-files=no` is empty (tracked-clean; untracked files never block removal), and - when landed - `git -C <worktree.path> log origin/<baseRefName>..HEAD` shows no commit outside the assessed head's history (`git -C <worktree.path> merge-base --is-ancestor HEAD <headRefOid>` succeeds). Eligible and (`worktree.created` or landed) -> run `worktree.destroy` when recorded, else `git worktree remove --force <worktree.path>` (the single `--force` removes a tree whose only dirt is untracked files; those files are deleted); then `git worktree prune`; print `worktree: done`. Reused and not landed -> `worktree: skipped - reused, left at <path>`. Dirty -> `worktree: skipped - uncommitted changes at <path>`. Commits beyond the assessed head -> `worktree: skipped - unmerged commits <shas> at <path>`. Under `approved` on a `rebased locally` head this step reports `unmerged commits` and leaves the tree, and `stop` leaves the rewritten local head in place and names it.
10
- 2. **Branch.** Landed, the branch exists locally, and no worktree holds it (`git worktree list --porcelain` lists no `branch refs/heads/<worktree.branch>`) -> `git branch -D <worktree.branch>`; print `branch: done`. Not landed -> `branch: skipped - PR not merged`. Still checked out -> `branch: skipped - checked out at <path>`. Never delete a remote branch.
9
+ 1. **Worktree.** Eligible when `worktree.path` is not the primary, `git -C <worktree.path> status --porcelain --untracked-files=no` is empty (tracked-clean; untracked files never block removal), and - when landed - `git -C <worktree.path> log origin/<baseRefName>..HEAD` shows no commit outside the assessed head's history (`git -C <worktree.path> merge-base --is-ancestor HEAD <headRefOid>` succeeds). When the merge-base `## using-git-worktrees` section has at least one of `- home:`, `- create:`, `- destroy:` (the keyed contract), eligibility also requires the ownership match of `../../finishing-a-development-branch/SKILL.md` Step 6 (the recorded `worktree.destroy` already carries the recovered identifier): `home:` resolved against `$PRIMARY` (absent -> `.worktrees/<name>`), the `<name>` segment matched as `<prefix>*<suffix>` within one segment (`../acme-mono-<name>` against `/work/acme-mono-fix-x` recovers `fix-x`), `$WORKTREE` (the digest `worktree.path`) and the pattern both through `realpath`; an ambiguous match stops; no match -> `worktree: skipped - outside configured home, left at <path>` and the branch step reports it still checked out. Eligible and (`worktree.created` or landed) -> run `worktree.destroy` when recorded (from the primary; a non-zero exit prints `worktree: failed - <its output>`, keeps the branch (the branch step reports it still checked out), and never falls back to a forced removal), else `git worktree remove --force <worktree.path>` (the single `--force` removes a tree whose only dirt is untracked files; those files are deleted); then `git worktree prune`; print `worktree: done`. Reused and not landed -> `worktree: skipped - reused, left at <path>`. Dirty -> `worktree: skipped - uncommitted changes at <path>`. Commits beyond the assessed head -> `worktree: skipped - unmerged commits <shas> at <path>`. Under `approved` on a `rebased locally` head this step reports `unmerged commits` and leaves the tree, and `stop` leaves the rewritten local head in place and names it.
10
+ 2. **Branch.** A non-zero `worktree.destroy` exit in step 1 -> `branch: skipped - worktree destroy failed`, whatever `git worktree list` shows. Landed, the branch exists locally, and no worktree holds it (`git worktree list --porcelain` lists no `branch refs/heads/<worktree.branch>`) -> `git branch -D <worktree.branch>`; print `branch: done`. Not landed -> `branch: skipped - PR not merged`. Still checked out -> `branch: skipped - checked out at <path>`. Never delete a remote branch.
11
11
  3. **Base.** Landed, the primary is on `<baseRefName>`, and its tree is tracked-clean -> `git fetch origin` then `git pull --ff-only`; print `base: synced <sha>` when `git merge-base --is-ancestor <pr.merge_commit> HEAD` succeeds, else `base: failed - merge commit not on local <baseRefName>`. Primary on another branch -> `base: skipped - primary on <branch>`; dirty -> `base: skipped - uncommitted changes`; not landed -> `base: skipped - PR not merged`. Never switch the primary's branch.
12
12
  4. **Override steps**, one per `## cleanup` item in list order. An item is `<label>: <text>`; any other shape -> `skipped - malformed item: <text>`.
13
13
  - Landed-change guard first: not landed and the text contains `<merge-sha>` or `/skill:release` -> `skipped - needs a landed change`. The guard decides before any placeholder is read, so an item it skips never prints a `no <name> resolved` line, whatever its placeholders hold. A `/skill:release` item when step 3 did not print `synced` -> `skipped - base not synced`.
@@ -81,7 +81,7 @@ provisioning, so it never re-reads; step 2 re-reads once after provisioning (`re
81
81
  - issue_ref: <ref> | null
82
82
  - issue: null # shape and fill: step 2, reference/assessment.md ## Fetch the ticket
83
83
  - worktree_discovery: { expected_path, exists, branch, dirty, ahead, behind }
84
- - worktree: { path, branch, created, destroy } # filled in step 2, reference/assessment.md: worktree.path; worktree.branch is the actual local branch (headRefName, pr-<N>, or whatever a worktree wrapper created); worktree.created is true when this run created it; worktree.destroy is the wrapper's exact destroy invocation, else null
84
+ - worktree: { path, branch, created, destroy } # filled in step 2, reference/assessment.md: worktree.path; worktree.branch is the actual local branch (headRefName, pr-<N>, or whatever a worktree wrapper created); worktree.created is true when this run created it; worktree.destroy is the substituted ## using-git-worktrees destroy: command, else a legacy wrapper's exact destroy invocation, else null
85
85
  - sync: <record> # only with --rebase; grammar: reference/sync.md ## Sync record
86
86
  - truncation_notes: []
87
87
  ```
@@ -115,3 +115,5 @@ verification, worktrees, etc.), or by workflow convention - to override or
115
115
  extend the instructions above. Project-local `AGENTS.md` is already in
116
116
  context - check it for project-specific routing tables, service paths, and
117
117
  verification commands.
118
+
119
+ The recognized headings, their readers, and the rules an override cannot change are listed in the [configuration front door](../../README.md#project-specific-overrides); an override extends or replaces the step it names and never lifts this skill's HARD CONSTRAINT or MUST text.
@@ -46,3 +46,5 @@ verification, worktrees, etc.), or by workflow convention - to override or
46
46
  extend the instructions above. Project-local `AGENTS.md` is already in
47
47
  context - check it for project-specific routing tables, service paths, and
48
48
  verification commands.
49
+
50
+ The recognized headings, their readers, and the rules an override cannot change are listed in the [configuration front door](../../README.md#project-specific-overrides); an override extends or replaces the step it names and never lifts this skill's HARD CONSTRAINT or MUST text.
@@ -166,3 +166,5 @@ verification, worktrees, etc.), or by workflow convention - to override or
166
166
  extend the instructions above. Project-local `AGENTS.md` is already in
167
167
  context - check it for project-specific routing tables, service paths, and
168
168
  verification commands.
169
+
170
+ The recognized headings, their readers, and the rules an override cannot change are listed in the [configuration front door](../../README.md#project-specific-overrides); an override extends or replaces the step it names and never lifts this skill's HARD CONSTRAINT or MUST text.
@@ -259,3 +259,5 @@ for product behavior the CLI doesn't expose.
259
259
  ## Project overrides
260
260
 
261
261
  If a gauntlet overrides file exists - checked in order: `.pi/gauntlet-overrides.md`, `<repo root>/gauntlet-overrides.md`, `<repo root>/doc/gauntlet-overrides.md`; first found wins - read it. Read and apply `## conventions` whenever present, without a relevance judgment. Give this skill's named section precedence over conflicting `## conventions` rules. Use other relevant sections - by name match, by topic (routing, verification, worktrees, etc.), or by workflow convention - to override or extend the instructions above. Project-local `AGENTS.md` is already in context - check it for project-specific routing tables, service paths, and verification commands. `## Issue tracker` is the named extension point for this skill.
262
+
263
+ The recognized headings, their readers, and the rules an override cannot change are listed in the [configuration front door](../../README.md#project-specific-overrides); an override extends or replaces the step it names and never lifts this skill's HARD CONSTRAINT or MUST text.
@@ -178,3 +178,5 @@ No performative agreement. Technical rigor always.
178
178
  ## Project overrides
179
179
 
180
180
  If a gauntlet overrides file exists - checked in order: `.pi/gauntlet-overrides.md`, `<repo root>/gauntlet-overrides.md`, `<repo root>/doc/gauntlet-overrides.md`; first found wins - read it. Read and apply `## conventions` whenever present, without a relevance judgment. Give this skill's named section precedence over conflicting `## conventions` rules. Use other relevant sections - by name match, by topic (routing, verification, worktrees, etc.), or by workflow convention - to override or extend the instructions above. Project-local `AGENTS.md` is already in context — check it for project-specific routing tables, service paths, and verification commands.
181
+
182
+ The recognized headings, their readers, and the rules an override cannot change are listed in the [configuration front door](../../README.md#project-specific-overrides); an override extends or replaces the step it names and never lifts this skill's HARD CONSTRAINT or MUST text.
@@ -81,3 +81,5 @@ See template at: `code-reviewer.md` in this skill directory
81
81
  ## Project overrides
82
82
 
83
83
  If a gauntlet overrides file exists - checked in order: `.pi/gauntlet-overrides.md`, `<repo root>/gauntlet-overrides.md`, `<repo root>/doc/gauntlet-overrides.md`; first found wins - read it. Read and apply `## conventions` whenever present, without a relevance judgment. Give this skill's named section precedence over conflicting `## conventions` rules. Use other relevant sections - by name match, by topic (routing, verification, worktrees, etc.), or by workflow convention - to override or extend the instructions above. Project-local `AGENTS.md` is already in context — check it for project-specific routing tables, service paths, and verification commands.
84
+
85
+ The recognized headings, their readers, and the rules an override cannot change are listed in the [configuration front door](../../README.md#project-specific-overrides); an override extends or replaces the step it names and never lifts this skill's HARD CONSTRAINT or MUST text.
@@ -160,3 +160,5 @@ Single pass — no automatic re-roast loop. The user can invoke this skill again
160
160
  ## Project overrides
161
161
 
162
162
  If a gauntlet overrides file exists - checked in order: `.pi/gauntlet-overrides.md`, `<repo root>/gauntlet-overrides.md`, `<repo root>/doc/gauntlet-overrides.md`; first found wins - read it. Read and apply `## conventions` whenever present, without a relevance judgment. Give this skill's named section precedence over conflicting `## conventions` rules. Use other relevant sections - by name match, by topic (routing, verification, worktrees, etc.), or by workflow convention - to override or extend the instructions above. Project-local `AGENTS.md` is already in context — check it for project-specific routing tables, service paths, and verification commands.
163
+
164
+ The recognized headings, their readers, and the rules an override cannot change are listed in the [configuration front door](../../README.md#project-specific-overrides); an override extends or replaces the step it names and never lifts this skill's HARD CONSTRAINT or MUST text.
@@ -325,3 +325,5 @@ Read this when applying the AC integrity gate (drafting, repairing, or adjudicat
325
325
  ## Project overrides
326
326
 
327
327
  If a gauntlet overrides file exists - checked in order: `.pi/gauntlet-overrides.md`, `<repo root>/gauntlet-overrides.md`, `<repo root>/doc/gauntlet-overrides.md`; first found wins - read it. Read and apply `## conventions` whenever present, without a relevance judgment. Give this skill's named section precedence over conflicting `## conventions` rules. Use other relevant sections - by name match, by topic (routing, verification, worktrees, etc.), or by workflow convention - to override or extend the instructions above. Project-local `AGENTS.md` is already in context - check it for project-specific routing tables, service paths, and verification commands.
328
+
329
+ The recognized headings, their readers, and the rules an override cannot change are listed in the [configuration front door](../../README.md#project-specific-overrides); an override extends or replaces the step it names and never lifts this skill's HARD CONSTRAINT or MUST text.
@@ -319,3 +319,5 @@ For the fan-out + worktree + patch-integration + conflict mechanics, see `dispat
319
319
  ## Project overrides
320
320
 
321
321
  If a gauntlet overrides file exists - checked in order: `.pi/gauntlet-overrides.md`, `<repo root>/gauntlet-overrides.md`, `<repo root>/doc/gauntlet-overrides.md`; first found wins - read it. Read and apply `## conventions` whenever present, without a relevance judgment. Give this skill's named section precedence over conflicting `## conventions` rules. Use other relevant sections - by name match, by topic (routing, verification, worktrees, etc.), or by workflow convention - to override or extend the instructions above. Project-local `AGENTS.md` is already in context — check it for project-specific routing tables, service paths, and verification commands.
322
+
323
+ The recognized headings, their readers, and the rules an override cannot change are listed in the [configuration front door](../../README.md#project-specific-overrides); an override extends or replaces the step it names and never lifts this skill's HARD CONSTRAINT or MUST text.
@@ -237,3 +237,5 @@ phase_tracker({ action: "complete", phase: "implement" })
237
237
  ## Project overrides
238
238
 
239
239
  If a gauntlet overrides file exists - checked in order: `.pi/gauntlet-overrides.md`, `<repo root>/gauntlet-overrides.md`, `<repo root>/doc/gauntlet-overrides.md`; first found wins - read it. Read and apply `## conventions` whenever present, without a relevance judgment. Give this skill's named section precedence over conflicting `## conventions` rules. Use other relevant sections - by name match, by topic (routing, verification, worktrees, etc.), or by workflow convention - to override or extend the instructions above. Project-local `AGENTS.md` is already in context — check it for project-specific routing tables, service paths, and verification commands.
240
+
241
+ The recognized headings, their readers, and the rules an override cannot change are listed in the [configuration front door](../../README.md#project-specific-overrides); an override extends or replaces the step it names and never lifts this skill's HARD CONSTRAINT or MUST text.
@@ -55,7 +55,30 @@ Pause for explicit consent **only** when one of these holds:
55
55
 
56
56
  Otherwise create it. The gate is "is this real work?", not "did the user approve this worktree?"
57
57
 
58
- ## Step 1a — Prefer Native Worktree Tools
58
+ ## Step 1a - Read the `## using-git-worktrees` contract
59
+
60
+ Read the gauntlet overrides file (ladder in Project overrides) before any tool or wrapper discovery. Its `## using-git-worktrees` section carries up to three key lines, written like `## cleanup` items; prose before, between, or after them is instruction too:
61
+
62
+ | Key | Meaning | Absent (keyed contract active) |
63
+ |---|---|---|
64
+ | `- home: <path pattern>` | Where this repo's worktrees live, relative to the primary checkout (an absolute path is used as-is). `<name>` substitutes and must appear exactly once, inside one path segment that may carry a literal prefix or suffix (`../acme-mono-<name>`). Ownership test for finishing Step 6 and gatekeep cleanup. | `<primary>/.worktrees/<name>` |
65
+ | `- create: <command>` | Shell command run from the primary with `<name>` and `<branch>` substituted. Any other `<token>` stays literal: resolve it from the task context when the plan, ticket, or prompt names exactly one value for it (`<subproject>`: the one top-level directory the change touches); zero or several candidates -> ask once. | Built-in: `git worktree add "<home>" -b "<branch>"`, gitignore-first only when the home is inside the primary |
66
+ | `- destroy: <command>` | Removal command run from the primary, same substitution; read by `finishing-a-development-branch` Step 6 and gatekeep-pr cleanup. | `git worktree remove "<path>" && git worktree prune` when the path matches `home:`; host-owned, keep, when it does not |
67
+
68
+ The **keyed contract is active** when at least one key is present. A duplicate key: the first wins; name the duplicate. `home:` without a `<name>` segment, or with it twice: stop and name the line.
69
+
70
+ Keyed contract active:
71
+
72
+ 1. Run the Step 3 clean-base check in the source checkout.
73
+ 2. `NAME` is the branch name with every `/` replaced by `-` (`jacek/fix-x` -> `jacek-fix-x`). `HOME` is `home:` resolved against `$ROOT` with `<name>` -> `NAME`.
74
+ 3. `create:` set -> run it from `$ROOT` with each resolved token inserted as one single-quoted shell word (`'...'`, an embedded `'` escaped), including when the template already quotes it; a `<token>` the context rule cannot resolve is never executed - ask once for its value. A non-zero exit stops this skill with the command's output: no `git worktree add` fallback, no Step 4 report.
75
+ `create:` absent -> when `HOME` is inside `$ROOT`, gitignore its parent directory first (the Step 2b sequence with that directory in place of `.worktrees`); then `git -C "$ROOT" worktree add "$HOME" -b "$BRANCH"`.
76
+ 4. Post-create check, always: `git -C "$ROOT" worktree list --porcelain` must print `worktree $HOME`; otherwise stop and report the mismatch (a wrong `home:` pattern, or a wrapper that places trees elsewhere).
77
+ 5. `WORKTREE="$HOME"`; `$WORKTREE` is the value every later step carries (`home: ../acme-mono-<name>` with branch `fix-x` gives `/work/acme-mono-fix-x`, so the basename `acme-mono-fix-x` is not the name). Go to Step 4.
78
+
79
+ No overrides file, no section, or a section with none of the three keys (both shapes are the **legacy path**): the prose, if any, is instruction; continue at Step 1b - native tools, then a wrapper discovered from `AGENTS.md`, the repo root, `script/`, or `bin/`, then `.worktrees/`.
80
+
81
+ ## Step 1b - Prefer Native Worktree Tools (legacy path)
59
82
 
60
83
  Do you already have a way to create a worktree? It might be a tool with a name like `EnterWorktree`, `WorktreeCreate`, a `/worktree` command, or a `--worktree` flag. If you do, run the Step 3 clean-base check in the source checkout *before* invoking it, then use it and skip to Step 3.
61
84
 
@@ -76,7 +99,7 @@ Only when no native tool exists:
76
99
 
77
100
  ### 2a. Pick a location
78
101
 
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.
102
+ The canonical home is `<repo>/.worktrees/<branch>`. A keyed `## using-git-worktrees` section never reaches this step (Step 1a creates at `home:`); on the legacy path a wrapper may define another path, otherwise use the canonical home. Do not ask local-vs-global or invent another path.
80
103
 
81
104
  ### 2b. Create - gitignore the home first
82
105
 
@@ -170,7 +193,9 @@ Re-run tests after rebasing.
170
193
  | `GIT_DIR != GIT_COMMON` | Already in worktree - report its path, create nothing |
171
194
  | Worktree path already listed by `git worktree list` | Report it, create nothing |
172
195
  | `git rev-parse --show-superproject-working-tree` returns a path | Submodule — treat as normal repo |
173
- | Project-native wrapper exists | Use the wrapper (commonly `script/worktree create`) |
196
+ | `## using-git-worktrees` has `home:`/`create:`/`destroy:` | Keyed contract (Step 1a): run `create:` or the built-in add at `home:`, then the post-create check |
197
+ | `## using-git-worktrees` absent or keyless | Legacy path: native tool, then wrapper discovery, then `<repo>/.worktrees/<branch>` |
198
+ | Project-native wrapper exists (legacy path) | Use the wrapper (commonly `script/worktree create`) |
174
199
  | No native tool | Create `<repo>/.worktrees/<branch>` (gitignore `.worktrees/` first) |
175
200
  | Detached HEAD | Ask before branching |
176
201
  | Sandbox/permission failure | Work in place on a feature branch |
@@ -182,9 +207,11 @@ Re-run tests after rebasing.
182
207
  - About to `cd` into the worktree (carry the path instead)
183
208
  - About to call `git worktree add` directly when the project ships a wrapper (use the wrapper)
184
209
  - Created a `.worktrees/` worktree without gitignoring `.worktrees/` first
185
- - Placed a worktree outside `.worktrees/` (or the project's configured path) for no reason
210
+ - Placed a worktree outside `.worktrees/` (or the `home:` key of `## using-git-worktrees`) for no reason
186
211
  - Source checkout dirty and you proceed without asking
187
212
  - About to run a test suite during worktree creation
213
+ - Executed a `create:` or `destroy:` template with an unresolved `<token>` still in it
214
+ - Fell back to `git worktree add` after a configured `create:` failed
188
215
 
189
216
  ## Integration
190
217
 
@@ -201,3 +228,5 @@ Re-run tests after rebasing.
201
228
  ## Project overrides
202
229
 
203
230
  If a gauntlet overrides file exists - checked in order: `.pi/gauntlet-overrides.md`, `<repo root>/gauntlet-overrides.md`, `<repo root>/doc/gauntlet-overrides.md`; first found wins - read it. Read and apply `## conventions` whenever present, without a relevance judgment. Give this skill's named section precedence over conflicting `## conventions` rules. Use other relevant sections - by name match, by topic (routing, verification, worktrees, etc.), or by workflow convention - to override or extend the instructions above. Project-local `AGENTS.md` is already in context — check it for project-specific routing tables, service paths, and verification commands.
231
+
232
+ The recognized headings, their readers, and the rules an override cannot change are listed in the [configuration front door](../../README.md#project-specific-overrides); an override extends or replaces the step it names and never lifts this skill's HARD CONSTRAINT or MUST text.
@@ -169,3 +169,5 @@ phase_tracker({ action: "complete", phase: "verify" })
169
169
  ## Project overrides
170
170
 
171
171
  If a gauntlet overrides file exists - checked in order: `.pi/gauntlet-overrides.md`, `<repo root>/gauntlet-overrides.md`, `<repo root>/doc/gauntlet-overrides.md`; first found wins - read it. Read and apply `## conventions` whenever present, without a relevance judgment. Give this skill's named section precedence over conflicting `## conventions` rules. Use other relevant sections - by name match, by topic (routing, verification, worktrees, etc.), or by workflow convention - to override or extend the instructions above. Project-local `AGENTS.md` is already in context — check it for project-specific routing tables, service paths, and verification commands.
172
+
173
+ The recognized headings, their readers, and the rules an override cannot change are listed in the [configuration front door](../../README.md#project-specific-overrides); an override extends or replaces the step it names and never lifts this skill's HARD CONSTRAINT or MUST text.
@@ -313,3 +313,5 @@ Auto-invoke `/skill:subagent-driven-development` in this session. Do not wait fo
313
313
  ## Project overrides
314
314
 
315
315
  If a gauntlet overrides file exists - checked in order: `.pi/gauntlet-overrides.md`, `<repo root>/gauntlet-overrides.md`, `<repo root>/doc/gauntlet-overrides.md`; first found wins - read it. Read and apply `## conventions` whenever present, without a relevance judgment. Give this skill's named section precedence over conflicting `## conventions` rules. Use other relevant sections - by name match, by topic (routing, verification, worktrees, etc.), or by workflow convention - to override or extend the instructions above. Project-local `AGENTS.md` is already in context — check it for project-specific routing tables, service paths, and verification commands.
316
+
317
+ The recognized headings, their readers, and the rules an override cannot change are listed in the [configuration front door](../../README.md#project-specific-overrides); an override extends or replaces the step it names and never lifts this skill's HARD CONSTRAINT or MUST text.