pi-gauntlet 5.6.2 → 5.8.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.
@@ -25,21 +25,14 @@
25
25
  */
26
26
 
27
27
  import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
28
- import { resolveVerifyBeforeShip, settingsErrorWarning } from "./lib/gauntlet-settings.ts";
28
+ import {
29
+ DEFAULT_TEST_COMMANDS,
30
+ buildTestCmdRegex,
31
+ resolveVerifyBeforeShip,
32
+ settingsErrorWarning,
33
+ } from "./lib/gauntlet-settings.ts";
29
34
  import { loadGauntletSettings } from "./lib/gauntlet-settings-loader.ts";
30
35
 
31
- // Default verification entrypoints. Override via settings.
32
- const DEFAULT_TEST_COMMANDS = [
33
- "make\\s+(?:ci|test)(?![-\\w])", // rejects make test-smoke, test-corpus, etc.
34
- "npm\\s+(?:test|run\\s+test)",
35
- "pnpm\\s+test",
36
- "yarn\\s+test",
37
- "pytest",
38
- "rspec",
39
- "cargo\\s+test",
40
- "go\\s+test",
41
- ];
42
-
43
36
  const SHIP_CMD = /\b(git\s+push|gh\s+pr\s+create)\b/;
44
37
 
45
38
  const SOURCE_EXT = /\.(ts|tsx|js|jsx|py|rb|go|rs|java|swift|kt)$/;
@@ -50,9 +43,6 @@ const isSourceWrite = (filePath: string | undefined): boolean => {
50
43
  return SOURCE_EXT.test(filePath) && !TEST_PATH.test(filePath);
51
44
  };
52
45
 
53
- const buildTestCmdRegex = (commands: string[]): RegExp =>
54
- new RegExp(`\\b(${commands.join("|")})\\b`);
55
-
56
46
  const formatWarning = (command: string, testCommands: string[], reference: string | undefined): string => {
57
47
  const examples = testCommands
58
48
  .slice(0, 3)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pi-gauntlet",
3
- "version": "5.6.2",
3
+ "version": "5.8.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",
@@ -38,7 +38,8 @@
38
38
  "extensions": [
39
39
  "./extensions/phase-tracker.ts",
40
40
  "./extensions/plan-tracker.ts",
41
- "./extensions/verify-before-ship.ts"
41
+ "./extensions/verify-before-ship.ts",
42
+ "./extensions/telemetry.ts"
42
43
  ],
43
44
  "image": "https://raw.githubusercontent.com/jjuraszek/pi-gauntlet/main/pi-gauntlet.png"
44
45
  },
@@ -50,5 +51,8 @@
50
51
  "postinstall": "node ./bin/install-agents.mjs",
51
52
  "link-agents": "node ./bin/install-agents.mjs",
52
53
  "test": "node scripts/ci.mjs"
54
+ },
55
+ "dependencies": {
56
+ "yaml": "^2.9.0"
53
57
  }
54
58
  }
@@ -38,7 +38,7 @@ This skill ends with a **written, user-reviewed spec inside a worktree**. Nothin
38
38
 
39
39
  ## Foreground dispatch policy
40
40
 
41
- Flow-owned execution dispatches run in the foreground: set top-level `async: false` on gather, critique, council, summary, implementation, review, conformance, and retry calls. `forceTopLevelAsync` must remain unset or false; it is incompatible with this flow. See [pi-cohort dispatch configuration](https://github.com/jjuraszek/pi-cohort/blob/main/doc/configuration.md). If a dispatch returns an async handle despite `async: false`, stop and report the configuration error: do not poll it, relaunch work, or advance the flow. An intercom-detached child is likewise incomplete work; use the existing coordination path and never accept or duplicate it.
41
+ Flow-owned execution dispatches run in the foreground: set top-level `async: false` on gather, critique, council, summary, implementation, review, conformance, and retry calls. `forceTopLevelAsync` must remain unset or false; it is incompatible with this flow. See [pi-cohort dispatch configuration](https://github.com/jjuraszek/pi-cohort/blob/main/doc/configuration.md). If a dispatch returns an async handle despite `async: false`, stop and report the configuration error: do not poll it, relaunch work, or advance the flow. A child that detached from the foreground run is likewise incomplete work; use the existing coordination path and never accept or duplicate it.
42
42
 
43
43
  Foreground does not serialize independent work: preserve existing isolated parallel `tasks` batches and await their terminal results before acceptance or tracker/phase advancement.
44
44
 
@@ -206,7 +206,7 @@ subagent({
206
206
  })
207
207
  ```
208
208
 
209
- For chains, async runs, intercom coordination, and the full agent roster, read the `pi-cohort` skill — this skill covers only the parallel fan-out case.
209
+ For chains, async runs, and the full agent roster, read the `pi-cohort` skill — this skill covers only the parallel fan-out case.
210
210
 
211
211
  ## Verification
212
212
 
@@ -0,0 +1,122 @@
1
+ ---
2
+ name: gauntlet-resume
3
+ description: Use when a human wants to continue an interrupted gauntlet flow in a fresh session - from a pi-cohort handoff brief (file or pasted) or from a bare worktree that already holds a spec. Human-only; the sole resume entry point. Restores phase/plan tracker state through the legal arming sequence, never creates a worktree, never infers approval.
4
+ disable-model-invocation: true
5
+ argument-hint: "[<brief-file>] [<worktree-name-or-path>]"
6
+ ---
7
+
8
+ > **Related skills:** Continues into `/skill:writing-plans`, `/skill:subagent-driven-development`, or `/skill:verification-before-completion` depending on the restored stage. `/skill:brainstorming` is where new ideas go - a free-form prompt is not a resume input.
9
+
10
+ # Gauntlet Resume
11
+
12
+ ## Overview
13
+
14
+ Re-enter an interrupted gauntlet flow in a fresh session. Two inputs: a handoff brief
15
+ produced by pi-cohort's `/handoff` (grammar in `reference/brief-contract.md`), or a bare
16
+ worktree whose spec/plan artifacts are reconstructed into tracker state
17
+ (`reference/reconstruction.md`). Every check runs before any tracker mutation; every
18
+ stop names the offending path, field, or line.
19
+
20
+ **Announce at start:** "I'm using the gauntlet-resume skill to continue an interrupted flow."
21
+
22
+ ## Boundaries
23
+
24
+ - Reads: anything.
25
+ - Writes: `phase_tracker` / `plan_tracker` state, only after every entry check passes
26
+ and every human question is answered. Nothing on disk.
27
+ - Never: `git worktree add`; infer approval from artifact presence; restore gate history,
28
+ closure-review evidence, or fix rounds; start a later phase directly (that does not arm
29
+ the flow).
30
+
31
+ ## Arguments
32
+
33
+ `/skill:gauntlet-resume [<brief>] [<worktree>]` - zero to two positional tokens, plus
34
+ optional pasted text after the command line.
35
+
36
+ | Form | Meaning |
37
+ |---|---|
38
+ | `<brief-file>` | readable file whose line 1 starts `# Handoff:` |
39
+ | pasted text whose first line starts `# Handoff:` | inline brief (equivalent to a file) |
40
+ | `<worktree>` alone | bare name resolved as `<primary>/.worktrees/<name>`, or an absolute path; must already be a git worktree |
41
+ | `<brief> <worktree>` | brief plus an explicit worktree override (required when the brief's worktree field is `no`/`unavailable`/not a git repo; must equal the brief's worktree after `realpath` otherwise) |
42
+ | anything else | not a resume input - stop with "this is a new idea - run /skill:brainstorming" |
43
+
44
+ `<primary>` is the checkout owning `.worktrees/`: `dirname $(git rev-parse --git-common-dir)`
45
+ (not `--show-toplevel`, which returns the linked worktree when run inside one). A pasted
46
+ brief that needs an override uses the file form. This skill never runs `git worktree add`.
47
+
48
+ ## Entry checks
49
+
50
+ In order. All before any tracker mutation; entry check 1 is read-only.
51
+
52
+ 1. **Idle session.** `phase_tracker({ action: "status" })`. Any phase not pending ->
53
+ stop: "session already carries flow state - reset is your call".
54
+ 2. **Target worktree.** Resolve from the brief's `worktree:` field, the override, or the
55
+ bare argument. Stops: path missing or `git -C <path> rev-parse --is-inside-work-tree`
56
+ fails; override and brief worktree differ after `realpath`; brief has no
57
+ `## Repo state` heading (prefix match: `## Repo state` or
58
+ `## Repo state: not a git repo`); brief worktree is `no`, `unavailable`, or
59
+ `not a git repo` and no override was given - except a `worktree: no` brief **without**
60
+ process state, which is the brainstorming route in Dispatch, not a stop. Other
61
+ `unavailable` fields inside `## Repo state` are legal.
62
+ 3. **Session cwd binding.** `phase_tracker`, `plan_check`, and the flow guards resolve
63
+ every path against the extension's session cwd; a child-shell `cd` cannot relocate it.
64
+ If `realpath $(git rev-parse --show-toplevel)` in the session cwd differs from the
65
+ resolved worktree, stop: "restart pi in <worktree> and re-run". Every restoration
66
+ therefore runs with the session rooted in the resolved worktree.
67
+ 4. **Drift notice.** Compare the brief's `HEAD` and `dirty` fields in `## Repo state`
68
+ with the live worktree (`git rev-parse HEAD`, `git status --porcelain`). Announce
69
+ differences. Informational, never a stop.
70
+ 5. **Skills loaded.** For each name in `## Skills loaded` (none for
71
+ `## Skills loaded: none`): match against the frontmatter `name` of every
72
+ `skills/*/SKILL.md` in this package; `Read` each match's complete file into the
73
+ transcript; list non-matches as skipped. Loaded bodies are context only - no skill's
74
+ entry actions run until Dispatch names one.
75
+
76
+ ## Dispatch
77
+
78
+ | Input | Route |
79
+ |---|---|
80
+ | brief with `## Process state` | process-state restore - `reference/brief-contract.md` "Process-state restore" |
81
+ | brief without process state, `## Skills loaded` names `chase-bug` | hotfix route below, before any artifact reconstruction, no tracker calls |
82
+ | brief without process state, `worktree: no` | invoke `/skill:brainstorming` with `## Intent` as the idea, in the current directory; resume creates no worktree - brainstorming's own Worktree First applies (a plain handoff is a new flow) |
83
+ | brief without process state, worktree present | `reference/reconstruction.md`, with `## Intent` and `## Decisions` carried into every confirmation prompt |
84
+ | bare worktree | `reference/reconstruction.md`; prompts state that no brief context is available (never invent Intent/Decisions) |
85
+
86
+ **Hotfix route.** `skills/chase-bug/hotfix.md` consumes only a hotfix record at
87
+ `$TMPDIR/hotfix-<slug>.md`. If `## Decisions` or `## Intent` names an existing record
88
+ path, hand it to hotfix.md and skip its worktree-create step when the brief's worktree
89
+ exists (reuse it). Otherwise invoke `/skill:chase-bug` triage with `## Intent` to
90
+ re-derive the record.
91
+
92
+ ## Post-restore continuation
93
+
94
+ After a successful restore, print the closing line from `reference/brief-contract.md`
95
+ (gate history not restored; the task to re-validate), then continue in the stage's
96
+ owning skill **without** its reset-bearing entry:
97
+
98
+ | Active after restore | Continue in | Entry point |
99
+ |---|---|---|
100
+ | brainstorm | brainstorming checklist | on-disk state decides the step: draft marker on line 1 of the spec file -> step 4; spec title -> step 8. Never `/skill:brainstorming` entry (it resets both trackers) |
101
+ | plan | writing-plans body | skip its `start plan` call (already in_progress) |
102
+ | implement | subagent-driven-development | re-validate `<task>` first (re-run its `Tests:`), then the task loop from the first non-complete task |
103
+ | verify | verification-before-completion | full conformance gate; nothing carried over |
104
+
105
+ ## Red flags — STOP
106
+
107
+ - Any `phase_tracker` or `plan_tracker` mutation before entry checks 1-5 pass and every
108
+ human question is answered.
109
+ - `start <phase>` for anything other than brainstorm as the first arming call.
110
+ - `complete` on a prior phase during restore (priors are `skip`ped with a `resume:` reason).
111
+ - Running `git worktree add`, or `cd`-ing to "fix" a cwd mismatch.
112
+ - Accepting a free-form prompt as a brief.
113
+
114
+ ## Project overrides
115
+ If a gauntlet overrides file exists - checked in order:
116
+ `.pi/gauntlet-overrides.md`, `<repo root>/gauntlet-overrides.md`,
117
+ `<repo root>/doc/gauntlet-overrides.md`; first found wins - read it. Any
118
+ sections relevant to this skill - by name match, by topic (routing,
119
+ verification, worktrees, etc.), or by workflow convention - override or
120
+ extend the instructions above. Project-local `AGENTS.md` is already in
121
+ context - check it for project-specific routing tables, service paths, and
122
+ verification commands.
@@ -0,0 +1,121 @@
1
+ # Handoff brief contract (gauntlet-resume supplementary)
2
+
3
+ Consumed only by `SKILL.md` in this directory. This file is the single concentration
4
+ point for text coupled to pi-cohort's `/handoff` template (`doc/handoff-template.md`
5
+ in pi-cohort; baseline inlined from its `prune-prompts` branch, commit `d737eb9`).
6
+ Cohort drift is reconciled here and nowhere else.
7
+
8
+ ## Brief grammar
9
+
10
+ Headings, fixed order. A consumer keys on headings, never prose.
11
+
12
+ ```markdown
13
+ # Handoff: <one line>
14
+ ## Intent
15
+ ## Repo state
16
+ ## Decisions
17
+ ## Open questions
18
+ ## Skills loaded
19
+ ## Process state
20
+ ```
21
+
22
+ | Section | Content | Presence |
23
+ |---|---|---|
24
+ | `## Repo state` | one field per line: `toplevel`, `worktree: yes <path>` or `worktree: no`, `branch` (`detached` when none), `HEAD`, `base` (`unknown` when no remote resolves), `dirty: <porcelain>` or `dirty: clean`, `diff-stat` (`unavailable` when base unknown), `test cmd`; any field `unavailable` when its command failed; heading `## Repo state: not a git repo` outside git | always |
25
+ | `## Decisions` | bullets; rejected alternatives marked `rejected:` | always |
26
+ | `## Skills loaded` | frontmatter `name`s; `## Skills loaded: none` when none | always |
27
+ | `## Process state` | `phase_tracker status` then `plan_tracker status` verbatim; `Active task: <name|none>`; the line `Gate history not restored - re-validate before advancing.` | only when both tracker tools exist and a phase is `in_progress` |
28
+
29
+ Consumer rules (cohort): process state absent -> plain handoff (the consumer starts its
30
+ own process from `## Intent`); present with `No plan active.` -> phase-only, restore no
31
+ plan; loading named skills is the consumer's job.
32
+
33
+ A brief is any text whose first line starts `# Handoff:` - a file on disk or pasted
34
+ inline. `## Repo state` is matched by prefix: `## Repo state` or
35
+ `## Repo state: not a git repo`.
36
+
37
+ ## Tracker output grammar
38
+
39
+ Must match `formatStatus` in the phase-tracker and plan-tracker extensions.
40
+
41
+ ```
42
+ Phases:
43
+ ✓ brainstorm
44
+ → implement(W2)
45
+ ○ verify (reason)
46
+ ```
47
+
48
+ Glyphs `✓` complete, `→` in_progress, `⊘` skipped, `○` pending; `(reason)` suffix when
49
+ set; `name(substep)` only on the in-progress phase.
50
+
51
+ ```
52
+ Plan: 2/5 done (1 in progress, 2 pending)
53
+
54
+ ✓ [0] <name>
55
+ → [1] <name>
56
+ ```
57
+
58
+ or `No plan active.`. Task glyphs `✓` complete, `→` in_progress, `✗` failed, `⊘` skipped,
59
+ `○` pending, mapping 1:1 onto `plan_tracker init` `{name, status}` statuses.
60
+
61
+ Parse stops (print the offending line, make no tracker call):
62
+
63
+ - a task line not matching `^\s*[✓→✗⊘○] \[\d+\] .+$` - the "unparsable process-state
64
+ task line" stop;
65
+ - a process-state section whose phase block shows all `○` - contradictory (the producer
66
+ emits the section only with an in-progress phase);
67
+ - a phase block with more than one `→` line - contradictory (the tracker holds one active
68
+ phase; print both lines).
69
+
70
+ ## Process-state restore
71
+
72
+ Facts that fix the order (from the extensions):
73
+
74
+ - Arming happens only on `start brainstorm`; `reset` disarms; `skip` and `complete`
75
+ preserve it.
76
+ - `plan_check` stamps only inside an armed flow; unarmed it returns
77
+ `PASS (no flow to stamp)`.
78
+ - `start implement` is rejected without a current `plan_check` stamp.
79
+ - `skip` has no state precondition and takes a `reason`; one phase is active at a time.
80
+ - `complete verify` is blocked without a fresh `conformance-reviewer` dispatch when
81
+ closure review is enforced.
82
+ - `plan_tracker init` on an in-progress implement with every task `complete`/`skipped`
83
+ auto-completes implement.
84
+
85
+ Per-stage call table, keyed by the brief's active phase (`→`). `R` is the reason string
86
+ `resume: <brief file or "pasted brief">`.
87
+
88
+ | Active | Calls, in order |
89
+ |---|---|
90
+ | brainstorm | `start brainstorm`; `substep` if the brief shows one |
91
+ | plan | `start brainstorm`; `skip brainstorm R`; `start plan`; `substep` if shown |
92
+ | implement | `start brainstorm`; `skip brainstorm R`; `start plan`; `plan_check({ planPath })`; on FAIL print findings and stop with plan in_progress, no init; on PASS `skip plan R`; `start implement`; `substep` if shown; `plan_tracker init` |
93
+ | verify | as implement through `skip plan R`, then `skip implement R`; `start verify`; `substep` if shown; `plan_tracker init` |
94
+ | ship | as verify. Restoration stops at verify in_progress: `complete verify` needs a fresh conformance dispatch and `skip verify` would bypass a real gate. Announce that the closure review re-runs before ship |
95
+
96
+ `planPath`: the brief carries none. Resolve as reconstruction does
97
+ (`reconstruction.md`, "Candidates", including its `flowGuards.specDirs` resolution): the
98
+ single spec/plan pair added after base in the worktree, paired by identical basename
99
+ (`<specDir>/<name>.md` <-> `<sibling plans dir>/<name>.md`, the writing-plans contract);
100
+ zero pairs -> stop; more than one -> human picks.
101
+
102
+ "Exact" restoration binds: the active phase identity and substep, and the plan task list
103
+ (names, order, statuses) verbatim. Prior phases show `⊘ (resume: ...)` regardless of the
104
+ brief's glyph - skip-arming is the mechanism and completing priors would fabricate gated
105
+ history. `No plan active.` -> no `init` call.
106
+
107
+ Before `init`, validate feasibility against the tracker's own rules:
108
+
109
+ - pending-suffix order - every `○` task must trail every non-pending task;
110
+ - the implement auto-complete edge - an implement brief whose tasks are all
111
+ complete/skipped is infeasible as stated; propose verify as the target and ask.
112
+
113
+ Every restore ends with:
114
+
115
+ ```
116
+ Gate history not restored; re-validating `<task>` before any stage advance
117
+ ```
118
+
119
+ where `<task>` is the brief's `Active task`, else the first in-progress task, else `none`
120
+ (whole-deliverable re-validation). Gate history, closure-review evidence, and fix rounds
121
+ are never inferred or restored; a ship-stage brief resumes at verify.
@@ -0,0 +1,96 @@
1
+ # Bare-worktree reconstruction (gauntlet-resume supplementary)
2
+
3
+ Consumed only by `SKILL.md` in this directory, for a resolved worktree with no
4
+ `## Process state` to restore from - a bare worktree argument, or a brief without
5
+ process state whose worktree exists. Artifact presence never implies approval; task
6
+ commits never imply review acceptance. Every question below is a human question, and
7
+ no tracker call happens before the human answers.
8
+
9
+ Brief context: when the input was a brief, carry its `## Intent`/`## Decisions` verbatim
10
+ into every prompt below. When the input was a bare worktree, say so - "no brief context
11
+ available" - and never invent Intent or Decisions.
12
+
13
+ ## Base
14
+
15
+ ```bash
16
+ git merge-base HEAD origin/HEAD 2>/dev/null \
17
+ || git merge-base HEAD main 2>/dev/null \
18
+ || git merge-base HEAD master 2>/dev/null
19
+ ```
20
+
21
+ Base = `git merge-base HEAD origin/HEAD`, else `main`/`master`. Empty -> ask the human
22
+ for a base ref before reading any artifact.
23
+
24
+ ## Candidates
25
+
26
+ Spec/plan directories: `piGauntlet.flowGuards.specDirs` plus each one's sibling `plans` directory. Resolve with the precedence `doc/configuration.md` documents for every `piGauntlet.*` key: the session cwd's `.pi/settings.json` if it defines `flowGuards`,
27
+ else the active pi profile's `settings.json`, else the default `["doc/specs"]` (sibling
28
+ `doc/plans`). An empty array is the default. `<dirs>` below is that resolved list,
29
+ space-separated - never the literal defaults when a setting is present.
30
+
31
+ ```bash
32
+ git diff --diff-filter=A --name-only <base>..HEAD -- <dirs>
33
+ git ls-files --others --exclude-standard -- <dirs>
34
+ ```
35
+
36
+ Candidates are files under those directories added after base, plus untracked files
37
+ there. A spec and a plan pair by identical basename (`<specDir>/<name>.md` <->
38
+ `<sibling plans dir>/<name>.md`). The plan commit is the first post-base commit that added the
39
+ plan file: `git log --diff-filter=A --format=%H --reverse <base>..HEAD -- <plan>`, first
40
+ line. An uncommitted plan has no plan commit; treat every task as `pending`.
41
+
42
+ | Candidates | Route |
43
+ |---|---|
44
+ | no spec | stop; offer `/skill:brainstorming`; no tracker call |
45
+ | more than one spec | the human picks one, then continue below with that spec |
46
+ | one spec, no plan | "Spec without plan" |
47
+ | one spec with plan | "Spec with plan" |
48
+
49
+ ## Spec without plan
50
+
51
+ Ask exactly one question: is this spec approved? Show the spec path (and the brief's
52
+ `## Intent`/`## Decisions` when present).
53
+
54
+ - Approved: `start brainstorm`; `skip brainstorm resume: <spec path>`; `start plan`;
55
+ continue in writing-plans (its own `start plan` is skipped - plan is already
56
+ in_progress).
57
+ - Not approved: invoke `/skill:brainstorming` with the spec as the draft; arm nothing.
58
+ using-git-worktrees Step 0 detects the existing worktree and creates none.
59
+
60
+ ## Spec with plan
61
+
62
+ Show, and ask the human to confirm or edit both in one reply:
63
+
64
+ 1. Per task, in plan order: the commits after the plan commit that touch any path in
65
+ the task's declared `Files:` block. Strip a trailing `:digits[-digits]` range from
66
+ each `Modify:` path before matching `git log -- <path>`:
67
+ `git log --format=%h --oneline <plan-commit>..HEAD -- <path>`. Uncommitted plan (no
68
+ plan commit): skip this query entirely - there is no range to search - and show
69
+ "plan uncommitted; no task evidence" in its place; every task is proposed `pending`.
70
+ 2. Uncommitted files: `git status --porcelain`.
71
+ 3. Proposed task statuses: `complete` iff at least one matching commit, else `pending`.
72
+ 4. Proposed stage: `implement` if any task is `pending`, else `verify`.
73
+
74
+ Validate the confirmed snapshot before any tracker call:
75
+
76
+ - pending-suffix order - every `pending` task trails every non-pending one;
77
+ - all tasks complete/skipped with stage `implement` is infeasible (implement would
78
+ auto-complete on `init`).
79
+
80
+ Reject an infeasible edit by citing the offending rows and re-asking. Confirmation
81
+ edits override proposals; never rewrite confirmed state silently.
82
+
83
+ After confirmation:
84
+
85
+ 1. `start brainstorm`; `skip brainstorm resume: <spec path>`; `start plan`.
86
+ 2. `plan_check` with `planPath` = the plan. FAIL -> print the findings, stop with plan
87
+ in_progress, no `init`.
88
+ 3. PASS -> `skip plan` with the same `resume:` reason; for stage verify also
89
+ `skip implement`; `start <stage>`.
90
+ 4. `init` the confirmed non-empty task list as `{name, status}` elements.
91
+ 5. `phase_tracker status` and `plan_tracker status` must match the confirmed active
92
+ stage and task list exactly; a mismatch is reported verbatim, not patched.
93
+
94
+ End with the standard line from `brief-contract.md`. `<task>` follows the same rule as
95
+ there: there is no brief `Active task` on this route, so it is the first confirmed
96
+ `in_progress` task, else `none` (whole-deliverable re-validation).
@@ -3,7 +3,7 @@ name: writing-plans
3
3
  description: Use when you have a spec or requirements for a multi-step task, before touching code
4
4
  ---
5
5
 
6
- > **Related skills:** Reached via the auto-chain from `/skill:brainstorming`, or via the spec-in-hand handoff path (see "Resuming with a spec in hand" below) — otherwise not a direct human entry point. On completion this skill auto-invokes `/skill:subagent-driven-development`.
6
+ > **Related skills:** Reached via the auto-chain from `/skill:brainstorming`, or via `/skill:gauntlet-resume` when a restored flow lands at the plan stage — otherwise not a direct human entry point. On completion this skill auto-invokes `/skill:subagent-driven-development`.
7
7
 
8
8
  # Writing Plans
9
9
 
@@ -15,9 +15,9 @@ DRY. YAGNI. TDD. Frequent commits.
15
15
 
16
16
  **Announce at start:** "I'm using the writing-plans skill to create the implementation plan."
17
17
 
18
- Before drafting the plan, call `phase_tracker({ action: "start", phase: "plan" })` (if resuming with a spec in hand, see "Resuming with a spec in hand" below first -- its arming sequence already performs this call).
18
+ Before drafting the plan, check `phase_tracker({ action: "status" })`. If `plan` is already `in_progress` (a flow restored by `/skill:gauntlet-resume` arrives this way), do **not** call `start` again - a repeat `start` on the in_progress phase resets its guard ledger. Otherwise call `phase_tracker({ action: "start", phase: "plan" })`.
19
19
 
20
- **Input:** an approved spec in `<project>/doc/specs/<filename>.md` — produced by `/skill:brainstorming` in this session, or handed off from another session (see "Resuming with a spec in hand").
20
+ **Input:** an approved spec in `<project>/doc/specs/<filename>.md` — produced by `/skill:brainstorming` in this session, or restored from another session by `/skill:gauntlet-resume`. Those two are the only entry points.
21
21
 
22
22
  **Save plans to:** the sibling `doc/plans/` directory next to the spec. The plan filename matches the spec filename exactly — same date, same ticket ID (if any), same topic slug, no `-design` suffix.
23
23
 
@@ -29,36 +29,6 @@ Before drafting the plan, call `phase_tracker({ action: "start", phase: "plan" }
29
29
 
30
30
  If no spec exists, send the work back to `/skill:brainstorming`. Do not invent a plan without a spec.
31
31
 
32
- ## Resuming with a spec in hand
33
-
34
- A handoff path, not a shortcut: use it when an **approved spec arrives from another session** (a handoff doc, a fresh top-level session resuming ratified work). New work still enters via `/skill:brainstorming`. The trigger is **phase-tracker state, not handoff prose** — it works even when the handoff doc says nothing about arming. On invocation, check `phase_tracker({ action: "status" })` and branch on the brainstorm phase:
35
-
36
- | brainstorm status | meaning | action |
37
- |---|---|---|
38
- | `in_progress` or `complete` | auto-chain from brainstorming | normal flow below, unchanged |
39
- | `pending`, no other phase `in_progress` | fresh resume | arm, then plan (this section) |
40
- | `skipped` | already resumed in this session | do **not** re-run the sequence (`start` errors on a skipped phase without `force`); verify plan state and continue |
41
- | `pending`, another phase `in_progress` | not a fresh resume (`start brainstorm` would error) | stop and ask the user; do not arm |
42
-
43
- On a fresh resume:
44
-
45
- 1. **Verify the spec exists** at the given path. Missing → stop and ask; never arm on a missing spec.
46
- 2. **Confirm approval.** Any unambiguous assertion in the prompt, handoff doc, or user message ("Brainstorming is complete", "spec approved" — examples, not an allowlist) counts. No assertion → ask once; on "no", route to `/skill:brainstorming`.
47
- 3. **Worktree.** If not already in an isolated worktree, set one up per `/skill:using-git-worktrees` and commit the spec there (the spec must live in the worktree, same as the brainstorm path).
48
- 4. **Arm the flow** — run exactly:
49
-
50
- ```
51
- phase_tracker({ action: "start", phase: "brainstorm" })
52
- phase_tracker({ action: "skip", phase: "brainstorm", reason: "resume: approved spec at <path>" })
53
- phase_tracker({ action: "start", phase: "plan" })
54
- ```
55
-
56
- This is the existing arming mechanism, not new mechanics: the `start` arms `gauntletEntered`, `skip` preserves it, session replay reconstructs it, `reset` disarms. The sequence already performed this skill's own `start plan` call — **do not** issue a second one (a repeat `start` on the in_progress phase is a no-op reset that re-clears the warn-once guard ledger).
57
-
58
- Then continue with the normal flow below (Scope Check onward, including Recon).
59
-
60
- **Writing a handoff doc** (from the producing session): name `/skill:writing-plans` as the entry point — never a phase past planning, since this gesture only arms through `start plan` — give the spec's path, and assert its approval status.
61
-
62
32
  ## Boundaries
63
33
 
64
34
  - Read code and docs: yes