@pilotspace/add 1.17.0 → 2.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 (114) hide show
  1. package/CHANGELOG.md +144 -0
  2. package/GETTING-STARTED.md +20 -64
  3. package/README.md +128 -56
  4. package/agents/add.md +68 -0
  5. package/bin/cli.js +86 -21
  6. package/package.json +2 -3
  7. package/personas-teacher/VENDOR.md +6 -0
  8. package/skill/add/SKILL.md +100 -134
  9. package/skill/add/adopt.md +28 -0
  10. package/skill/add/beyond.md +36 -0
  11. package/skill/add/deltas.md +25 -2
  12. package/skill/add/design.md +56 -74
  13. package/skill/add/{report-template.md → gate-udd.md} +28 -38
  14. package/skill/add/intake.md +56 -25
  15. package/skill/add/loop.md +32 -19
  16. package/skill/add/phases/build.md +78 -0
  17. package/skill/add/phases/direction.md +280 -0
  18. package/skill/add/phases/verify.md +160 -0
  19. package/skill/add/run.md +11 -18
  20. package/skill/add/terms.md +18 -0
  21. package/tooling/add.py +2383 -3261
  22. package/tooling/add_engine/autonomy.py +2 -37
  23. package/tooling/add_engine/components.py +4 -87
  24. package/tooling/add_engine/constants.py +145 -91
  25. package/tooling/add_engine/guidelines.py +9 -11
  26. package/tooling/add_engine/io_state.py +69 -2
  27. package/tooling/add_engine/predicates.py +90 -2
  28. package/tooling/add_engine/search.py +6 -6
  29. package/tooling/add_engine/taskdoc.py +15 -10
  30. package/tooling/templates/CONVENTIONS.md.tmpl +1 -1
  31. package/tooling/templates/GLOSSARY.md.tmpl +10 -4
  32. package/tooling/templates/MILESTONE.md.tmpl +20 -16
  33. package/tooling/templates/PLAN.md.tmpl +128 -0
  34. package/tooling/templates/PROJECT.md.tmpl +6 -1
  35. package/tooling/templates/PROMPT.persona.md.tmpl +17 -21
  36. package/tooling/templates/personas/_template.md.tmpl +33 -29
  37. package/tooling/templates/personas/build-engineer.md.tmpl +45 -0
  38. package/tooling/templates/personas/data-steward.md.tmpl +45 -0
  39. package/tooling/templates/personas/evidence-verifier.md.tmpl +45 -0
  40. package/tooling/templates/personas/platform-engineer.md.tmpl +45 -0
  41. package/tooling/templates/personas/product-lead.md.tmpl +51 -0
  42. package/tooling/templates/personas/quality-auditor.md.tmpl +47 -0
  43. package/tooling/templates/personas/release-manager.md.tmpl +52 -0
  44. package/tooling/templates/personas/security-gatekeeper.md.tmpl +45 -0
  45. package/tooling/templates/personas/software-architect.md.tmpl +45 -0
  46. package/tooling/templates/personas/stream-orchestrator.md.tmpl +44 -0
  47. package/tooling/templates/personas/technical-writer.md.tmpl +49 -0
  48. package/tooling/templates/personas/ux-experience-lead.md.tmpl +48 -0
  49. package/tooling/templates/specs/SPEC.md.tmpl +18 -0
  50. package/tooling/templates/udd-wireframe.md +1 -1
  51. package/agents/add-advisor.md +0 -31
  52. package/agents/add-build.md +0 -29
  53. package/agents/add-design.md +0 -32
  54. package/agents/add-persona.md +0 -33
  55. package/agents/add-verify.md +0 -36
  56. package/docs/00-introduction.md +0 -46
  57. package/docs/01-principles.md +0 -71
  58. package/docs/02-the-flow.md +0 -113
  59. package/docs/03-step-1-specify.md +0 -123
  60. package/docs/04-step-2-scenarios.md +0 -90
  61. package/docs/05-step-3-contract.md +0 -80
  62. package/docs/06-step-4-tests.md +0 -85
  63. package/docs/07-step-5-build.md +0 -82
  64. package/docs/08-step-6-verify.md +0 -105
  65. package/docs/09-the-loop.md +0 -75
  66. package/docs/10-setup-and-stages.md +0 -118
  67. package/docs/11-governance.md +0 -91
  68. package/docs/12-roles.md +0 -99
  69. package/docs/13-adoption.md +0 -67
  70. package/docs/14-foundation.md +0 -142
  71. package/docs/15-foundations-and-lineage.md +0 -106
  72. package/docs/16-releasing.md +0 -182
  73. package/docs/17-components.md +0 -143
  74. package/docs/18-personas.md +0 -80
  75. package/docs/README.md +0 -77
  76. package/docs/add-competencies.png +0 -0
  77. package/docs/add-flow.png +0 -0
  78. package/docs/add-foundation.png +0 -0
  79. package/docs/add-hierarchy.png +0 -0
  80. package/docs/add-milestone-task-lifecycle.png +0 -0
  81. package/docs/add-task-growth-wheel.png +0 -0
  82. package/docs/appendix-a-templates.md +0 -88
  83. package/docs/appendix-b-prompts.md +0 -154
  84. package/docs/appendix-c-glossary.md +0 -176
  85. package/docs/appendix-d-worked-example.md +0 -231
  86. package/docs/appendix-e-checklists.md +0 -92
  87. package/docs/appendix-f-requirements-matrix.md +0 -171
  88. package/docs/appendix-g-references.md +0 -106
  89. package/skill/add/advisor.md +0 -81
  90. package/skill/add/compact-foundation.md +0 -40
  91. package/skill/add/components.md +0 -52
  92. package/skill/add/confidence.md +0 -32
  93. package/skill/add/fold.md +0 -63
  94. package/skill/add/graduate.md +0 -39
  95. package/skill/add/phases/0-ground.md +0 -64
  96. package/skill/add/phases/0-setup.md +0 -103
  97. package/skill/add/phases/1-specify.md +0 -61
  98. package/skill/add/phases/2-scenarios.md +0 -48
  99. package/skill/add/phases/3-contract.md +0 -60
  100. package/skill/add/phases/4-tests.md +0 -61
  101. package/skill/add/phases/5-build.md +0 -62
  102. package/skill/add/phases/6-verify.md +0 -69
  103. package/skill/add/phases/7-observe.md +0 -45
  104. package/skill/add/phases/fast-lane.md +0 -34
  105. package/skill/add/release.md +0 -61
  106. package/skill/add/scope.md +0 -72
  107. package/skill/add/self-improve.md +0 -20
  108. package/skill/add/sensitivity.md +0 -51
  109. package/skill/add/setup-review.md +0 -48
  110. package/skill/add/soul.md +0 -58
  111. package/skill/add/streams.md +0 -269
  112. package/tooling/add_engine/release.py +0 -86
  113. package/tooling/templates/TASK.fast.md.tmpl +0 -78
  114. package/tooling/templates/TASK.md.tmpl +0 -181
package/agents/add.md ADDED
@@ -0,0 +1,68 @@
1
+ ---
2
+ name: add
3
+ description: The ADD specialist — ONE execution shell for every beat of the loop. The spawn prompt names the beat (direction · build · verify) or a service mode (advise · persona); the agent loads that beat's phase guide plus the best-fit persona and becomes the specialist. Personas carry the expertise; this agent carries the discipline. Recommended tier — top for direction/verify/advise, mid for build.
4
+ model: inherit
5
+ color: cyan
6
+ ---
7
+
8
+ You are the **ADD specialist** — the one execution shell of the roster. Your spawn
9
+ prompt names a MODE; everything else about who you are comes from the persona you
10
+ load. Personas are the method's core value: they carry the domain expertise, the
11
+ critical rules, and the measurable done-bar. You carry the loop discipline that
12
+ never changes.
13
+
14
+ ## 1 · Resolve your mode (from the spawn prompt)
15
+ - **direction** — draft the whole direction bundle (setup on a fresh project ·
16
+ ground · rules · scenarios · contract · scope · red-suite intent) up to, never
17
+ past, the ONE human freeze. Guide: `phases/direction.md`.
18
+ - **build** — turn the frozen contract + scenarios into a red suite, then drive
19
+ it green honestly. Guide: `phases/build.md`.
20
+ - **verify** — evidence · 3 lenses (security → concurrency → architecture) ·
21
+ earned-green refute-read · one outcome · observe/delta drafting. Guide:
22
+ `phases/verify.md`.
23
+ - **advise** — a consultative second opinion on a named decision: recommendation
24
+ + tradeoffs weighed + confidence. No guide; you advise, never decide.
25
+ - **persona** — select the best-fit existing persona for a described piece of
26
+ work, or DRAFT a new one from the seed templates when none fits (never
27
+ overwrite an existing persona file).
28
+
29
+ Read YOUR mode's guide from the project's skill tree (`.claude/skills/add/phases/`)
30
+ at spawn — the orchestrator reads only SKILL.md and does not pre-read it for you.
31
+
32
+ ## 2 · Become the persona (FIRST — before any task-specific instruction)
33
+ Select from `.add/personas/` by frontmatter alone (name · vibe · flow ·
34
+ task-kinds): prefer a persona whose `flow:` names your mode's surface
35
+ (direction→design · build→build · verify→verify · advise→advisor) AND whose
36
+ `task-kinds:` covers the task's declared `kind:`. In verify mode select a
37
+ `flow: verify` persona first, falling back to `flow: advisor` when none
38
+ declares verify. Read the body of the ONE you become. Its `## Critical Rules` are your constraints; its `## Success Metrics`
39
+ are your done-bar; tag findings with its severity convention (🔴 blocker ·
40
+ 🟡 concern · 💭 note). No persona matched? Use the generic fallback — a
41
+ 15-year specialist in the task's domain, correctness over speed; the fallback
42
+ never blocks and never lowers a gate.
43
+
44
+ ## 3 · Boundary (the irreducible floor — binds every mode, above any persona)
45
+ - MAY: read real code, run the suite, draft sections, propose scope/strategy/verdicts.
46
+ - MUST NOT: mark a freeze, gate, or lock on your own authority (human seams) ·
47
+ edit a frozen contract or locked scope · weaken, delete, or skip a test ·
48
+ touch files outside the declared Scope · add a dependency off the allow-list ·
49
+ invent a file or symbol you have not opened · resolve genuine ambiguity by guessing.
50
+ - STOP-and-escalate (return findings; never decide): any SECURITY finding is
51
+ always HARD-STOP · a needed test/contract change (a change request back to
52
+ Specify, never a silent edit) · residue the evidence cannot clear · an
53
+ ambiguity only the human can resolve.
54
+
55
+ ## 4 · Self-improve before you return
56
+ Any Strategy you received is a PREFERRED plan — improve on it and report what
57
+ you ACTUALLY did. Self-score the six confidence dimensions (Completeness ·
58
+ Clarity · Practicality · Optimization · Edge cases · Self-evaluation); below
59
+ 0.9 anywhere → refine before returning.
60
+
61
+ ## 5 · Return (disclose progress — the orchestrator parses this)
62
+ `{ mode, persona, kind, result, evidence|bundle|verdict, residue, deltas,
63
+ confidence: {per-dimension 0–1}, open_questions }`
64
+ You PROPOSE; the orchestrator RECORDS — never run the engine or write shared
65
+ state. A lesson about HOW an agent should behave → recommend tagging it
66
+ `persona:<slug>` so the fold grows that persona, not the shared pile.
67
+
68
+ Method depth: the AIDD book — read only when a decision is genuinely unclear.
package/bin/cli.js CHANGED
@@ -6,10 +6,9 @@
6
6
  *
7
7
  * npx @pilotspace/add init [targetDir] [--force] [--stage <stage>] [--name <name>] [--yes|--non-interactive]
8
8
  *
9
- * Installs the ADD skill + tooling + book into a target project:
9
+ * Installs the ADD skill + tooling into a target project:
10
10
  * <target>/.claude/skills/add/ (the skill Claude loads)
11
11
  * <target>/.add/tooling/ (add.py scaffolder + state tracker)
12
- * <target>/.add/docs/ (the AIDD book — the trust layer)
13
12
  * It DROPS FILES ONLY — it does NOT run `add.py init`. Initialisation is deferred to
14
13
  * the AI (via `/add`, which runs `init --await-lock` to arm the v12 lock-down gate) or
15
14
  * to a CLI user. A pre-run plain init would grandfather-lock the gate before `/add` runs
@@ -58,9 +57,9 @@ function parseArgs(argv) {
58
57
  // non-interactive selector the interactive() gate honors (CI/pipes do this too).
59
58
  else if (a === "--yes" || a === "-y") args.yes = true;
60
59
  else if (a === "--non-interactive") args.nonInteractive = true;
61
- // --no-skill: drop the engine + book ONLY, not the skill. The Claude Code plugin
60
+ // --no-skill: drop the engine ONLY, not the skill. The Claude Code plugin
62
61
  // already provides the `add` skill, so a plugin bootstrap uses this to materialize
63
- // .add/tooling/ + .add/docs/ into the project without a duplicate .claude/skills/add.
62
+ // .add/tooling/ into the project without a duplicate .claude/skills/add.
64
63
  else if (a === "--no-skill") args.noSkill = true;
65
64
  // --rule-file: write the ADD block to .claude/rules/add-workflows.md + reference it from
66
65
  // CLAUDE.md instead of inlining (auto-on for ccsk projects with a .ccsk/ dir).
@@ -217,7 +216,7 @@ function agentPointerBlock(profile) {
217
216
  GUIDE_BEGIN + "\n" +
218
217
  "## ADD — how to work in this repo\n" +
219
218
  "\n" +
220
- "This project uses **ADD (AI-Driven Development)**. The engine + book are installed.\n" +
219
+ "This project uses **ADD (AI-Driven Development)**. The engine is installed.\n" +
221
220
  "To begin: run `python3 .add/tooling/add.py status` (the resume point), read\n" +
222
221
  "`.add/PROJECT.md`, then `python3 .add/tooling/add.py guide` for the current phase.\n" +
223
222
  "\n" +
@@ -410,10 +409,11 @@ async function loadClack() {
410
409
  // --- brand + feature showcase (interactive path only; fail-soft) -------------
411
410
  // Wordmark + value line + the 7-step Specify->Observe loop, rendered BEFORE the first
412
411
  // prompt on the interactive path only — so the non-interactive byte stream is unchanged.
413
- // The 7 labels are the real ADD phases (grounded in the method, never invented). Fail-soft:
414
- // any draw error is swallowed so a banner can never abort the install. No color is emitted
415
- // (default accent: none); the glyphs / tagline / accent are a SWAPPABLE content slot.
416
- const BRAND_LOOP = ["Specify", "Scenarios", "Contract", "Tests", "Build", "Verify", "Observe"];
412
+ // The 7 labels are the real ADD phases (grounded in the method, never invented; grounding
413
+ // itself is folded into step 3, Plan, not a separate phase). Fail-soft: any draw error is
414
+ // swallowed so a banner can never abort the install. No color is emitted (default accent:
415
+ // none); the glyphs / tagline / accent are a SWAPPABLE content slot.
416
+ const BRAND_LOOP = ["Specify", "Plan", "Tests", "Build", "Verify"];
417
417
 
418
418
  function terminalCaps(env, stream) {
419
419
  const width = Number(env.COLUMNS) || (stream && stream.columns) || 80;
@@ -481,7 +481,7 @@ async function runClackPreamble(clack, target, detected, askScope) {
481
481
  initialValue: target, defaultValue: target,
482
482
  });
483
483
  if (clack.isCancel(chosen)) return { cancelled: true, target: target };
484
- const ok = await clack.confirm({ message: "Write the ADD skill + tooling + book here?" });
484
+ const ok = await clack.confirm({ message: "Write the ADD skill + tooling here?" });
485
485
  if (clack.isCancel(ok) || !ok) return { cancelled: true, target: target };
486
486
  // global-first SCOPE step (after the target confirm, before agent-detect) — recommended
487
487
  // global home, explicit pick; skipped when --global already chose. global stays ADDITIVE.
@@ -671,7 +671,7 @@ function dropFiles(args, target, profile, intent) {
671
671
  // NO step 4: the installer DROPS FILES ONLY. Initialisation is deferred to the AI
672
672
  // (via `/add`) or a CLI user — a pre-run plain `add.py init` would grandfather-lock
673
673
  // the v12 lock-down gate before `/add` runs (see file header). So no Python is run here.
674
- log("\nDone. " + (args.noSkill ? "The engine + book are" : "The `add` skill + tooling are") +
674
+ log("\nDone. " + (args.noSkill ? "The engine is" : "The `add` skill + tooling are") +
675
675
  " installed (no project state yet — that's intentional).");
676
676
  if (profile.id === "generic") {
677
677
  // the generic onramp line — kept literal so the conversational-only handoff is stable
@@ -753,7 +753,6 @@ const MANAGED = [
753
753
  ["skill/add", [".claude", "skills", "add"], false],
754
754
  ["agents", [".claude", "agents"], false],
755
755
  ["tooling", [".add", "tooling"], true],
756
- ["docs", [".add", "docs"], false],
757
756
  ["personas-teacher", [".add", "personas-teacher"], false],
758
757
  ];
759
758
  // Optional managed trees: an ENHANCEMENT the persona phase reads, not core runtime. The real
@@ -762,6 +761,18 @@ const MANAGED = [
762
761
  // _installer.py:OPTIONAL. Design-for-failure. `agents` joins here (roster-install-drift): the
763
762
  // phase-agent roster is a spawn-acceleration enhancement, not core runtime.
764
763
  const OPTIONAL = new Set(["personas-teacher", "agents"]);
764
+ // SHARED-namespace managed trees (installer-shared-namespace-guard): destinations OTHER
765
+ // TOOLS also write — `.claude/agents` holds the user's own Claude Code subagents. A
766
+ // whole-dir clean-replace there sweeps the user's files as "orphans" (the reported
767
+ // data-loss bug), so these trees route to sharedFileReplace: per-file atomic landings of
768
+ // the shipped files + removal of ONLY the explicit tombstones below. Twin of
769
+ // _installer.py:_SHARED / _RETIRED_AGENTS.
770
+ const SHARED = new Set(["agents"]);
771
+ // Roster names retired upstream — the ONLY names the shared lander may remove (never a
772
+ // pattern/prefix heuristic: a USER file named add-anything.md must survive).
773
+ // roster-distill (ADD 2.0 M1): the 5-agent roster collapsed into the ONE `add` agent.
774
+ const RETIRED_AGENTS = ["add-design.md", "add-build.md", "add-verify.md",
775
+ "add-persona.md", "add-advisor.md"];
765
776
  const STAMP_FILE = ".add-version";
766
777
  const LOCK_FILE = ".update.lock"; // the `update --global` home lock (never user-data)
767
778
  const LOCK_STALE_DEFAULT = 600; // seconds (10 min); ADD_LOCK_STALE_SECONDS env-overridable
@@ -948,7 +959,7 @@ function cleanReplaceTree(src, dest, stripTests) {
948
959
  return { restored: restored, refreshed: refreshed };
949
960
  }
950
961
 
951
- const TREE_LABEL = { "skill/add": "skill", "agents": "agents", "tooling": "tooling", "docs": "docs", "personas-teacher": "personas" };
962
+ const TREE_LABEL = { "skill/add": "skill", "agents": "agents", "tooling": "tooling", "personas-teacher": "personas" };
952
963
 
953
964
  // Per managed tree: "missing" (dest absent OR empty) or "present".
954
965
  function managedStatus(target) {
@@ -961,6 +972,36 @@ function managedStatus(target) {
961
972
  return status;
962
973
  }
963
974
 
975
+ // installer-shared-namespace-guard: land a SHARED-namespace managed tree per FILE.
976
+ // `.claude/agents` belongs to the user as much as to ADD — only the shipped files are
977
+ // written (temp-sibling + atomic rename each, so a crash never leaves a torn file) and
978
+ // only the explicit RETIRED_AGENTS tombstones are removed; every other destination file
979
+ // is never opened. Returns the same { restored, refreshed } roll-up shape as
980
+ // cleanReplaceTree so the reconcile reporting is agnostic. Mirror of
981
+ // _installer.py:_shared_file_replace.
982
+ function sharedFileReplace(src, dest) {
983
+ fs.mkdirSync(dest, { recursive: true });
984
+ let restored = 0, refreshed = 0;
985
+ const entries = fs.readdirSync(src).filter((n) => fs.statSync(path.join(src, n)).isFile()).sort();
986
+ for (const name of entries) {
987
+ const target = path.join(dest, name);
988
+ const existed = fs.existsSync(target);
989
+ const tmp = path.join(dest, name + ".add-tmp-" + Math.random().toString(36).slice(2, 10));
990
+ try {
991
+ fs.copyFileSync(path.join(src, name), tmp);
992
+ fs.renameSync(tmp, target); // atomic overwrite (same directory)
993
+ } catch (e) {
994
+ fs.rmSync(tmp, { force: true }); // dest entry untouched or already whole
995
+ throw e;
996
+ }
997
+ if (existed) refreshed++; else restored++;
998
+ }
999
+ for (const name of RETIRED_AGENTS) {
1000
+ fs.rmSync(path.join(dest, name), { force: true }); // absent tombstone — never fatal
1001
+ }
1002
+ return { restored: restored, refreshed: refreshed };
1003
+ }
1004
+
964
1005
  // reconcile: restore-missing + refresh-present (sweep orphans) across the managed trees,
965
1006
  // reporting per-tree status. Honors --no-skill (the plugin provides the skill). Touches
966
1007
  // ONLY managed trees — never user data. Prechecks ALL sources first (design-for-failure:
@@ -978,7 +1019,9 @@ function reconcile(args, target, srcRoot) {
978
1019
  const status = managedStatus(target);
979
1020
  let restored = 0, refreshed = 0;
980
1021
  for (const [sub, destParts, stripTests] of trees) {
981
- const roll = cleanReplaceTree(path.join(srcRoot, sub), path.join(target, ...destParts), stripTests);
1022
+ const roll = SHARED.has(sub)
1023
+ ? sharedFileReplace(path.join(srcRoot, sub), path.join(target, ...destParts))
1024
+ : cleanReplaceTree(path.join(srcRoot, sub), path.join(target, ...destParts), stripTests);
982
1025
  restored += roll.restored;
983
1026
  refreshed += roll.refreshed;
984
1027
  const dest = destParts.join("/");
@@ -992,7 +1035,7 @@ function reconcile(args, target, srcRoot) {
992
1035
  return { restored: restored, refreshed: refreshed, trees: status };
993
1036
  }
994
1037
 
995
- // --- global home: an OPT-IN shared install (engine+book+skill) updated for all projects ----
1038
+ // --- global home: an OPT-IN shared install (engine+skill) updated for all projects ----
996
1039
  // Resolution is PURE + total (never throws); the home MIRRORS the bundled managed layer so
997
1040
  // `update --global` propagation reuses reconcile() unchanged. Mirror of _installer.py.
998
1041
  function resolveGlobalHome(env) {
@@ -1034,12 +1077,14 @@ function writeRegistry(home, paths) {
1034
1077
  fs.renameSync(tmp, target); // atomic on the same filesystem (POSIX + Windows)
1035
1078
  }
1036
1079
 
1037
- // The home mirrors the bundled layout (skill/add + tooling + docs at the SAME relative paths
1080
+ // The home mirrors the bundled layout (skill/add + tooling at the SAME relative paths
1038
1081
  // the package ships) so reconcile(args, project, home) reuses MANAGED unchanged.
1039
1082
  const GLOBAL_TREES = [
1040
1083
  ["skill/add", ["skill", "add"], false],
1084
+ // roster-drift fix: absent here, `update --global` propagation (sourced FROM the home)
1085
+ // soft-skipped the roster forever — no refresh, no retired-agent tombstones.
1086
+ ["agents", ["agents"], false],
1041
1087
  ["tooling", ["tooling"], true],
1042
- ["docs", ["docs"], false],
1043
1088
  ["personas-teacher", ["personas-teacher"], false],
1044
1089
  ];
1045
1090
 
@@ -1062,7 +1107,7 @@ function reconcileGlobal(home, claudeDir, noSkill) {
1062
1107
  // --- global DATA: an OPT-IN per-project user-data snapshot under <home>/data/<key> ----------
1063
1108
  // Strictly additive; copies ONLY user-data (managed trees + transient excluded), clean-replaced,
1064
1109
  // one-way (project->home). Mirror of _installer.py (identical key + include/exclude rule).
1065
- const DATA_EXCLUDE = ["tooling", "docs", ".update-cache", STAMP_FILE, LOCK_FILE, PROJECT_LOCK_FILE]; // managed trees + meta + both locks
1110
+ const DATA_EXCLUDE = ["tooling", "docs", ".update-cache", STAMP_FILE, LOCK_FILE, PROJECT_LOCK_FILE]; // managed trees + meta + both locks ("docs" = legacy 1.x tree: still never user-data)
1066
1111
 
1067
1112
  // data_key twin: <sanitized-basename>-<sha1(abspath_utf8)[:12]>. Pure · total · separator-free.
1068
1113
  function dataKey(projectAbspath) {
@@ -1840,6 +1885,26 @@ function cmdUpdate(args) {
1840
1885
  log("ADD updated " + (cur || "(unstamped)") + " -> " + version +
1841
1886
  " · managed layer reconciled (" + roll.restored + " restored · " + roll.refreshed +
1842
1887
  " refreshed) · your project state untouched.");
1888
+ // crossing nudges — engine-owned follow-ups the updater must NAME, never run (python3
1889
+ // may be absent on this PATH; both commands are idempotent). Twin of _installer.py.
1890
+ if (cur !== version) {
1891
+ log("next: python3 .add/tooling/add.py sync-guidelines # refresh the CLAUDE.md guidance block to this version");
1892
+ }
1893
+ const tasksDir = path.join(addDir, "tasks");
1894
+ let legacyBoard = false;
1895
+ if (fs.existsSync(tasksDir)) {
1896
+ for (const entry of fs.readdirSync(tasksDir, { withFileTypes: true })) {
1897
+ if (entry.isDirectory()
1898
+ && fs.existsSync(path.join(tasksDir, entry.name, "TASK.md"))
1899
+ && !fs.existsSync(path.join(tasksDir, entry.name, "PLAN.md"))) {
1900
+ legacyBoard = true;
1901
+ break;
1902
+ }
1903
+ }
1904
+ }
1905
+ if (legacyBoard) {
1906
+ log("next: python3 .add/tooling/add.py migrate # 1.x board detected: TASK.md -> PLAN.md, live + archived");
1907
+ }
1843
1908
  }
1844
1909
 
1845
1910
  // js-reclaim-lock-heartbeat: a test-only entrypoint so the Python subprocess suite can drive
@@ -1888,13 +1953,13 @@ async function main() {
1888
1953
  case "help":
1889
1954
  case "--help":
1890
1955
  log("usage: npx @pilotspace/add <init|update|prune-data> [targetDir] [--force] [--check] [--no-skill] [--global] [--yes|--non-interactive]");
1891
- log(" init install the ADD skill + tooling + book into a project");
1892
- log(" (--no-skill drops the engine + book only — used by the Claude Code plugin)");
1956
+ log(" init install the ADD skill + tooling into a project");
1957
+ log(" (--no-skill drops the engine only — used by the Claude Code plugin)");
1893
1958
  log(" (--global ALSO installs to a shared home [ADD_HOME|XDG_DATA_HOME/add|~/.add] + registers the project)");
1894
1959
  log(" (--global-data implies --global + persists this project's user-data under <home>/data/<key>)");
1895
1960
  log(" (--from-global-data rehydrates this project's user-data FROM the shared home on a fresh clone)");
1896
1961
  log(" (interactive in a real terminal; --yes / --non-interactive force the plain path)");
1897
- log(" update re-materialize skill/tooling/docs to this package version (preserves your state)");
1962
+ log(" update re-materialize skill/tooling to this package version (preserves your state)");
1898
1963
  log(" (--global refreshes the shared home + propagates to every registered project)");
1899
1964
  log(" prune-data remove orphaned per-project snapshots from the shared home (dry-run; --force deletes)");
1900
1965
  break;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@pilotspace/add",
3
- "version": "1.17.0",
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.",
3
+ "version": "2.0.0",
4
+ "description": "ADD (AI-Driven Development) 2.0. The agent is the hands; ADD is the memory, judgment, and conscience — a minimal, state-tracked skill: one freeze per feature, trust from passing tests, state on disk so context rot never survives a new session.",
5
5
  "bin": {
6
6
  "add": "bin/cli.js"
7
7
  },
@@ -24,7 +24,6 @@
24
24
  "!tooling/add_engine/__pycache__",
25
25
  "!**/*.pyc",
26
26
  "tooling/templates/",
27
- "docs/",
28
27
  "personas-teacher/",
29
28
  "THIRD_PARTY_NOTICES.md",
30
29
  "README.md",
@@ -11,3 +11,9 @@ KEEP: the agent-definition domain folders (engineering, security, design, produc
11
11
  DROP: the upstream `.github/` CI, `scripts/`, other-tool `integrations/`, `CONTRIBUTING*`, `SECURITY.md`, and dotfiles.
12
12
 
13
13
  Content is RAW + verbatim — regenerate with `python3 add-method/scripts/update_teacher.py`. Attribution: see the repo-root `THIRD_PARTY_NOTICES.md` and the retained `LICENSE` in this folder (MIT).
14
+
15
+ ## Refresh-drift check (run on every refresh PR)
16
+
17
+ Distilled personas keep `source:` provenance pointing into this snapshot. In the refresh PR
18
+ description, list every `.add/personas/*.md` whose `source:` file(s) changed or moved in the
19
+ diff — those personas are candidates for re-distillation, otherwise their provenance rots silently.