task-pipeline-skill 1.93.2 → 1.94.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (49) hide show
  1. package/CHANGELOG.md +151 -1
  2. package/README.md +42 -9
  3. package/SKILL-CARD.md +1 -1
  4. package/bin/task-pipeline.js +64 -33
  5. package/cursor/rules/task-pipeline.mdc +10 -5
  6. package/evals/RESULTS.md +1 -1
  7. package/evals/task-pipeline.evals.json +16 -0
  8. package/package.json +3 -3
  9. package/plugins/task-pipeline/.claude-plugin/plugin.json +1 -1
  10. package/plugins/task-pipeline/agents/verifier.md +4 -1
  11. package/plugins/task-pipeline/commands/task-pipeline.md +22 -8
  12. package/plugins/task-pipeline/hooks/memory-nudge.sh +45 -3
  13. package/plugins/task-pipeline/skills/evidence-docs/references/gates.md +6 -3
  14. package/plugins/task-pipeline/skills/evidence-docs/references/hooks.md +2 -1
  15. package/plugins/task-pipeline/skills/evidence-docs/references/retrospective.md +26 -1
  16. package/plugins/task-pipeline/skills/task-pipeline/SKILL.md +13 -11
  17. package/plugins/task-pipeline/skills/task-pipeline/graph.schema.json +89 -4
  18. package/plugins/task-pipeline/skills/task-pipeline/pipeline.schema.json +7 -0
  19. package/plugins/task-pipeline/skills/task-pipeline/references/backlog.md +25 -0
  20. package/plugins/task-pipeline/skills/task-pipeline/references/certification.md +45 -1
  21. package/plugins/task-pipeline/skills/task-pipeline/references/continuity.md +95 -26
  22. package/plugins/task-pipeline/skills/task-pipeline/references/deploy-targets.md +30 -4
  23. package/plugins/task-pipeline/skills/task-pipeline/references/doctrine-map.md +1 -0
  24. package/plugins/task-pipeline/skills/task-pipeline/references/gates.md +6 -3
  25. package/plugins/task-pipeline/skills/task-pipeline/references/grill.md +1 -1
  26. package/plugins/task-pipeline/skills/task-pipeline/references/hooks.md +2 -1
  27. package/plugins/task-pipeline/skills/task-pipeline/references/iteration.md +387 -0
  28. package/plugins/task-pipeline/skills/task-pipeline/references/knowledge-sources.md +1 -0
  29. package/plugins/task-pipeline/skills/task-pipeline/references/loop-guard.md +4 -1
  30. package/plugins/task-pipeline/skills/task-pipeline/references/portability.md +1 -0
  31. package/plugins/task-pipeline/skills/task-pipeline/references/retrospective.md +26 -1
  32. package/plugins/task-pipeline/skills/task-pipeline/references/stages.md +35 -11
  33. package/plugins/task-pipeline/skills/task-pipeline/references/waves.md +80 -36
  34. package/plugins/task-pipeline/skills/task-pipeline/references/work-graph.md +54 -5
  35. package/plugins/task-pipeline/skills/task-pipeline/scripts/backlog_sources.py +212 -0
  36. package/plugins/task-pipeline/skills/task-pipeline/scripts/context_packets.py +3 -3
  37. package/plugins/task-pipeline/skills/task-pipeline/scripts/graph.py +205 -22
  38. package/plugins/task-pipeline/skills/task-pipeline/scripts/lessons.py +1137 -0
  39. package/plugins/task-pipeline/skills/task-pipeline/scripts/stage_checkpoint.py +120 -15
  40. package/plugins/task-pipeline/skills/task-pipeline/scripts/waves.py +546 -0
  41. package/plugins/task-pipeline/skills/task-pipeline/templates/README.md +6 -0
  42. package/plugins/task-pipeline/skills/task-pipeline/templates/backlog-sources.schema.json +96 -0
  43. package/plugins/task-pipeline/skills/task-pipeline/templates/canvas.md +97 -0
  44. package/plugins/task-pipeline/skills/task-pipeline/templates/dossier.md +82 -0
  45. package/plugins/task-pipeline/skills/task-pipeline/templates/inventory.schema.json +94 -0
  46. package/plugins/task-pipeline/skills/task-pipeline/templates/lesson.schema.json +221 -0
  47. package/plugins/task-pipeline/skills/task-pipeline/templates/questions.md +45 -0
  48. package/plugins/task-pipeline/skills/task-pipeline/templates/retro.md +4 -0
  49. package/plugins/task-pipeline/skills/task-pipeline/templates/run.md +2 -2
package/CHANGELOG.md CHANGED
@@ -1,10 +1,160 @@
1
+ ## v1.94.1 — 2026-10-13
2
+
3
+ Records the missing retrospective declarations that stopped the v1.94.0 release
4
+ before publication. The accepted release-iteration payload is unchanged; the
5
+ version metadata advances so the failed tag remains immutable. Local-tag
6
+ structural validation reads both declarations before another release attempt.
7
+
8
+ ## v1.94.0 — 2026-10-13
9
+
10
+ Guards: 438 → **438**; property checks 15 → **15**. The owner validator and
11
+ focused regression suites gain coverage; the counted negative-file corpus is unchanged.
12
+
13
+ The accepted feature now also rejects loss of node identity or evidence during
14
+ inventory synchronization. Waiting nodes retain typed wait IDs and watcher
15
+ locators, cannot certify or close while waiting, and report the runnable frontier
16
+ with distinct exit states. Release authority is recorded separately from a locator;
17
+ source policies and scoped grants are carried into execution packets. Local regression
18
+ and history checks cover these boundaries. Native Observatory/Fabric handoff
19
+ execution remains unverified in this release receipt.
20
+
21
+ **The release iteration — the loop around the waves** (`references/iteration.md`). The
22
+ project moves in whole releases: survey, module dossiers integrated into one canvas,
23
+ question rounds in batches, a parallel build, verification as each node lands, one release
24
+ verified as released, the next pool handed back. A finding made mid-iteration joins the
25
+ inventory; a closed hotfix lane of five entries is the only exception.
26
+
27
+ - **Trigger.** "release iteration" / "итерация релиза" reaches the mode beside "waves" /
28
+ "волнами"; `/task-pipeline iteration` is listed in the command, and the Cursor rule's
29
+ wave paragraph names the loop.
30
+ - **Risk classes R1–R3** on each node (`graph.schema.json` and `graph.py validate` accept
31
+ `risk`; any other value is refused). A round is the three blind tiers plus one fix cycle;
32
+ the first is always the full three; R1 owes one passing round, R2 two, R3 three, one of
33
+ them recorded adversarial. A wave's stage 7 integrates without tagging; the release's stage-7 gate and
34
+ stage 8's trio run once, at steps 10 and 11.
35
+ - **Lessons across projects.** lesson/1 (`templates/lesson.schema.json`) and
36
+ `scripts/lessons.py`: a retro entry with a `**Lesson:**` line becomes a lesson in a local
37
+ index every install has (`~/.sshlg-skills/lessons/index.jsonl` where the family's directory
38
+ exists — hosted there as task-pipeline's by the family: sshlg-skills B-181 and its
39
+ `state-json.md` section *Other members' files under `~/.sshlg-skills/`* (#209);
40
+ `~/.task-pipeline/lessons/index.jsonl` otherwise, moved there once, aloud, if the family's
41
+ directory appears later; `$TASK_PIPELINE_LESSONS` or `--index` move it). Source 7b
42
+ of the harvest reads it by the task's nouns, then a shared store whose search filters by
43
+ kind. Writing to Observatory works today through `observatory_record`. The redaction list
44
+ binds every lesson; on the estate it relaxes rule 2 for the evidence commit and a
45
+ pseudonymous project key only.
46
+ - **Wave tooling.** `scripts/waves.py` (merge, assign, count, validate, sync-graph) with
47
+ inventory/1 (`templates/inventory.schema.json`), and the canvas, question-queue, dossier
48
+ and backlog-sources templates. waves.md links the schemas instead of a field table and
49
+ no longer sends public readers to a private repository; the shipped
50
+ `backlog-sources.schema.json` is the rule, the Fabric contract its provenance.
51
+ - **Continuity.** The loop is armed by `run.loop`, the preflight answer or a standing
52
+ instruction the host carries, cited as `loop: armed by <source>`; a watcher may merge,
53
+ release a lease, rebase or notify where a standing instruction names the act; waits that
54
+ outlive the session go on a durable trigger; at the compaction signal the next task is
55
+ written down, not started.
56
+ - New suites in `npm test`: `lessons_test.py`, `waves_test.py`, `continuity_doc_test.py`;
57
+ eval INSTR-08 (wave 0).
58
+ - **Rounds owed are enforced.** `graph.py close` refuses a node with a `risk` until its
59
+ class's rounds have passed — passing rounds, read from the certification history; a
60
+ failed round counts for nothing (R1 one, R2 two, R3 three, one of them a passing round
61
+ recorded with `certify --kind adversarial`); `certify` prints `round N: k of M owed passing
62
+ rounds — not closable yet`. certification.md
63
+ gains *Rounds owed by risk class*, and the churn doctrine exempts owed rounds from "a clean
64
+ round ends the loop".
65
+ - `waves.py sync-graph` judges a re-cut as a whole, so a chain moved up a wave is never
66
+ refused halfway. `backlog_sources.py` refuses unknown keys and applies every source rule
67
+ to every source, and the shipped schema where `jsonschema` is installed.
68
+ - `lessons.py emit-observatory` sends the commit as `commit:` + 12 hex (the store's redactor
69
+ keeps that form and removes a 40-hex SHA) and revises a recorded lesson instead of minting
70
+ a second; a git that does not answer in time is its own refusal.
71
+ - `waves.py sync-graph` also writes each plan node's `risk` onto its work-graph node (a
72
+ `risk` revision; lowering a class needs `--lower-why`), so the rounds `close` enforces
73
+ apply to every planned node, not only to a hand-edited graph.
74
+ - `lessons.py` reads stdin as UTF-8 and prints machine output as ASCII-escaped JSON, so a
75
+ non-UTF-8 locale loses nothing a lesson carries. `rebuild` reports unreadable sources
76
+ and preserves the prior index. A complete scan can replace a corrupt index after
77
+ keeping its backup (`python3 test/lessons_test.py`).
78
+ - Every lessons-index operation runs under one lock (the index directory's `.lock`, plus the
79
+ standalone directory's on the default path). A file that cannot be READ is a refusal that
80
+ names it and writes nothing; one that cannot be PARSED — the family index or the
81
+ standalone one alike — is kept as `.corrupt-<date>` and never makes a command exit 1. Lines
82
+ in a newer index format are skipped, counted and kept on write. When both index files
83
+ exist they are merged once: only lessons the family index lacks are copied, its own copy
84
+ wins, newer-format lines are carried across, and the old file becomes `.migrated`.
85
+ - `emit-observatory --tool observatory_lesson` emits the engine's lesson-kind arguments
86
+ (the lesson's own fields, plus `origin{projectId, commit}` — the engine's inputSchema); the agent
87
+ picks it where the session lists that tool, `observatory_record` otherwise.
88
+ - `waves.py` refuses a plan whose risk, wave, closes or release value it does not know.
89
+ - **Memory unavailable, said once per run.** `stage_checkpoint.py record --unavailable
90
+ "<why>" --for-run` appends one `unavailable for this run` line and leaves a marker in
91
+ `.task-pipeline/memory.json` keyed to the run's topic and start date (the module-map field
92
+ may change mid-run; a ledger with no `Run:` line is refused, exit 2); `hooks/memory-nudge.sh`
93
+ and `stage_checkpoint.py state` honour it only while that run's ledger still carries the
94
+ marker's own line — a ledger reseeded at stage 0, even the same day, does not — and any
95
+ later `record --answer` clears it. The first nudge of a run names the Observatory engine.
96
+ - **Plain and npm installs deliver all three skills.** `./install.sh` and
97
+ `npx task-pipeline-skill` now install `task-pipeline`, `evidence-docs` and
98
+ `project-audit` into `~/.claude/skills/<name>`, plus the command; every source is
99
+ verified present before anything is copied. **`--force` now overwrites all three skill
100
+ directories and the command**, not the task-pipeline skill alone. The closing notice
101
+ names the role agents and every hook a plain copy cannot carry, and the plugin command.
102
+ **A partial earlier install is refused as mixed versions** (some of the three skills
103
+ present, others not), nothing written, until `--force` brings all three to one version.
104
+ - Suite `test/install_test.sh` (both installers, fresh `HOME`) joins `npm test`.
105
+
106
+ ## v1.93.3 — the wave-2 evidence declares its dead commits; a retried handoff stays one offer
107
+
108
+ A re-certification reading of v1.93.2 and an independent observer found six things.
109
+
110
+ - **The v1.93.2 evidence rewrite passed the documentation gate by de-backticking.** Six
111
+ pre-squash SHAs of PR #109 (`941bed8`, `36cfc1c`, `ffa42ab`, `933cf63`, `340556e`,
112
+ `7357522`) were left as plain text beside a branch that no longer exists; `docgate.sh`
113
+ only resolves backticked SHAs, so it read none of them. They are backticked again and
114
+ listed in a `docgate:known-dead` marker in `docs/evidence/retro.md`, with the reason and
115
+ the way to reach them: `git fetch origin pull/109/head` (all six are ancestors of that
116
+ ref). The deleted branch name is gone. The make-skill commit `60ca8e2` in row R09 and
117
+ B-120 is declared there too: it is make-skill's commit, not this repository's. A fresh
118
+ clone still cannot resolve the seven; the gate now passes because they are declared.
119
+ - **A retried handoff no longer replaces itself (R11).** `stage_checkpoint.py handoff` put
120
+ the ledger's whole length in the idempotency key, so a `gate:` line from
121
+ `hooks/gate-observer.sh` or a `record --unavailable` line between two retries made the
122
+ retry a new offer, and Observatory replaces an unaccepted older offer with a new one.
123
+ The key now counts only memory events (checkpoint, refused, handoff offered), so
124
+ unrelated appends leave it alone and a recorded offer still moves it.
125
+ `test/stage_checkpoint_test.py` pins both; `references/continuity.md` Part 3 says it.
126
+ - **Declared task sources have a mechanism and a test (R13).**
127
+ `scripts/backlog_sources.py` reads `docs/backlog-sources.json` (the Fabric workspace's
128
+ `knowledge/backlog.md` contract), prints the sources a wave-0 harvest reads, refuses a
129
+ manifest the harvest could not follow (exit 1) and reports a discovered source the
130
+ manifest does not list (exit 3). `test/backlog_sources_test.py` builds fixture
131
+ repositories: 19 malformed manifests, a symlinked source, the finding and the no-manifest
132
+ case. The script accepted all 22 manifests in the operator's checkouts.
133
+ - **The release approval mode has a test (R16).** `test/release_approval_test.py` pins
134
+ the schema's `checks | reviewers` enum (six other values refused under `jsonschema`),
135
+ the example's value and the doctrine section in `references/deploy-targets.md`. No
136
+ script reads the mode, because the agent reads it at stage 7, so the test pins the
137
+ schema, the example and the doctrine.
138
+ - **CI runs every suite of the `npm test` equation.** The validate job's explicit list
139
+ lacked `memory_nudge_test.py`, which `npm test` has run since v1.93.0. It now runs that
140
+ suite and the two new ones.
141
+ - **Recorded late, from v1.93.0:** the eight `negatives` shards report as one status,
142
+ *Negative self-tests*, and the ruleset on `main` requires it beside `validate` and
143
+ *House skill audit*, so a red shard blocks a merge.
144
+ - **Correction to v1.93.2's entry:** it says the SHAs "now name the squash commit". They
145
+ were still unresolvable, and only the gate stopped seeing them. This entry fixes that.
146
+
147
+ Guards: 438 → **438**; property checks 15 → **15**. No plant changed; two suites were added
148
+ to `npm test` and `test:all`.
149
+
1
150
  ## v1.93.2 — v1.93.0's payload, with evidence a clone can follow
2
151
 
3
152
  `v1.93.1` published nothing either: its release suite reached the documentation gate
4
153
  (`npm run test:docs`, run by `release.yml` and not by the PR's checks) and refused 17
5
154
  commit references in `docs/evidence/` — the wave-2 branch SHAs became unreachable when
6
155
  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
156
+ They now name the squash commit and the runs as plain numbers (corrected in v1.93.3: the six SHAs
157
+ were de-backticked, not resolved). Same payload; this is
8
158
  the third tag for it, and `docgate.sh` passed locally before this one was pushed.
9
159
 
10
160
  Guards: 438 → **438**; property checks 15 → **15**. No check changed.
package/README.md CHANGED
@@ -201,7 +201,7 @@ until it is installed.
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
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 |
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 — unless the run recorded memory unavailable with `--for-run` |
205
205
 
206
206
  **Ported, not depended on.** Stage 0 is adapted from
207
207
  [Matt Pocock's `grilling` / `grill-with-docs`](https://github.com/mattpocock/skills)
@@ -471,6 +471,26 @@ close pass verifies, runs one fix round, updates the docs, re-measures the inven
471
471
  and re-cuts what is left. The run takes the next wave without asking; a board too big
472
472
  for one release becomes a program, carried on the canvas, never dropped.
473
473
 
474
+ **The project moves in releases, not fix by fix**
475
+ ([`iteration.md`](plugins/task-pipeline/skills/task-pipeline/references/iteration.md)).
476
+ A finding joins the inventory; only a closed five-entry hotfix lane ships alone. Each
477
+ iteration runs in this order:
478
+ - the survey;
479
+ - module dossiers written in parallel, laid onto one canvas until a pass changes nothing;
480
+ - questions asked in rounds, never one at a time, while agents keep working;
481
+ - a parallel build, each node checked the moment it lands: one round of three blind
482
+ readings for every node, and two or three passing rounds by its risk class (R2, R3 — one
483
+ of the three recorded adversarial);
484
+ - one release, checked as released;
485
+ - the next pool, handed to you grouped by module.
486
+
487
+ Lessons carry over. Every install reads the project's retrospective, and keeps a local
488
+ index of every project's lessons on the machine (`scripts/lessons.py`), which stage 0
489
+ queries by the task's nouns. Where the session lists Project Observatory, agents also write
490
+ their lessons there — that works today. Reading them back from the store needs an engine
491
+ whose search filters by kind; until the session's engine has it, the ledger says
492
+ `shared lessons: unfilterable` and only the local index is read.
493
+
474
494
  ### Loop guard — churn is detected, not endured
475
495
 
476
496
  Any repeating pass can start undoing the previous one: two shapes alternating, the
@@ -614,7 +634,7 @@ must say so.
614
634
  ### Held to Anthropic's own Skill authoring guidance
615
635
 
616
636
  Audited against the four Agent Skills pages. Most of it already held — `name`
617
- 13/64 chars, `description` 890/1024 chars, `SKILL.md` 268/500 lines, all 40 references
637
+ 13/64 chars, `description` 887/1024 chars, `SKILL.md` 270/500 lines, all 41 references
618
638
  linked **directly** from `SKILL.md`, and the bundle far under the 30 MB ceiling. What
619
639
  did not, now does:
620
640
 
@@ -874,8 +894,8 @@ npx github:ssheleg/task-pipeline # straight from GitHub
874
894
  npx task-pipeline-skill # from the npm registry
875
895
  ```
876
896
  (package is `task-pipeline-skill` — the unscoped `task-pipeline` name is taken
877
- on npm; installs the same skill + `/task-pipeline` command into `~/.claude`,
878
- idempotent, `--force` to overwrite)
897
+ on npm; installs the same three skills + `/task-pipeline` command into `~/.claude` as
898
+ the plain-skill path below, idempotent, `--force` to overwrite)
879
899
 
880
900
  **Moving the paperwork off the legacy directory name — optional, always:**
881
901
  ```bash
@@ -902,9 +922,21 @@ Rules. The rule is self-contained (no external links), so it works copied anywhe
902
922
  git clone https://github.com/ssheleg/task-pipeline
903
923
  cd task-pipeline && ./install.sh
904
924
  ```
905
- (copies the skill into `~/.claude/skills/task-pipeline` and the `/task-pipeline`
906
- command into `~/.claude/commands/`; idempotent — rerun skips existing installs,
907
- `./install.sh --force` overwrites)
925
+ (copies the plugin's three skills — `task-pipeline`, `evidence-docs`, `project-audit` —
926
+ into `~/.claude/skills/<name>` and the `/task-pipeline` command into
927
+ `~/.claude/commands/`; idempotent — rerun skips existing installs, `./install.sh --force`
928
+ overwrites. **What it cannot carry, and says so at the end of the run:** the role agents
929
+ (`plugins/task-pipeline/agents/`, which then run on the main thread) and the hooks
930
+ (`build-gate`, `gate-observer`, `memory-nudge`, `release-gate`, `run-lifecycle`, so the
931
+ gates are held by the doctrine and the run ledger rather than by the harness). Both
932
+ arrive only with the plugin above. Both installers refuse while the plugin is installed,
933
+ because a plain copy would shadow it.)
934
+
935
+ **Optional companion — Project Observatory.** Workflow checkpoints, planned handoffs
936
+ between executors and the shared lesson store come from a separately installed public
937
+ engine, [passioncode-ai/project-observatory-dashboard](https://github.com/passioncode-ai/project-observatory-dashboard)
938
+ (its README: *Install*, *MCP*). Without it every one of those degrades to one ledger line
939
+ and the run continues.
908
940
 
909
941
  ### Updating
910
942
 
@@ -929,8 +961,8 @@ the same Claude Code install yields a duplicate, shadowing skill.
929
961
  | Claude Code (plugin) | `claude plugin marketplace update task-pipeline` → `claude plugin update task-pipeline@task-pipeline` → restart |
930
962
  | Any agent (skills CLI) | `npx skills update task-pipeline --global --yes`; to add: repeated `--agent <name>` (never `claude-code` when the plugin is installed) |
931
963
  | Cursor | skills CLI (above) with `--agent cursor`, or re-copy the `.mdc` per project |
932
- | npm | `npx task-pipeline-skill@latest` / `npx github:ssheleg/task-pipeline` (ephemeral — always latest) |
933
- | Plain skill | `git pull && ./install.sh --force` |
964
+ | npm | `npx task-pipeline-skill@latest --force` / `npx github:ssheleg/task-pipeline --force` — `--force` brings all three skills and the command to that version; without it an existing install is skipped, and a partial one is refused as mixed versions |
965
+ | Plain skill | `git pull && ./install.sh --force` (all three skills and the command) |
934
966
 
935
967
  ### Prerequisites
936
968
 
@@ -970,6 +1002,7 @@ recommendation, so you arm the whole run in one exchange. Detail:
970
1002
  | [`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 |
971
1003
  | [`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
1004
  | [`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 |
1005
+ | [`references/iteration.md`](plugins/task-pipeline/skills/task-pipeline/references/iteration.md) | release iteration: the loop around the waves — dossiers, integration until it converges, question rounds, checks as each node lands (R1–R3), one release checked as released, the next pool, the shared lesson store |
973
1006
  | [`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 |
974
1007
  | [`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 |
975
1008
  | [`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.93.2 |
15
+ | **Version** | 1.94.1 |
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` |
@@ -2,9 +2,11 @@
2
2
  /*
3
3
  * task-pipeline installer CLI.
4
4
  *
5
- * Installs the task-pipeline skill into ~/.claude/skills/task-pipeline and
6
- * the /task-pipeline slash command into ~/.claude/commands/ (same layout as
7
- * install.sh). Idempotent: existing installs are skipped unless --force.
5
+ * Installs the plugin's three skills (task-pipeline, evidence-docs,
6
+ * project-audit) into ~/.claude/skills/<name> and the /task-pipeline slash
7
+ * command into ~/.claude/commands/ (same layout as install.sh), and names the
8
+ * agents and hooks a plain copy cannot carry. Idempotent: existing installs are
9
+ * skipped unless --force.
8
10
  *
9
11
  * Zero dependencies, non-interactive. For other agents (Cursor, Codex, 70+)
10
12
  * use: npx skills add ssheleg/task-pipeline
@@ -22,8 +24,10 @@ function usage() {
22
24
  console.log(`task-pipeline installer
23
25
 
24
26
  Usage:
25
- npx task-pipeline-skill [--force] install skill + /task-pipeline command
26
- into ~/.claude (skip existing unless --force)
27
+ npx task-pipeline-skill [--force] install the three skills (task-pipeline,
28
+ evidence-docs, project-audit) + /task-pipeline
29
+ command into ~/.claude (skip existing unless
30
+ --force); agents and hooks need the plugin
27
31
  npx task-pipeline-skill --help
28
32
 
29
33
  npx task-pipeline-skill migrate-artifacts [--dry-run]
@@ -124,30 +128,38 @@ function installOne(label, src, dest, isDir, force) {
124
128
  /**
125
129
  * Say what this path does NOT install, and what runs instead.
126
130
  *
127
- * `agents/` is a Claude Code plugin capability; `install()` copies the skill directory
128
- * and the command and nothing else. That is the design — the brief chose plugin agents
129
- * with honest degradation — and it was silent, which is the part that is not. An
130
- * operator reading doctrine that names `task-pipeline:verifier` finds a name that
131
- * resolves to nothing and no explanation anywhere in what they ran.
131
+ * `agents/` and `hooks/` are Claude Code plugin capabilities; `main()` copies the three
132
+ * skills and the command and nothing else. That is the design — the brief chose plugin
133
+ * agents with honest degradation — and it was silent about the hooks, which is the part
134
+ * that was not. An operator reading doctrine that names `task-pipeline:verifier` or
135
+ * `hooks/memory-nudge.sh` would find a name that resolves to nothing. The notice lists
136
+ * the agents' count and every hook by name, says what runs instead, gives the plugin
137
+ * command, and points at the optional Observatory engine.
132
138
  */
133
139
  function discloseAgents() {
134
- const dir = path.join(ROOT, 'plugins', 'task-pipeline', 'agents');
135
- let files = [];
136
- try {
137
- files = fs.readdirSync(dir).filter((f) => f.endsWith('.md'));
138
- } catch (e) {
139
- return; // no agents shipped: nothing to disclose
140
+ const base = path.join(ROOT, 'plugins', 'task-pipeline');
141
+ const list = (dir, ext) => {
142
+ try { return fs.readdirSync(path.join(base, dir)).filter((f) => f.endsWith(ext)).sort(); }
143
+ catch (e) { return []; }
144
+ };
145
+ const agents = list('agents', '.md');
146
+ const hooks = list('hooks', '.sh').map((f) => f.replace(/\.sh$/, ''));
147
+ if (!agents.length && !hooks.length) return;
148
+ const lines = ['', 'Not installed — Claude Code plugin capabilities a plain copy cannot carry:'];
149
+ if (agents.length) {
150
+ lines.push(` - plugins/task-pipeline/agents/ (${agents.length} role agents): every role still runs, on the`,
151
+ ' main thread instead of in its own context — context and speed, not doctrine.');
140
152
  }
141
- if (!files.length) return;
142
- console.log(
143
- `\nNot installed: plugins/task-pipeline/agents/ (${files.length} file(s)).\n` +
144
- ' Role agents are a Claude Code plugin capability; this path installs the skill\n' +
145
- ' and the command only. Every role still runs — on the main thread instead of in\n' +
146
- ' its own context, which costs context and speed, not doctrine.\n' +
147
- ' For the agent-backed version, install the plugin:\n' +
148
- ` claude plugin marketplace add ${REPO}\n` +
149
- ' claude plugin install task-pipeline@task-pipeline'
150
- );
153
+ if (hooks.length) {
154
+ lines.push(` - hooks: ${hooks.join(', ')}. Without them the gates`,
155
+ ' are checked by the doctrine and the run ledger, not by the harness.');
156
+ }
157
+ lines.push(' For both, install the plugin instead (then remove these plain copies):',
158
+ ` claude plugin marketplace add ${REPO}`,
159
+ ' claude plugin install task-pipeline@task-pipeline',
160
+ ' Optional companion for checkpoints, handoffs and shared lessons: Project Observatory,',
161
+ ' https://github.com/passioncode-ai/project-observatory-dashboard (README: Install, MCP).');
162
+ console.log(lines.join('\n'));
151
163
  }
152
164
 
153
165
  function offerRouters() {
@@ -244,9 +256,15 @@ function main(argv) {
244
256
  return 2;
245
257
  }
246
258
 
247
- const skillSrc = path.join(ROOT, 'plugins/task-pipeline/skills/task-pipeline');
259
+ // All three skills the plugin ships: task-pipeline names evidence-docs as its doc
260
+ // doctrine and runs project-audit as wave 0's sidecar (CHANGELOG, Unreleased).
261
+ const SKILLS = ['task-pipeline', 'evidence-docs', 'project-audit'];
262
+ const skillSrcs = SKILLS.map((s) => path.join(ROOT, 'plugins/task-pipeline/skills', s));
248
263
  const cmdSrc = path.join(ROOT, 'plugins/task-pipeline/commands/task-pipeline.md');
249
- for (const [p, what] of [[skillSrc, 'skill sources'], [cmdSrc, 'command source']]) {
264
+ // Every source is checked before anything is copied: a skill counts as present only
265
+ // with its SKILL.md, the same test install.sh makes.
266
+ for (const [p, what] of [...skillSrcs.map((p) => [path.join(p, 'SKILL.md'), 'skill sources']),
267
+ [cmdSrc, 'command source']]) {
250
268
  if (!fs.existsSync(p)) {
251
269
  console.error(`error: ${what} missing at ${p} — corrupted package?`);
252
270
  return 1;
@@ -278,13 +296,26 @@ Rerun with --force if you deliberately want the plain copy instead.`);
278
296
  return 3;
279
297
  }
280
298
 
281
- installOne(
282
- 'task-pipeline skill ',
283
- skillSrc,
284
- path.join(claude, 'skills', 'task-pipeline'),
299
+ // Mixed versions: an earlier install left some of the three skills and not the others.
300
+ // Installing only the missing ones would pair skills from two releases — refuse, name both
301
+ // sets, and let --force bring all three to this version (install.sh does the same).
302
+ if (!force) {
303
+ const present = SKILLS.filter((s) => fs.existsSync(path.join(claude, 'skills', s)));
304
+ const absent = SKILLS.filter((s) => !present.includes(s));
305
+ if (present.length && absent.length) {
306
+ console.error(`refusing: mixed versions — ${present.join(', ')} already installed, ` +
307
+ `${absent.join(', ')} not. Rerun with --force to install all three at this ` +
308
+ 'version. Nothing was written.');
309
+ return 4;
310
+ }
311
+ }
312
+ SKILLS.forEach((s, i) => installOne(
313
+ `${s} skill`.padEnd(22),
314
+ skillSrcs[i],
315
+ path.join(claude, 'skills', s),
285
316
  true,
286
317
  force
287
- );
318
+ ));
288
319
  installOne(
289
320
  '/task-pipeline command',
290
321
  cmdSrc,
@@ -8,7 +8,7 @@ alwaysApply: false
8
8
  Self-contained rule (Cursor copies this file into projects — no external links).
9
9
  Run a substantial task through an up-front **intake grill + 10 gated stages**. No
10
10
  stage advances until its **gate** passes. Each gate is `auto` (verify it yourself,
11
- pass/fail) or `manual` (wait for the user's explicit go).
11
+ pass/fail) or `manual` (the user's explicit go or specific standing authorization naming the act).
12
12
 
13
13
  **No companion skill is required.** Every rule below is the doctrine itself — the
14
14
  grill, the design gate, the plan format, the build loop and TDD. Nothing to
@@ -220,7 +220,12 @@ not authorize an outward, irreversible action — stage 7 stops and asks.
220
220
  in one pass (wave 1 the walking skeleton, exit criteria named first); stages 5–8
221
221
  run per wave with a close pass after each — verify, one fix round, docs,
222
222
  re-measure, re-cut — and 9–10 close the release. No wave builds a shape a later
223
- wave undoes.
223
+ wave undoes. **Around the waves runs the release iteration** ("release iteration" /
224
+ "итерация релиза"): module dossiers integrated into one canvas, questions in batches,
225
+ each node verified as it lands in one to three rounds by its risk class (R1–R3), a
226
+ wave's stage 7 integrated without tagging, one release gated and verified as
227
+ released, the next pool handed back; a finding made mid-iteration joins the
228
+ inventory rather than being fixed alone.
224
229
  3. **Spec** (manual) — write and commit the design; lock every shared contract
225
230
  (types, schemas, signatures, file layout) plus a **Global Constraints** block of
226
231
  exact values every later task inherits. Self-review it for placeholders,
@@ -509,9 +514,9 @@ type the run produced, then run the documentation gate and print its ratchet cou
509
514
 
510
515
  **Axis A — the stage gate type.** `auto` = verify the check yourself and stop on
511
516
  fail; `judgment` = a named judge rules where no deterministic check exists, and the
512
- ruling is recorded as judgement, never as a measurement; `manual` = wait for an
513
- explicit operator go. Neither of the first two ever substitutes
514
- for a required manual approval.
517
+ ruling is recorded as judgement, never as a measurement; `manual` = an explicit
518
+ operator go or specific standing authorization naming this act. Cite its source and scope;
519
+ otherwise wait. Neither an auto/judgment result nor a generic loop flag supplies authority.
515
520
 
516
521
  **Axis B — where the rule is actually enforced**, and a rule climbs this ladder
517
522
  rather than starting at the top: doctrine line → review question at a named gate →
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 | 47 (three suites: task-pipeline 29, evidence-docs 9, project-audit 9) | `python3 evals/run.py` → `suite: N evals` | 2026-10-11 |
43
+ | Evals authored | 48 (three suites: task-pipeline 30, evidence-docs 9, project-audit 9) | `python3 evals/run.py` → `suite: N evals` | 2026-10-12 |
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 |
@@ -295,6 +295,22 @@
295
295
  ],
296
296
  "why": "Four PRs of check work merged on a review app's `skipping` with nobody noticing. A requested reader and a reader that reported are different facts that look identical afterwards."
297
297
  },
298
+ {
299
+ "id": "INSTR-08",
300
+ "category": "instruction_following",
301
+ "skills": [
302
+ "task-pipeline"
303
+ ],
304
+ "query": "close the whole board in waves: here is a repo whose docs/evidence/backlog.md has 12 open rows; two of them were already shipped last month",
305
+ "expected_behavior": [
306
+ "Builds ONE inventory by id (inventory/1) from every source before any design, and runs `scripts/waves.py validate` on it, so no row lands nowhere",
307
+ "Verifies each row against the code first: the two shipped rows are closed in the board with the receipt that shows them done, not carried into a wave",
308
+ "Assigns modules, nodes and waves with `waves.py assign` from two short tables, not by hand, and shows the counts per wave",
309
+ "Asks the operator in batches (rounds) with a recommendation per question, never one question at a time; never 'shall I continue?' between waves",
310
+ "Gives each node its own risk class (R1-R3), and starts a node's verification when it lands rather than waiting for the wave"
311
+ ],
312
+ "why": "Wave mode had one trigger eval and no instruction case. An agent that reaches the mode but hand-edits the inventory, trusts stale rows or prompts between waves builds the intermediate states the mode exists to refuse."
313
+ },
298
314
  {
299
315
  "id": "NOTRIG-05",
300
316
  "category": "should_not_trigger",
package/package.json CHANGED
@@ -1,13 +1,13 @@
1
1
  {
2
2
  "name": "task-pipeline-skill",
3
- "version": "1.93.2",
3
+ "version": "1.94.1",
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 && 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",
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/backlog_sources_test.py && python3 test/release_approval_test.py && python3 test/memory_nudge_test.py && python3 test/lessons_test.py && python3 test/waves_test.py && python3 test/continuity_doc_test.py && bash test/install_test.sh && 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/backlog_sources_test.py && python3 test/release_approval_test.py && python3 test/memory_nudge_test.py && python3 test/lessons_test.py && python3 test/waves_test.py && python3 test/continuity_doc_test.py && bash test/install_test.sh && 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",
@@ -3,7 +3,7 @@
3
3
  "name": "task-pipeline",
4
4
  "displayName": "Task Pipeline",
5
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",
6
+ "version": "1.94.1",
7
7
  "author": {
8
8
  "name": "ssheleg",
9
9
  "url": "https://x.com/sshlg93"
@@ -15,7 +15,10 @@ tools: Read, Grep, Glob, Bash
15
15
  > and wrong one level out, and a single context cannot see both. Doctrine:
16
16
  > `references/certification.md`. This agent remains for the case `certify` does not
17
17
  > cover: a verdict already in flight, or a hand-written one fed to
18
- > `close --verdict` directly. Reach for the three tiers first.
18
+ > `close --verdict` directly. Reach for the three tiers first. **A node that carries
19
+ > `risk` cannot be closed by a hand-written verdict alone**: `close` refuses it until
20
+ > `certify` has recorded the passing rounds its class owes, or `waive` records an
21
+ > authorized exception.
19
22
 
20
23
  You close **one node**. You do not fix, you do not implement, and you do not
21
24
  review style. You answer four questions about work that claims to be finished, and
@@ -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: `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"
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; `iteration` — the release loop around the waves; `setup` — audit the docs you already have; `checkup` — what has shipped unverified, with no task running."
3
+ argument-hint: "<one-line task> | waves | iteration | 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,10 +8,11 @@ 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
- > **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.
11
+ > **Four other modes.** `waves` takes the whole board instead of one task;
12
+ > `iteration` runs the release loop around the waves — survey, design, build, release,
13
+ > the next pool; `setup` audits the documentation this project already has; `checkup`
14
+ > reports what has shipped without a person confirming it, with no task in flight. All
15
+ > four are at the bottom of this page.
15
16
 
16
17
  **Idempotent entry — inspect state first, never restart blindly.** If a pipeline
17
18
  TaskList from a previous run exists for this task, **resume** from the first incomplete
@@ -103,8 +104,8 @@ Anything deferred enters the carry-over ledger the moment it is said.
103
104
  | 10 | Acceptance | the ladder walk first, then the table, then the retrospective |
104
105
 
105
106
  **Honor every gate by its type**: `auto` — verify the check yourself; `judgment` —
106
- record the named judge's ruling as judgement, never as a measurement; `manual` — wait
107
- for an explicit go.
107
+ record the named judge's ruling as judgement, never as a measurement; `manual` — cite
108
+ an explicit go or specific standing authorization naming the act, otherwise wait.
108
109
 
109
110
  ## Cross-cutting — the three that fire at any stage
110
111
 
@@ -203,6 +204,19 @@ It takes the next wave without asking, says once when the board is empty, and le
203
204
  every sign-in, consent, payment and outward act to a person.
204
205
  Doctrine: `references/waves.md`.
205
206
 
207
+ ## `/task-pipeline iteration`
208
+
209
+ **The loop around the waves: a project moves in whole releases.** Survey every source into
210
+ one inventory (`scripts/waves.py merge`), write module dossiers in parallel, integrate them
211
+ into one canvas until a pass changes nothing, ask the operator in batches (rounds), never
212
+ one question at a time, then build in parallel. Each node is verified as it lands, in one
213
+ to three rounds by its risk class (R1–R3); a wave's stage 7 integrates without tagging, and
214
+ the release's stage-7 gate and stage 8's trio run once on what was released. The next pool
215
+ is re-measured and handed back once. Every run reads earlier runs' lessons
216
+ (`scripts/lessons.py query`) and writes its own at the retro. A finding made mid-iteration
217
+ joins the inventory; only the closed hotfix lane ships alone.
218
+ Doctrine: `references/iteration.md`.
219
+
206
220
  ## `/task-pipeline setup`
207
221
 
208
222
  **The entry audit instead of a feature.** Seven passes over the documentation this