shapeup-sdlc 1.7.0 → 3.0.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 (98) hide show
  1. package/.claude/settings.local.example.json +5 -5
  2. package/.claude-plugin/plugin.json +1 -1
  3. package/AGENTS.md +17 -3
  4. package/README.md +124 -103
  5. package/SECURITY.md +37 -30
  6. package/bin/init.mjs +77 -47
  7. package/bin/lib/grant.mjs +145 -0
  8. package/commands/build.md +7 -6
  9. package/commands/ship.md +29 -16
  10. package/commands/wire.md +1 -1
  11. package/hooks/dispatch-receipt.mjs +195 -0
  12. package/hooks/gate-intake.mjs +3 -3
  13. package/hooks/gate-zerowork.mjs +25 -24
  14. package/hooks/hooks.json +9 -48
  15. package/hooks/lib/decision.mjs +19 -8
  16. package/hooks/safety-spine.mjs +3 -3
  17. package/hooks/sandbox-guard.mjs +84 -40
  18. package/{skills/tech-lead/scripts/compile-order.mjs → kernel/compile.mjs} +283 -41
  19. package/{skills/tech-lead/scripts/gate-answers.mjs → kernel/gate.mjs} +58 -14
  20. package/kernel/harness.mjs +134 -0
  21. package/{skills/tech-lead/scripts/fit-check.mjs → kernel/init/fit.mjs} +15 -12
  22. package/{skills/tech-lead/scripts/init-run.mjs → kernel/init/run.mjs} +152 -31
  23. package/{skills/tech-lead/scripts → kernel}/lib/argv.mjs +52 -31
  24. package/{skills/tech-lead/scripts/lib/contract-md.mjs → kernel/lib/contract.mjs} +251 -7
  25. package/kernel/lib/paths.mjs +491 -0
  26. package/kernel/probe/concurrency.mjs +510 -0
  27. package/{skills/tech-lead/scripts/aegis-digest.mjs → kernel/probe/digest.mjs} +9 -10
  28. package/kernel/probe/eval.mjs +77 -0
  29. package/kernel/probe/leg.mjs +125 -0
  30. package/{skills/tech-lead/scripts/resume-state.mjs → kernel/probe/resume.mjs} +204 -63
  31. package/{skills/tech-lead/scripts → kernel/probe}/stats.mjs +14 -9
  32. package/kernel/probe/t0.mjs +66 -0
  33. package/{skills/ba-pitch-analyzer/scripts/board-derive.mjs → kernel/reduce/board.mjs} +99 -23
  34. package/kernel/reduce/graph.mjs +437 -0
  35. package/{skills/tech-lead/scripts/hill-derive.mjs → kernel/reduce/hill.mjs} +28 -9
  36. package/kernel/reduce/ingest.mjs +633 -0
  37. package/{hooks/slop-cleaner.mjs → kernel/reduce/leftovers.mjs} +40 -57
  38. package/{skills/tech-lead/scripts/ship-report.mjs → kernel/reduce/ship.mjs} +61 -13
  39. package/{skills/tech-lead/scripts/run-snapshot.mjs → kernel/reduce/snapshot.mjs} +21 -15
  40. package/{skills/spec-evaluator/scripts/verdict-ledger.mjs → kernel/reduce/verdict.mjs} +13 -7
  41. package/kernel/report/export.mjs +321 -0
  42. package/kernel/report/facts.mjs +209 -0
  43. package/{skills/tech-lead/scripts/budget-check.mjs → kernel/verify/budget.mjs} +15 -12
  44. package/kernel/verify/dispatch.mjs +114 -0
  45. package/{skills/tech-lead/scripts/validate-envelope.mjs → kernel/verify/envelope.mjs} +20 -15
  46. package/{skills/tech-lead/scripts/lib → kernel/verify}/ratchet-tree.mjs +36 -14
  47. package/kernel/verify/skills.mjs +125 -0
  48. package/kernel/verify/spec.mjs +559 -0
  49. package/{skills/tech-lead/scripts/t0-verify.mjs → kernel/verify/t0.mjs} +134 -24
  50. package/{skills/tech-lead/scripts/trace-lint.mjs → kernel/verify/trace.mjs} +26 -11
  51. package/oracles/http-oracle.mjs +1 -1
  52. package/oracles/process-oracle.mjs +1 -1
  53. package/oracles/snapshot-oracle.mjs +1 -1
  54. package/oracles/test-oracle.mjs +1 -1
  55. package/package.json +11 -9
  56. package/skills/ba-pitch-analyzer/SKILL.md +5 -5
  57. package/skills/ba-pitch-analyzer/assets/templates/_index.tmpl.md +1 -1
  58. package/skills/ba-pitch-analyzer/assets/templates/api-feasibility.tmpl.md +12 -7
  59. package/skills/ba-pitch-analyzer/assets/templates/contracts/third-party-api.contract.tmpl.md +6 -3
  60. package/skills/ba-pitch-analyzer/assets/templates/cross-context/migration-plan.tmpl.md +5 -4
  61. package/skills/ba-pitch-analyzer/assets/templates/cross-context/team-handoff.tmpl.md +23 -13
  62. package/skills/ba-pitch-analyzer/assets/templates/scope-summary.tmpl.md +17 -12
  63. package/skills/ba-pitch-analyzer/assets/templates/synthesis.tmpl.md +17 -38
  64. package/skills/ba-pitch-analyzer/assets/templates/task.tmpl.md +3 -0
  65. package/skills/ba-pitch-analyzer/references/contract-patterns.md +8 -4
  66. package/skills/ba-pitch-analyzer/references/doc-schemas.md +2 -0
  67. package/skills/ba-pitch-analyzer/references/task-generation.md +2 -2
  68. package/skills/qa-edge-hunter/SKILL.md +7 -3
  69. package/skills/scope-architect/SKILL.md +40 -6
  70. package/skills/solution-architect/SKILL.md +19 -4
  71. package/skills/spec-evaluator/SKILL.md +12 -2
  72. package/skills/task-executor/SKILL.md +7 -6
  73. package/skills/tech-lead/SKILL.md +50 -38
  74. package/skills/tech-lead/references/gates.md +71 -20
  75. package/skills/tech-lead/references/protocol.md +832 -0
  76. package/skills/tech-lead/schemas/domain.schema.json +341 -66
  77. package/skills/tech-lead/schemas/work-order.schema.json +11 -2
  78. package/skills/tech-lead/schemas/work-result.schema.json +1 -1
  79. package/skills/tech-lead/workflows/shapeup-run.js +1327 -750
  80. package/hooks/anti-rationalization.mjs +0 -238
  81. package/hooks/compact-snapshot.mjs +0 -47
  82. package/hooks/gate-deadline.mjs +0 -147
  83. package/hooks/gate-l2.mjs +0 -161
  84. package/hooks/session-rehydrate.mjs +0 -108
  85. package/skills/ba-pitch-analyzer/scripts/spec-lint.mjs +0 -239
  86. package/skills/spec-evaluator/README.md +0 -93
  87. package/skills/tech-lead/README.md +0 -71
  88. package/skills/tech-lead/references/delegation.md +0 -261
  89. package/skills/tech-lead/references/hard-rules.md +0 -34
  90. package/skills/tech-lead/references/invocation.md +0 -45
  91. package/skills/tech-lead/references/ledger-schema.md +0 -213
  92. package/skills/tech-lead/references/round-protocol.md +0 -234
  93. package/skills/tech-lead/references/state-model.md +0 -66
  94. package/skills/tech-lead/scripts/ingest-result.mjs +0 -258
  95. package/skills/tech-lead/scripts/lib/is-main.mjs +0 -81
  96. package/skills/tech-lead/scripts/lib/paths.mjs +0 -280
  97. package/skills/tech-lead/scripts/run-workflow.mjs +0 -381
  98. package/skills/translator/README.md +0 -66
@@ -1,5 +1,5 @@
1
1
  {
2
- "_readme": "Tier C template (design spec addendum §F.2). Copy to .claude/settings.local.json and edit that file is gitignored and merges over the committed .claude/settings.json team defaults. Every key under env is optional; omit what you don't want to override. GATE L0.5/L0.8 resolves: /ship flags > settings.local.json (this file) > settings.json (team) > skill-shipped defaults. Model keys degrade one tier down (never hard-fail) when unavailable on your plan (R2). Budget keys are the two-level circuit breaker (DD-9): round_budget is outer (build+eval cycles), attempt_budget is inner (per-scope T0 attempts).",
2
+ "_readme": "Tier C template (design spec addendum \u00a7F.2). Copy to .claude/settings.local.json and edit \u2014 that file is gitignored and merges over the committed .claude/settings.json team defaults. Every key under env is optional; omit what you don't want to override. GATE L0.5/L0.8 resolves: /ship flags > settings.local.json (this file) > settings.json (team) > skill-shipped defaults. Model keys degrade one tier down (never hard-fail) when unavailable on your plan (R2). Budget keys are the two-level circuit breaker (DD-9): round_budget is outer (build+eval cycles), attempt_budget is inner (per-scope T0 attempts).",
3
3
  "env": {
4
4
  "SHAPEUP_ORCH_MODEL": "opus",
5
5
  "SHAPEUP_EXEC_MODEL": "sonnet",
@@ -9,12 +9,12 @@
9
9
  "SHAPEUP_ATTEMPT_BUDGET": "5",
10
10
  "SHAPEUP_DIGESTER_MODEL": "script"
11
11
  },
12
- "_permissions_readme": "The harness's pipeline scripts ship with the plugin and therefore live OUTSIDE your project. Under any permission mode short of bypassPermissions, running a script from outside the working directory needs approval once per session interactively, and never in a headless run, where nobody is there to grant it. `npx shapeup-sdlc init` writes this block for you; it is reproduced here so you can see exactly what is being pre-approved. Scope is the harness's own deterministic, dependency-free, network-free scripts and nothing else not a general Bash(node:*).",
12
+ "_permissions_readme": "The harness kernel ships with the plugin and therefore lives OUTSIDE your project. Under any permission mode short of bypassPermissions, running a script from outside the working directory needs approval \u2014 once per session interactively, and never in a headless run, where nobody is there to grant it. `npx shapeup-sdlc init` writes this block for you; it is reproduced here so you can see exactly what is being pre-approved. TWO Bash rules, because the trailing ` *` form requires at least one argument and the bare form is what covers a no-flag invocation. The leading `*` spans the install root, which differs between a marketplace install (a version-stamped cache directory) and a `--plugin-dir` checkout \u2014 that wildcard is what keeps the grant working across a plugin upgrade instead of silently expiring. Scope is one dependency-free, network-free script and nothing else \u2014 not a general Bash(node:*). The third entry, \"Workflow\", is what lets the tech-lead launch its run script without approving each launch; it is UNSCOPED (it authorises every dynamic workflow script in the project, not only this plugin's), so `npx shapeup-sdlc init --no-native-workflow` declines it and the harness stays fully usable interactively. This list is GENERATED by bin/lib/grant.mjs and verified by execution rather than by string comparison: npm run test:grant.",
13
13
  "permissions": {
14
14
  "allow": [
15
- "Bash(node ${CLAUDE_PLUGIN_ROOT}/skills/tech-lead/scripts/:*)",
16
- "Bash(node ${CLAUDE_PLUGIN_ROOT}/skills/ba-pitch-analyzer/scripts/:*)",
17
- "Bash(node ${CLAUDE_PLUGIN_ROOT}/skills/spec-evaluator/scripts/:*)"
15
+ "Bash(node \"*/kernel/harness.mjs\" *)",
16
+ "Bash(node \"*/kernel/harness.mjs\")",
17
+ "Workflow"
18
18
  ]
19
19
  }
20
20
  }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "shapeup-sdlc-plugin",
3
3
  "displayName": "ShapeUp SDLC Plugin",
4
- "version": "1.7.0",
4
+ "version": "3.0.1",
5
5
  "description": "Shape Up SDLC harness for Claude Code: shaping, intake, orient, scope-mapping, building (T0-verified, sandboxed, scope-contracted), evaluation and QA skills orchestrated by a tech-lead.",
6
6
  "author": {
7
7
  "name": "Liberty Nguyen",
package/AGENTS.md CHANGED
@@ -5,9 +5,13 @@
5
5
 
6
6
  A three-phase Shape Up loop orchestrated by `/tech-lead`. Invariants live in the runtime, not this file — expect hook denials, not arguments.
7
7
 
8
+ Skills and commands are named short throughout this file; every one of them resolves only under the plugin's namespace — `Skill(shapeup-sdlc-plugin:orient)`, `/shapeup-sdlc-plugin:ship`. A bare name is not a typo you get a warning for: an unknown skill name is rejected upstream of the hook layer, so the dispatch fires no hook, leaves no decision row, and is answered by improvisation.
9
+
8
10
  - Hook-denied: dispatching a worker without a schema-valid WorkOrder, writing outside the scope's substrate, stopping a run with no receipt (the run's first act writes one).
11
+ - Attested, not assumed: a dispatch leaves a receipt naming the skill that ran, and ingest refuses an orchestrated result that has none. A dispatch that fails is answered by the sub-agent improvising the craft, which every other check accepts — so "the artifact exists" is not evidence that the shipped skill produced it. `--no-receipt-check` is the way through when the receipt channel itself fails.
9
12
  - GATE L2 is advisory — warns when EVAL runs over unfinished tasks, permits the call (per-machine board, operator asked; ADR-0001) — a signal, not a bug.
10
13
  - Sign-off is a file: each gate resolves from the answer set (`ci`/`guarded`/`interactive`) — cross, stop for the PO, or abort; the decision's source is ledgered.
14
+ - **Your scope cut decides your concurrency, not the dial.** Two scopes that both declare a write to one path never build at the same time: `shared` substrate is the sanctioned escape from disjointness, and an edit is read-modify-write, so concurrent writers silently drop each other's work. An entry point listed as writable by five scopes therefore builds five scopes one at a time whatever `--parallel-scopes` says. The run states the ceiling its contracts actually permit before dispatching anything, as a BUILD-order line — a peak below that ceiling is a dispatch problem, a ceiling below the dial is a scope-cut problem, and only the second is fixable by re-cutting. The fix is a cut where exactly one scope owns each entry point. Note the ceiling is narrated, not gated: it does not travel in the ⏸ L1b block, so an unattended run carries it only in its log.
11
15
  - The build+eval loop breaks only three ways ✦: EVAL PASS → QA → Ship; outer `round_budget` exhausted; opt-in `wall_clock_budget_s` tripped (the wall-clock axis event counters miss). Budget trips route to GATE H — ship what's green, never kill the run from outside. A scope exhausting its per-scope `attempt_budget` (T0 attempts) queues a GATE H proposal, never blocks the round.
12
16
 
13
17
  ### Phase 1 — Shaping (`/shapeup`)
@@ -22,17 +26,19 @@ Betting Table: PO decides; rejected pitches loop back to raw idea.
22
26
  ### Phase 3 — Building
23
27
  | Step | Gate | Action |
24
28
  |------|------|--------|
25
- | Kick-off | ⏸ **L0** — Intake & Config (L0.8 model/budget matrix) | `/translator` if non-English |
29
+ | Kick-off | ⏸ **L0** — Intake & Config (L0.8 model/budget matrix) + worker roster ✧ | `/translator` if non-English |
26
30
  | Orient (Scout) | ⏸ **L1a** — Orient Review | `/orient` |
27
31
  | Analyze | — (reviewed at L1b) | `/ba-pitch-analyzer` (`analyze`): spec tree + board (UC + Invariants + Test Surface ★); before Wire (needs its use cases) |
28
32
  | Wire | ⏸ **L1a.5** — Wiring Review ✚ | `/solution-architect` (`wire`): sole writer of committed `wiring-map.md` — per-UC engine → seam → entry-point call site → affordance, per `project-profile.md` |
29
33
  | Map Scopes | ⏸ **L1b** — Board Review (+ substrate disjointness lint) | `/scope-architect` (scope contracts ✦ — sole writer); traceability oracle advisory ✚ |
30
- | Build Vertically | ⏸ **L2** — Board 100% ✅ + T0-green ✦ | per dispatch: compile order → `/task-executor` (--order) → ingest result; T0-verified per attempt (fixtures + DB probe + seesaw ✦), substrate-sandboxed ✦ |
34
+ | Build Vertically | ⏸ **L2** — Board 100% ✅ + T0-green ✦ | per dispatch: compile order → `/task-executor` (--order) → ingest result; T0-verified per attempt (fixtures + DB probe + seesaw ✦), substrate-sandboxed ✦. Scopes build **concurrently** — `--parallel-scopes N` caps it (default 4), a scope is released the moment its own dependencies are green, and a scope green in this round is skipped rather than rebuilt |
31
35
  | EVAL (once per round) | ⏸ **L3** — Verdict | `/spec-evaluator` (--order): spec- + test-surface-conformance ★, T0 citation ✦; refuted boxes/verdict applied by ingest |
32
36
  | FAIL → round r+1 | — | regression rule ★: bugs + full Test Surface of touched UC |
33
37
 
34
38
  ✦ = requires scope contracts (`shapeup/<slug>/scopes/*.md`); ✚ = requires the spine artifacts (`requirements.md`, `wiring-map.md`, `project-profile.md`). Traceability stays advisory until `covers:` is populated. Absent artifact ⇒ arm skipped (non-regression).
35
39
 
40
+ ✧ **Two refusals, and they answer different questions.** Opening a run refuses outright when the worker skills are not on disk — the roster comes from the schema that defines it, so it cannot drift from a hand-kept list. That alone passes green on the two states that actually happen (installed but disabled, or a different version loaded), so the run's first act is one live canary dispatch, and the evidence is the hook layer's rather than the sub-agent's account of it. A run that cannot reach its workers stops before it spends anything, instead of reporting phases complete while none of the shipped craft was applied.
41
+
36
42
 
37
43
  ### QA Edge Hunt (`/qa-edge-hunter`, post-PASS, pre-ship)
38
44
  **Q0** Preflight → **Q1** Charter (6 lenses − EVAL-covered) → **Hunt** (repro required, findings `~` → ledger) → report (no verdict, no score). Skip with `--no-qa`.
@@ -58,8 +64,16 @@ Everything discovered funnels into `.shapeup/<slug>/discovery/ledger.md` (Orient
58
64
  ## Setup & Execution
59
65
 
60
66
  - Orders/results live in `.shapeup/<slug>/orders|results/`; the envelope schemas ship inside the tech-lead skill.
61
- - The plugin's run entry points need a one-time permission grant — `npx shapeup-sdlc init` writes it into `.claude/settings.json` (`permissions.allow`); without it a headless run stalls at step one.
67
+ - The plugin's run entry points need a one-time permission grant — `npx shapeup-sdlc init` writes it into `.claude/settings.json` (`permissions.allow`); without it a headless run stalls at step one. That grant is necessary, not sufficient: it covers the run's own deterministic entry points, not the generic file edits every worker skill makes constantly, or any command a worker reaches for beyond the grant's own exact shape. A truly unattended run also needs a Claude Code permission mode that covers those (`acceptEdits` at minimum) — the plugin cannot grant that on your behalf.
62
68
  - Two storage tiers (ADR-0001): COMMITTED `shapeup/<slug>/` (shaping, spec, scopes, wiring-map, project-profile, requirements, hill, `REPORT.md` frozen at L4) vs GITIGNORED `.shapeup/` (board, orders/results, T0/eval/QA artifacts, ledgers, metrics, gate answers).
69
+ - Every run has a `run_id` — the receipt mints it, and orders, T0 artifacts, trial rows, agent-call journal rows and hook decisions all carry it. It is the only key that separates two runs of the same feature: everything else (`order_id`, round/attempt) repeats. It is **not** a time boundary — a relaunch resumes the same run and reuses the key, so one `run_id` legitimately spans every launch after a paused gate or a kill, with hours of wall clock between them, and `orders/<id>.json` is rewritten by each. Anything measuring elapsed time reads the append-only records, never the span of a key. SHIP S.7 exports the run's records as fact tables under `.shapeup/exports/<run_id>/` before the run trace is superseded; a WorkResult carries no `run_id` and reaches it through `order_id`.
70
+ - Every run projects a **run graph** — `.shapeup/<slug>/graph.jsonl`, append-only, written only by
71
+ `reduce graph`. Two families kept separate: work lineage (Run, Order, Result, Verdict, Trial,
72
+ GateDecision) and domain (Scope, UseCase, Requirement, Seam). It is derived from the artifacts,
73
+ never authored, so it can be deleted and rebuilt — and a run recorded before it existed backfills
74
+ on first touch. `--subgraph run` is the fast-forward as one bounded query; `--trace <node>` walks
75
+ a verdict back to the objective, the plan, the source, the execution record and the gate that
76
+ crossed it.
63
77
  - Contracts: markdown on disk, JSON on the wire; a single library reads/writes the file form.
64
78
  - Never hard-code a storage root — generated paths resolve through the shared path resolver.
65
79
  - The traceability oracle emits `.shapeup/<slug>/trace/report.json` from the spine artifacts.
package/README.md CHANGED
@@ -15,11 +15,11 @@ The ceremony is right-sized: `/ship` runs the full gated pipeline for real featu
15
15
  fixes where the gates would have nothing to say.
16
16
 
17
17
  <p align="center">
18
- <img src="docs/assets/demo-gate.svg" alt="Terminal recording: the agent tries to run EVAL with two tasks unfinished, and a PreToolUse hook names both unfinished tasks and records the evaluation as taken over a partial board." width="700">
18
+ <img src="docs/assets/demo-gate.svg" alt="Terminal recording: a worker tries to edit a file outside the scope it was given, a PreToolUse hook denies the write and names the path, and the next edit inside the scope is permitted." width="700">
19
19
  </p>
20
20
 
21
21
  <p align="center"><sub>
22
- The GATE L2 text above is <b>verbatim stdout</b> from <code>hooks/gate-l2.mjs</code> —
22
+ The denial above is <b>verbatim stdout</b> from <code>hooks/sandbox-guard.mjs</code> —
23
23
  <a href="tools/demo/record-demo.mjs">the recorder runs the real hook</a> and fails rather than
24
24
  draw a picture. <a href="docs/assets/demo-gate.txt">Plain-text transcript.</a>
25
25
  </sub></p>
@@ -59,10 +59,19 @@ they are documented for [contributors](CONTRIBUTING.md), not for users.
59
59
  ```
60
60
  /plugin marketplace add nguyenvanphituoc/shapeup-sdlc-plugin
61
61
  /plugin install shapeup-sdlc-plugin@nvptuoc-marketplace
62
- /ship "add dark mode to the settings screen"
62
+ /shapeup-sdlc-plugin:ship "add dark mode to the settings screen"
63
63
  ```
64
64
 
65
- `/ship` walks the whole lifecycle and pauses at each gate for you. That's the whole quickstart.
65
+ That last one walks the whole lifecycle and pauses at each gate for you. That's the whole
66
+ quickstart.
67
+
68
+ > **The `shapeup-sdlc-plugin:` prefix is not optional.** A plugin's commands are namespaced by the
69
+ > plugin that ships them, so the bare `/ship` is not a command and answers `Unknown command: /ship`
70
+ > — measured on both a marketplace install and a `--plugin-dir` checkout. Interactively you will
71
+ > normally pick the command off `/`-completion and never type the prefix yourself; it matters when
72
+ > you are writing the command down, which is exactly what a headless `claude -p` invocation or a CI
73
+ > step does. **Everything below writes commands in the short form for readability — prepend
74
+ > `shapeup-sdlc-plugin:` to any of them you actually type.**
66
75
 
67
76
  > **Running unattended?** The plugin install grants no permissions — every pipeline step is a Node
68
77
  > script that ships *with* the plugin and therefore lives outside your project, so it needs
@@ -72,6 +81,19 @@ they are documented for [contributors](CONTRIBUTING.md), not for users.
72
81
  > ```bash
73
82
  > npx shapeup-sdlc init -d . -y
74
83
  > ```
84
+ >
85
+ > **And lift the print-mode background ceiling, or the run is killed at ten minutes.** `claude -p`
86
+ > terminates a session's background tasks after 600 s by default, and the whole pipeline runs as
87
+ > one background launch — so an unattended run dies mid-BUILD with the CLI reporting nothing worse
88
+ > than "background tasks still running after 600s; terminating". Measured, on a run that had
89
+ > reached WIRE:
90
+ >
91
+ > ```bash
92
+ > CLAUDE_CODE_PRINT_BG_WAIT_CEILING_MS=0 claude -p "/shapeup-sdlc-plugin:ship …" …
93
+ > ```
94
+ >
95
+ > Nothing is lost when it happens — resume state is on disk, so relaunching fast-forwards past the
96
+ > phases that finished. It costs a relaunch, not a run.
75
97
 
76
98
  Want to see a full run before installing anything? **[docs/quickstart.md](docs/quickstart.md)**
77
99
  walks one small feature end to end — including what the hooks do to a premature eval, a FAIL round
@@ -85,7 +107,7 @@ installer, and troubleshooting are in
85
107
  ## Agent support
86
108
 
87
109
  The harness targets **Claude Code only**. The reason is the row that never travelled when we
88
- compiled to other CLIs: hooks. The 12 skills, 10 slash commands and pipeline scripts are
110
+ compiled to other CLIs: hooks. The 12 skills, 10 slash commands and the kernel are
89
111
  portable prose and plain Node — but hook-enforced gates (envelope validation, substrate
90
112
  sandbox, safety spine, the zero-work block) are a per-CLI mechanism, and without them every gate degrades from
91
113
  **enforced** to **instructed** — the same honor system every other framework runs on
@@ -118,37 +140,24 @@ A longer version, including the internals, is in [docs/glossary.md](docs/glossar
118
140
  The harness walks a pitch from idea to ship. The full annotated pipeline — the build round,
119
141
  the gate walkthrough, the circuit breaker — is
120
142
  [`docs/design/04-functional-design.md`](docs/design/04-functional-design.md), and the design
121
- document as a whole starts at [`docs/design/`](docs/design/README.md). A simplified view:
122
-
123
- ```mermaid
124
- graph LR
125
- A([Raw Idea]) --> S["Shaping<br>/shapeup"]
126
- S --> P["Pitch"]
127
- P --> BET{"Betting<br>(PO)"}
128
- BET --> KO["Kick-off + Orient<br>/orient"]
129
- KO --> WIRE["Wire<br>/solution-architect"]
130
- WIRE --> MAP["Map Scopes<br>/ba-pitch-analyzer<br>+ /scope-architect"]
131
- MAP --> BUILD["Build Vertically<br>/task-executor"]
132
- BUILD --> EVAL["Evaluate<br>/spec-evaluator"]
133
- EVAL -- FAIL --> BUILD
134
- EVAL -- PASS --> QA["Edge Hunt<br>/qa-edge-hunter"]
135
- QA --> SHIP["Triage + Ship<br>/scope-hammer"]
136
- SHIP --> RETRO["Coach Retro<br>/coach"]
137
- TL["/tech-lead orchestrates Orient → Ship"] -.-> KO
138
-
139
- classDef plan fill:#e3f2fd,stroke:#1e88e5;
140
- classDef build fill:#e8f5e9,stroke:#43a047;
141
- classDef qa fill:#fce4ec,stroke:#c2185b;
142
- class S,WIRE,MAP plan;
143
- class KO,BUILD build;
144
- class QA,EVAL qa;
145
- ```
143
+ document as a whole starts at [`docs/design/`](docs/design/README.md). This diagram shows the
144
+ full phase and gate mechanism — simpler than that per-attempt detail, but the whole pipeline:
145
+
146
+ <p align="center">
147
+ <img src="docs/assets/workflow-mechanism.svg" alt="The shapeup-sdlc harness pipeline from raw idea to Coach Retro: Shaping produces a Pitch, the Betting Table bets into the tech-lead-orchestrated run or rejects back to raw idea, Kick-off through Ship Sign-off cross gates L0, L1a, L1a.5, L1b, advisory L2, L3, GATE H and L4, the Build/Evaluate round loops on FAIL, and a circuit breaker routes straight to GATE H — bypassing QA — when the round or wall-clock budget runs out." width="900">
148
+ </p>
149
+
150
+ <p align="center"><sub>
151
+ Plan-phase skills in blue, build-phase in green, QA-phase in pink; amber pills are gates —
152
+ the outlined <b>L2</b> is advisory, the rest block. The dashed region marks what
153
+ <code>/tech-lead</code> orchestrates end to end.
154
+ </sub></p>
146
155
 
147
156
  Since v1.3 the pipeline carries a **traceability spine**: `ba-pitch-analyzer`'s `coverage`
148
157
  operation writes a requirement registry (`requirements.md`), `solution-architect` commits a
149
158
  per-use-case wiring map (`wiring-map.md`, gate L1a.5) resolved against the L0
150
159
  `project-profile.md`, and the covers-closure + reachability oracle
151
- `skills/tech-lead/scripts/trace-lint.mjs` checks that no engine ships orphaned. It runs
160
+ `kernel/verify/trace.mjs` checks that no engine ships orphaned. It runs
152
161
  advisory (warn-only) and is promoted to a blocking gate only once `covers:` is populated;
153
162
  every arm is skipped when its artifact is absent, so older specs are unaffected.
154
163
 
@@ -161,8 +170,8 @@ every arm is skipped when its artifact is absent, so older specs are unaffected.
161
170
  | Shaping (1–4) | `shapeup` | — | Frame the problem, breadboard affordances, spike risks, write the pitch. Sub-commands: `full`, `shaping`, `spike`, `breadboarding`, `framing-doc`, `kickoff-doc`, `breadboard-reflection`. |
162
171
  | Intake (GATE L0) | `translator` | — | Normalizes non-English intake (pitch/PRD/transcript) to faithful English before planning. The harness is English-only downstream. |
163
172
  | Orient (7) | `orient` | — | Builder-led recon: reads the code, spikes the single riskiest area, emits a code-surface map, spike findings, discovered-task seed, and a hill signal. Writes no production code. |
164
- | Wire (GATE L1a.5) | `solution-architect` | v1.1 | Sole writer of the committed wiring map (`wiring-map.md`): per-UC engine → integration seam → entry-point call site → player-visible affordance, resolved against `project-profile.md`. Front-loads the integration seam so no engine ships orphaned; the reachability input `trace-lint.mjs` checks. Operation: wire. |
165
- | Map Scopes (8) | `ba-pitch-analyzer` | v4.0 | The spec-analyzer (pure worker). Decomposes a pitch into a linked DDD document tree (domain model → use cases → tasks) with BDD scenarios, a UC system flow, and a derived `## Test Surface`. One craft, four order-selected operations (analyze / reconcile / retrofit-surface / coverage — the last writes the shared `requirements.md` registry for covers-closure); graph math + audits delegated to `board-derive.mjs`/`spec-lint.mjs`. |
173
+ | Wire (GATE L1a.5) | `solution-architect` | v1.1 | Sole writer of the committed wiring map (`wiring-map.md`): per-UC engine → integration seam → entry-point call site → player-visible affordance, resolved against `project-profile.md`. Front-loads the integration seam so no engine ships orphaned; the reachability input `harness verify trace` checks. Operation: wire. |
174
+ | Map Scopes (8) | `ba-pitch-analyzer` | v4.0 | The spec-analyzer (pure worker). Decomposes a pitch into a linked DDD document tree (domain model → use cases → tasks) with BDD scenarios, a UC system flow, and a derived `## Test Surface`. One craft, four order-selected operations (analyze / reconcile / retrofit-surface / coverage — the last writes the shared `requirements.md` registry for covers-closure); graph math + audits delegated to `harness reduce board`/`harness verify spec`. |
166
175
  | Map Scopes (8) | `scope-architect` | v1.0 | Sole writer of committed, write-whitelisted scope contracts (`scopes/*.md`): import-graph slicing by flow, substrates, affordance manifests, fixtures. Operation: map-scopes. |
167
176
  | Build (9) | `task-executor` | v2.0 | Pure worker: work order in → code out. Assumption scan, minimum-code/surgical-change discipline, Layer 1/2/3 UI rules, substrate-sandboxed, zero-memory. Never writes boards/ledgers/run-state. |
168
177
  | Evaluate (GATE L3) | `spec-evaluator` | v1.0 | The single judge (pure worker). Verifies spec-conformance, TDD surface, and integration against the running app — skeptical, files `file:line` bugs, runs exactly once per build round. Requires a T0 artifact citation, grades UI affordance-only; verdict + refuted boxes return as data. |
@@ -174,7 +183,8 @@ every arm is skipped when its artifact is absent, so older specs are unaffected.
174
183
  ### Commands
175
184
 
176
185
  `/ship` runs the whole lifecycle; the phase commands run one step each, so the pipeline is
177
- learnable from `/`-completion alone.
186
+ learnable from `/`-completion alone. Names are written short here; the real name of each carries the
187
+ `shapeup-sdlc-plugin:` prefix, which `/`-completion fills in for you and a script must spell out.
178
188
 
179
189
  | Command | Phase | Description |
180
190
  |---------|-------|-------------|
@@ -189,55 +199,71 @@ learnable from `/`-completion alone.
189
199
  | `/hammer` | H | Must-have census, baseline comparison, cut list + ship verdict. |
190
200
  | `/retro` | post-L4 | File ship-gate feedback into the per-skill knowledge base. |
191
201
 
192
- ### Hooks
193
-
194
- Ten Node hooks in `hooks/`, plus `validate-envelope.mjs` which ships with the orchestrator skill.
195
- What each one reads and what it can deny:
196
-
197
- - `SessionStart` prints a load confirmation so you know the plugin is active; on
198
- `startup|compact|resume|clear`, `hooks/session-rehydrate.mjs` additionally injects the mid-run
199
- `RunSnapshot` hint ("trust the files, not the summary") when a harness run is in flight. On a
200
- cold `startup` it leads with the stronger sentence *a run is already open; resume it, do not
201
- re-open it*because that is the failure a fresh session actually makes. Silent when no run is
202
- in flight, which is the ordinary case.
203
- - `PreToolUse` (matcher `Skill`) — **`hooks/gate-l2.mjs` warns when the once-per-round EVAL
204
- delegation runs over an unfinished task board**, naming the offending tasks and recording a
205
- `warn` row. Advisory since ADR-0001 the board is per-machine and the operator asked for the
206
- call. This is the gate in the demo above.
207
- - `PreToolUse` (matcher `Skill`) **`hooks/gate-intake.mjs` denies a `tech-lead` dispatch that
208
- carries no pitch, no spec folder, and no requirement text.** Measured on the SDD harness
209
- benchmark: when the requirement text was dropped on the hand-off and only a flag survived, the
210
- run printed the gate list, built nothing, and scored 29% against a hidden acceptance suite while
211
- looking like a success (n=3, zero variance). An orchestrator with no spec now fails loudly
212
- instead of narrating.
213
- - `PreToolUse` (matcher `Skill`) **`hooks/gate-deadline.mjs` denies a `task-executor` dispatch
214
- once the run's opt-in wall-clock budget is spent**, routing to GATE H instead. `spec-evaluator`,
215
- `scope-hammer` and `qa-edge-hunter` stay reachable a run past its deadline
216
- must still be able to judge, hammer and close. Off unless a budget is configured.
217
- - `PreToolUse` (matcher `Bash|Read|Write|Edit|MultiEdit`) `hooks/safety-spine.mjs` denies
218
- destructive commands (`rm -rf` on unrecoverable targets, force-push/push-to-main,
219
- `git reset --hard`, `DROP TABLE`) and secret-file reads. Machine guard, not pipeline guard;
220
- escape hatch is the human-authored `.shapeup/safety-overrides.json`.
221
- - `PreToolUse` (matcher `Edit|Write|MultiEdit`) — `hooks/sandbox-guard.mjs` blocks writes
222
- outside the active scope's substrate whitelist (no-op unless scope contracts exist).
223
- - `PreToolUse` (matcher `Skill|Agent`)`skills/tech-lead/scripts/validate-envelope.mjs`
224
- denies any worker dispatch whose order file is missing or schema-invalid.
225
- - `Stop` **`hooks/gate-zerowork.mjs` blocks a session that dispatched the orchestrator and
226
- left no run receipt.** The one blocking `Stop` hook, and the narrowest: its predicate is
227
- mechanical orchestrator dispatched AND no `.shapeup/<slug>/receipt.json` so it never
228
- judges quality, it reports that no work exists to judge. It exists because the benchmark caught
229
- this harness describing its own pipeline instead of running it (Haiku 4.5, n=5, zero variance,
230
- 29% acceptance) while both existing guards structurally could not see it: one is scoped to an
231
- active run, and a run that never started leaves no files; the other matches past-tense
232
- completion claims, and narration is future-tense. Fails open on everything ambiguous, and
233
- `stop_hook_active` caps it at one block per stop chain.
234
- - `Stop` two **advisory, never-blocking** hooks (`hooks/anti-rationalization.mjs` flags
235
- completion claims the board/T0 facts contradict — including a future-tense promise left as the
236
- session's last word; `hooks/slop-cleaner.mjs` flags TODO/`console.log`/commented-out-code
237
- leftovers in the session's diff). They emit at most a `systemMessage` "QA is a level-up, not
238
- a gate."
239
- - `PreCompact` `hooks/compact-snapshot.mjs` persists the mid-run `RunSnapshot` to
240
- `.shapeup/<slug>/run-snapshot.json` before the conversation is compacted.
202
+ ### What is enforced, and by what
203
+
204
+ The honest version of this table matters more than a long one. A guarantee is only as strong as
205
+ the layer that carries it, and the three layers here fail differently:
206
+
207
+ | Layer | Works when | Fails how |
208
+ |---|---|---|
209
+ | **Wall** — a hook | Under every permission mode, including `bypassPermissions`. The CLI runs it; the model cannot decline it. | Fail-OPEN on anything ambiguous, and every evaluation writes a decision row, so "permitted" never looks like "never ran". |
210
+ | **Runtime** the kernel and the run script | When the run goes through the harness. A schema rejection or a non-zero exit stops the step. | A lane that never calls the kernel is never checked which is why the hooks below cover the doors, not the steps. |
211
+ | **Advisory**a report section | When somebody reads the artifact. | Silently, if nobody does. It is a cleanup list, never a verdict. |
212
+
213
+ **Four walls.** These are hooks because nothing in the runtime can substitute for them:
214
+
215
+ - `PreToolUse` (`Skill`) **`hooks/gate-intake.mjs` denies a `tech-lead` dispatch that carries no
216
+ pitch, no spec folder, and no requirement text.** Observed, not theorized: when the requirement
217
+ text is dropped on the hand-off and only a flag survives, the run prints the gate list, builds
218
+ nothing, and reads like a success while leaving every defect in the deliverable.
219
+ - `PreToolUse` (`Skill|Agent`) **`harness verify envelope` denies any worker dispatch whose order
220
+ file is missing or fails the WorkOrder schema.** A malformed envelope never reaches a worker.
221
+ - `PreToolUse` (`Edit|Write|MultiEdit`) **`hooks/sandbox-guard.mjs` blocks a write that no LIVE
222
+ order's substrate permits.** It reads every compiled-but-not-yet-ingested order rather than a
223
+ pointer to one, so scopes building concurrently are each held to their own contract; `frozen`
224
+ outranks everything, across all of them.
225
+ - `PreToolUse` (`Bash|Read|Write|Edit|MultiEdit`)**`hooks/safety-spine.mjs` denies destructive
226
+ commands** (`rm -rf` on unrecoverable targets, force-push/push-to-main, `git reset --hard`,
227
+ `DROP TABLE`) and secret-file reads. A machine guard, not a pipeline guard; the escape hatch is
228
+ the human-authored `.shapeup/safety-overrides.json`.
229
+
230
+ **One recorder**, which denies nothing and is what makes a wall possible one layer down:
231
+
232
+ - `PostToolUse` (`Skill|Agent`) **`hooks/dispatch-receipt.mjs` writes down which skill actually
233
+ ran.** Until it existed, a dispatch that failed plugin absent, disabled, or a different version
234
+ loaded was indistinguishable from one that succeeded: the sub-agent would do the craft itself
235
+ from the prose in its own prompt, the artifacts landed in exactly the place the order permitted, so
236
+ the order gate and the sandbox guard both passed and the run advanced having applied none of the
237
+ shipped craft. A green run was consistent with zero worker craft. The hook appends
238
+ `{order_id, worker_declared, skill_invoked, dispatch_ok, at}` to `.shapeup/<slug>/receipts/`, and
239
+ `harness reduce ingest` refuses an orchestrated result with no matching receipt. A failed dispatch
240
+ never reaches `PostToolUse` at all, so the receipt's *existence* is the evidence. It has no deny
241
+ path, every write is guarded, and `--no-receipt-check` is the documented way through when the
242
+ channel itself fails.
243
+
244
+ **One blocking Stop hook**, and it is the narrowest thing in the repo:
245
+
246
+ - `Stop` **`hooks/gate-zerowork.mjs` blocks a session that dispatched the orchestrator and left
247
+ no run receipt.** Its predicate is mechanicalorchestrator dispatched AND no
248
+ `.shapeup/<slug>/receipt.json` — so it never judges quality; it reports that no work exists to
249
+ judge. It exists because this harness was repeatedly observed describing its own pipeline instead
250
+ of running it: a narrated run that reads like a clean success. Fails open on everything
251
+ ambiguous, and `stop_hook_active` caps it at one block per stop chain.
252
+
253
+ **What the runtime carries instead** (v2.0 retired six hooks whose work moved here):
254
+
255
+ | Was a hook | Is now | What changed |
256
+ |---|---|---|
257
+ | `gate-l2` (EVAL over an unfinished board) | The GATE L2 block, which names `green_scopes` and `hammer_proposals` | It was advisory either way; now the same facts reach the human who answers the gate rather than a warning line above it. |
258
+ | `gate-deadline` (deny builds past the wall clock) | `harness verify budget --strict`, checked at every round boundary | **A real coverage change, stated rather than hidden:** the round loop stops the run from opening ANOTHER round, but no longer interrupts a single build leg that runs long. `attempt_budget` bounds that leg by attempts instead. |
259
+ | `session-rehydrate` + `compact-snapshot` | `harness reduce graph --slug <slug> --subgraph run` | A hook fired at two moments the platform chose; a command answers whenever the question is asked, including the moments a hook never saw. |
260
+ | `anti-rationalization` (claims the facts contradict) | The ship report's census, derived from the board and the T0 artifacts | The facts are in an artifact a teammate finds on `git pull`, not in a transcript nobody re-reads. |
261
+ | `slop-cleaner` (TODO/`console.log` leftovers) | The ship report's **Leftovers** section | Same scan, same added-lines-only rule; it lands somewhere checkable. |
262
+
263
+ **Nothing load-bearing depends on permission mode.** The four walls plus the zero-work gate run
264
+ under every mode. The kernel needs a grant to be *invoked* — two Bash lines `npx shapeup-sdlc init`
265
+ writes — but a session that never gets that grant is a session that cannot run the pipeline at all,
266
+ not one that runs it unguarded.
241
267
 
242
268
  No hook makes a network request, none has dependencies, and all are plain, readable `.mjs`
243
269
  files. **[SECURITY.md](SECURITY.md)** states what each hook reads, what it can deny, and what
@@ -264,8 +290,8 @@ These hold across the harness and are the reason it stays predictable:
264
290
  - **Hill phase is mechanical, never self-reported** — derived only from T0/T1/seesaw facts, closing
265
291
  the self-reported-confidence risk outright.
266
292
  - **One writer per shared file** — every board/ledger/verdict write goes through
267
- `ingest-result.mjs`; workers return data and never touch shared state.
268
- - **Traceability is oracle-checked, opt-in** — `trace-lint.mjs` verifies covers-closure and
293
+ `harness reduce ingest`; workers return data and never touch shared state.
294
+ - **Traceability is oracle-checked, opt-in** — `harness verify trace` verifies covers-closure and
269
295
  wiring reachability from the committed spine artifacts; it ships advisory (warn-only) and every
270
296
  arm is skipped when its artifact is absent, so older specs are non-regressed.
271
297
 
@@ -275,13 +301,11 @@ Stated plainly, because you will hit them:
275
301
 
276
302
  - **The `--tiny` lane is young.** It right-sizes the ceremony (two gates instead of eight) but
277
303
  keeps the T0 verification floor; its fit-check heuristics will need tuning against real use.
278
- - **Nothing here measures skill quality or activation.** The repo used to carry two evidence
279
- layers a Tier-1 activation dataset per skill, and a Day-1/Day-2 craft-and-efficacy register
280
- and both have been removed. What that cost is worth stating plainly rather than leaving to be
281
- discovered: there is now no number for whether a skill's description makes it fire on the right
282
- request, no measured craft delta, and no CI check enforcing the honesty invariant on such
283
- numbers. The structural suite (Tier 0) and the functional planted-bug fixtures (Tier 2) are the
284
- coverage that remains, and both are about mechanism rather than quality.
304
+ - **Nothing here measures skill quality or activation.** There is no number for whether a
305
+ skill's description makes it fire on the right request, no measured craft delta, and no CI
306
+ check enforcing the honesty invariant on such numbers. The structural suite is the coverage
307
+ that exists, and it is about mechanism rather than quality it proves a gate denies and an
308
+ oracle discriminates, never that a skill's output is good.
285
309
  - **The gates are verified; the craft is not.** A hook that denies is proven by a test that
286
310
  watches it deny. A skill that writes a good spec tree is, at present, taken on trust.
287
311
 
@@ -303,17 +327,15 @@ claude --plugin-dir . # load this working copy without installing
303
327
  plugin.json # plugin manifest
304
328
  marketplace.json # marketplace listing (points at this repo)
305
329
  skills/<name>/SKILL.md # the 12 harness skills (+ references/ and assets/)
306
- skills/tech-lead/scripts|schemas/ # orchestrator pipeline: init-run, gate-answers,
307
- # budget-check, compile-order, ingest-result, validate-envelope,
308
- # t0-verify, trace-lint, aegis-digest, run-snapshot,
309
- # stats + envelope and gate-answer schemas
310
- skills/ba-pitch-analyzer/scripts/ # planner mechanics: board-derive, spec-lint
311
- skills/spec-evaluator/scripts/ # verdict-ledger (reference impl of the flip/confidence grammar)
330
+ skills/tech-lead/schemas/ # the envelope port: WorkOrder, WorkResult, domain registry
331
+ skills/tech-lead/workflows/shapeup-run.js # the BUILD-phase pipeline, on the native Workflow runtime
332
+ kernel/harness.mjs # ONE entry point for every deterministic step; the whole permission grant
333
+ kernel/{verify,reduce,probe,init,report}/ # its subcommands, plus compile and gate at the root
334
+ kernel/lib/ # argv (the typed CLI boundary), paths (+ the run key), contract (shape)
312
335
  commands/*.md # slash commands (/ship + the 9 phase commands)
313
- hooks/ # hooks.json + safety-spine, gate-l2, gate-intake, gate-deadline,
314
- # sandbox-guard (PreToolUse),
315
- # gate-zerowork (Stop, blocking), anti-rationalization, slop-cleaner (Stop, advisory),
316
- # compact-snapshot (PreCompact), session-rehydrate (SessionStart)
336
+ hooks/ # hooks.json + the four walls: safety-spine, gate-intake, sandbox-guard
337
+ # (PreToolUse) + gate-zerowork (Stop, the one blocking hook)
338
+ # + dispatch-receipt (PostToolUse, denies nothing, attests which skill ran)
317
339
  # + lib/decision.mjs (every hook records allow / deny / error)
318
340
  oracles/ # the evaluation-contract oracle registry (test · snapshot · http · process)
319
341
  bin/init.mjs # `npx shapeup-sdlc init` — scaffolds all three CLI targets
@@ -321,7 +343,6 @@ scripts/install-harness.sh, migrate.sh # stable public entrypoints (fresh inst
321
343
  scripts/shapeup-sdlc/lib/ # shell libs both entrypoints source
322
344
  tools/ # repo-only: demo/
323
345
  # demo/record-demo.mjs (regenerates docs/assets/demo-gate.svg)
324
- evals/ # Tier-2 functional apparatus only: fixtures/, oracles/
325
346
  tests/structural.mjs, tests/structural/*.mjs # Tier 0 — 880+ checks, zero LLM calls
326
347
  docs/install.md, upgrading.md, glossary.md
327
348
  docs/design/ # the design document (pipeline, gates, circuit breaker, ERD) + adr/
package/SECURITY.md CHANGED
@@ -1,45 +1,57 @@
1
1
  # Security
2
2
 
3
- This plugin installs **twelve hook entries (eleven Node scripts + one `echo`)**: six in a
4
- `PreToolUse` position, of which **five can deny a tool call**, plus one `Stop`-position hook that
5
- can block a session from ending. That is the product — and it is also exactly the kind of surface
6
- a careful reviewer should want spelled out before installing. This page is that spelling-out.
3
+ This plugin installs **seven hook entries (six Node scripts + one `echo`)**: four in a
4
+ `PreToolUse` position, **all four of which can deny a tool call**, one `PostToolUse` hook that has no
5
+ deny path at all, and one `Stop`-position hook that can block a session from ending. That is the
6
+ product and it is also exactly the kind of surface a careful reviewer should want spelled out
7
+ before installing. This page is that spelling-out.
8
+
9
+ Count them yourself rather than taking the paragraph's word for it, because this paragraph has been
10
+ wrong before — it described a twelve-entry surface for the whole life of v2.0, after the hook diet cut
11
+ it to four walls and updated the table below without updating the sentence above it:
12
+
13
+ ```bash
14
+ node -e "const h=require('./hooks/hooks.json').hooks;
15
+ for (const [e,gs] of Object.entries(h)) for (const g of gs) for (const x of g.hooks)
16
+ console.log(e, g.matcher||'*', x.command.match(/[^/ ]+\.mjs/)?.[0] ?? '(echo)')"
17
+ ```
7
18
 
8
19
  ## Reporting a vulnerability
9
20
 
10
21
  Use [GitHub private vulnerability reporting](https://github.com/nguyenvanphituoc/shapeup-sdlc-plugin/security/advisories/new)
11
- for anything exploitable — especially anything that would let a run **escape a deny** (talk
12
- past GATE L2, write outside a substrate, widen its own safety overrides) or exfiltrate data.
22
+ for anything exploitable — especially anything that would let a run **escape a deny** (write
23
+ outside a substrate, dispatch on an uncompiled order, widen its own safety overrides) or
24
+ exfiltrate data.
13
25
  For non-sensitive hardening ideas, an ordinary issue is fine.
14
26
 
15
- In scope: the hooks, the pipeline scripts (`compile-order` / `ingest-result` /
16
- `validate-envelope` / `t0-verify`), the installer/migration shell scripts, and any prompt-
17
- injection path through skill files. Please do not test against machines you don't own.
27
+ In scope: the hooks, the kernel (`kernel/harness.mjs` and every subcommand beneath it), the
28
+ installer/migration shell scripts, and any prompt-injection path through skill files. Please do not
29
+ test against machines you don't own.
18
30
 
19
31
  ## The claims, stated so they can be falsified
20
32
 
21
- 1. **No hook or pipeline script makes a network request.** There is no `fetch`, no
33
+ 1. **No hook or kernel subcommand makes a network request.** There is no `fetch`, no
22
34
  `node:http(s)`, no `node:net`, no shelling out to `curl`/`wget` anywhere in `hooks/` or
23
- `skills/*/scripts/`. Verify: `grep -rnE "fetch|node:http|node:net|curl|wget" hooks/ skills/*/scripts/`.
35
+ `kernel/`. Verify: `grep -rnE "fetch|node:http|node:net|curl|wget" hooks/ kernel/`.
24
36
  2. **No hook has dependencies.** Plain `.mjs`, Node standard library only, no `node_modules`,
25
37
  no install-time scripts. What you read is what runs.
26
38
  3. **Every hook is fail-open by design.** Unparseable input, missing state files, or an
27
39
  unrecognized invocation shape → the hook defers and the normal permission flow proceeds. A
28
40
  hook denies only when it can positively prove its condition (a matched destructive command, a
29
- path the active order's substrate does not permit, an invalid order file, an empty intake, a
30
- spent wall-clock budget).
41
+ path no live order's substrate permits, an invalid order file, an empty intake).
31
42
  4. **The model cannot widen its own safety envelope.** The escape hatch
32
43
  (`.shapeup/safety-overrides.json`) is human-authored; `safety-spine` itself denies any
33
44
  write/move/delete touching that file, a malformed overrides file is treated as absent
34
45
  (override channel fails closed), and every exercised override is logged. The same principle
35
- covers `.shapeup/active-order`, the pointer `sandbox-guard` reads to decide what a worker may
36
- write: it sits outside the run-trace carve-out, so a worker cannot repoint its own sandbox.
37
- 5. **Exactly one hook can block, and only on a mechanical absence.** Two of the three
38
- `Stop`-position hooks (`anti-rationalization`, `slop-cleaner`) are advisory at most a
39
- `systemMessage`, always exit 0. The third, `gate-zerowork`, **does** return
40
- `decision: "block"`, and only in one state: the session dispatched the orchestrator and left
41
- no run receipt on disk. It makes no judgement about quality it reports that there is no work
42
- to judge. `stop_hook_active` caps it at one block per stop chain.
46
+ covers `.shapeup/active-order`, which `sandbox-guard` reads to find the run whose orders fence
47
+ a worker's writes: it sits outside the run-trace carve-out, so a worker cannot repoint its own
48
+ sandbox.
49
+ 5. **Exactly one hook can block, and only on a mechanical absence.** `gate-zerowork` returns
50
+ `decision: "block"` in one state: the session dispatched the orchestrator and left no run
51
+ receipt on disk. It makes no judgement about quality it reports that there is no work to
52
+ judge. `stop_hook_active` caps it at one block per stop chain. Every other check that used to
53
+ emit an advisory `systemMessage` at `Stop` now lands in the ship report instead, where it is a
54
+ section a person can read afterwards rather than a line in a transcript.
43
55
  6. **Every hook decision is recorded.** `hooks/lib/decision.mjs` is the only exit path a hook
44
56
  has, so allow, deny, block and error each leave a row in `.shapeup/decisions.jsonl`. An
45
57
  inert hook and a permitting hook are therefore distinguishable — which matters, because
@@ -56,17 +68,12 @@ sitting, and reading them is the recommended review.
56
68
  |---|---|---|---|---|
57
69
  | [`safety-spine.mjs`](hooks/safety-spine.mjs) | PreToolUse (`Bash\|Read\|Write\|Edit\|MultiEdit`) | The proposed command/path; `.shapeup/safety-overrides.json` | Yes — provably destructive ops only: `rm -rf` on unrecoverable targets, `git push --force` / push to main, `git reset --hard`, `git clean -fdx`, `DROP TABLE`/`TRUNCATE`, reads of `.env`/keys/cloud credentials, and any write to its own overrides file | Never blocks an unmatched command; `--force-with-lease` stays allowed |
58
70
  | [`gate-intake.mjs`](hooks/gate-intake.mjs) | PreToolUse (`Skill`) | The `tech-lead` dispatch's own arguments | Yes — an orchestrator dispatch carrying no resolvable intake (no pitch, spec, resume or requirement text) | Fails open on `--order` and on any ambiguous arg shape |
59
- | [`gate-deadline.mjs`](hooks/gate-deadline.mjs) | PreToolUse (`Skill`) | The run's opt-in `wall_clock_budget_s` and start time | Yes — a `task-executor` dispatch once the budget is spent, routing to the ship gate instead | Never denies `spec-evaluator`, `scope-hammer` or `qa-edge-hunter`; off entirely unless a budget is configured |
60
- | [`validate-envelope.mjs`](skills/tech-lead/scripts/validate-envelope.mjs) | PreToolUse (`Skill\|Agent`) | The `--order` file named in the dispatch; the JSON schemas | Yes — a worker dispatch whose order file is missing or schema-invalid | Never gates a dispatch that carries no `--order` (standalone skill use stays free) |
61
- | [`sandbox-guard.mjs`](hooks/sandbox-guard.mjs) | PreToolUse (`Edit\|Write\|MultiEdit`) | The target path; the active order's `substrate` block, via `.shapeup/active-order` | Yesany write the order does not permit: outside `allowed`/`shared`, inside `frozen`, or a `Write` to an `append_only` path | No-op unless an order is live; the active feature's own `.shapeup/<slug>/` run-trace is always writable. Appends denials to the local pathology log |
62
- | [`gate-l2.mjs`](hooks/gate-l2.mjs) | PreToolUse (`Skill`) | The round's task board (`.shapeup/<slug>/tasks/`) | **No** — advisory since ADR-0001. It detects a non-green board by two independent reads, names the unfinished tasks in a `systemMessage`, and permits the call | Never denies; records a `warn` row so "evaluated a partial board" stays countable |
71
+ | [`harness verify envelope`](kernel/verify/envelope.mjs) | PreToolUse (`Skill\|Agent`) | The `--order` file named in the dispatch; the JSON schemas | Yes — a worker dispatch whose order file is missing or schema-invalid | Never gates a dispatch that carries no `--order` (standalone skill use stays free) |
72
+ | [`sandbox-guard.mjs`](hooks/sandbox-guard.mjs) | PreToolUse (`Edit\|Write\|MultiEdit`) | The target path; the `substrate` block of every LIVE order (compiled, not yet ingested) | Yes — any write no live order permits: outside every `allowed`/`shared`, inside any `frozen`, or a `Write` to an `append_only` path | No-op unless an order is live; the active feature's own `.shapeup/<slug>/` run-trace is always writable. Appends denials to the local pathology log |
73
+ | [`dispatch-receipt.mjs`](hooks/dispatch-receipt.mjs) | PostToolUse (`Skill\|Agent`) | The `--order` file named in the dispatch; the tool result's own report of which skill ran | **Noit has no deny path at all.** It records that the shipped skill ran, so `harness reduce ingest` can refuse a result no dispatch produced | Never writes an attestation for a result that does not name a resolved skill; never fails the call it observes (every write is inside `try`/`catch`) |
63
74
  | [`gate-zerowork.mjs`](hooks/gate-zerowork.mjs) | Stop | Run receipts on disk; the session transcript; the decision ledger | **Yes — the one blocking hook.** Returns `decision:"block"` when the session dispatched the orchestrator and produced no run receipt | Defers the moment any receipt exists; `stop_hook_active` caps it at one block per stop chain |
64
- | [`anti-rationalization.mjs`](hooks/anti-rationalization.mjs) | Stop | Board/T0 facts vs. the reply's completion claims | **No** — advisory `systemMessage` only | Never `decision:"block"`, never exit 2 |
65
- | [`slop-cleaner.mjs`](hooks/slop-cleaner.mjs) | Stop | The session's git diff (local `git diff`, via `spawnSync`) | **No** — advisory `systemMessage` flagging TODO / `console.log` / commented-out leftovers | Same — never blocks |
66
- | [`compact-snapshot.mjs`](hooks/compact-snapshot.mjs) | PreCompact | Run state | No — writes `.shapeup/<slug>/run-snapshot.json` before compaction | Touches nothing outside `.shapeup/` |
67
- | [`session-rehydrate.mjs`](hooks/session-rehydrate.mjs) | SessionStart (`startup\|compact\|resume\|clear`) | The saved run snapshot | No — injects the "trust the files, not the summary" hint when a run is in flight | Silent when no run is in flight |
68
75
 
69
- (The twelfth `hooks.json` entry is a plain `echo` on SessionStart confirming the plugin loaded.)
76
+ (The remaining `hooks.json` entry is a plain `echo` on SessionStart confirming the plugin loaded.)
70
77
 
71
78
  ## Data handling
72
79