@pilotspace/add 1.8.0 → 1.10.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 (38) hide show
  1. package/CHANGELOG.md +109 -0
  2. package/bin/cli.js +137 -2
  3. package/docs/16-releasing.md +2 -2
  4. package/docs/17-components.md +125 -0
  5. package/docs/appendix-c-glossary.md +8 -0
  6. package/package.json +2 -2
  7. package/skill/add/SKILL.md +90 -116
  8. package/skill/add/adopt.md +13 -34
  9. package/skill/add/advisor.md +9 -10
  10. package/skill/add/compact-foundation.md +21 -34
  11. package/skill/add/components.md +54 -0
  12. package/skill/add/confidence.md +9 -25
  13. package/skill/add/deltas.md +12 -28
  14. package/skill/add/design.md +26 -32
  15. package/skill/add/fold.md +26 -51
  16. package/skill/add/graduate.md +18 -54
  17. package/skill/add/intake.md +30 -34
  18. package/skill/add/loop.md +30 -34
  19. package/skill/add/phases/0-ground.md +6 -14
  20. package/skill/add/phases/0-setup.md +30 -81
  21. package/skill/add/phases/1-specify.md +7 -22
  22. package/skill/add/phases/2-scenarios.md +1 -3
  23. package/skill/add/phases/3-contract.md +8 -22
  24. package/skill/add/phases/4-tests.md +3 -6
  25. package/skill/add/phases/5-build.md +8 -22
  26. package/skill/add/phases/6-verify.md +14 -49
  27. package/skill/add/phases/7-observe.md +1 -3
  28. package/skill/add/phases/fast-lane.md +31 -0
  29. package/skill/add/release.md +36 -90
  30. package/skill/add/report-template.md +41 -126
  31. package/skill/add/run.md +89 -159
  32. package/skill/add/scope.md +40 -89
  33. package/skill/add/setup-review.md +10 -27
  34. package/skill/add/soul.md +17 -36
  35. package/skill/add/streams.md +90 -149
  36. package/tooling/add.py +804 -14
  37. package/tooling/templates/TASK.fast.md.tmpl +72 -0
  38. package/tooling/templates/TASK.md.tmpl +1 -1
package/CHANGELOG.md CHANGED
@@ -4,6 +4,115 @@ All notable changes to the ADD method (`@pilotspace/add` on npm,
4
4
  `pilotspace-add` on PyPI) are documented here. The format follows
5
5
  [Keep a Changelog](https://keepachangelog.com/); versions follow semver.
6
6
 
7
+ ## [Unreleased]
8
+
9
+ ## [1.10.0] — 2026-06-25
10
+
11
+ Component-aware major — ADD now models every codebase as a **graph of components**,
12
+ each owning a source root, its own green bar, and the contracts it produces or
13
+ consumes, so **one milestone can ship a vertical slice across components** in a
14
+ monorepo or across repos. Bundles the closed `component-aware-add` major plus the
15
+ `docs-site` (the book as a live MkDocs site) and `loop-steering` milestones, and the
16
+ ccsk `--rule-file` mode. Every new gate is **opt-in or grandfathered** — a project
17
+ that declares no components is byte-identical to 1.9.0.
18
+
19
+ ### Added
20
+ - **Component registry (`component-aware-add`)** — declare parts of a multi-part
21
+ codebase in `.add/components.toml` under `[component.<name>]` (a `root` + a
22
+ `green-bar`). A task binds to one with a `component:` header line, which anchors its
23
+ §5 Scope to that component's root. Declared, never inferred; zero components ⇒
24
+ byte-identical to today.
25
+ - **Per-component verify** — a bound task is held to ITS component's green-bar at the
26
+ verify gate (the cite-gate refuses `component_green_bar_uncited`), so two tasks in
27
+ one milestone can pass on two different toolchains (e.g. `pytest` and `vitest`). The
28
+ engine still never runs a suite — the AI runs it, the gate checks the right bar was
29
+ cited.
30
+ - **Cross-component contracts (`produces:` / `consumes:`)** — declare `[contract.<id>]`
31
+ (producer + consumers). A producer's §3 freeze writes an immutable snapshot at
32
+ `.add/contracts/<id>.json`; a consumer pins its hash; a changed re-freeze flags every
33
+ consumer stale. A missing/malformed snapshot HARD-STOPS — never build against a
34
+ guessed shape.
35
+ - **One milestone, full-stack slice** — a `consumes:` task is HELD from entering §3
36
+ (`producer_contract_unfrozen`) until its producer's contract is frozen, so a BE→FE
37
+ vertical slice ships in one milestone, ordered by the frozen contract.
38
+ - **Multi-repo federation (`add.py federate pull <id>`)** — a consumer repo declares
39
+ `[federation.<id>]` (a `source` path + optional `pin`) and pulls a byte-for-byte copy
40
+ of a producer repo's published snapshot into its local `.add/contracts/`, where the
41
+ rest of ADD treats mono- and multi-repo identically. Fail-loud: unknown id /
42
+ unreadable source / invalid snapshot / version mismatch each HARD-STOPS and lands
43
+ nothing.
44
+ - **Component pillar docs** — a new book chapter `17 · Components`, a skill guide
45
+ (`components.md`), and glossary terms (Component · Cross-component contract ·
46
+ Federation) teach the whole loop.
47
+ - **The book as a live site (`docs-site`)** — the AIDD book ships to GitHub Pages as a
48
+ MkDocs-Material site (`mkdocs.yml` + `requirements-docs.txt`, build-time only — the
49
+ published packages stay zero-dependency); `mkdocs build --strict` fails the deploy on
50
+ a broken intra-book link.
51
+ - **Rule-file mode for ccsk projects (`--rule-file`)** — when a project keeps its
52
+ workflow rules under `.claude/rules/` (the ccsk convention, detected by a `.ccsk/`
53
+ dir), ADD relocates CLAUDE.md's block to `.claude/rules/add-workflows.md` and leaves a
54
+ single reference bullet, instead of inlining. Triggers three ways (the explicit
55
+ `--rule-file` flag, a `.ccsk/` directory, or a rule file already present),
56
+ **CLAUDE-only**, migrates a prior inline block out (`.bak` on change), idempotent and
57
+ fail-soft. Mirrored across all three installers (engine `add.py`, pip `_installer.py`,
58
+ npm `cli.js`).
59
+
60
+ ### Changed
61
+ - **Guided dynamic loop (`loop-steering`)** — `status` and `guide` now STEER into the
62
+ build→verify loop at the loop juncture rather than only reporting it, so an agent is
63
+ pointed at the next loop step instead of having to infer it.
64
+
65
+ ### Compatibility
66
+ - Python 3.11+ is required to USE the component pillar (it parses `components.toml` with
67
+ the stdlib `tomllib`); on 3.10 the engine runs unchanged but a declared
68
+ `components.toml` fails loud (`components_malformed`). The published packages remain
69
+ zero-dependency.
70
+
71
+ ## [1.9.0] — 2026-06-24
72
+
73
+ Lean-pass major — make ADD's own surface (skill · flow · engine) the most-effective
74
+ prompt at optimized token cost, *not* token-golf. Bundles four closed milestones:
75
+ `skill-effectiveness` (M1), `flow-simplification` (M3), `flow-enforcement` (M4), and
76
+ the `fast-lane` sub-milestone. The skill tree routes identically but loads lighter;
77
+ the method's three fill-seams are now engine-enforced rather than convention; and a
78
+ new opt-in **fast lane** collapses ceremony for small tasks without lowering the trust
79
+ floor. Every new gate is opt-in or grandfathered — existing flows are byte-unchanged.
80
+
81
+ ### Added
82
+ - **Fast lane (`fast-lane`)** — `add.py new-task <slug> --fast` runs a small task
83
+ through a minimal `TASK.fast.md` (sections {0,1,3,4,5,6}) that still freezes a
84
+ contract, proves a red→green, and reads back cold in a later session. The lane is
85
+ *collapse-never-skip*: a `--fast` task is freeze-gated under ANY milestone (the floor
86
+ fires on `_optin OR fast`). Human-triggered only — the engine never auto-classifies a
87
+ task as "small". New `phases/fast-lane.md` guide + a SKILL.md quick-ref document it.
88
+ - **Freeze-before-build gate (`fast-lane`)** — crossing tests→build now refuses
89
+ `contract_not_frozen` when §3 is still DRAFT and the task is opted-in or fast, closing
90
+ the gap where a task could reach `gate=PASS` without an approved, frozen contract.
91
+ - **Contract-fill + build-expectations gates (opt-in, `flow-enforcement`)** — under
92
+ `new-milestone --await-confirm`, the engine HOLDS a task whose §3 CONTRACT or §6
93
+ Build-expectations block is still a placeholder, so the method's fill-seams are
94
+ enforced rather than trusted. `await_confirm` is the master switch; without it no key
95
+ is written → grandfathered → byte-unchanged.
96
+ - **Gate-record write-back (`flow-enforcement`)** — recording a verify gate now stamps
97
+ the verdict into the §6 GATE RECORD of the TASK.md for ALL tasks (grandfathered
98
+ backfill), so the file itself carries the outcome the Seam audit reads.
99
+ - **Confirm-parent gate (opt-in, `flow-simplification`)** — `new-milestone <slug>
100
+ --await-confirm` seeds the milestone *unconfirmed*, so `new-task` is HELD (reject
101
+ `milestone_unconfirmed`) until you show the filled `MILESTONE.md`, get the human's go,
102
+ and run the new `add.py milestone-confirm <slug>`. Closes the gap where the AI would
103
+ detail a task's §0–§5 before the human had agreed the parent milestone. Mirrors
104
+ `init --await-lock` one level down.
105
+
106
+ ### Changed
107
+ - **Skill tree 25% lighter (`skill-effectiveness`)** — the on-demand skill guides were
108
+ compacted tree-wide (164,333 → ~123,000 bytes) with zero routing, gate, reject-code,
109
+ threshold, or rule lost; an independent adversarial review confirmed every operative
110
+ element preserved (it flagged 6 dropped nuances → all restored). Same flow an agent
111
+ reads, fewer tokens to load.
112
+ - **One home for the worker-spawn model tiers (`spawn-fold`)** — the tier→model mapping
113
+ (mid→sonnet / top→opus) now lives only in `streams.md`; `advisor.md` points at it
114
+ instead of copying. Advisor keeps its own advisory template.
115
+
7
116
  ## [1.8.0] — 2026-06-23
8
117
 
9
118
  Team collaboration: ADD becomes git-native and multi-user, with N
package/bin/cli.js CHANGED
@@ -39,7 +39,7 @@ function parseArgs(argv) {
39
39
  // defaults the stage and infers the name from the folder, so the manual-init
40
40
  // hint only echoes flags the user actually chose (shortest true command).
41
41
  const args = { _: [], force: false, check: false, noSkill: false, stage: null, name: null,
42
- yes: false, nonInteractive: false, global: false, globalData: false };
42
+ yes: false, nonInteractive: false, global: false, globalData: false, ruleFile: false };
43
43
  for (let i = 0; i < argv.length; i++) {
44
44
  const a = argv[i];
45
45
  if (a === "--force") args.force = true;
@@ -58,6 +58,9 @@ function parseArgs(argv) {
58
58
  // already provides the `add` skill, so a plugin bootstrap uses this to materialize
59
59
  // .add/tooling/ + .add/docs/ into the project without a duplicate .claude/skills/add.
60
60
  else if (a === "--no-skill") args.noSkill = true;
61
+ // --rule-file: write the ADD block to .claude/rules/add-workflows.md + reference it from
62
+ // CLAUDE.md instead of inlining (auto-on for ccsk projects with a .ccsk/ dir).
63
+ else if (a === "--rule-file") args.ruleFile = true;
61
64
  else if (a === "--stage" || a === "--name") {
62
65
  const v = argv[++i];
63
66
  // fail loudly on a trailing/abutting flag — never silently drop a value
@@ -249,6 +252,126 @@ function writeAgentPointer(target, profile) {
249
252
  }
250
253
  }
251
254
 
255
+ // --- rule-file mode: ccsk-style relocation of the CLAUDE.md block ---------------------
256
+ // Mirror of add.py / _installer.py rule-file logic (twins by duplication). For ccsk projects
257
+ // (.ccsk/ dir) or an explicit --rule-file, the ADD pointer goes to .claude/rules/add-workflows.md
258
+ // and CLAUDE.md keeps only a reference bullet. CLAUDE-only — AGENTS.md/.clinerules stay inline.
259
+ const RULES_FILE_REL = path.join(".claude", "rules", "add-workflows.md");
260
+ const WORKFLOW_HEADINGS = ["Rules & Workflows", "Workflows", "Rules"];
261
+ const RULE_REF_LINE = "- ADD (AI-Driven Development) Workflows rules: ./.claude/rules/add-workflows.md";
262
+
263
+ // True when the ADD block belongs in .claude/rules/add-workflows.md instead of inline.
264
+ // Re-derived from disk: explicit flag, a ccsk project (.ccsk/), or a rule file already present.
265
+ function ruleFileMode(root, flag) {
266
+ if (flag) return true;
267
+ try {
268
+ if (fs.existsSync(path.join(root, ".ccsk")) &&
269
+ fs.statSync(path.join(root, ".ccsk")).isDirectory()) return true;
270
+ if (fs.existsSync(path.join(root, RULES_FILE_REL))) return true;
271
+ } catch (_e) { /* fail-soft */ }
272
+ return false;
273
+ }
274
+
275
+ // Remove an inline ADD:BEGIN..END region (migration), collapsing the gap. An unterminated
276
+ // BEGIN is left as-is rather than eating the rest of the file.
277
+ function stripInlineBlock(text) {
278
+ const begin = text.indexOf(GUIDE_BEGIN);
279
+ if (begin === -1) return text;
280
+ let end = text.indexOf(GUIDE_END, begin);
281
+ if (end === -1) return text;
282
+ end += GUIDE_END.length;
283
+ const head = text.slice(0, begin).replace(/\n+$/, "");
284
+ const tail = text.slice(end).replace(/^\n+/, "");
285
+ if (head && tail) return head + "\n\n" + tail;
286
+ return head || tail;
287
+ }
288
+
289
+ // Insert the ADD rule-file bullet under an existing Workflows/Rules heading, or append a fresh
290
+ // '## Workflows' section. Caller guarantees the bullet is absent.
291
+ function insertRuleReference(text) {
292
+ const lines = text.split("\n");
293
+ let headingIdx = -1;
294
+ for (let i = 0; i < lines.length; i++) {
295
+ const m = lines[i].match(/^(#{1,6})\s+(.*?)\s*$/);
296
+ if (m && WORKFLOW_HEADINGS.some((h) => m[2].trim().toLowerCase() === h.toLowerCase())) {
297
+ headingIdx = i;
298
+ break;
299
+ }
300
+ }
301
+ if (headingIdx === -1) {
302
+ const body = text.replace(/\n+$/, "");
303
+ const sep = body ? "\n\n" : "";
304
+ return body + sep + "## Workflows\n\n" + RULE_REF_LINE + "\n";
305
+ }
306
+ const level = lines[headingIdx].match(/^(#{1,6})/)[1].length;
307
+ let end = lines.length;
308
+ for (let j = headingIdx + 1; j < lines.length; j++) {
309
+ const m = lines[j].match(/^(#{1,6})\s+/);
310
+ if (m && m[1].length <= level) { end = j; break; }
311
+ }
312
+ let insertAt = headingIdx + 1;
313
+ for (let j = headingIdx + 1; j < end; j++) {
314
+ if (lines[j].trim()) insertAt = j + 1;
315
+ }
316
+ lines.splice(insertAt, 0, RULE_REF_LINE);
317
+ return lines.join("\n");
318
+ }
319
+
320
+ // Make CLAUDE.md reference the ADD rule file under a Workflows/Rules heading, migrating any prior
321
+ // inline ADD block out. created|updated|unchanged|skipped; .bak on change; fail-soft.
322
+ function ensureClaudeReference(claudeMd) {
323
+ try {
324
+ const existed = fs.existsSync(claudeMd);
325
+ const current = existed ? fs.readFileSync(claudeMd, "utf8") : "";
326
+ let next = stripInlineBlock(current);
327
+ if (next.indexOf("add-workflows.md") === -1) next = insertRuleReference(next);
328
+ if (!next.endsWith("\n")) next += "\n";
329
+ if (next === current) return "unchanged";
330
+ if (existed) fs.writeFileSync(claudeMd + ".bak", current);
331
+ fs.writeFileSync(claudeMd, next);
332
+ return existed ? "updated" : "created";
333
+ } catch (e) {
334
+ warn("could not write CLAUDE.md — " + (e && e.message ? e.message : e) + "; skipped");
335
+ return "skipped";
336
+ }
337
+ }
338
+
339
+ // Rule-file variant of writeAgentPointer for the Claude profile: write the ADD pointer block to
340
+ // .claude/rules/add-workflows.md and leave a reference in CLAUDE.md. Fail-soft.
341
+ function writeRuleFilePointer(target, profile) {
342
+ const rulesPath = path.join(target, RULES_FILE_REL);
343
+ const block = agentPointerBlock(profile);
344
+ try {
345
+ if (fs.existsSync(rulesPath)) {
346
+ const current = fs.readFileSync(rulesPath, "utf8");
347
+ const begin = current.indexOf(GUIDE_BEGIN);
348
+ let next;
349
+ if (begin !== -1) {
350
+ const endIdx = current.indexOf(GUIDE_END, begin);
351
+ if (endIdx !== -1) {
352
+ next = current.slice(0, begin) + block + current.slice(endIdx + GUIDE_END.length);
353
+ } else {
354
+ next = current.replace(/\n+$/, "") + "\n\n" + block + "\n";
355
+ }
356
+ } else {
357
+ next = current.replace(/\n+$/, "") + "\n\n" + block + "\n";
358
+ }
359
+ if (next !== current) {
360
+ fs.writeFileSync(rulesPath + ".bak", current);
361
+ fs.writeFileSync(rulesPath, next);
362
+ }
363
+ } else {
364
+ fs.mkdirSync(path.dirname(rulesPath), { recursive: true });
365
+ fs.writeFileSync(rulesPath, block + "\n");
366
+ }
367
+ } catch (e) {
368
+ warn("could not write " + RULES_FILE_REL + " — " + (e && e.message ? e.message : e) + "; skipped");
369
+ return "skipped";
370
+ }
371
+ ensureClaudeReference(path.join(target, "CLAUDE.md"));
372
+ return "ok";
373
+ }
374
+
252
375
  // --- interactive layer (clack on a real TTY; plain text everywhere else) -----
253
376
  // Designed-for-failure: any doubt (non-TTY, CI, --yes, a failed import, an
254
377
  // un-promptable stream) degrades to the EXACT plain-text path below. The clack
@@ -450,7 +573,16 @@ function dropFiles(args, target, profile, intent) {
450
573
  // Agent detection: write THE detected agent's integration file (a marker-delimited
451
574
  // pointer init's sync-guidelines later supersedes) + tailor the closing next-step.
452
575
  // Best-effort + fail-soft — never aborts the successful drop above.
453
- writeAgentPointer(target, profile);
576
+ // Rule-file mode (ccsk projects / --rule-file) relocates the CLAUDE.md pointer to
577
+ // .claude/rules/add-workflows.md + a reference — CLAUDE-only; other agents stay inline.
578
+ if (profile.integration_file === "CLAUDE.md" && ruleFileMode(target, args.ruleFile)) {
579
+ if (fs.existsSync(path.join(target, ".ccsk"))) {
580
+ log(" ccsk detected — ADD rules go to .claude/rules/add-workflows.md");
581
+ }
582
+ writeRuleFilePointer(target, profile);
583
+ } else {
584
+ writeAgentPointer(target, profile);
585
+ }
454
586
 
455
587
  // Gemini CLI auto-loads GEMINI.md, not AGENTS.md — so for the gemini profile we ALSO merge
456
588
  // .gemini/settings.json (context.fileName) to load the AGENTS.md pointer. Fail-soft + idempotent.
@@ -847,4 +979,7 @@ module.exports = {
847
979
  scopeOptions: scopeOptions,
848
980
  writeIntentNote: writeIntentNote,
849
981
  writeGeminiSettings: writeGeminiSettings,
982
+ ruleFileMode: ruleFileMode,
983
+ ensureClaudeReference: ensureClaudeReference,
984
+ writeRuleFilePointer: writeRuleFilePointer,
850
985
  };
@@ -1,6 +1,6 @@
1
1
  # 16 · Releasing
2
2
 
3
- [← 15 Foundations & Lineage](./15-foundations-and-lineage.md) · [Contents](./README.md) · Next: [Appendix A Templates →](./appendix-a-templates.md)
3
+ [← 15 Foundations & Lineage](./15-foundations-and-lineage.md) · [Contents](./README.md) · Next: [17 Components →](./17-components.md)
4
4
 
5
5
  ---
6
6
 
@@ -179,4 +179,4 @@ the risk, record the marker, and let a person make the outward call.
179
179
 
180
180
  ---
181
181
 
182
- [← 15 Foundations & Lineage](./15-foundations-and-lineage.md) · [Contents](./README.md) · Next: [Appendix A Templates →](./appendix-a-templates.md)
182
+ [← 15 Foundations & Lineage](./15-foundations-and-lineage.md) · [Contents](./README.md) · Next: [17 Components →](./17-components.md)
@@ -0,0 +1,125 @@
1
+ # 17 · Components — monorepo and multi-repo
2
+
3
+ [← 16 Releasing](./16-releasing.md) · [Contents](./README.md) · Next: [Appendix A Templates →](./appendix-a-templates.md)
4
+
5
+ ---
6
+
7
+ Most of this book treats a project as one codebase with one green bar. Real
8
+ systems are rarely that tidy: a backend and a frontend, a shared library and two
9
+ apps, or three services across three repos. ADD models all of these the same
10
+ way — as a **graph of components**. A component owns a source root, its own
11
+ green bar, and the contracts it produces or consumes. With that, **one milestone
12
+ can ship a vertical slice across components** — a backend endpoint and the
13
+ frontend that calls it — instead of splitting the slice across milestones.
14
+
15
+ This pillar is **opt-in and additive**: a project that declares no components
16
+ behaves exactly as the rest of the book describes. You reach for it only when a
17
+ milestone genuinely spans more than one green bar.
18
+
19
+ ## Declare the components
20
+
21
+ Components are **declared, never inferred** — ADD does not scan `apps/*` and
22
+ guess. You name them in `.add/components.toml`:
23
+
24
+ ```toml
25
+ [component.gateway]
26
+ root = "apps/gateway"
27
+ green-bar = "pytest + pyright"
28
+
29
+ [component.dashboard]
30
+ root = "apps/web"
31
+ green-bar = "vitest + a11y"
32
+ ```
33
+
34
+ Each component owns a **root** (the source subtree it governs) and a
35
+ **green-bar** (the suite + checks that prove *that* component healthy). A task
36
+ binds to a component with a `component:` header line; the component's root is
37
+ then added to the task's §5 Scope automatically. A project with no
38
+ `components.toml`, or a task with no `component:` line, is byte-identical to a
39
+ single-component project.
40
+
41
+ ## Verify each task against its own green bar
42
+
43
+ In a mixed milestone, a backend task and a frontend task pass on **different
44
+ toolchains**. The verify gate enforces this per component: a task bound to
45
+ `gateway` must cite its component's green-bar (`pytest + pyright`) in the §6
46
+ Build-expectations evidence, or the gate refuses `component_green_bar_uncited`.
47
+ The engine never *runs* the suite — that invariant holds here too. The AI runs
48
+ the right suite for the bound component; the gate checks the **right bar was
49
+ cited** in the evidence. Two tasks, one milestone, two green bars — each held to
50
+ its own.
51
+
52
+ ## Freeze a contract between components
53
+
54
+ When one component produces an interface another consumes, that boundary needs a
55
+ **frozen, machine-checkable contract**. Declare it, name its producer and
56
+ consumers:
57
+
58
+ ```toml
59
+ [contract.gateway-api]
60
+ producer = "gateway"
61
+ consumers = ["dashboard"]
62
+ ```
63
+
64
+ A task declares its role with a header line — `produces: gateway-api` or
65
+ `consumes: gateway-api`. When the **producer** task freezes its §3 and crosses
66
+ contract→tests, the engine writes an immutable snapshot at
67
+ `.add/contracts/gateway-api.json` (id, producer, version, frozen date, and a
68
+ hash over the frozen §3 shape). When a **consumer** task crosses contract→tests,
69
+ it **pins** that live hash. If the producer later re-freezes a *changed* shape,
70
+ `add.py check` flags every consumer `contract_consumer_stale` — a §7 delta to
71
+ re-pin against the new shape. A missing or malformed snapshot is a HARD-STOP, not
72
+ a guess: the consumer never builds against a shape that was never frozen.
73
+
74
+ ## One milestone, a full-stack slice
75
+
76
+ The reason to put a producer and a consumer in the *same* milestone is to ship a
77
+ vertical slice — but the frontend must not commit to an endpoint the backend has
78
+ not frozen yet. ADD enforces that ordering with a **hold**: a `consumes:` task
79
+ cannot advance scenarios→contract (it cannot write its §3) while its producer's
80
+ snapshot does not yet exist. The engine refuses `producer_contract_unfrozen` and
81
+ the task stays at `scenarios`. Once the backend freezes its contract, the
82
+ frontend proceeds and pins it. The slice is **ordered by the frozen contract**,
83
+ all inside one milestone — the FE stays downstream of the BE endpoint, not split
84
+ into a later milestone.
85
+
86
+ ## Across repositories: federation
87
+
88
+ Components in separate repositories work the same way; only the
89
+ **snapshot transport** differs. A consumer repo declares where a producer repo
90
+ publishes its frozen contract:
91
+
92
+ ```toml
93
+ [federation.gateway-api]
94
+ source = "../gateway/.add/contracts/gateway-api.json"
95
+ pin = "v1" # optional — the version this repo expects
96
+ ```
97
+
98
+ `add.py federate pull gateway-api` reads that source, validates it (valid JSON,
99
+ matching id, a hash, and — if `pin` is set — a matching version), and lands a
100
+ **byte-for-byte copy** at the local `.add/contracts/gateway-api.json`. From
101
+ there, the consuming repo's task holds and pins exactly as in a monorepo. The
102
+ pull is **fail-loud by design**: an unknown id, an unreadable source, an invalid
103
+ snapshot, or a version mismatch each HARD-STOPS and lands nothing — federation
104
+ never builds an FE against a guessed or stale endpoint. The producer's snapshot
105
+ is the published artifact; "publishing" is committing that file in the producer
106
+ repo. Each repo keeps its own git-native `state.json`; federation transports only
107
+ the immutable frozen shape, never shared mutable state.
108
+
109
+ ## What this pillar is not
110
+
111
+ - **Not auto-discovery.** Components are declared in `components.toml`, not
112
+ inferred from the directory tree.
113
+ - **Not a central server.** Federation copies an immutable snapshot between
114
+ repos; there is no shared service and no shared mutable state.
115
+ - **Not a new approval.** The component machinery rides the existing six-step
116
+ flow and its single contract-freeze approval — it adds gates the engine
117
+ enforces, not human checkpoints.
118
+
119
+ The whole pillar is structure, not policy: who *owns* a component and how
120
+ autonomy is set per component is the identity/governance story (chapters 11–12),
121
+ layered on top of this graph.
122
+
123
+ ---
124
+
125
+ [← 16 Releasing](./16-releasing.md) · [Contents](./README.md) · Next: [Appendix A Templates →](./appendix-a-templates.md)
@@ -16,12 +16,20 @@
16
16
 
17
17
  **Co-specification** — how a spec is made in ADD: the AI and the human **brainstorm the shape together** (diverge), the AI **drafts** it, and the human **validates with the AI's advice** (validate). The AI's decisive advice is the *lowest-confidence flag*. It replaces dictation-by-one-side — the human owns the decision, the AI owns surfacing what it does not yet know. See [03 Specify](./03-step-1-specify.md).
18
18
 
19
+ **Component** — a declared part of a multi-part codebase that owns a source `root` and its own `green-bar` (suite + checks), named in `.add/components.toml` under `[component.<name>]`. A task binds to one with a `component:` header line, which adds that root to its §5 Scope and holds it to that component's green bar at verify. Declared, never inferred; a project with no components is byte-identical to a single-codebase project. See [17 Components](./17-components.md).
20
+
21
+ **Cross-component contract** — the frozen, machine-checkable interface between a producer component and its consumers, declared under `[contract.<id>]` (producer + consumers). A task names its role with a `produces: <id>` or `consumes: <id>` header. On the producer's freeze the engine writes an immutable snapshot at `.add/contracts/<id>.json`; a consumer pins its hash and is flagged `contract_consumer_stale` if the producer later re-freezes a changed shape. Inside one milestone a `consumes:` task is HELD from writing its §3 until the producer's snapshot exists — the intra-milestone BE→FE ordering. See [17 Components](./17-components.md).
22
+
23
+ **Federation (multi-repo)** — the transport that carries a frozen cross-component contract between separate repositories. A consumer repo declares `[federation.<id>]` with a `source` (and optional `pin`); `add.py federate pull <id>` validates the producer repo's published snapshot and lands a byte-for-byte copy locally, where it behaves exactly as in a monorepo. Fail-loud: an unknown id, unreadable source, invalid snapshot, or version mismatch HARD-STOPS and lands nothing. Each repo keeps its own git-native `state.json`; only the immutable snapshot crosses. See [17 Components](./17-components.md).
24
+
19
25
  **Disposable code** — the view that code is one regenerable implementation of the artifacts, not a durable asset to be preserved.
20
26
 
21
27
  **Evidence bundle** — the proof attached to a change (passing tests, clean security scan, no coverage loss) that justifies trusting it and may unlock more AI autonomy.
22
28
 
23
29
  **Foundation version** — a monotonic integer marker in `PROJECT.md` that advances by one each time confirmed lessons learned are consolidated into the foundation. It makes the living documentation's evolution auditable: a rising version with fewer new deltas per milestone is the signal that a competency is converging rather than drifting. Bumped only by the retrospective consolidation (see the `add` skill's `fold.md`).
24
30
 
31
+ **Fast lane** — the collapsed, opt-in task path for small, low-risk work. `add.py new-task <slug> --fast` scaffolds a minimal `TASK.fast.md` (sections {0,1,3,4,5,6}; scenarios and observe dropped) and the specification bundle is approved in one freeze. It runs the SAME flow with fewer sections — it never drops the trust floor: a `--fast` task is held to a frozen contract, a red test before build, and a recorded verify gate under any milestone. Collapse, never skip; the human opts in (the engine never auto-classifies a task as small). See the `add` skill's `phases/fast-lane.md`.
32
+
25
33
  **Gate** — a checkpoint with an explicit pass/fail exit. Its outcome is `PASS`, `RISK-ACCEPTED`, or `HARD-STOP`.
26
34
 
27
35
  **Ground (phase-0 preamble)** — the per-task phase *before* Specify in which the AI gathers the real current codebase the task touches — files, symbols, signatures, patterns, conventions — into a lean **grounding map**, surfacing the **anchors** the frozen contract will cite. It is AI-owned and adds no approval (the one approval stays at the contract freeze); it precedes the seven steps as step 0 so the contract, tests, and build are grounded in the code as it actually is, not in assumption. Lives in the `add` skill's `phases/0-ground.md`.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pilotspace/add",
3
- "version": "1.8.0",
3
+ "version": "1.10.0",
4
4
  "description": "ADD (AI-Driven Development). One skill. Eight steps. Five disciplines. Every feature ships through the loop — a minimal, state-tracked Claude Code skill that ships the AIDD book as its trust layer.",
5
5
  "bin": {
6
6
  "add": "bin/cli.js"
@@ -46,7 +46,7 @@
46
46
  "type": "git",
47
47
  "url": "git+https://github.com/pilotspace/ADD.git"
48
48
  },
49
- "homepage": "https://github.com/pilotspace/ADD#readme",
49
+ "homepage": "https://pilotspace.github.io/ADD/",
50
50
  "bugs": {
51
51
  "url": "https://github.com/pilotspace/ADD/issues"
52
52
  }