task-pipeline-skill 1.91.2 → 1.93.2

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.
Files changed (42) hide show
  1. package/CHANGELOG.md +168 -0
  2. package/CONTRIBUTING.md +12 -6
  3. package/HOW-IT-WORKS.md +9 -4
  4. package/README.md +32 -4
  5. package/SKILL-CARD.md +1 -1
  6. package/cursor/rules/task-pipeline.mdc +11 -2
  7. package/evals/RESULTS.md +1 -1
  8. package/evals/task-pipeline.evals.json +16 -1
  9. package/package.json +3 -3
  10. package/plugins/task-pipeline/.claude-plugin/plugin.json +2 -2
  11. package/plugins/task-pipeline/commands/task-pipeline.md +23 -8
  12. package/plugins/task-pipeline/hooks/hooks.json +11 -0
  13. package/plugins/task-pipeline/hooks/memory-nudge.sh +49 -0
  14. package/plugins/task-pipeline/skills/evidence-docs/references/hooks.md +3 -1
  15. package/plugins/task-pipeline/skills/project-audit/SKILL.md +2 -1
  16. package/plugins/task-pipeline/skills/task-pipeline/SKILL.md +10 -20
  17. package/plugins/task-pipeline/skills/task-pipeline/execution-packet.example.json +1 -1
  18. package/plugins/task-pipeline/skills/task-pipeline/execution-packet.schema.json +2 -2
  19. package/plugins/task-pipeline/skills/task-pipeline/graph.schema.json +8 -2
  20. package/plugins/task-pipeline/skills/task-pipeline/pipeline.example.json +2 -1
  21. package/plugins/task-pipeline/skills/task-pipeline/pipeline.schema.json +7 -0
  22. package/plugins/task-pipeline/skills/task-pipeline/references/artifacts.md +4 -0
  23. package/plugins/task-pipeline/skills/task-pipeline/references/brainstorm.md +6 -3
  24. package/plugins/task-pipeline/skills/task-pipeline/references/build.md +2 -2
  25. package/plugins/task-pipeline/skills/task-pipeline/references/continuity.md +20 -2
  26. package/plugins/task-pipeline/skills/task-pipeline/references/decomposition.md +4 -0
  27. package/plugins/task-pipeline/skills/task-pipeline/references/deploy-targets.md +31 -0
  28. package/plugins/task-pipeline/skills/task-pipeline/references/doctrine-map.md +1 -0
  29. package/plugins/task-pipeline/skills/task-pipeline/references/grill.md +14 -5
  30. package/plugins/task-pipeline/skills/task-pipeline/references/hooks.md +3 -1
  31. package/plugins/task-pipeline/skills/task-pipeline/references/knowledge-sources.md +1 -0
  32. package/plugins/task-pipeline/skills/task-pipeline/references/planning.md +8 -0
  33. package/plugins/task-pipeline/skills/task-pipeline/references/portability.md +1 -0
  34. package/plugins/task-pipeline/skills/task-pipeline/references/stages.md +15 -7
  35. package/plugins/task-pipeline/skills/task-pipeline/references/waves.md +233 -0
  36. package/plugins/task-pipeline/skills/task-pipeline/references/work-graph.md +3 -1
  37. package/plugins/task-pipeline/skills/task-pipeline/scripts/context_packets.py +8 -2
  38. package/plugins/task-pipeline/skills/task-pipeline/scripts/graph.py +89 -5
  39. package/plugins/task-pipeline/skills/task-pipeline/scripts/packet.py +4 -2
  40. package/plugins/task-pipeline/skills/task-pipeline/scripts/plan_audit.py +1 -1
  41. package/plugins/task-pipeline/skills/task-pipeline/scripts/stage_checkpoint.py +68 -1
  42. package/plugins/task-pipeline/skills/task-pipeline/templates/run.md +2 -2
package/CHANGELOG.md CHANGED
@@ -1,3 +1,171 @@
1
+ ## v1.93.2 — v1.93.0's payload, with evidence a clone can follow
2
+
3
+ `v1.93.1` published nothing either: its release suite reached the documentation gate
4
+ (`npm run test:docs`, run by `release.yml` and not by the PR's checks) and refused 17
5
+ commit references in `docs/evidence/` — the wave-2 branch SHAs became unreachable when
6
+ PR #109 was squash-merged as `8260042`, and five CI run ids in backticks read as SHAs.
7
+ They now name the squash commit and the runs as plain numbers. Same payload; this is
8
+ the third tag for it, and `docgate.sh` passed locally before this one was pushed.
9
+
10
+ Guards: 438 → **438**; property checks 15 → **15**. No check changed.
11
+
12
+ ## v1.93.1 — v1.93.0's payload, released with its stamp declaration
13
+
14
+ `v1.93.0` published nothing: `release.yml` ran the suite on the tag's own tree and
15
+ `validate.py` refused it, because `docs/evidence/retro.md` → *Releases that carry no
16
+ stamp* did not name it — the check working as written (the same shape as `v1.91.1`).
17
+ The tag cannot be removed, so this release ships the same payload with that declaration.
18
+ Everything below under v1.93.0 is what 1.93.1 contains.
19
+
20
+ Guards: 438 → **438**; property checks 15 → **15**. No check changed.
21
+
22
+ ## v1.93.0 — the negative self-tests leave the workflow; temp state leaves with the run
23
+
24
+ Integration wave 2 of the family's waves run (R07–R16), one release. The headline is
25
+ the workflow: `.github/workflows/validate.yml` was **507,836 of GitHub's 512,000 bytes**,
26
+ and past that limit a workflow does not go red — it creates no runs and `gh pr checks`
27
+ says *no checks reported*. 448 of its 464 steps were plants and property checks, run one
28
+ after another in one job for 90–111 minutes (runs 38127381666, 38112068258,
29
+ 38104711459).
30
+
31
+ - **Every plant is a file (R08, #91).** The 433 negative self-tests and 15 property checks
32
+ moved verbatim into `test/negatives/NNN-<slug>.sh`: line 1 the shebang, line 2
33
+ `# name: <the step's name>`, then the step's `run` value exactly as GitHub parsed it —
34
+ checked byte for byte against the YAML on the commit that moved them. The directory is
35
+ the only list. `validate.yml` fell to 12,181 bytes.
36
+ - **CI shards them.** A `negatives` job runs `python3 test/negatives.py --shard N/8` on an
37
+ eight-value matrix, fail-fast off; each shard is its own runner, so the fixed
38
+ `/tmp/<name>-copy` scratch names still never meet. `--shard I/N` takes every Nth check
39
+ by position, so a red shard is the same set of checks on a maintainer's machine.
40
+ `--list` and `-k` work as before and with `--shard`.
41
+ - **The runner reads the directory, and refuses what it cannot read.** A file with no
42
+ `# name:` header, a name that is neither kind, a bad file name, a duplicate number or
43
+ name — each one stops the run before it starts, and `test/validate.py` fails on the
44
+ same list, because a check the loader drops is a guard nobody proves while every count
45
+ stays green. MIN_EXPECTED and MIN_PROPS count the directory, before any shard.
46
+ - **The runner runs `bash -e`, what GitHub ran.** A `run:` block with no `shell:` is
47
+ `bash -e {0}`; the local runner used plain `bash -c`, and it is now the thing CI runs.
48
+ - **Scratch copies are judged and removed inside each worker.** They were swept only
49
+ after the whole pool returned, so one local run held every copy at once — 433 copies of
50
+ the tree with its `.git`, ~6 GB, measured filling a disk with 4 GB free.
51
+ - **Every check that read the workflow reads the directory**, through the runner's own
52
+ loader: the guard and property counts, the newest CHANGELOG section's counts, the
53
+ floors, `sed -i`, scratch-directory reuse, a scratch dir wiped by a step that does not
54
+ own it, the plant-landed assertion, and the anchor census (`test/anchors.py`). The
55
+ plant-landed check used to skip a name with `)` inside its parentheses; it reads every
56
+ one now. The ten plants whose payload was the workflow text were re-pointed to the
57
+ check files and assert on the value the re-pointed guard reads; the YAML plant breaks
58
+ the first plain step name that is still in the workflow.
59
+ - **New guards, each with its plant:** a `Negative self-test` or `Property check` written
60
+ inline in the workflow again; a shard matrix that does not list every slice the
61
+ runner cuts; a check file the loader cannot read. The workflow-size guard had no
62
+ plant while the file sat 4 KB under the limit — it has one now.
63
+ - **Temp state leaves with the run (R07).** `tp-b80` in `test/validate.py`, the
64
+ `tp-stage-ckpt` trees and 15 test files with bare `mkdtemp` clean up after
65
+ themselves; one machine's TMPDIR held 15,146 `tp-b80-*` trees. A new validator check
66
+ refuses a test file under `test/` — the check files included — that calls `mkdtemp(`,
67
+ `mkstemp(` or keeps a `NamedTemporaryFile(..., delete=False)` and carries no cleanup.
68
+ It is per file, so a file with one cleanup and two leaks passes; writing it found two
69
+ such leaks in `test/validate.py` itself — the graph-coverage tree and the installers'
70
+ fake HOME, ~1.8 MB per validator run and so per plant — and both are fixed.
71
+ - **Budget (R09).** The description is 890 of 1024 chars (909 before; ≤ 900 was the
72
+ target, B-154 in the family board), and the `SKILL.md` body 4646 of the 4750-token
73
+ working limit (4736 before; B-120 asked for 100 spare, and 104 are). The Optional-bridge
74
+ paragraph is trimmed to a pointer (its full text was already in
75
+ `references/companion-skills.md`); the kernel-precedence rule stays
76
+ in `SKILL.md`, which `fix-tp-03.01` pins.
77
+ - **Execution packets carry a namespaced id (R14):** `task-pipeline/execution-packet/1`.
78
+ Fabric's former packet used the bare `execution-packet/1` until it renamed its format
79
+ `session-handoff/1`; `packet.py`, `context_packets.py` and the schema still read the bare
80
+ id: 19 live packets in one consumer repository carry it (B-135), so it is refused only
81
+ after they are migrated.
82
+ - **Wave mode reads declared task sources (R13).** Where a repository declares them in
83
+ `docs/backlog-sources.json`, the harvest reads exactly those, updates status only in
84
+ the owning files and never edits a generated view.
85
+ - **The release stage reads the approval mode (R16).** `pipeline.json` `release.approval`
86
+ is `checks` (tag, watch, report) or `reviewers` (the direct link to the run that is
87
+ actually waiting); absent, it is read from the organisation or the environment, never
88
+ assumed.
89
+ - **Fabric's pipeline adapter is a pinned contract (R15).** `test/fixtures/
90
+ fabric-pipeline-contract.json` pins `passioncode-ai/fabric` main `5bf15e5c`, and
91
+ `fix-pf-06.01` checks the gate types and the example config against it with no Fabric
92
+ checkout.
93
+ - **Continuity through Observatory (R11).** `stage_checkpoint.py` gains `handoff` and
94
+ `accept`; `hooks/memory-nudge.sh` reminds once per returned gate that wrote no memory
95
+ event.
96
+ - **Ledgers (R10).** The verification headers say *released*; this repository's merged
97
+ branches are gone.
98
+
99
+ Guards: 433 → **438**; property checks 15 → **15**. The five new plants are files in
100
+ `test/negatives/` (449–453); every guard's plant was run on this tree, and the CI wall
101
+ clock per shard is in `docs/evidence/verification.md`.
102
+
103
+ ## v1.92.0 — wave mode: the whole board, closed in its final form; the grill asks one batch
104
+
105
+ The operator's standard approach, decided on 2026-10-11 and codified here: when the request
106
+ is not one change but **the whole board** — every open item plus the new requests — gather
107
+ it all first, close every question the sources can close, ask what remains **once, as one
108
+ batch, at the end of planning**, lay the target state over the current logic on one canvas,
109
+ plan from the post-integration target, and cut the work into waves that each close in one
110
+ pass, with a verification, finishing, fixing and documentation pass after every wave. The
111
+ run takes the next wave without asking, says once when the board is empty, and leaves every
112
+ sign-in, consent, payment, message to a person and outward act to a human. The rule under
113
+ all of it: **build the system in its final form, never through intermediate states.**
114
+
115
+ - **`references/waves.md`, invoked as `/task-pipeline waves`** — a third mode beside `setup`
116
+ and `checkup`, and a program mode of the existing stages, not a parallel cycle: stages 0–4
117
+ once for the whole board, 5–8 per wave, 9–10 to close the release. Wave 0 is the survey
118
+ (with `project-audit` as a read-only sidecar for whole-project scope) and **one
119
+ machine-readable inventory**, every item by id with `id`, `source`, `status`, `area`,
120
+ `node`, `wave`, `release`, verified against the code — stale rows closed with their
121
+ receipt, duplicates clustered — and assigned to nodes and waves by a committed,
122
+ deterministic script. The **canvas** extends the module map: as-is → to-be per module and
123
+ contract, the integration seams, REQ → module → wave, and what the new version deletes.
124
+ No wave builds a shape a later wave undoes; a stub only at a declared contract with its
125
+ removal named. Wave 1 is the walking skeleton, and each wave names its exit criteria
126
+ before it starts. The close pass after each wave certifies, re-measures `audit.md`'s
127
+ exit, runs **one fix round** under the loop guard's caps, documents through the Doc Loop
128
+ scoped to the wave, marks the canvas, re-reads the goal, and re-cuts what is left. A board
129
+ bigger than one release becomes a program, carried on the canvas by node, never dropped.
130
+ The name is not "dynamic": that word is `run.loop.mode: dynamic`'s.
131
+ - **The grill's default changed — a decision by the operator, 2026-10-11.** It was *one
132
+ question per turn, never bundle*. It is now: close from the sources first, then ONE batch
133
+ of the material unknowns, ordered by dependency, each with a recommended answer and what
134
+ each answer changes; one question at a time only where answers depend on each other
135
+ (then depth-first) or when the operator asks for it. The reason is the operator's time: a
136
+ question asked alone costs a human round and a batch costs one, and
137
+ `prioritisation.md` → *5. Where the human goes* already said so for the rest of the run.
138
+ Mirrored in `grill.md`, `stages.md` (stages 0 and 2), `brainstorm.md`, the command, the
139
+ Cursor rule, `HOW-IT-WORKS.md`, the README, `pipeline.example.json`, this repository's
140
+ `pipeline.json`, and eval TRIG-01; TRIG-11 is the wave-mode trigger in Russian.
141
+ - **`continuity.md`: a block or an ambiguity stops its node, not the run.** The node is
142
+ parked `needs-operator` with the question written into it, the run continues on what it
143
+ does not block, and stops only when the whole frontier is blocked. An empty board is said
144
+ once. A goal re-read that moves the queue is a committed `revisions` entry.
145
+ - **`planning.md`: a wave re-cut keeps the static-graph decision** — every move is a
146
+ `revisions` entry plus a canvas edit, written before the next pass begins.
147
+ **`decomposition.md`**: the whole board runs one wave at a time, and a wave may hold several
148
+ bricks. **`build.md`**: "fix wave" is now "fix round", so *wave* means one thing.
149
+ **`project-audit`**: its rows and sidecar are wave mode's wave-0 input.
150
+ - **The work graph carries the wave.** `graph.schema.json` gains `nodes[].wave` (an integer
151
+ from 1) and the `wave` revision verb. `graph.py validate` refuses an edge from a later
152
+ wave's node into an earlier wave's node; `graph.py next --wave N` prints that wave's
153
+ frontier only, exiting `3` when the wave is done; `graph.py wave N-007 --to 3 --why …`
154
+ moves a node, writes the revision, and refuses a move that breaks the order, a `done`
155
+ node, or no reason. `test/graph_test.py` 158 → **166** cases.
156
+ - **The description names the mode** and paid for it: `'waves' / 'волнами' closes the whole
157
+ board`, while the stage list reads *through gated stages: …* instead of *… with explicit
158
+ gates*, `docs study` reads `docs`, and `docs/wiki sync` reads `docs/wiki`. 901 → 909 of
159
+ 1024 chars — inside the umbrella's 60-character reserve below the 970 working limit,
160
+ which a longer description would have broken. The `SKILL.md` body is 4736 tokens
161
+ (cl100k), one under where it was: the new sentence in *How to run* displaced a restated
162
+ kernel clause and the compiler sentence's tail.
163
+
164
+ Guards: 430 → **433**. The three new negatives live in `test/plant_wave.py` (the workflow
165
+ sits near GitHub's 512 000-byte limit) and disarm the order check, the `--wave` filter and
166
+ the re-cut's revision in turn; each was watched turning `test/graph_test.py` red before the
167
+ step was written.
168
+
1
169
  ## v1.91.2 — v1.91.1's payload, released with its no-stamp declaration
2
170
 
3
171
  `release.yml` refused the `v1.91.1` tag's own tree: the release carried no run stamp and was
package/CONTRIBUTING.md CHANGED
@@ -27,9 +27,13 @@ npm run test:negatives # python3 test/negatives.py
27
27
  npm run test:all # both, in order
28
28
  ```
29
29
 
30
- The corruptions live in [`.github/workflows/validate.yml`](.github/workflows/validate.yml)
31
- and `test/negatives.py` reads them from there — never duplicated, because a second
32
- copy of a corruption is a second thing to drift. The runner also tells a **broken
30
+ The corruptions live in [`test/negatives/`](test/negatives/), one file per check —
31
+ `#!/usr/bin/env bash`, then `# name: Negative self-test (<what is planted>)`, then
32
+ the script, run from the repository root. `test/negatives.py` reads that directory
33
+ and nothing else, so it is the only list; CI runs it in eight shards
34
+ (`--shard N/8`, the `negatives` job in `validate.yml`). Until v1.93.0 every plant was
35
+ an inline workflow step, and the workflow reached 507,836 of GitHub's 512,000 bytes —
36
+ past the limit a workflow creates no runs rather than going red. The runner also tells a **broken
33
37
  test** from a **guard that didn't fire**: if a planted defect changed nothing, the
34
38
  validator passing means the test proved nothing, and it is reported as `BROKEN`
35
39
  rather than as a failure of the guard.
@@ -37,7 +41,7 @@ rather than as a failure of the guard.
37
41
  **Corrupt files in python, never with `sed -i`.** BSD sed needs an argument GNU sed
38
42
  refuses, and `0,/re/` does not exist on BSD at all — there it edits nothing
39
43
  silently, and the test reads as a guard that failed. The validator rejects `sed -i`
40
- in the workflow for exactly this reason: a self-test that only runs on CI cannot be
44
+ in a check file for exactly this reason: a self-test that only runs on CI cannot be
41
45
  used while you are writing the guard, which is the moment it is worth most.
42
46
 
43
47
  To try your change in a real agent:
@@ -616,8 +620,10 @@ pass over an empty set is a refused measurement.
616
620
  `pipeline.example.json`, the command, the Cursor rule and the README before you
617
621
  commit. The validator catches much of this — do not rely on it to think for you.
618
622
  - **A new guard needs a negative self-test.** If you teach `test/validate.py` a new
619
- rule, add a step to `.github/workflows/validate.yml` that corrupts a copy and
620
- asserts the validator fails, then watch it with `npm run test:negatives`. A guard
623
+ rule, add the next-numbered file to `test/negatives/` that corrupts a copy and
624
+ asserts the validator fails, then watch it with
625
+ `python3 test/negatives.py -k <words from its name>`. Never a step inline in the
626
+ workflow: the validator refuses one, because it would run on CI only. A guard
621
627
  nobody proved can fail is decoration. **Check the base is green first** — if the
622
628
  repo already fails your new rule, the self-test passes for the wrong reason and
623
629
  proves nothing.
package/HOW-IT-WORKS.md CHANGED
@@ -46,7 +46,9 @@ It is written in three parts, and the middle one was learned the hard way:
46
46
  the pipeline entirely.
47
47
 
48
48
  Two modes need no task at all. `checkup` reports what has shipped without anyone
49
- confirming it. `setup` audits the documentation a project already has.
49
+ confirming it. `setup` audits the documentation a project already has. A third,
50
+ `waves`, takes the whole board as the task: one inventory, one canvas of the target
51
+ state, one batch of questions, then waves that each close in one pass.
50
52
 
51
53
  **Honest limit:** this measures the *description's* discriminating power, not the
52
54
  host's selection machinery. Three measured runs scored 7/10, 9/10 and 8/10 — and
@@ -92,8 +94,10 @@ An absent source that is never named looks identical to a source that was read.
92
94
 
93
95
  ### Then the grill, and it is mandatory
94
96
 
95
- One question per turn, each with a recommended answer, exploring the codebase
96
- before asking, until every decision branch is resolved.
97
+ Close what the sources can answer, then ask the material unknowns in one batch,
98
+ ordered by dependency, each with a recommended answer — one at a time only where the
99
+ answers depend on each other or the operator asks — until every decision branch is
100
+ resolved.
97
101
 
98
102
  - **Every answer is validated against the harvested sources.** The operator
99
103
  outranks any document — but only *out loud*, and a document the run proves stale
@@ -238,7 +242,8 @@ This is the part most pipelines skip, and it is the reason this one is trustwort
238
242
  rather than merely tidy.
239
243
 
240
244
  **Every guard is proven against a planted defect.** `npm run test:all` breaks the
241
- thing each of the **309** checks is about, and requires that check to reject it. A
245
+ thing each check is about, and requires that check to reject it — one file per
246
+ check in `test/negatives/`, eight shards on CI. A
242
247
  guard that has never been watched failing is not a guard; it is a comment.
243
248
 
244
249
  **The neighbour probe.** A check has a *subject* — the rule it is about — and
package/README.md CHANGED
@@ -200,6 +200,8 @@ until it is installed.
200
200
  | 3 + 4 · every spec and plan | the self-review reads its rules back — is every named check real, does anything contradict a locked decision or a rejected option, and what does this cost now versus at design time. Answers land as a committed `## Self-review` of computed numbers |
201
201
  | 6–10 + any check you write | [`gates.md`](plugins/task-pipeline/skills/task-pipeline/references/gates.md) — the three axes, the promotion ladder, gate anatomy, the probe recipe, ratchet floors |
202
202
  | any agent-time enforcement | [`hooks.md`](plugins/task-pipeline/skills/task-pipeline/references/hooks.md) — the `PreToolUse` contract, the fail-open hazard, the Claude-Code-only limit |
203
+ | 7 · the tag | [`deploy-targets.md`](plugins/task-pipeline/skills/task-pipeline/references/deploy-targets.md) → *When the release waits for an approval* — `pipeline.json` → `release.approval`: `checks` (tag, watch the run selected by the tag, report) or `reviewers` (the direct link to the run that is `waiting`) |
204
+ | between stages | [`continuity.md`](plugins/task-pipeline/skills/task-pipeline/references/continuity.md) Part 3 — workflow memory through Observatory, a planned handoff (`stage_checkpoint.py handoff` / `accept`), and `hooks/memory-nudge.sh`, which reminds once when a gate returned with no memory line after it |
203
205
 
204
206
  **Ported, not depended on.** Stage 0 is adapted from
205
207
  [Matt Pocock's `grilling` / `grill-with-docs`](https://github.com/mattpocock/skills)
@@ -214,9 +216,11 @@ an external provider.
214
216
 
215
217
  ### The intake grill (stage 0) — mandatory
216
218
 
217
- Before any technical work, task-pipeline interviews you relentlessly — one question
218
- per turn, each with a recommended answer, exploring the codebase before asking —
219
- until every decision branch is resolved and locked into a **task brief**. There is
219
+ Before any technical work, task-pipeline closes every question the codebase and the
220
+ project's records can answer, then asks you the rest in **one batch**, ordered by
221
+ dependency, each with a recommended answer — one at a time only where the answers
222
+ depend on each other or you ask for it — until every decision branch is resolved and
223
+ locked into a **task brief**. There is
220
224
  no "clear enough task" exemption: no stage-1 work starts without a committed,
221
225
  confirmed brief.
222
226
 
@@ -444,6 +448,29 @@ stopped. Each module's spec is a full dossier: architecture, entities and
444
448
  ownership, contracts in and out with their failure behavior, business rules, edge
445
449
  and failure cases, UI/Figma chain, limits, open questions.
446
450
 
451
+ ### Wave mode — the whole board, closed in its final form
452
+
453
+ `/task-pipeline waves` takes every open item a project carries — the board, the
454
+ carry-over ledgers, plan rows, unverified rows, uncovered scenarios, other products'
455
+ asks — plus your new requests, and closes them **in the system's final form rather
456
+ than through intermediate states**
457
+ ([`waves.md`](plugins/task-pipeline/skills/task-pipeline/references/waves.md)). It is
458
+ a program mode of the same stages: 0–4 once for the whole board, 5–8 once per wave,
459
+ 9–10 to close.
460
+
461
+ Wave 0 is the survey: one machine-readable inventory of every item by id, each verified
462
+ against the code — stale rows closed with their receipt, duplicates clustered. Questions
463
+ are closed from the sources first; what is genuinely yours (access, consent, money,
464
+ direction, an outward act) reaches you **once, as one batch, at the end of planning**,
465
+ each with a recommendation. A committed **canvas** lays the target state over the
466
+ current logic — as-is → to-be per module and contract, the integration seams, REQ →
467
+ module → wave, and what the new version deletes. The work is then cut into waves that
468
+ each close in one pass, the walking skeleton first, each with its exit criteria named
469
+ before it starts, and no wave builds a shape a later wave undoes. After every wave a
470
+ close pass verifies, runs one fix round, updates the docs, re-measures the inventory
471
+ and re-cuts what is left. The run takes the next wave without asking; a board too big
472
+ for one release becomes a program, carried on the canvas, never dropped.
473
+
447
474
  ### Loop guard — churn is detected, not endured
448
475
 
449
476
  Any repeating pass can start undoing the previous one: two shapes alternating, the
@@ -587,7 +614,7 @@ must say so.
587
614
  ### Held to Anthropic's own Skill authoring guidance
588
615
 
589
616
  Audited against the four Agent Skills pages. Most of it already held — `name`
590
- 13/64 chars, `description` 901/1024 chars, `SKILL.md` 278/500 lines, all 39 references
617
+ 13/64 chars, `description` 890/1024 chars, `SKILL.md` 268/500 lines, all 40 references
591
618
  linked **directly** from `SKILL.md`, and the bundle far under the 30 MB ceiling. What
592
619
  did not, now does:
593
620
 
@@ -942,6 +969,7 @@ recommendation, so you arm the whole run in one exchange. Detail:
942
969
  | [`references/model-tiering.md`](plugins/task-pipeline/skills/task-pipeline/references/model-tiering.md) | model policy, the `/model` reminder, overrides |
943
970
  | [`templates/`](plugins/task-pipeline/skills/task-pipeline/templates/README.md) | brief, carry-over ledger, `CONTEXT.md` and ADR skeletons, the doc map, both registers, the retro and its archive, the seeded `docgate.sh` and `hygiene.sh`, a worked hook |
944
971
  | [`references/adoption.md`](plugins/task-pipeline/skills/task-pipeline/references/adoption.md) | the first run in a project: greenfield seeding, and the brownfield walkthrough |
972
+ | [`references/waves.md`](plugins/task-pipeline/skills/task-pipeline/references/waves.md) | wave mode: the whole board as one inventory, one canvas of the target state, one question batch, then waves that each close in one pass |
945
973
  | [`references/setup.md`](plugins/task-pipeline/skills/task-pipeline/references/setup.md) | the entry audit: seven passes over the docs a project already has, offered once, output as a fix plan |
946
974
  | [`references/portability.md`](plugins/task-pipeline/skills/task-pipeline/references/portability.md) | the manifest of workflow decisions and their homes in the bundle, and the boundary against a project's own answers |
947
975
  | [`references/learned.md`](plugins/task-pipeline/skills/task-pipeline/references/learned.md) | rules earned by failure on a real multi-repository build, each with its incident, its check and its exit criterion — the table is the count, and it grows |
package/SKILL-CARD.md CHANGED
@@ -12,7 +12,7 @@ harmless.
12
12
  |---|---|
13
13
  | **Purpose** | Runs a substantial task through ten gated delivery stages — intake grill, docs study, brainstorm, spec, plan, subagent build, tests, lint/deploy, post-deploy, docs+registers, acceptance — refusing to advance until each gate passes |
14
14
  | **Owner** | ssheleg ([github.com/ssheleg/task-pipeline](https://github.com/ssheleg/task-pipeline)) |
15
- | **Version** | 1.91.2 |
15
+ | **Version** | 1.93.2 |
16
16
  | **Surface** | Claude Code (filesystem skill + plugin) and the vercel `skills` CLI. **Not** uploaded to the Skills API; custom Skills do not sync across surfaces |
17
17
  | **Dependencies** | None required. Optional: `context7` (MCP), `figma` (MCP), super-ux, agent-sync, graphify, obsidian-wiki, and **one of two browser channels** — `playwright` (CLI or MCP) or `chrome-devtools` (MCP); either satisfies the browser step and neither is required. Every stage's doctrine ships in-repo; the one conditional requirement is super-ux for the stage-3 UX track on a user-facing task |
18
18
  | **Evaluation status** | Suite authored, 5 categories. One recorded run, **self-observed by the author**; **zero blind runs on zero of three models** — the split, and the numbers, live in [`evals/RESULTS.md`](evals/RESULTS.md) and are computed by `evals/run.py` |
@@ -108,7 +108,9 @@ built, recommend it once and continue: `uv tool install graphifyy` →
108
108
 
109
109
  **Phase 2 — grill the user against that harvest**, then run the rest without
110
110
  mid-flight questions:
111
- 1. One question per turn — never bundle.
111
+ 1. Close what the sources answer; ask the rest in ONE batch, ordered by
112
+ dependency. One at a time only when answers depend on each other or the user
113
+ asks.
112
114
  2. Give a recommended answer with every question (+ one-line rationale).
113
115
  3. Explore the codebase before asking — if a search/read answers it, do that.
114
116
  4. **Validate every answer against the harvest.** When what the user says
@@ -211,7 +213,14 @@ not authorize an outward, irreversible action — stage 7 stops and asks.
211
213
  first**, then topologically, no cycles (a cycle means the cut is wrong). Every REQ
212
214
  maps to exactly one module. Then stages 3→10 run **per module**, one brick at a
213
215
  time; stages 0–2 run once, and the map's status column is the resume point. Single
214
- module → record "single module: <name>" and move on.
216
+ module → record "single module: <name>" and move on. **If the request is the whole
217
+ board** (wave mode, `waves`) — every open item plus the new requests — stages 0–4
218
+ run once over one machine-readable inventory verified against the code and a
219
+ committed canvas of the target state; the work is cut into waves that each close
220
+ in one pass (wave 1 the walking skeleton, exit criteria named first); stages 5–8
221
+ run per wave with a close pass after each — verify, one fix round, docs,
222
+ re-measure, re-cut — and 9–10 close the release. No wave builds a shape a later
223
+ wave undoes.
215
224
  3. **Spec** (manual) — write and commit the design; lock every shared contract
216
225
  (types, schemas, signatures, file layout) plus a **Global Constraints** block of
217
226
  exact values every later task inherits. Self-review it for placeholders,
package/evals/RESULTS.md CHANGED
@@ -40,7 +40,7 @@ or it belongs in a check.
40
40
 
41
41
  | Metric | Value | Computed by | As of |
42
42
  |---|---|---|---|
43
- | Evals authored | 46 (three suites: task-pipeline 28, evidence-docs 9, project-audit 9) | `python3 evals/run.py` → `suite: N evals` | 2026-08-31 |
43
+ | Evals authored | 47 (three suites: task-pipeline 29, evidence-docs 9, project-audit 9) | `python3 evals/run.py` → `suite: N evals` | 2026-10-11 |
44
44
  | Categories covered | 5 of 5, per suite | the suite's own `category` fields | 2026-08-31 |
45
45
  | Dated runs recorded | **4** | `python3 evals/run.py` → `recorded runs: N` | 2026-08-31 |
46
46
  | …of those, **blind** | **3** | run headings not marked `self-observed` | 2026-08-31 |
@@ -17,7 +17,7 @@
17
17
  "expected_behavior": [
18
18
  "Invokes the task-pipeline skill rather than starting to design or code inline",
19
19
  "Runs the stage-0 knowledge harvest BEFORE the first interview question, and writes a source ledger",
20
- "Asks interview questions one at a time, each with a recommended answer",
20
+ "Asks the material interview questions in one batch ordered by dependency, each with a recommended answer, after closing what the sources answer",
21
21
  "Writes no implementation code before a brief is committed and confirmed"
22
22
  ],
23
23
  "why": "The explicit invocation phrase is the primary trigger; the failure it guards is jumping to code."
@@ -361,6 +361,21 @@
361
361
  ],
362
362
  "why": "Measured before the change: answered `none` because no description offered a phrase for reviewing a PR, while review.md owns exactly that contract."
363
363
  },
364
+ {
365
+ "id": "TRIG-11",
366
+ "category": "should_trigger",
367
+ "skills": [
368
+ "task-pipeline"
369
+ ],
370
+ "query": "собери все задачи с доски и новые запросы и закрой их волнами",
371
+ "expected_behavior": [
372
+ "Recognises this as wave mode and runs `/task-pipeline waves`, not one change at a time",
373
+ "Builds one machine-readable inventory of every open item by id, each verified against the code, before any design",
374
+ "Closes questions from the sources first and asks the operator the rest once, as one batch with a recommendation each, at the end of planning",
375
+ "Cuts the work into waves that each close in one pass, wave 1 the walking skeleton, each with its exit criteria named before it starts"
376
+ ],
377
+ "why": "Wave mode is the operator's standard approach for a whole board (2026-10-11). A model that cannot reach it from the natural Russian request runs the board item by item and builds the intermediate states the mode exists to refuse."
378
+ },
364
379
  {
365
380
  "id": "NOTRIG-06",
366
381
  "category": "should_not_trigger",
package/package.json CHANGED
@@ -1,13 +1,13 @@
1
1
  {
2
2
  "name": "task-pipeline-skill",
3
- "version": "1.91.2",
3
+ "version": "1.93.2",
4
4
  "description": "Full-cycle delivery pipeline for coding agents: a mandatory built-in intake grill, then 10 gated stages (docs, brainstorm+decompose, spec, plan, build, tests, lint/deploy, post-deploy, docs/wiki, acceptance). Every stage's doctrine ships inside the skill — no companion plugin required. This package is the installer CLI.",
5
5
  "bin": {
6
6
  "task-pipeline": "bin/task-pipeline.js"
7
7
  },
8
8
  "scripts": {
9
- "test": "python3 test/validate.py && python3 test/graph_test.py && python3 test/project_audit_test.py && python3 test/packet_schema_test.py && python3 test/browser_claims_test.py && python3 test/visual_gate_test.py && python3 test/stage_checkpoint_test.py && npm run test:audit-regressions",
10
- "test:all": "python3 test/validate.py && python3 test/graph_test.py && python3 test/project_audit_test.py && python3 test/packet_schema_test.py && python3 test/browser_claims_test.py && python3 test/visual_gate_test.py && python3 test/stage_checkpoint_test.py && python3 test/negatives.py && npm run test:certify && npm run test:exposure && npm run test:probe && npm run test:anchors && npm run test:runner && npm run test:hooks && npm run test:artifacts && npm run test:docs && npm run test:audit-regressions",
9
+ "test": "python3 test/validate.py && python3 test/graph_test.py && python3 test/project_audit_test.py && python3 test/packet_schema_test.py && python3 test/browser_claims_test.py && python3 test/visual_gate_test.py && python3 test/stage_checkpoint_test.py && python3 test/memory_nudge_test.py && npm run test:audit-regressions",
10
+ "test:all": "python3 test/validate.py && python3 test/graph_test.py && python3 test/project_audit_test.py && python3 test/packet_schema_test.py && python3 test/browser_claims_test.py && python3 test/visual_gate_test.py && python3 test/stage_checkpoint_test.py && python3 test/memory_nudge_test.py && python3 test/negatives.py && npm run test:certify && npm run test:exposure && npm run test:probe && npm run test:anchors && npm run test:runner && npm run test:hooks && npm run test:artifacts && npm run test:docs && npm run test:audit-regressions",
11
11
  "test:negatives": "python3 test/negatives.py",
12
12
  "test:exposure": "python3 test/exposure_test.py",
13
13
  "test:probe": "python3 test/probe.py --self-test",
@@ -2,8 +2,8 @@
2
2
  "$schema": "https://json.schemastore.org/claude-code-plugin-manifest.json",
3
3
  "name": "task-pipeline",
4
4
  "displayName": "Task Pipeline",
5
- "description": "Runs a substantial task through a mandatory built-in intake grill, then 10 gated stages (docs, brainstorm+decompose, spec, plan, subagent build, tests, lint/deploy, post-deploy, docs/wiki, acceptance). Every stage's doctrine is built into the skill — no companion plugin required — with typed auto/judgment/manual gates, a frozen requirement spine that closes with evidence, a work board and a verification ledger that outlive a run, an exposure line naming what shipped unconfirmed, a progress rail computed from the project's own config, a loop guard whose review ceiling measures rather than stops, and stage-3 tracks for what a product does, how it sounds and how it looks. Two modes need no task: `checkup` (what is unverified) and `setup` (audit existing docs). Retro insights can publish upstream as issues, opt-in and redacted.",
6
- "version": "1.91.2",
5
+ "description": "Runs a substantial task through a mandatory built-in intake grill, then 10 gated stages (docs, brainstorm+decompose, spec, plan, subagent build, tests, lint/deploy, post-deploy, docs/wiki, acceptance). Every stage's doctrine is built into the skill — no companion plugin required — with typed auto/judgment/manual gates, a frozen requirement spine that closes with evidence, a work board and a verification ledger that outlive a run, an exposure line naming what shipped unconfirmed, a progress rail computed from the project's own config, a loop guard whose review ceiling measures rather than stops, and stage-3 tracks for what a product does, how it sounds and how it looks. Two modes need no task: `checkup` (what is unverified) and `setup` (audit existing docs); a third, `waves`, takes the whole board and closes it in waves that each finish in one pass. Retro insights can publish upstream as issues, opt-in and redacted.",
6
+ "version": "1.93.2",
7
7
  "author": {
8
8
  "name": "ssheleg",
9
9
  "url": "https://x.com/sshlg93"
@@ -1,6 +1,6 @@
1
1
  ---
2
- description: "Run a task through task-pipeline's gated stages (intake grill → docs → brainstorm → spec → plan → build → tests → deploy → post-deploy → docs/wiki → acceptance). Also: `setup` — audit the docs you already have; `checkup` — what has shipped unverified, with no task running."
3
- argument-hint: "<one-line task> | setup | checkup"
2
+ description: "Run a task through task-pipeline's gated stages (intake grill → docs → brainstorm → spec → plan → build → tests → deploy → post-deploy → docs/wiki → acceptance). Also: `waves` — close the whole board in waves; `setup` — audit the docs you already have; `checkup` — what has shipped unverified, with no task running."
3
+ argument-hint: "<one-line task> | waves | setup | checkup"
4
4
  ---
5
5
  Run the task below through `task-pipeline`'s gated stages. **Every stage's doctrine
6
6
  ships inside the skill** — no companion plugin is required for any of it. The
@@ -8,9 +8,10 @@ reference files are indexed in `SKILL.md`; this page is the run order, not the i
8
8
 
9
9
  Task: $ARGUMENTS
10
10
 
11
- > **Two other modes.** `setup` audits the documentation this project already has;
12
- > `checkup` reports what has shipped without a person confirming it, with no task in
13
- > flight. Both are at the bottom of this page.
11
+ > **Three other modes.** `waves` takes the whole board instead of one task;
12
+ > `setup` audits the documentation this project already has; `checkup` reports what
13
+ > has shipped without a person confirming it, with no task in flight. All three are at
14
+ > the bottom of this page.
14
15
 
15
16
  **Idempotent entry — inspect state first, never restart blindly.** If a pipeline
16
17
  TaskList from a previous run exists for this task, **resume** from the first incomplete
@@ -59,9 +60,10 @@ Pull what the project already knows about *this task*:
59
60
 
60
61
  Write the **source ledger** into the brief: a row per source, or an explicit *none found*.
61
62
 
62
- **Then the grill, and it is mandatory** (`references/grill.md`). One question per turn,
63
- each with a recommended answer, exploring the codebase before asking, until every
64
- decision branch is resolved.
63
+ **Then the grill, and it is mandatory** (`references/grill.md`). Close what the sources
64
+ can, then ask the material unknowns in ONE batch, ordered by dependency, each with a
65
+ recommended answer — one at a time only where answers depend on each other or the
66
+ operator asks — until every decision branch is resolved.
65
67
 
66
68
  - **Validate every answer against the harvested sources.** The operator outranks any
67
69
  document — but only out loud, and a doc the run proves stale is logged for stage 9.
@@ -188,6 +190,19 @@ Where you ask it to file what it found, it appends board rows whose `Source` nam
188
190
  checkup and its date — printing what it would add first, never silently.
189
191
  Doctrine: `references/exposure.md`.
190
192
 
193
+ ## `/task-pipeline waves`
194
+
195
+ **The whole board, closed in its final form.** Every open item — board, ledgers, plan
196
+ rows, unverified rows, uncovered scenarios, other products' asks — plus the new requests,
197
+ in one machine-readable inventory verified against the code. Questions are closed from
198
+ the sources; what remains goes to the operator once, as one batch, at the end of
199
+ planning. A committed canvas lays the target state over the current logic, and the work
200
+ is cut into waves that each close in one pass. Stages 0–4 run once, 5–8 per wave with a
201
+ close pass after each (verify, one fix round, docs, re-measure, re-cut), 9–10 to close.
202
+ It takes the next wave without asking, says once when the board is empty, and leaves
203
+ every sign-in, consent, payment and outward act to a person.
204
+ Doctrine: `references/waves.md`.
205
+
191
206
  ## `/task-pipeline setup`
192
207
 
193
208
  **The entry audit instead of a feature.** Seven passes over the documentation this
@@ -37,6 +37,17 @@
37
37
  "timeout": 20
38
38
  }
39
39
  ]
40
+ },
41
+ {
42
+ "matcher": "Bash|Edit|Write|MultiEdit",
43
+ "hooks": [
44
+ {
45
+ "type": "command",
46
+ "shell": "bash",
47
+ "command": "\"${CLAUDE_PLUGIN_ROOT}/hooks/memory-nudge.sh\"",
48
+ "timeout": 20
49
+ }
50
+ ]
40
51
  }
41
52
  ],
42
53
  "PostToolUseFailure": [
@@ -0,0 +1,49 @@
1
+ #!/usr/bin/env bash
2
+ # PostToolUse — a stage gate returned and no workflow-memory line follows it.
3
+ #
4
+ # The checkpoint doctrine (references/continuity.md, Part 3) asked every returned gate to
5
+ # write an Observatory checkpoint, or to record that memory is unavailable. It was a step
6
+ # the agent had to remember, and the measured adoption was one write in 293 sessions over
7
+ # fourteen days (sshlg-skills waves, 2026-10-11). This hook reminds at the moment it
8
+ # matters: once per stage line, as context the model reads, and never again for the same
9
+ # line. It decides nothing and blocks nothing.
10
+ #
11
+ # Silent everywhere else: no ledger means exit 0 after one file test.
12
+ set -uo pipefail
13
+ ledger="${CLAUDE_PROJECT_DIR:-$PWD}/.task-pipeline/run.md"
14
+ [ -f "$ledger" ] || exit 0
15
+ python3 - "$ledger" <<'PY' 2>/dev/null || true
16
+ import hashlib, json, os, re, sys
17
+ ledger = sys.argv[1]
18
+ try:
19
+ lines = open(ledger, encoding="utf-8").read().splitlines()
20
+ except OSError:
21
+ sys.exit(0)
22
+ last_stage = last_mem = -1
23
+ for i, l in enumerate(lines):
24
+ if re.match(r"^stage:\s*\S+\s", l):
25
+ last_stage = i
26
+ elif l.startswith("event: memory"):
27
+ last_mem = i
28
+ if last_stage < 0 or last_mem > last_stage:
29
+ sys.exit(0)
30
+ line = lines[last_stage]
31
+ mark = os.path.join(os.path.dirname(ledger), ".memory-nudged")
32
+ key = hashlib.sha256(line.encode()).hexdigest()[:16]
33
+ try:
34
+ if open(mark).read().strip() == key:
35
+ sys.exit(0)
36
+ except OSError:
37
+ pass
38
+ try:
39
+ open(mark, "w").write(key + "\n")
40
+ except OSError:
41
+ pass
42
+ sid = re.match(r"^stage:\s*(\S+)", line).group(1)
43
+ msg = (f"task-pipeline: stage {sid}'s gate returned and no workflow-memory line follows it. "
44
+ "With Observatory's tools: `scripts/stage_checkpoint.py emit` → observatory_checkpoint_write "
45
+ "→ `stage_checkpoint.py record --answer -`. Without them: "
46
+ "`stage_checkpoint.py record --unavailable \"<why>\"`. (references/continuity.md, Part 3)")
47
+ print(json.dumps({"hookSpecificOutput": {"hookEventName": "PostToolUse", "additionalContext": msg}}))
48
+ PY
49
+ exit 0
@@ -218,7 +218,9 @@ Since v1.50.0 the plugin carries hooks of its own. `hooks/release-gate.sh`
218
218
  (`PreToolUse` on `Bash`) refuses an **outward, irreversible act** — `git tag`, a
219
219
  tag push, `gh release create`, `npm publish` — while the run says the suite has not
220
220
  passed. `hooks/gate-observer.sh` (`PostToolUse` and `PostToolUseFailure`) records
221
- what the declared gate command actually did.
221
+ what the declared gate command actually did. `hooks/memory-nudge.sh` (`PostToolUse` on `Bash|Edit|Write|MultiEdit`) reminds,
222
+ once per returned gate, that no workflow-memory line follows it
223
+ ([`continuity.md`](https://github.com/ssheleg/task-pipeline/blob/main/plugins/task-pipeline/skills/task-pipeline/references/continuity.md), Part 3).
222
224
 
223
225
  **Two lessons from v1.50.0, both shipped as defects and both fixed in v1.51.0.**
224
226
 
@@ -121,7 +121,8 @@ default is `Sev × Blast + age_bonus` ([`references/portable-method.md`](referen
121
121
  the local priority contract) — and the operator accepts them. Effort never ranks inside an
122
122
  audit: what a fix costs is the fixer's decision, not the finder's
123
123
  ([`references/portable-method.md`](references/portable-method.md)). An audit
124
- that edits while it reads cannot be re-run to check itself.
124
+ that edits while it reads cannot be re-run to check itself. In `task-pipeline`'s wave
125
+ mode these rows and the JSON sidecar are wave 0's input: they join its inventory by id.
125
126
 
126
127
  ## A finding keeps its axes apart, or it is a guess wearing a verdict
127
128