shapeup-sdlc 3.18.2 → 4.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.
Files changed (141) hide show
  1. package/.claude/settings.local.example.json +2 -3
  2. package/.claude-plugin/plugin.json +1 -1
  3. package/AGENTS.md +115 -56
  4. package/README.md +101 -143
  5. package/SECURITY.md +16 -25
  6. package/agents/orient.md +14 -0
  7. package/agents/qa-edge-hunter.md +13 -0
  8. package/agents/spec-evaluator.md +14 -0
  9. package/agents/task-executor.md +14 -0
  10. package/bin/init.mjs +13 -16
  11. package/bin/lib/grant.mjs +8 -19
  12. package/commands/build.md +9 -14
  13. package/commands/eval.md +3 -3
  14. package/commands/hammer.md +9 -5
  15. package/commands/retro.md +12 -11
  16. package/commands/scopes.md +1 -12
  17. package/commands/ship.md +45 -88
  18. package/commands/wire.md +1 -8
  19. package/hooks/dispatch-receipt.mjs +94 -8
  20. package/hooks/hooks.json +0 -41
  21. package/hooks/lib/decision.mjs +6 -9
  22. package/hooks/lib/tier.mjs +50 -0
  23. package/hooks/sandbox-guard.mjs +140 -64
  24. package/kernel/gate.mjs +203 -22
  25. package/kernel/harness.mjs +20 -67
  26. package/kernel/init/run.mjs +175 -523
  27. package/kernel/lib/contract.mjs +9 -93
  28. package/kernel/lib/floor.mjs +64 -0
  29. package/kernel/lib/paths.mjs +39 -112
  30. package/kernel/order.mjs +157 -0
  31. package/kernel/probe/digest.mjs +2 -38
  32. package/kernel/schemas/domain.schema.json +146 -1125
  33. package/kernel/schemas/work-order.schema.json +8 -4
  34. package/kernel/schemas/work-result.schema.json +1 -1
  35. package/kernel/verify/envelope.mjs +2 -2
  36. package/kernel/verify/skills.mjs +27 -8
  37. package/kernel/verify/t0.mjs +2 -2
  38. package/package.json +4 -2
  39. package/skills/building/SKILL.md +144 -0
  40. package/skills/building/resources/gates.md +76 -0
  41. package/skills/building/resources/guidance.md +23 -0
  42. package/skills/{translator/references/preservation-rules.md → building/resources/intake-preservation.md} +1 -1
  43. package/skills/building/resources/intake.md +157 -0
  44. package/skills/building/resources/orders.md +69 -0
  45. package/skills/{ba-pitch-analyzer/references → building/resources/plan-references}/doc-schemas.md +1 -1
  46. package/skills/{ba-pitch-analyzer/references → building/resources/plan-references}/task-generation.md +13 -13
  47. package/skills/{ba-pitch-analyzer/references → building/resources/plan-references}/test-surface.md +6 -7
  48. package/skills/building/resources/plan-scopes.md +95 -0
  49. package/skills/building/resources/plan-spec.md +102 -0
  50. package/skills/{ba-pitch-analyzer/assets/templates → building/resources/plan-templates}/_index.tmpl.md +1 -1
  51. package/skills/{ba-pitch-analyzer/assets/templates → building/resources/plan-templates}/assess-report.tmpl.md +10 -11
  52. package/skills/{ba-pitch-analyzer/assets/templates → building/resources/plan-templates}/run-state.tmpl.md +4 -4
  53. package/skills/{ba-pitch-analyzer/assets/templates → building/resources/plan-templates}/scope-summary.tmpl.md +2 -2
  54. package/skills/{ba-pitch-analyzer/assets/templates → building/resources/plan-templates}/synthesis.tmpl.md +4 -4
  55. package/skills/{ba-pitch-analyzer/assets/templates → building/resources/plan-templates}/usecase.tmpl.md +2 -2
  56. package/skills/building/resources/plan-wire.md +82 -0
  57. package/skills/building/resources/plan.md +98 -0
  58. package/skills/building/resources/retro-research.md +60 -0
  59. package/skills/building/resources/retro-scan.md +49 -0
  60. package/skills/building/resources/retro.md +225 -0
  61. package/skills/building/resources/rounds.md +78 -0
  62. package/skills/building/resources/stop.md +127 -0
  63. package/skills/orient/SKILL.md +37 -37
  64. package/skills/qa-edge-hunter/SKILL.md +29 -14
  65. package/skills/shapeup/SKILL.md +5 -5
  66. package/skills/shapeup/resources/breadboarding.md +1 -1
  67. package/skills/shapeup/resources/context-compaction.md +5 -5
  68. package/skills/shapeup/resources/shaping.md +1 -1
  69. package/skills/spec-evaluator/SKILL.md +17 -21
  70. package/skills/spec-evaluator/references/dimension-contract.md +1 -1
  71. package/skills/spec-evaluator/references/dimensions/completeness.md +3 -3
  72. package/skills/spec-evaluator/references/dimensions/spec-conformance.md +1 -1
  73. package/skills/spec-evaluator/references/dimensions/test-surface-conformance.md +5 -5
  74. package/skills/task-executor/SKILL.md +11 -15
  75. package/commands/hill.md +0 -10
  76. package/hooks/gate-intake.mjs +0 -109
  77. package/hooks/gate-zerowork.mjs +0 -349
  78. package/hooks/tier-guard.mjs +0 -162
  79. package/kernel/compile.mjs +0 -1419
  80. package/kernel/init/fit.mjs +0 -199
  81. package/kernel/init/run-args.mjs +0 -206
  82. package/kernel/lib/breadboard.mjs +0 -165
  83. package/kernel/probe/attempts.mjs +0 -161
  84. package/kernel/probe/concurrency.mjs +0 -535
  85. package/kernel/probe/eval.mjs +0 -405
  86. package/kernel/probe/hunt.mjs +0 -104
  87. package/kernel/probe/leg.mjs +0 -229
  88. package/kernel/probe/owner.mjs +0 -142
  89. package/kernel/probe/requirements.mjs +0 -328
  90. package/kernel/probe/resume.mjs +0 -1110
  91. package/kernel/probe/rounds.mjs +0 -115
  92. package/kernel/probe/staged.mjs +0 -83
  93. package/kernel/probe/stats.mjs +0 -477
  94. package/kernel/probe/t0.mjs +0 -115
  95. package/kernel/reduce/board.mjs +0 -350
  96. package/kernel/reduce/graph.mjs +0 -482
  97. package/kernel/reduce/hill.mjs +0 -322
  98. package/kernel/reduce/ingest.mjs +0 -767
  99. package/kernel/reduce/leftovers.mjs +0 -159
  100. package/kernel/reduce/ship.mjs +0 -529
  101. package/kernel/reduce/snapshot.mjs +0 -291
  102. package/kernel/reduce/verdict.mjs +0 -172
  103. package/kernel/report/export.mjs +0 -384
  104. package/kernel/report/facts.mjs +0 -234
  105. package/kernel/verify/budget.mjs +0 -153
  106. package/kernel/verify/build.mjs +0 -428
  107. package/kernel/verify/dispatch.mjs +0 -114
  108. package/kernel/verify/spec.mjs +0 -975
  109. package/kernel/verify/trace.mjs +0 -604
  110. package/skills/ba-pitch-analyzer/SKILL.md +0 -204
  111. package/skills/coach/SKILL.md +0 -397
  112. package/skills/hill-chart/SKILL.md +0 -154
  113. package/skills/hill-chart/assets/dashboard.template.html +0 -1432
  114. package/skills/scope-architect/SKILL.md +0 -174
  115. package/skills/scope-hammer/SKILL.md +0 -231
  116. package/skills/solution-architect/SKILL.md +0 -158
  117. package/skills/tech-lead/SKILL.md +0 -151
  118. package/skills/tech-lead/references/gates.md +0 -605
  119. package/skills/tech-lead/references/protocol.md +0 -889
  120. package/skills/tech-lead/references/tiny-lane.md +0 -53
  121. package/skills/tech-lead/workflows/shapeup-run.js +0 -2187
  122. package/skills/translator/SKILL.md +0 -258
  123. /package/skills/{ba-pitch-analyzer/references → building/resources/plan-references}/contract-patterns.md +0 -0
  124. /package/skills/{ba-pitch-analyzer/references → building/resources/plan-references}/ddd-patterns.md +0 -0
  125. /package/skills/{ba-pitch-analyzer/references → building/resources/plan-references}/integration-analysis.md +0 -0
  126. /package/skills/{ba-pitch-analyzer/references → building/resources/plan-references}/ux-behavior-patterns.md +0 -0
  127. /package/skills/{ba-pitch-analyzer/assets/templates → building/resources/plan-templates}/api-feasibility.tmpl.md +0 -0
  128. /package/skills/{ba-pitch-analyzer/assets/templates → building/resources/plan-templates}/contracts/be-service.contract.tmpl.md +0 -0
  129. /package/skills/{ba-pitch-analyzer/assets/templates → building/resources/plan-templates}/contracts/offline-storage.contract.tmpl.md +0 -0
  130. /package/skills/{ba-pitch-analyzer/assets/templates → building/resources/plan-templates}/contracts/third-party-api.contract.tmpl.md +0 -0
  131. /package/skills/{ba-pitch-analyzer/assets/templates → building/resources/plan-templates}/cross-context/context-map.tmpl.md +0 -0
  132. /package/skills/{ba-pitch-analyzer/assets/templates → building/resources/plan-templates}/cross-context/event-choreography.tmpl.md +0 -0
  133. /package/skills/{ba-pitch-analyzer/assets/templates → building/resources/plan-templates}/cross-context/migration-plan.tmpl.md +0 -0
  134. /package/skills/{ba-pitch-analyzer/assets/templates → building/resources/plan-templates}/cross-context/team-handoff.tmpl.md +0 -0
  135. /package/skills/{ba-pitch-analyzer/assets/templates → building/resources/plan-templates}/domain-model.tmpl.md +0 -0
  136. /package/skills/{ba-pitch-analyzer/assets/templates → building/resources/plan-templates}/feedback.tmpl.md +0 -0
  137. /package/skills/{ba-pitch-analyzer/assets/templates → building/resources/plan-templates}/integration.tmpl.md +0 -0
  138. /package/skills/{ba-pitch-analyzer/assets/templates → building/resources/plan-templates}/task-board.tmpl.md +0 -0
  139. /package/skills/{ba-pitch-analyzer/assets/templates → building/resources/plan-templates}/task-spike.tmpl.md +0 -0
  140. /package/skills/{ba-pitch-analyzer/assets/templates → building/resources/plan-templates}/task.tmpl.md +0 -0
  141. /package/skills/{ba-pitch-analyzer/assets/templates → building/resources/plan-templates}/ux-behavior.tmpl.md +0 -0
package/bin/init.mjs CHANGED
@@ -26,9 +26,9 @@ import { fileURLToPath } from "node:url";
26
26
  import { spawnSync } from "node:child_process";
27
27
  import { createInterface } from "node:readline";
28
28
  import { LOCAL, LEGACY, metricsDir } from "../kernel/lib/paths.mjs";
29
- import { mergePipelinePermissions as mergeGrant, isWorkspaceTrusted, WORKFLOW_RULE } from "./lib/grant.mjs";
29
+ import { mergePipelinePermissions as mergeGrant, isWorkspaceTrusted } from "./lib/grant.mjs";
30
30
 
31
- /** The root a project migrating off the pre-ADR-0001 layout may still be carrying. */
31
+ /** The root a project migrating off the earlier layout may still be carrying. */
32
32
  const LEGACY_LOCAL = LEGACY.local;
33
33
 
34
34
  const PKG_ROOT = resolve(dirname(fileURLToPath(import.meta.url)), "..");
@@ -43,24 +43,21 @@ Options:
43
43
  -d, --directory <path> Target project directory (default: current directory)
44
44
  -o, --override Overwrite existing files in target
45
45
  -y, --yes Run unattended (answer yes to all prompts)
46
- --no-native-workflow Do not grant the unscoped "Workflow" permission (see below)
46
+ --no-native-workflow Accepted and ignored (kept so existing scripts that pass it still run)
47
47
  -h, --help Print this help
48
48
 
49
- The grant this writes is two Bash rules for the harness kernel, plus — unless
50
- --no-native-workflow is given — the "Workflow" token that lets the tech-lead
51
- launch its run script without approving each launch. That token is UNSCOPED: it
52
- authorises every dynamic workflow script in the project, not only this plugin's.
53
- Declining it leaves the harness fully functional in an interactive session; only
54
- the unattended lane needs the pre-approval.`;
49
+ The grant this writes is two Bash rules for the harness kernel, and nothing else.
50
+ The plugin no longer asks for the unscoped "Workflow" permission and no longer
51
+ needs it; a "Workflow" token already in your settings is yours and is left alone.`;
55
52
 
56
- let targetDir = ".", yes = false, override = false, nativeWorkflow = true;
53
+ let targetDir = ".", yes = false, override = false;
57
54
  const positional = [];
58
55
  for (let i = 0; i < argv.length; i++) {
59
56
  const a = argv[i];
60
57
  if (a === "-d" || a === "--directory") targetDir = argv[++i];
61
58
  else if (a === "-y" || a === "--yes") yes = true;
62
59
  else if (a === "-o" || a === "--override") override = true;
63
- else if (a === "--no-native-workflow") nativeWorkflow = false;
60
+ else if (a === "--no-native-workflow") { /* accepted, ignored: the installer never writes the token */ }
64
61
  else if (a === "-h" || a === "--help") { console.log(usage); process.exit(0); }
65
62
  else if (a.startsWith("-")) { console.error(`Unknown option: ${a}\n${usage}`); process.exit(1); }
66
63
  else positional.push(a);
@@ -125,7 +122,7 @@ warnIfUntrusted(target);
125
122
  ensureAgentImport(join(target, "CLAUDE.md"), "CLAUDE.md");
126
123
 
127
124
  // ---- 3. .gitignore ----------------------------------------------------------
128
- // Both roots are listed, deliberately. A project may still be carrying the pre-ADR-0001 local root
125
+ // Both roots are listed, deliberately. A project may still be carrying the earlier local root
129
126
  // alongside the current one, and a run trace committed by accident from either is exactly the
130
127
  // mistake the tier split exists to prevent. Ignoring a directory that does not exist costs nothing.
131
128
  const GITIGNORE_RULE = `# Shape Up SDLC run workspace
@@ -274,10 +271,10 @@ function installClaude() {
274
271
  * @returns {void}
275
272
  */
276
273
  function mergePipelinePermissions(settings) {
277
- mergeGrant(settings, { nativeWorkflow });
278
- if (!nativeWorkflow) {
279
- console.log(` [claude] --no-native-workflow: "${WORKFLOW_RULE}" not granted — launch the run`);
280
- console.log(" script interactively and approve it, or re-run init without the flag.");
274
+ mergeGrant(settings);
275
+ if ((settings.permissions?.allow || []).includes("Workflow")) {
276
+ console.log(' [claude] your settings carry a "Workflow" permission. This plugin no longer needs it and');
277
+ console.log(" leaves it alone — remove it yourself if nothing else in the project uses it.");
281
278
  }
282
279
  }
283
280
 
package/bin/lib/grant.mjs CHANGED
@@ -48,10 +48,10 @@
48
48
  // verify by eye. Scope is unchanged in kind and narrower in fact: one dependency-free, network-free
49
49
  // script that ships with the plugin. It grants no general `Bash(node:*)`.
50
50
  //
51
- // THE WORKFLOW GRANT is separate and optional (see {@link workflowRule}). The `Workflow` permission
52
- // token is UNSCOPED — it authorises every dynamic workflow script in the project, not just this
53
- // plugin's — so the installer states that plainly and lets `--no-native-workflow` decline it. A
54
- // project that declines runs the harness interactively, approving the launch each time.
51
+ // NO `Workflow` TOKEN. The run is driven by the loop in the session, not launched as a script, so
52
+ // nothing here needs the unscoped `Workflow` permission and the installer does not add it. It does not
53
+ // remove it either: a project may rely on that token for workflow scripts of its own, so a token already
54
+ // in a user's settings is the user's, and the merge below leaves it exactly where it is.
55
55
 
56
56
  import { existsSync, readFileSync } from "node:fs";
57
57
  import { join, resolve } from "node:path";
@@ -60,14 +60,6 @@ import { homedir } from "node:os";
60
60
  /** The kernel's path inside the installed plugin — the one executable the grant has to cover. */
61
61
  export const KERNEL_ENTRY = "kernel/harness.mjs";
62
62
 
63
- /**
64
- * The unscoped permission token that lets the tech-lead launch its Workflow script.
65
- *
66
- * Opt-in at install. Named here rather than spelled at each call site so the installer, the docs
67
- * check and the structural suite all mean the same string.
68
- */
69
- export const WORKFLOW_RULE = "Workflow";
70
-
71
63
  /**
72
64
  * The `permissions.allow` rules for the harness kernel.
73
65
  *
@@ -127,19 +119,16 @@ export function isWorkspaceTrusted(projectDir) {
127
119
  /**
128
120
  * Merge the harness grant into a parsed settings object, in place.
129
121
  *
122
+ * Adds the two kernel rules and drops only the rules this plugin itself once wrote and superseded;
123
+ * every other entry — a user's own rule, a `Workflow` token — is left alone.
124
+ *
130
125
  * @param {object} settings - Parsed settings.json.
131
- * @param {object} [opts] - Options.
132
- * @param {boolean} [opts.nativeWorkflow=true] - Also grant the unscoped `Workflow` token, which is
133
- * what lets the tech-lead launch its run script without a per-launch approval. `false` removes it
134
- * if a previous install added it, so `--no-native-workflow` is a real opt-out and not a no-op.
135
126
  * @returns {void}
136
127
  */
137
- export function mergePipelinePermissions(settings, { nativeWorkflow = true } = {}) {
128
+ export function mergePipelinePermissions(settings) {
138
129
  settings.permissions = settings.permissions || {};
139
130
  const allow = new Set(settings.permissions.allow || []);
140
131
  for (const r of [...allow]) if (isSupersededRule(r)) allow.delete(r);
141
132
  for (const r of pipelineRules()) allow.add(r);
142
- if (nativeWorkflow) allow.add(WORKFLOW_RULE);
143
- else allow.delete(WORKFLOW_RULE);
144
133
  settings.permissions.allow = [...allow].sort();
145
134
  }
package/commands/build.md CHANGED
@@ -4,8 +4,8 @@ description: Implement a task's acceptance criteria exactly (minimum code, surgi
4
4
  Use the **task-executor** skill on $ARGUMENTS.
5
5
 
6
6
  Standalone build: implements one task (`TASK-NNN`) from a spec folder — assumption scan first,
7
- minimum code, surgical diffs, verified observable outcomes. Inside an orchestrated run the
8
- tech-lead dispatches this skill through the envelope port instead; this command is for picking
7
+ minimum code, surgical diffs, verified observable outcomes. Inside a run the `building` loop
8
+ dispatches this skill through the envelope port instead; this command is for picking
9
9
  up a single task directly.
10
10
 
11
11
  If no task ID was given, read the board (`.shapeup/<slug>/tasks/_index.md`) and take the
@@ -16,19 +16,14 @@ the harness working, not an error to route around.
16
16
  ## Building a whole scoped feature is not this command
17
17
 
18
18
  This command builds **one task**. A full BUILD round — every scope, the per-scope attempt loop,
19
- T0 verification, the inner circuit breaker, then the single EVAL — is a workflow-script launch, and
20
- it belongs to the orchestrator:
19
+ T0 verification, the inner circuit breaker, then the single EVAL — belongs to the loop:
21
20
 
22
21
  ```
23
- Workflow({
24
- scriptPath: ".shapeup/workflows/shapeup-run.js",
25
- args: <the RunArgs object>
26
- })
22
+ /ship <pitch>
27
23
  ```
28
24
 
29
- Reach it through `/ship` (or the `tech-lead` skill), which opens the run properly — `harness init run`
30
- first, so the receipt exists. Do not hand-roll the round by calling this command once per task: the
31
- attempt loop, the T0 ratchet and the breakers are branches in that script, not steps a caller can
32
- be trusted to reproduce, and a session that rebuilds them by hand is the prose lane the cutover
33
- replaced. On a `--tiny` run or a spec with no committed `scopes/*.md`, the prose loop in
34
- `skills/tech-lead/references/protocol.md` still applies, unchanged and by design.
25
+ `/ship` opens the run properly — `harness init run` first, so the receipt and the launch record
26
+ exist — and then follows the loop's phase table over the run's files. Do not hand-roll the
27
+ round by calling this command once per task: the attempt loop, the T0 ratchet and the breakers are
28
+ the loop's discipline, not steps a caller can be trusted to reproduce, and a session that
29
+ rebuilds them by hand is the prose lane the loop replaced.
package/commands/eval.md CHANGED
@@ -9,8 +9,8 @@ The single judge. Two modes, chosen by the arguments:
9
9
  - `--spec <folder> --feature <slug> --single-pass` — the once-per-round verdict on the whole
10
10
  board.
11
11
 
12
- Round mode is watched: a PreToolUse hook (GATE L2) **warns** while any task on the board is
13
- unfinished, naming the offenders — advisory since ADR-0001, so the call proceeds, but a verdict
14
- taken now grades a partial board and the warning is recorded. The correct response is to route
12
+ Round mode crosses the Round Close gate first: while any task on the board is unfinished the gate block
13
+ carries the unfinished scopes — advisory, so the call proceeds, but a verdict
14
+ taken now grades a partial board and the crossing is recorded as a `warn`. The correct response is to route
15
15
  back to `/build` and finish them — do not shrug the warning off, and do not use `--task` as a
16
16
  loophole to simulate a round verdict piecemeal.
@@ -1,12 +1,16 @@
1
1
  ---
2
- description: GATE H — must-have census, baseline comparison, cut list + ship verdict
2
+ description: The Cut-List Review gate — must-have census, baseline comparison, cut list + ship verdict
3
3
  ---
4
- Use the **scope-hammer** skill on $ARGUMENTS.
4
+ Use the **building** skill's `stop` sub-command on $ARGUMENTS.
5
5
 
6
6
  The stop decision. Censuses the open items (QA findings, discovered-ledger rows, attempt-budget
7
- hammer proposals), compares the product to the **pitch's baseline — what customers live with
8
- today, never the ideal** — and returns a cut list plus a ship verdict for the TL/PO to confirm.
7
+ proposals), compares the product to the **pitch's baseline — what customers live with today, never
8
+ the ideal** — and returns a cut list plus a ship verdict for the TL/PO to confirm. You do it in this
9
+ session, and every ownership, exhaustion and requirement claim cites the file it came from — the scope
10
+ contracts, the dispatch receipts and trials, the verdict and `requirements.md`.
9
11
 
10
12
  Handles all three arrival paths: the normal stop (all scopes finished), an exhausted round
11
13
  budget, and an exhausted per-scope attempt budget. The verdict is a proposal — promotion of cut
12
- items is the human's call at the gate, not the skill's.
14
+ items is the human's call at the gate, not the census's — and it is written as data to
15
+ `reports/hammer-census.json` under the run's local root, which the Ship Sign-off gate reads before any answer set
16
+ may say `ship`.
package/commands/retro.md CHANGED
@@ -1,29 +1,30 @@
1
1
  ---
2
- description: File ship-gate feedback into the team-shared, per-skill knowledge base
2
+ description: File ship-gate feedback into the team-shared, per-reader knowledge base
3
3
  ---
4
- Use the **coach** skill on $ARGUMENTS.
4
+ Use the **building** skill's `retro` sub-command on $ARGUMENTS.
5
5
 
6
- Turns raw PO/TL feedback (usually from the L4 Ship gate) into per-skill guideline files under
7
- committed `shapeup/knowledge-base/<skill>.md`, which the coachable skills read back at
8
- the top of their next run, and which the tech lead reads at GATE L0 for workflow guidance.
6
+ Turns raw PO/TL feedback (usually from the Ship Sign-off gate) into per-reader guideline files under
7
+ committed `shapeup/knowledge-base/<reader>.md` — readers are `task-executor`, `orient`,
8
+ `qa-edge-hunter`, the `plan` activity and the loop itself (`building`, read at the Intake & Config gate, where it may
9
+ also suggest Intake & Config values the loop confirms before pinning).
9
10
 
10
- `/retro --scan` runs the coach's **scan** operation instead: it reads the project on disk (build
11
+ `/retro --scan` runs the retro's **scan** instead: it reads the project on disk (build
11
12
  and toolchain files, CI config, CLAUDE.md, README) and drafts the same kind of guidelines from
12
13
  it, before the first feature or after the toolchain changes. Optional, and never on the scan's
13
- own authority — every drafted rule goes through GATE COACH-1 like feedback.
14
+ own authority — every drafted rule goes through the Retro Ownership gate like feedback.
14
15
 
15
- `/retro --research <stack>` runs the **research** operation: for a project with nothing on disk
16
+ `/retro --research <stack>` runs the **research**: for a project with nothing on disk
16
17
  yet, it drafts the same kind of guidelines from the platform's official documentation only —
17
18
  build, launch, test, package manager, lint, in that order of leverage — each rule cited with url,
18
19
  version and fetch date; on a project that has been scanned, it cross-checks every scan rule
19
20
  against the documentation and reports each as confirmed, contradicted or unknown. The stack is
20
21
  required and never guessed. Research is a source, not a verification: nothing it reads runs, and
21
- the tech lead still pins every suggested command at GATE L0 before the kernel executes it. A
22
+ the loop still pins every suggested command at the Intake & Config gate before the kernel executes it. A
22
23
  later `--scan`, once the first feature has created a toolchain, retires the research rules it
23
24
  confirms with disk evidence.
24
25
 
25
- Two rules the skill enforces and this command must not soften: GATE COACH-1 **asks** the PO
26
- which skill owns each rule — it never assumes; and feedback whose root cause is the mechanism
26
+ Two rules the retro enforces and this command must not soften: the Retro Ownership gate **asks** the PO
27
+ which reader owns each rule — it never assumes; and feedback whose root cause is the mechanism
27
28
  itself (a gate, hook, or contract defect) is categorized `harness-defect` and filed to the
28
29
  defect register as a raw idea for the Betting Table, never as worker steering. A third holds
29
30
  for every category: guidance never decides a gate — a rule may add a question or a check to a
@@ -1,15 +1,4 @@
1
1
  ---
2
2
  description: Decompose the pitch into a spec tree + board, then map the scope contracts
3
3
  ---
4
- This is step 8 (Map Scopes), which is two skills in sequence:
5
-
6
- 1. Use the **ba-pitch-analyzer** skill on $ARGUMENTS — pitch → linked DDD spec tree (domain
7
- model → use cases → tasks) with BDD scenarios and the derived Test Surface. Pass through an
8
- operation when the user names one: `analyze` (the default — spec tree + board), `reconcile`
9
- (fold discovered-ledger items back into the board and UC invariants), `retrofit-surface`
10
- (append a Test Surface to a spec written before there was one), or `coverage` (extract the
11
- shared `requirements.md` registry that anchors covers-closure).
12
- 2. Then use the **scope-architect** skill (`map-scopes`) to write the committed scope contracts
13
- (`scopes/*.md`) — import-graph slicing by flow, write-whitelist substrates, fixtures.
14
-
15
- If the user asked for only one half ("just analyze", "just the contracts"), run only that half.
4
+ Alias of `/ship plan`: use the **building** skill's plan activity on $ARGUMENTS and stop once the scope contracts are on disk and the Board Review gate is crossed — run the planning substeps the phase table hands out.
package/commands/ship.md CHANGED
@@ -1,106 +1,63 @@
1
1
  ---
2
2
  description: Run the full Shape Up harness on a pitch, with human sign-off at gates
3
3
  ---
4
- Use the **tech-lead** skill to run the full harness on $ARGUMENTS.
4
+ Use the **building** skill to run the full harness on $ARGUMENTS.
5
5
 
6
- Default to **interactive** (`auto_level = interactive`): pause at every ⏸ gate and require PO
7
- sign-off — especially the Ship gate (L4). The harness's safety depends on the human being in the
6
+ Default to **interactive** (`auto_level = interactive`): pause at every gate and require PO
7
+ sign-off — especially the Ship Sign-off gate. The harness's safety depends on the human being in the
8
8
  loop; do not skip gates by default.
9
9
 
10
- **Before anything else, dispatch `tech-lead` and let it open the run** — its first action is
11
- `harness init run`, which writes the run receipt. Do not summarise what the harness will do;
12
- a session that dispatches the orchestrator and leaves no receipt is blocked at `Stop` by
13
- `hooks/gate-zerowork.mjs`.
10
+ **Before anything else, dispatch `building` and let it open the run** — its first action is
11
+ `harness init run`, which writes the run receipt and the launch record. Do not summarise what the harness will do:
12
+ a run that left no receipt did not happen.
14
13
 
15
- ## How the run actually executes
14
+ ## How the run executes
16
15
 
17
- On a spec with committed `scopes/*.md` — the common case — `tech-lead` holds the L0 intake
18
- conversation, writes `project-profile.md`, then hands the whole pipeline to a single background
19
- launch and does not drive it turn by turn:
16
+ `building` drives the run in this session. It opens the run, then reads the run's files and takes the first
17
+ phase whose condition holds, over and over: dispatch a worker, build the released scopes, run a kernel
18
+ command, cross a gate, close. Three things follow:
20
19
 
21
- ```
22
- Workflow({
23
- scriptPath: ".shapeup/workflows/shapeup-run.js",
24
- args: <the RunArgs object>
25
- })
26
- ```
20
+ - **A gate is answered where it is reached.** The loop prints the gate block, asks the PO one
21
+ question with a recommendation, records the answer with the source `PO (live)`, and goes on. There
22
+ is no relaunch after an answer.
23
+ - **A killed session loses nothing.** The next phase is read off the files on disk, never from
24
+ the conversation, so `/ship` again over an open run resumes it: a finished phase is not re-run.
25
+ - **Every agent the run spawns is a worker** — `orient`, `task-executor`, `spec-evaluator` and
26
+ `qa-edge-hunter` — and each leaves a row in the run's records. Planning is not a worker: the loop does it in this session, under a write fence of its own. Nor are the census at the Cut-List Review gate, the ship report, the retro after a ship, or the English copy of a non-English pitch: the loop does those itself.
27
27
 
28
- ORIENT → L1a → ANALYZE → WIRE → L1a.5 → MAP SCOPES → L1b → rounds of BUILD/L2/EVAL → QA → GATE H
29
- all run inside it. Three things follow, and they are the point of the cutover rather than trivia:
30
-
31
- - **A gate pause is a return value, not a stop.** The launch returns `{status: "paused", paused_at,
32
- block}`; emit `block` **verbatim**, get the PO's decision, write it to
33
- `.shapeup/<slug>/gate-answers.json`, and **relaunch the same call with the same args**. The
34
- fast-forward re-derives position from disk and re-dispatches nothing already finished.
35
- - **A killed session loses nothing.** Resume state comes off disk, never from context, so a fresh
36
- session picks the run up where it died — the property the whole launch shape exists to buy.
37
- - **The launch is the `Workflow` tool**, which is what gives the run resume-from-journal, worktree
38
- isolation, and sub-agents that share the session's prompt cache instead of paying a cold start
39
- each. `npx shapeup-sdlc init` writes the `"Workflow"` grant it needs. That grant is unscoped — it
40
- authorises every dynamic workflow script in the project — so an install may decline it with
41
- `--no-native-workflow`, in which case the launch asks for approval once per session and the
42
- unattended lane is unavailable.
43
-
44
- `--tiny`, and any spec with no committed `scopes/*.md` yet, take the unchanged prose lane in
45
- `skills/tech-lead/references/protocol.md` instead — non-regression, by design.
28
+ **`--tiny` is no longer served** — a breaking change in 4.0. The separate small-change lane (the `tech-lead`
29
+ skill's prose loop) was retired with that skill, and `init run` refuses `--tiny` and `--lane` as unknown flags (exit 2). If
30
+ `--tiny` is typed, say so plainly and run the full loop instead, with the pitch's appetite small (`~1 week` gives
31
+ a two-round budget, and a small shape yields one scope): the gates and the verification floor are the same ones
32
+ a bigger pitch crosses, and nothing is waived for a one-file fix. Do not take any other route — a hand-built
33
+ change outside the loop is what the harness exists to prevent.
46
34
 
47
35
  Only run headless/auto if the user explicitly asks for it in their message:
48
- - `--auto` → advance low-risk gates automatically, still pause at L4 (Ship sign-off).
36
+ - `--auto` → advance low-risk gates automatically, still pause at Ship Sign-off.
49
37
  Implies `--gate-answers guarded` unless a set is named.
50
38
  - `--unattended` → fully headless, `max_rounds 3`. Intended for CI, not day-to-day local runs.
51
- Implies `--gate-answers ci` unless a set is named.
52
- **In a `claude -p` invocation, set `CLAUDE_CODE_PRINT_BG_WAIT_CEILING_MS=0` first.** Print mode
53
- terminates a session's background tasks after 600 s, and the entire pipeline is one background
54
- launch, so without it the run is killed roughly ten minutes in — mid-phase, with no error beyond
55
- the CLI's own "background tasks still running; terminating". Resume state is on disk, so a
56
- relaunch fast-forwards past whatever finished; the cost is a relaunch, not the run.
57
- **Typing the flag IS the confirmation — do not stop to ask for another one.** Emit the warning
58
- that no human will review the verdict before ship as the run's first line, then proceed straight
59
- into GATE L0 in the same turn.
60
-
61
- > Why this is spelled out: asking for confirmation here made `--unattended` unusable for the
62
- > only job it has. In a non-interactive invocation (`claude -p …`, a CI step) there is no second
63
- > turn in which to answer, so the run spent its turn requesting permission and
64
- > exited having written nothing. A headless flag that cannot complete a headless run is a defect,
65
- > not a safety feature — and the warning, which is the part that carries the safety value, is
66
- > still printed. `--auto` remains the middle setting that pauses at L4.
67
-
68
- - `--tiny` → the small-change lane: orient (light) → single-task board → build → T0 → done.
69
- Skips wiring, scope contracts, EVAL, and QA; only gates L0 and L4 pause. The tech-lead's L0
70
- fit-check applies (≤ ~2 files, no new domain concept/dependency/flow) — if the change isn't
71
- tiny, it will say so and recommend the full lane.
39
+ Implies `--gate-answers ci` unless a set is named. **Typing the flag IS the confirmation — do not
40
+ stop to ask for another one.** Emit the warning that no human will review the verdict before ship as
41
+ the run's first line, then proceed straight into the Intake & Config gate in the same turn. (In a non-interactive
42
+ invocation there is no second turn in which to answer; a headless flag that waits for one cannot
43
+ complete a headless run.)
72
44
 
73
- Additional flags, pass through to `tech-lead` only when the user names them:
45
+ Additional flags, pass through to `building` only when the user names them:
74
46
  - `--breadboard <path>` → the pitch's breadboard, when it is not beside the pitch. A pitch shaped
75
- with `/shapeup` is `shaping.md` + `breadboard.md`; the run finds a `breadboard.md` in the same
76
- folder (or in `shaping/`) on its own, and reads one written inline in a single `pitch.md`. Name
77
- it only when it lives somewhere else. Its Places become the spec's screens, and spec-lint stops
78
- the run at GATE L1b when one is missing or folded into another screen.
47
+ with `/shapeup` is `shaping.md` + `breadboard.md`; the loop finds a `breadboard.md` in the same
48
+ folder (or in `shaping/`) on its own, and reads one written inline in a single `pitch.md`. Its
49
+ Places become the spec's screens, and the Board Review gate is where a missing or folded one is caught.
79
50
  - `--gate-answers <ci|guarded|interactive|path.json>` → the pre-recorded PO decisions this run
80
- crosses its gates with. Gates still emit their blocks and still record a decision; the
81
- decision's **source** becomes the answer set instead of a live human, and the ledger says so.
82
- Generate one with `harness gate --init --preset ci --by "<name>"`. This is what makes a
83
- headless lane finish: without it an unattended run waits at the first ⏸ until the wall-clock
84
- budget expires, having built nothing.
85
- - `--wall-clock-budget <seconds>` → arm the deadline breaker. Off by default. Set it in any lane
86
- with a hard clock (CI, an overnight run) and set it *below* the external kill, so
87
- the harness trips its own breaker first: past the deadline `harness verify budget` denies new
88
- `task-executor` work and routes to GATE H, where scope-hammer ships whatever is green. A run
89
- killed from outside ships nothing — including the scopes that already passed T0.
90
- - `--parallel-scopes N` → how many scopes build at once (default 4). Concurrency is a cost
91
- question before it is a speed one — every extra leg is another worker's full context — so this
92
- is a dial rather than a constant. `1` builds scopes one at a time, which is the setting for a
93
- project whose workers are not safe to run beside each other.
94
- - `--adversarial-verify` → before a FAIL finding costs a whole fix round, spend one independent
95
- skeptic on it, prompted to refute and to default to "real" when it cannot. Off by default; it
96
- does not touch the single-judge invariant, because a refutation retracts a finding rather than
97
- issuing a verdict.
51
+ crosses its gates with. Gates still emit their blocks and still record a decision; the decision's
52
+ **source** becomes the answer set instead of a live human, and the ledger says so. Generate one
53
+ with `harness gate --init --preset ci --by "<name>"`. Without one an unattended run waits at the
54
+ first gate, having built nothing.
55
+ - `--parallel-scopes N` → how many scopes build at once (default 4). Concurrency is a cost question
56
+ before it is a speed one — every extra leg is another worker's full context. `1` builds scopes one
57
+ at a time.
98
58
  - `--no-qa` → skip the QA Edge Hunt. QA is a level-up, not a gate.
99
- - `--rounds N` → override the outer circuit breaker (build+eval cycles, default 3).
100
- - `--attempts N` → override the inner circuit breaker (per-scope T0 attempts, default 5;
101
- no-op on specs without scope contracts).
102
- - `--exec-model / --eval-model / --qa-model <name>` → override GATE L0.8's
103
- resolved model matrix for this run only (highest precedence over `.claude/settings.local.json`
104
- / `.claude/settings.json` / skill defaults). `--orch-model` is shown in the L0 block and changes
105
- nothing: the orchestrator is the session already running this command, so its model is the one
106
- that session was started with.
59
+ - `--no-eval` → skip the evaluator; the run ships as not evaluated, and says so.
60
+ - `--rounds N` → override the outer circuit breaker (build+eval cycles, default 3). Passed to `init run` as `--max-rounds N`.
61
+ - `--attempts N` → override the inner circuit breaker (per-scope T0 attempts, default 5). Passed to `init run` as `--attempts N`.
62
+ - `--exec-model / --eval-model / --qa-model <name>` → override the resolved model matrix for this run
63
+ only (highest precedence over `.claude/settings.local.json` / `.claude/settings.json` / skill defaults).
package/commands/wire.md CHANGED
@@ -1,11 +1,4 @@
1
1
  ---
2
2
  description: Write the wiring map — engine → seam → entry-point call site, per use case
3
3
  ---
4
- Use the **solution-architect** skill (operation `wire`) on $ARGUMENTS.
5
-
6
- This is gate L1a.5 — it front-loads the integration seam so no engine ships orphaned. The skill
7
- is the sole writer of the committed `wiring-map.md`, resolved against `project-profile.md`'s
8
- `entry_point`; `harness verify trace` later checks reachability against it.
9
-
10
- It needs the spec folder (for the use cases) and the project profile. If either is missing, say
11
- which one rather than inventing it.
4
+ Alias of `/ship plan`: use the **building** skill's plan activity on $ARGUMENTS and stop after the wiring map (the Wiring Review gate) — it needs the spec folder and `project-profile.md`; if either is missing, say which rather than inventing it.
@@ -33,6 +33,28 @@
33
33
  // because a future host that reports failures through this event must not be able to satisfy the
34
34
  // wall by firing at all.
35
35
  //
36
+ // THE PLUGIN'S WORKERS ARE AGENT DEFINITIONS (`agents/<worker>.md`), and a dispatch of one is an
37
+ // `Agent` call whose result names the AGENT that ran (`tool_response.agentType`). An agent type the
38
+ // host cannot resolve is rejected upstream exactly as an unknown skill is, and the worker's skill is
39
+ // preloaded by the definition, so no `Skill` call happens inside it — the agent's name is the
40
+ // attestation, and the same result carries what the host measured (`totalTokens`, `totalDurationMs`,
41
+ // `resolvedModel`), recorded on the row so no session has to copy a figure by hand.
42
+ //
43
+ // THE MODEL THE CALL ASKED FOR IS RECORDED BESIDE THE ONE THAT RAN. The agent definitions say
44
+ // `model: inherit`, so a dispatch that carries no `model` runs on the launching session's model whatever
45
+ // the launch record asked for — measured across every archived run: the record said `sonnet` and the
46
+ // receipts of the runs that were compared named two different models. `model_requested` is the call's own
47
+ // `tool_input.model` (null when it carried none, which is "inherited", never a guess), and the ship gate
48
+ // reads `usage.model` against the launch record; without both columns a cost or a verdict can be read
49
+ // against a model that never ran.
50
+ //
51
+ // A SCOPE LAUNCHED IN THE BACKGROUND reports no agent at all: the result is "Async agent launched"
52
+ // plus an `agentId`, because the host has not run anything yet. Parallel scope builds are exactly that
53
+ // case, and without this arm the receipt hook went blind to every one of them. What the host did
54
+ // establish is that it accepted the call — an agent type it cannot resolve is rejected before this
55
+ // event — so the name the CALL carried (`subagent_type`) is the attestation, and the usage is null
56
+ // because there is none to record yet.
57
+ //
36
58
  // WHAT IT WILL NOT ATTEST. A receipt is written only when the tool result NAMES the skill that ran
37
59
  // (`tool_response.commandName`). An `Agent` dispatch whose prompt merely mentions `--order` gets no
38
60
  // receipt: the prompt is a plan to dispatch, not evidence of one, and minting attestation from it
@@ -86,6 +108,60 @@ export function skillInvokedFrom(toolResponse) {
86
108
  return name.slice(name.lastIndexOf(":") + 1) || null;
87
109
  }
88
110
 
111
+ /**
112
+ * Did the host launch this `Agent` call in the background and accept it?
113
+ *
114
+ * A background launch returns no `agentType`: its result says the agent was launched and names an
115
+ * `agentId`. Both must hold — a call asked to run in the background AND a result that reports a launch —
116
+ * so a failed or empty result never counts as one.
117
+ *
118
+ * @param {object} toolResponse - The `tool_response` block of an `Agent` call.
119
+ * @param {object} toolInput - The `tool_input` block of the same call.
120
+ * @returns {boolean} True for an accepted background launch.
121
+ */
122
+ export function backgroundLaunch(toolResponse, toolInput) {
123
+ if (toolInput?.run_in_background !== true || !toolResponse) return false;
124
+ const text = typeof toolResponse === "string" ? toolResponse : JSON.stringify(toolResponse);
125
+ return /\bagentId\b/.test(text) && /launched/i.test(text);
126
+ }
127
+
128
+ /**
129
+ * Which worker an `Agent` dispatch ran, from the tool result — or, for a background launch, from the
130
+ * name the accepted call carried.
131
+ *
132
+ * The host reports the agent NAMESPACED (`shapeup-sdlc-plugin:orient`); the bare name is compared
133
+ * against the WorkOrder's `worker`, so a general-purpose agent that merely had `--order` in its prompt
134
+ * attests as `general-purpose` and the ingest gate refuses it.
135
+ *
136
+ * @param {object} toolResponse - The `tool_response` block of an `Agent` call.
137
+ * @param {object} [toolInput] - The `tool_input` block of the same call.
138
+ * @returns {string|null} The bare agent name, or null when nothing names an agent.
139
+ */
140
+ export function agentWorkerFrom(toolResponse, toolInput) {
141
+ const name = typeof toolResponse?.agentType === "string" && toolResponse.agentType
142
+ ? toolResponse.agentType
143
+ : (backgroundLaunch(toolResponse, toolInput) ? toolInput?.subagent_type : null);
144
+ if (typeof name !== "string" || !name) return null;
145
+ return name.slice(name.lastIndexOf(":") + 1) || null;
146
+ }
147
+
148
+ /**
149
+ * What the host measured for an `Agent` dispatch, as the leg row carries it.
150
+ *
151
+ * Absent figures stay null — a figure the host did not give is never inferred and never zero.
152
+ *
153
+ * @param {object} toolResponse - The `tool_response` block of an `Agent` call.
154
+ * @returns {{tokens_total:(number|null), duration_ms:(number|null), model:(string|null)}} The usage.
155
+ */
156
+ export function usageFrom(toolResponse) {
157
+ const num = (v) => (typeof v === "number" && Number.isFinite(v) && v >= 0 ? v : null);
158
+ return {
159
+ tokens_total: num(toolResponse?.totalTokens),
160
+ duration_ms: num(toolResponse?.totalDurationMs),
161
+ model: typeof toolResponse?.resolvedModel === "string" ? toolResponse.resolvedModel : null,
162
+ };
163
+ }
164
+
89
165
  /**
90
166
  * Build the receipt row for one dispatch.
91
167
  *
@@ -106,12 +182,20 @@ export function receiptRow(order, skillInvoked, payload) {
106
182
  skill_invoked: skillInvoked,
107
183
  // Corroboration, not the wall — see the header. `success` is absent on hosts that do not
108
184
  // report one, and an absent field must not read as a successful dispatch.
109
- dispatch_ok: payload?.tool_response?.success === true,
185
+ dispatch_ok: payload?.tool_response?.success === true || payload?.tool_response?.status === "completed"
186
+ || backgroundLaunch(payload?.tool_response, payload?.tool_input),
110
187
  tool: payload?.tool_name ?? null,
111
188
  // Present when the dispatch came from a sub-agent, absent when the operator called it directly.
112
189
  // That is the difference between an orchestrated leg and someone driving a skill by hand.
113
- agent_id: payload?.agent_id ?? null,
114
- agent_type: payload?.agent_type ?? null,
190
+ agent_id: payload?.agent_id ?? payload?.tool_response?.agentId ?? null,
191
+ agent_type: payload?.agent_type ?? payload?.tool_response?.agentType
192
+ ?? (backgroundLaunch(payload?.tool_response, payload?.tool_input) ? payload.tool_input.subagent_type : null),
193
+ // What the host measured for an Agent dispatch; null for a Skill call, which reports none.
194
+ usage: payload?.tool_name === "Agent" ? usageFrom(payload.tool_response) : null,
195
+ // The model the call asked for, as written; null when the call carried none and the agent inherited
196
+ // the session's. Compared with `usage.model` by whoever reads the row, never reconciled here.
197
+ model_requested: payload?.tool_name === "Agent" && typeof payload?.tool_input?.model === "string" && payload.tool_input.model
198
+ ? payload.tool_input.model : null,
115
199
  };
116
200
  }
117
201
 
@@ -166,11 +250,13 @@ export async function main() {
166
250
  const cited = orderPathFrom(p.tool_input);
167
251
  if (!cited) defer("no --order threaded — not an orchestrated dispatch", "no-order");
168
252
 
169
- const skillInvoked = skillInvokedFrom(p.tool_response);
253
+ const skillInvoked = p.tool_name === "Agent"
254
+ ? (agentWorkerFrom(p.tool_response, p.tool_input) ?? skillInvokedFrom(p.tool_response))
255
+ : skillInvokedFrom(p.tool_response);
170
256
  if (!skillInvoked) {
171
- // The `Agent` case, and any host result that does not name what ran. Attesting here would
172
- // mint the fact rather than record it.
173
- defer("dispatch result names no resolved skill — nothing to attest", "no-skill-named");
257
+ // A host result that does not name what ran. Attesting here would mint the fact rather than
258
+ // record it.
259
+ defer("dispatch result names no resolved skill or agent — nothing to attest", "no-skill-named");
174
260
  }
175
261
 
176
262
  // The order path is relative to the shell; the receipt file is relative to the project root
@@ -190,7 +276,7 @@ export async function main() {
190
276
  rule: written ? "receipt-written" : "receipt-write-failed",
191
277
  reason: written
192
278
  ? `dispatch receipt: ${row.order_id} ran ${skillInvoked} (declared ${row.worker_declared}, ok=${row.dispatch_ok})`
193
- : `dispatch receipt could not be written for ${row.order_id} — ingest will refuse this result unless --no-receipt-check`,
279
+ : `dispatch receipt could not be written for ${row.order_id} — this attempt cannot be counted as attested`,
194
280
  };
195
281
  });
196
282
  }