shapeup-sdlc 1.7.0 → 3.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude/settings.local.example.json +5 -5
- package/.claude-plugin/plugin.json +1 -1
- package/AGENTS.md +17 -3
- package/README.md +124 -103
- package/SECURITY.md +37 -30
- package/bin/init.mjs +77 -47
- package/bin/lib/grant.mjs +145 -0
- package/commands/build.md +7 -6
- package/commands/ship.md +29 -16
- package/commands/wire.md +1 -1
- package/hooks/dispatch-receipt.mjs +195 -0
- package/hooks/gate-intake.mjs +3 -3
- package/hooks/gate-zerowork.mjs +25 -24
- package/hooks/hooks.json +9 -48
- package/hooks/lib/decision.mjs +19 -8
- package/hooks/safety-spine.mjs +3 -3
- package/hooks/sandbox-guard.mjs +84 -40
- package/{skills/tech-lead/scripts/compile-order.mjs → kernel/compile.mjs} +283 -41
- package/{skills/tech-lead/scripts/gate-answers.mjs → kernel/gate.mjs} +58 -14
- package/kernel/harness.mjs +134 -0
- package/{skills/tech-lead/scripts/fit-check.mjs → kernel/init/fit.mjs} +15 -12
- package/{skills/tech-lead/scripts/init-run.mjs → kernel/init/run.mjs} +152 -31
- package/{skills/tech-lead/scripts → kernel}/lib/argv.mjs +52 -31
- package/{skills/tech-lead/scripts/lib/contract-md.mjs → kernel/lib/contract.mjs} +251 -7
- package/kernel/lib/paths.mjs +491 -0
- package/kernel/probe/concurrency.mjs +510 -0
- package/{skills/tech-lead/scripts/aegis-digest.mjs → kernel/probe/digest.mjs} +9 -10
- package/kernel/probe/eval.mjs +77 -0
- package/kernel/probe/leg.mjs +125 -0
- package/{skills/tech-lead/scripts/resume-state.mjs → kernel/probe/resume.mjs} +204 -63
- package/{skills/tech-lead/scripts → kernel/probe}/stats.mjs +93 -11
- package/kernel/probe/t0.mjs +66 -0
- package/{skills/ba-pitch-analyzer/scripts/board-derive.mjs → kernel/reduce/board.mjs} +99 -23
- package/kernel/reduce/graph.mjs +437 -0
- package/{skills/tech-lead/scripts/hill-derive.mjs → kernel/reduce/hill.mjs} +28 -9
- package/kernel/reduce/ingest.mjs +633 -0
- package/{hooks/slop-cleaner.mjs → kernel/reduce/leftovers.mjs} +40 -57
- package/{skills/tech-lead/scripts/ship-report.mjs → kernel/reduce/ship.mjs} +61 -13
- package/{skills/tech-lead/scripts/run-snapshot.mjs → kernel/reduce/snapshot.mjs} +21 -15
- package/{skills/spec-evaluator/scripts/verdict-ledger.mjs → kernel/reduce/verdict.mjs} +13 -7
- package/kernel/report/export.mjs +325 -0
- package/kernel/report/facts.mjs +347 -0
- package/{skills/tech-lead/scripts/budget-check.mjs → kernel/verify/budget.mjs} +15 -12
- package/kernel/verify/dispatch.mjs +114 -0
- package/{skills/tech-lead/scripts/validate-envelope.mjs → kernel/verify/envelope.mjs} +20 -15
- package/{skills/tech-lead/scripts/lib → kernel/verify}/ratchet-tree.mjs +36 -14
- package/kernel/verify/skills.mjs +125 -0
- package/kernel/verify/spec.mjs +559 -0
- package/{skills/tech-lead/scripts/t0-verify.mjs → kernel/verify/t0.mjs} +134 -24
- package/{skills/tech-lead/scripts/trace-lint.mjs → kernel/verify/trace.mjs} +26 -11
- package/oracles/http-oracle.mjs +1 -1
- package/oracles/process-oracle.mjs +1 -1
- package/oracles/snapshot-oracle.mjs +1 -1
- package/oracles/test-oracle.mjs +1 -1
- package/package.json +11 -9
- package/skills/ba-pitch-analyzer/SKILL.md +5 -5
- package/skills/ba-pitch-analyzer/assets/templates/_index.tmpl.md +1 -1
- package/skills/ba-pitch-analyzer/assets/templates/api-feasibility.tmpl.md +12 -7
- package/skills/ba-pitch-analyzer/assets/templates/contracts/third-party-api.contract.tmpl.md +6 -3
- package/skills/ba-pitch-analyzer/assets/templates/cross-context/migration-plan.tmpl.md +5 -4
- package/skills/ba-pitch-analyzer/assets/templates/cross-context/team-handoff.tmpl.md +23 -13
- package/skills/ba-pitch-analyzer/assets/templates/scope-summary.tmpl.md +17 -12
- package/skills/ba-pitch-analyzer/assets/templates/synthesis.tmpl.md +17 -38
- package/skills/ba-pitch-analyzer/assets/templates/task.tmpl.md +3 -0
- package/skills/ba-pitch-analyzer/references/contract-patterns.md +8 -4
- package/skills/ba-pitch-analyzer/references/doc-schemas.md +2 -0
- package/skills/ba-pitch-analyzer/references/task-generation.md +2 -2
- package/skills/qa-edge-hunter/SKILL.md +7 -3
- package/skills/scope-architect/SKILL.md +40 -6
- package/skills/solution-architect/SKILL.md +19 -4
- package/skills/spec-evaluator/SKILL.md +12 -2
- package/skills/task-executor/SKILL.md +7 -6
- package/skills/tech-lead/SKILL.md +50 -38
- package/skills/tech-lead/references/gates.md +69 -20
- package/skills/tech-lead/references/protocol.md +832 -0
- package/skills/tech-lead/schemas/domain.schema.json +341 -66
- package/skills/tech-lead/schemas/work-order.schema.json +11 -2
- package/skills/tech-lead/schemas/work-result.schema.json +1 -1
- package/skills/tech-lead/workflows/shapeup-run.js +1313 -750
- package/hooks/anti-rationalization.mjs +0 -238
- package/hooks/compact-snapshot.mjs +0 -47
- package/hooks/gate-deadline.mjs +0 -147
- package/hooks/gate-l2.mjs +0 -161
- package/hooks/session-rehydrate.mjs +0 -108
- package/skills/ba-pitch-analyzer/scripts/spec-lint.mjs +0 -239
- package/skills/spec-evaluator/README.md +0 -93
- package/skills/tech-lead/README.md +0 -71
- package/skills/tech-lead/references/delegation.md +0 -261
- package/skills/tech-lead/references/hard-rules.md +0 -34
- package/skills/tech-lead/references/invocation.md +0 -45
- package/skills/tech-lead/references/ledger-schema.md +0 -213
- package/skills/tech-lead/references/round-protocol.md +0 -234
- package/skills/tech-lead/references/state-model.md +0 -66
- package/skills/tech-lead/scripts/ingest-result.mjs +0 -258
- package/skills/tech-lead/scripts/lib/is-main.mjs +0 -81
- package/skills/tech-lead/scripts/lib/paths.mjs +0 -280
- package/skills/tech-lead/scripts/run-workflow.mjs +0 -381
- package/skills/translator/README.md +0 -66
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"_readme": "Tier C template (design spec addendum
|
|
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
|
|
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
|
|
16
|
-
"Bash(node
|
|
17
|
-
"
|
|
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": "
|
|
4
|
+
"version": "3.0.0",
|
|
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:
|
|
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
|
|
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
|
-
|
|
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
|
|
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).
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
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
|
-
`
|
|
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
|
|
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
|
|
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
|
-
###
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
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 mechanical — orchestrator 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
|
|
268
|
-
- **Traceability is oracle-checked, opt-in** — `trace
|
|
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.**
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
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/
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
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-
|
|
314
|
-
#
|
|
315
|
-
#
|
|
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 **
|
|
4
|
-
`PreToolUse` position, of which
|
|
5
|
-
can block a session from ending. That is the
|
|
6
|
-
|
|
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** (
|
|
12
|
-
|
|
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
|
|
16
|
-
|
|
17
|
-
|
|
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
|
|
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
|
-
`
|
|
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
|
|
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`,
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
`
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
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
|
-
| [`
|
|
60
|
-
| [`
|
|
61
|
-
| [`
|
|
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 | **No — it 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
|
|
76
|
+
(The remaining `hooks.json` entry is a plain `echo` on SessionStart confirming the plugin loaded.)
|
|
70
77
|
|
|
71
78
|
## Data handling
|
|
72
79
|
|