@pilotspace/add 1.17.0 → 2.1.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 (120) hide show
  1. package/CHANGELOG.md +193 -0
  2. package/GETTING-STARTED.md +20 -64
  3. package/README.md +138 -158
  4. package/agents/add-advisor.md +66 -21
  5. package/agents/add-worker.md +102 -0
  6. package/bin/cli.js +88 -21
  7. package/package.json +2 -3
  8. package/personas-teacher/VENDOR.md +6 -0
  9. package/skill/add/SKILL.md +100 -144
  10. package/skill/add/adopt.md +28 -0
  11. package/skill/add/beyond.md +37 -0
  12. package/skill/add/deltas.md +25 -2
  13. package/skill/add/design.md +56 -74
  14. package/skill/add/{report-template.md → gate-udd.md} +28 -38
  15. package/skill/add/intake.md +56 -25
  16. package/skill/add/loop.md +32 -19
  17. package/skill/add/persona-author/SKILL.md +116 -0
  18. package/skill/add/persona-author/assets/example-design-persona.md +55 -0
  19. package/skill/add/persona-author/assets/example-persona.md +57 -0
  20. package/skill/add/persona-author/references/contract.md +69 -0
  21. package/skill/add/persona-author/references/patterns.md +122 -0
  22. package/skill/add/persona-author/references/seeding.md +79 -0
  23. package/skill/add/phases/build.md +79 -0
  24. package/skill/add/phases/direction.md +287 -0
  25. package/skill/add/phases/verify.md +161 -0
  26. package/skill/add/run.md +16 -18
  27. package/skill/add/terms.md +18 -0
  28. package/tooling/add.py +2421 -3258
  29. package/tooling/add_engine/autonomy.py +2 -37
  30. package/tooling/add_engine/components.py +4 -87
  31. package/tooling/add_engine/constants.py +148 -93
  32. package/tooling/add_engine/guidelines.py +10 -11
  33. package/tooling/add_engine/io_state.py +72 -5
  34. package/tooling/add_engine/predicates.py +90 -2
  35. package/tooling/add_engine/search.py +6 -6
  36. package/tooling/add_engine/taskdoc.py +15 -10
  37. package/tooling/templates/CONVENTIONS.md.tmpl +1 -1
  38. package/tooling/templates/GLOSSARY.md.tmpl +10 -4
  39. package/tooling/templates/MILESTONE.md.tmpl +20 -16
  40. package/tooling/templates/PLAN.md.tmpl +129 -0
  41. package/tooling/templates/PROJECT.md.tmpl +6 -1
  42. package/tooling/templates/PROMPT.persona.md.tmpl +17 -21
  43. package/tooling/templates/personas/build-engineer.md.tmpl +45 -0
  44. package/tooling/templates/personas/data-steward.md.tmpl +45 -0
  45. package/tooling/templates/personas/evidence-verifier.md.tmpl +45 -0
  46. package/tooling/templates/personas/platform-engineer.md.tmpl +45 -0
  47. package/tooling/templates/personas/product-lead.md.tmpl +51 -0
  48. package/tooling/templates/personas/quality-auditor.md.tmpl +47 -0
  49. package/tooling/templates/personas/release-manager.md.tmpl +52 -0
  50. package/tooling/templates/personas/security-gatekeeper.md.tmpl +45 -0
  51. package/tooling/templates/personas/software-architect.md.tmpl +45 -0
  52. package/tooling/templates/personas/stream-orchestrator.md.tmpl +44 -0
  53. package/tooling/templates/personas/technical-writer.md.tmpl +49 -0
  54. package/tooling/templates/personas/ux-experience-lead.md.tmpl +48 -0
  55. package/tooling/templates/specs/SPEC.md.tmpl +18 -0
  56. package/tooling/templates/udd-wireframe.md +1 -1
  57. package/agents/add-build.md +0 -29
  58. package/agents/add-design.md +0 -32
  59. package/agents/add-persona.md +0 -33
  60. package/agents/add-verify.md +0 -36
  61. package/docs/00-introduction.md +0 -46
  62. package/docs/01-principles.md +0 -71
  63. package/docs/02-the-flow.md +0 -113
  64. package/docs/03-step-1-specify.md +0 -123
  65. package/docs/04-step-2-scenarios.md +0 -90
  66. package/docs/05-step-3-contract.md +0 -80
  67. package/docs/06-step-4-tests.md +0 -85
  68. package/docs/07-step-5-build.md +0 -82
  69. package/docs/08-step-6-verify.md +0 -105
  70. package/docs/09-the-loop.md +0 -75
  71. package/docs/10-setup-and-stages.md +0 -118
  72. package/docs/11-governance.md +0 -91
  73. package/docs/12-roles.md +0 -99
  74. package/docs/13-adoption.md +0 -67
  75. package/docs/14-foundation.md +0 -142
  76. package/docs/15-foundations-and-lineage.md +0 -106
  77. package/docs/16-releasing.md +0 -182
  78. package/docs/17-components.md +0 -143
  79. package/docs/18-personas.md +0 -80
  80. package/docs/README.md +0 -77
  81. package/docs/add-competencies.png +0 -0
  82. package/docs/add-flow.png +0 -0
  83. package/docs/add-foundation.png +0 -0
  84. package/docs/add-hierarchy.png +0 -0
  85. package/docs/add-milestone-task-lifecycle.png +0 -0
  86. package/docs/add-task-growth-wheel.png +0 -0
  87. package/docs/appendix-a-templates.md +0 -88
  88. package/docs/appendix-b-prompts.md +0 -154
  89. package/docs/appendix-c-glossary.md +0 -176
  90. package/docs/appendix-d-worked-example.md +0 -231
  91. package/docs/appendix-e-checklists.md +0 -92
  92. package/docs/appendix-f-requirements-matrix.md +0 -171
  93. package/docs/appendix-g-references.md +0 -106
  94. package/skill/add/advisor.md +0 -81
  95. package/skill/add/compact-foundation.md +0 -40
  96. package/skill/add/components.md +0 -52
  97. package/skill/add/confidence.md +0 -32
  98. package/skill/add/fold.md +0 -63
  99. package/skill/add/graduate.md +0 -39
  100. package/skill/add/phases/0-ground.md +0 -64
  101. package/skill/add/phases/0-setup.md +0 -103
  102. package/skill/add/phases/1-specify.md +0 -61
  103. package/skill/add/phases/2-scenarios.md +0 -48
  104. package/skill/add/phases/3-contract.md +0 -60
  105. package/skill/add/phases/4-tests.md +0 -61
  106. package/skill/add/phases/5-build.md +0 -62
  107. package/skill/add/phases/6-verify.md +0 -69
  108. package/skill/add/phases/7-observe.md +0 -45
  109. package/skill/add/phases/fast-lane.md +0 -34
  110. package/skill/add/release.md +0 -61
  111. package/skill/add/scope.md +0 -72
  112. package/skill/add/self-improve.md +0 -20
  113. package/skill/add/sensitivity.md +0 -51
  114. package/skill/add/setup-review.md +0 -48
  115. package/skill/add/soul.md +0 -58
  116. package/skill/add/streams.md +0 -269
  117. package/tooling/add_engine/release.py +0 -86
  118. package/tooling/templates/TASK.fast.md.tmpl +0 -78
  119. package/tooling/templates/TASK.md.tmpl +0 -181
  120. package/tooling/templates/personas/_template.md.tmpl +0 -82
@@ -11,15 +11,14 @@ from __future__ import annotations
11
11
  import re
12
12
  from pathlib import Path
13
13
 
14
- from add_engine.constants import _AUTONOMY_LEVELS, _STREAMS_POSTURES
14
+ from add_engine.constants import _AUTONOMY_LEVELS
15
15
  from add_engine.taskdoc import _task_header
16
16
 
17
17
  _AUTONOMY_LINE_RE = re.compile(r"(?:^|·)[ \t]*autonomy:[ \t]*([^\s<#|]+)", re.MULTILINE)
18
- _STREAMS_LINE_RE = re.compile(r"(?:^|·)[ \t]*streams:[ \t]*([^\s<#|]+)", re.MULTILINE)
19
18
 
20
19
 
21
20
  def _autonomy_level(hdr: str):
22
- """The declared autonomy rung from a TASK.md header region (HTML comments
21
+ """The declared autonomy rung from a PLAN.md header region (HTML comments
23
22
  already stripped by _task_header). Returns a member of _AUTONOMY_LEVELS, or
24
23
  None when no `autonomy:` line is present (UNSET — an unfilled `<…>` placeholder,
25
24
  whose value the regex declines, counts as unset), or "?" when a REAL token outside
@@ -57,37 +56,3 @@ def _project_autonomy(root: Path) -> str:
57
56
  Read-only and PURE — mirrors _project_goal; the seed source for cmd_new_task."""
58
57
  tok = _project_autonomy_token(root)
59
58
  return "auto" if tok is None else ("conservative" if tok == "?" else tok)
60
-
61
-
62
- # --- streams posture: the parallel-vs-sequential half of the run mode (persist-run-mode) ---
63
- # A project-scoped declaration in PROJECT.md beside autonomy. Mirrors the autonomy resolvers:
64
- # anchored read (a title/prose substring is never a declaration), fail-safe defaults.
65
-
66
- def _streams_posture(text: str):
67
- """The declared streams posture from a foundation region (HTML comments already stripped
68
- by the caller). A member of _STREAMS_POSTURES, None when no `streams:` line is present, or
69
- "?" when a REAL token outside the set was written (unknown). PURE."""
70
- m = _STREAMS_LINE_RE.search(text)
71
- if not m:
72
- return None
73
- tok = m.group(1).strip().lower()
74
- return tok if tok in _STREAMS_POSTURES else "?"
75
-
76
- def _project_streams_token(root: Path):
77
- """The RAW streams declaration in PROJECT.md — a recognized posture, None when no
78
- declaration line is present, or "?" for a real-but-unrecognized token. Uses the anchored
79
- _streams_posture (a title/prose substring is never a declaration) with HTML comments
80
- stripped. Unreadable foundation -> None. Read-only and PURE."""
81
- try:
82
- text = (root / "PROJECT.md").read_text(encoding="utf-8")
83
- except OSError:
84
- return None
85
- return _streams_posture(re.sub(r"<!--.*?-->", "", text, flags=re.S))
86
-
87
- def _project_streams(root: Path) -> str:
88
- """The streams posture the project runs under. Fail-SAFE: no declaration -> "parallel"
89
- (the documented project default: parallel+auto); an unrecognized token -> "sequential"
90
- (the conservative fallback, NEVER silently parallel); an unreadable foundation -> "parallel".
91
- Read-only and PURE — mirrors _project_autonomy."""
92
- tok = _project_streams_token(root)
93
- return "parallel" if tok is None else ("sequential" if tok == "?" else tok)
@@ -1,21 +1,13 @@
1
- """add_engine.components — the component-aware-add subsystem (engine-modularization 11/N).
1
+ """add_engine.components — scope-confinement utilities.
2
2
 
3
- Registry (.add/components.toml) + produced/consumed contracts + cross-repo federation +
4
- scope confinement. A closed, unpatched cluster (transitive-closure AST = zero outbound).
5
- Replicates add.py's degrade-safe tomllib guard so `import` stays safe on Python < 3.11
6
- (where the registry degrades to opt-out). Opt-in: no components.toml -> every reader is
7
- byte-identical to single-component. Deps: stdlib only (no add, no add_engine).
3
+ kernel-trim (ADD 2.0 M5): the components pillar (registry · cross-component contracts ·
4
+ federation) died with its verbs; only the two GENERIC path/scope utilities every scope
5
+ read shares survive here. Deps: stdlib only (no add, no add_engine).
8
6
  """
9
7
  from __future__ import annotations
10
8
 
11
- import re
12
9
  from pathlib import Path
13
10
 
14
- try: # component registry parse (Python 3.11+ stdlib); degrade-safe
15
- import tomllib
16
- except ModuleNotFoundError: # < 3.11: registry unsupported -> tomllib None -> opt-out
17
- tomllib = None
18
-
19
11
 
20
12
  def _confined(p: Path, rootp: Path) -> bool:
21
13
  """True only if p resolves (symlinks followed) inside rootp; errors -> False.
@@ -25,85 +17,10 @@ def _confined(p: Path, rootp: Path) -> bool:
25
17
  except OSError:
26
18
  return False
27
19
 
28
- def _components(root: Path) -> dict[str, dict]:
29
- """The registry from .add/components.toml → {name: {root, verify, green_bar,
30
- language}}. `root` required per entry; an entry missing it is skipped (the finding
31
- surface reports it). `verify` is stored OPAQUE — parsed as data, NEVER executed. PURE."""
32
- if tomllib is None:
33
- return {}
34
- try:
35
- raw = (root / "components.toml").read_bytes()
36
- except OSError:
37
- return {}
38
- try:
39
- data = tomllib.loads(raw.decode("utf-8"))
40
- except (tomllib.TOMLDecodeError, UnicodeDecodeError, ValueError):
41
- return {}
42
- out: dict[str, dict] = {}
43
- for name, spec in (data.get("component") or {}).items():
44
- # "?" is the reserved unknown-binding sentinel (_task_component) — a component
45
- # named "?" would collide and silently drop cover, so it never registers.
46
- if name == "?" or not isinstance(spec, dict) or not isinstance(spec.get("root"), str):
47
- continue
48
- out[name] = {"root": spec["root"], "verify": spec.get("verify"),
49
- "green_bar": spec.get("green_bar"), "language": spec.get("language")}
50
- return out
51
20
 
52
- def _cite_region(body: str) -> str:
53
- """The user-authored "Build expectations" evidence region of a §6 body, stamp-stripped —
54
- the only place a per-component green-bar cite counts (per-component-verify, v3). PURE.
55
21
 
56
- The marker matches BOTH template shapes: the standard "### Build expectations …" heading AND
57
- the fast-lane bare "Build expectations (from …):" line, running up to the GATE RECORD sub-block.
58
- So the top-of-§6 checklist ("- [ ] all tests pass") and the "Outcome: <PASS|…>" placeholder are
59
- excluded, and a component-bound FAST task is still citable. The trailing strip removes the
60
- engine's own "component: … · expected green-bar: …" stamp wherever it landed, so a stamp that
61
- fell inside the region can never self-satisfy the gate. No marker -> "" (fail-closed for a bound
62
- task: it must declare its evidence)."""
63
- m = re.search(r"(?im)^#*[ \t]*Build expectations\b.*?(?=\n#+[ \t]*GATE RECORD\b|\Z)", body, re.DOTALL)
64
- region = m.group(0) if m else ""
65
- return re.sub(r"(?m)^component:.*·.*expected green-bar:.*$", "", region)
66
22
 
67
- def _contracts(root: Path) -> dict[str, dict]:
68
- """[contract.<id>] from .add/components.toml -> {id: {producer: str, consumers: list[str]}}.
69
- A malformed entry (producer not a str) is skipped (the finding surface reports it). PURE."""
70
- if tomllib is None:
71
- return {}
72
- try:
73
- data = tomllib.loads((root / "components.toml").read_bytes().decode("utf-8"))
74
- except (OSError, tomllib.TOMLDecodeError, UnicodeDecodeError, ValueError):
75
- return {}
76
- out: dict[str, dict] = {}
77
- for cid, spec in (data.get("contract") or {}).items():
78
- if not isinstance(spec, dict) or not isinstance(spec.get("producer"), str):
79
- continue
80
- cons = spec.get("consumers")
81
- out[cid] = {"producer": spec["producer"],
82
- "consumers": [c for c in cons if isinstance(c, str)] if isinstance(cons, list) else []}
83
- return out
84
-
85
- def _federation(root: Path) -> dict[str, dict]:
86
- """[federation.<id>] from .add/components.toml -> {id: {source: str, pin: str|None}}.
87
- The cross-REPO join: a consumer repo names where a producer repo's published snapshot lives.
88
- A malformed entry (no string source) is skipped; a non-string `pin` degrades to None. Degrade-safe
89
- — never raises. PURE. On Python < 3.11 (no tomllib) this returns {} like the other component
90
- readers, so `federate` reports federation_unknown — components.toml needs a 3.11+ runtime."""
91
- if tomllib is None:
92
- return {}
93
- try:
94
- data = tomllib.loads((root / "components.toml").read_bytes().decode("utf-8"))
95
- except (OSError, tomllib.TOMLDecodeError, UnicodeDecodeError, ValueError):
96
- return {}
97
- out: dict[str, dict] = {}
98
- for fid, spec in (data.get("federation") or {}).items():
99
- if not isinstance(spec, dict) or not isinstance(spec.get("source"), str):
100
- continue
101
- pin = spec.get("pin")
102
- out[fid] = {"source": spec["source"], "pin": pin if isinstance(pin, str) else None}
103
- return out
104
23
 
105
- def _contract_snapshot(root: Path, cid: str) -> Path:
106
- return root / "contracts" / f"{cid}.json"
107
24
 
108
25
  def _in_scope(rel: str, declared: list[str]) -> bool:
109
26
  """True when rel falls under any declared token — exact match for a file
@@ -8,27 +8,35 @@ import re
8
8
  from pathlib import Path
9
9
 
10
10
  __all__ = [
11
+ "BOOK_URL",
12
+ "book_url",
11
13
  "ROOT_DIRNAME",
12
14
  "STATE_FILE",
13
15
  "MILESTONE_FILE",
14
16
  "GOAL_UNSET",
15
17
  "STAGES",
16
- "GRADUATION_CUE",
17
- "RELEASABLE_CUE",
18
- "RELEASES_FILE",
19
18
  "PHASES",
19
+ "LEGACY_PHASES",
20
20
  "GATES",
21
21
  "HEAL_CAP",
22
22
  "PHASE_GUIDE",
23
23
  "PHASE_OWNER",
24
+ "PHASE_GROUPS",
25
+ "PHASE_AGENT",
24
26
  "SETUP_FILES",
25
27
  "PERSONA_FRONTMATTER_KEYS",
26
28
  "PERSONA_REQUIRED_SECTIONS",
29
+ "PERSONA_FLOW_VALUES",
30
+ "TASK_KINDS",
31
+ "SPEC_DDS",
27
32
  "PERSONA_HINT",
28
33
  "PERSONA_FIT_HINT_TEMPLATE",
29
34
  "GUIDELINE_FILES",
30
35
  "RULES_FILE_REL",
31
36
  "WORKFLOW_HEADINGS",
37
+ "_GATE_MODES",
38
+ "_SKIPPABLE_PHASES",
39
+ "_DIALECT_CLASSES",
32
40
  ]
33
41
 
34
42
  ROOT_DIRNAME = ".add"
@@ -39,18 +47,19 @@ MILESTONE_FILE = "MILESTONE.md"
39
47
  # this sentinel so the read-only orientation surfaces never blank or crash.
40
48
  GOAL_UNSET = "(unset — add a 'goal:' line to PROJECT.md)"
41
49
  STAGES = ("prototype", "poc", "mvp", "production")
42
- # v22 stage-graduation: the read-only cue `status` shows when the MVP is covered.
43
- # Worded as the ACTION (never a file) so it stands before graduate.md exists.
44
- GRADUATION_CUE = "MVP covered propose graduation"
45
- # release-altitude: the read-only cue `status` shows when ≥1 closed milestone is
46
- # unreleased. The 5th scope level (release.md). `{n}` is filled at print time; the
47
- # wording matches SKILL.md's "Beyond the bundle" cross-ref byte-for-byte.
48
- RELEASABLE_CUE = "releasable: {n} milestone(s) closed since last release"
49
- # the append-only release ledger lives at the PROJECT ROOT (the dir containing .add/),
50
- # a sibling of CHANGELOG.md — NOT inside .add/. The ledger IS the attribution source:
51
- # a milestone is "released" iff its slug appears on a `milestones:` row.
52
- RELEASES_FILE = "RELEASES.md"
53
- PHASES = ("ground", "specify", "scenarios", "contract", "tests", "build", "verify", "observe", "done")
50
+ # kernel-trim (ADD 2.0 M5): GRADUATION_CUE / RELEASABLE_CUE / RELEASES_FILE died with the
51
+ # graduate/release verbs the release-manager persona owns that judgment now.
52
+ PHASES = ("direction", "build", "verify", "done")
53
+ # phase-collapse-3 (thin-engine-loop W2): the 6-phase walk collapsed to 3 work phases.
54
+ # `direction` is the whole front span (the old specify+plan+tests §1–§4 drafted
55
+ # top-to-bottom, ONE freeze approval crosses it into build). Legacy tokens normalize to
56
+ # their 3-phase home at READ time (load_state) 473 pre-collapse task records are never
57
+ # bulk-rewritten; the map below is the single source both load_state and _phase_index use.
58
+ LEGACY_PHASES = {
59
+ "ground": "direction", "specify": "direction", "scenarios": "direction",
60
+ "contract": "direction", "plan": "direction", "tests": "direction",
61
+ "observe": "verify",
62
+ }
54
63
  GATES = ("none", "PASS", "RISK-ACCEPTED", "HARD-STOP")
55
64
  # heal-then-escalate (verify-integrity): the bounded self-heal loop cap. A CONFIRMED cheat
56
65
  # (mechanical tripwire divergence, or an agent-reported semantic refute-read finding) returns
@@ -61,38 +70,63 @@ HEAL_CAP = 3
61
70
 
62
71
 
63
72
 
73
+ # The AIDD book's published home (book-stops-shipping, ADD 2.0 M6b): the book no
74
+ # longer installs into projects as .add/docs/ — every engine chapter pointer deep-
75
+ # links here instead. mkdocs pretty-URLs: docs/<stem>.md renders at <BOOK_URL>/<stem>/.
76
+ BOOK_URL = "https://pilotspace.github.io/ADD"
77
+
78
+
79
+ def book_url(chapter: str) -> str:
80
+ """Deep link for a book chapter filename ('02-the-flow.md' -> …/02-the-flow/)."""
81
+ stem = chapter[:-3] if chapter.endswith(".md") else chapter
82
+ return f"{BOOK_URL}/{stem}/"
83
+
84
+
64
85
  # `add.py guide` copy: per-phase (concrete next action, book chapter to read).
65
86
  # Keep the action wording aligned with each phase's EXIT line in the TASK template.
66
87
  PHASE_GUIDE = {
67
- "ground": ("gather the real codebase the task touches files, symbols, signatures, conventions, and the anchor points the contract will cite; defer to PROJECT.md/CONVENTIONS.md and gather only the task delta",
68
- "02-the-flow.md"),
69
- "specify": ("state every rule — Must / Reject (+ named code) / After; rank assumptions lowest-confidence first and flag the biggest risk",
88
+ "direction": ("draft the Direction bundle top-to-bottom §1 rules (Must / Reject + named codes / After, assumptions ranked lowest-confidence first) · §2 one scenario per rule · §3 the change PLAN: ground the real code, draft the contract, and DESCRIBE what this task will do (scope · ordered batches · approach — the plan-of-action the freeze report shows the human) · §4 red suite failing for the right reason; then the ONE approval: freeze --by <name> --cross",
70
89
  "03-step-1-specify.md"),
71
- "scenarios": ("write one Given/When/Then per Must AND per Reject; every result observable",
72
- "04-step-2-scenarios.md"),
73
- "contract": ("freeze the shape — signature, fields, error codes; names match the glossary",
74
- "05-step-3-contract.md"),
75
- "tests": ("write one failing test per scenario; run them RED for the right reason",
76
- "06-step-4-tests.md"),
77
90
  "build": ("write the minimum code to pass the tests; change no test and no contract",
78
91
  "07-step-5-build.md"),
79
- "verify": ("run the suite + non-functional checks, then record the gate",
92
+ "verify": ("run the suite + non-functional checks, then record the gate; then note what to watch + the spec delta for the next loop (§7)",
80
93
  "08-step-6-verify.md"),
81
- "observe": ("note what to watch + the spec delta for the next loop",
82
- "09-the-loop.md"),
83
94
  "done": ("this task is done — pick the next feature",
84
95
  "02-the-flow.md"),
85
96
  }
86
97
  # Phase -> who owns it, for the `--json` autonomy signal. An autonomous harness may run a
87
98
  # phase only when owner=="ai" (stop is false); every other phase is a checkpoint. The map
88
- # follows the book's who-does-what table (Verify is "human only"); `tests`/`build`/`observe`
99
+ # follows the book's who-does-what table (Verify is "human only"); `tests`/`build`
89
100
  # are AI-led. A phase missing here is `unmapped_phase` (fail closed) — never defaulted.
90
101
  PHASE_OWNER = {
91
- "ground": "ai",
92
- "specify": "human", "scenarios": "human", "contract": "seam",
93
- "tests": "ai", "build": "ai", "verify": "human", "observe": "ai", "done": "human",
102
+ "direction": "seam",
103
+ "build": "ai", "verify": "human", "done": "human",
104
+ }
105
+ # phase-bundles: the work phases (PHASES minus the terminal "done") group into 3
106
+ # agent-owned bundles surfaced at `status`/`guide` — DIRECTION fixes the shape (through
107
+ # the frozen change plan — grounding + contract + build-strategy — AND the red suite; the
108
+ # method thesis is "fix spec/scenarios/plan/failing-tests BEFORE the build"), BUILD makes
109
+ # it green, VERIFY earns trust and feeds the next loop. A grouping OVER PHASES, never a
110
+ # reorder; "done" (terminal, human-led) deliberately has no bundle — see PHASE_AGENT/
111
+ # _phase_bundle below. Union == set(PHASES) - {"done"}, pairwise disjoint (test_phase_bundles.py).
112
+ PHASE_GROUPS = {
113
+ "DIRECTION": ("direction",),
114
+ "BUILD": ("build",),
115
+ "VERIFY": ("verify",),
116
+ }
117
+ # phase-bundles: the roster agent PREFERRED for each phase (per-PHASE, not per-bundle —
118
+ # advisor-split: `add-worker` is the execution shell for every phase; the spawn prompt names
119
+ # the mode (direction·build·verify·persona) and the agent loads that beat's guide + the fitting
120
+ # persona (personas carry the expertise, the agent carries the discipline). `add-advisor` is
121
+ # spawned on demand to propose/pressure-test/decide — it is not a per-phase default, so it is
122
+ # absent here. A phase missing here is a bug (PHASE_GROUPS' own union covers every key);
123
+ # `_phase_bundle` is the fail-closed resolver for an unmapped/corrupted phase token, not this map.
124
+ PHASE_AGENT = {
125
+ "direction": "add-worker",
126
+ "build": "add-worker",
127
+ "verify": "add-worker",
94
128
  }
95
- SETUP_FILES = ("PROJECT.md", "CONVENTIONS.md", "GLOSSARY.md", "MODEL_REGISTRY.md", "dependencies.allowlist", "DESIGN.md", "SOUL.md", "personas/_template.md")
129
+ SETUP_FILES = ("PROJECT.md", "CONVENTIONS.md", "GLOSSARY.md", "MODEL_REGISTRY.md", "dependencies.allowlist", "DESIGN.md", "SOUL.md")
96
130
 
97
131
  # persona-setup: a PERSONA living doc (`.add/personas/<slug>.md`) is a frozen-schema file
98
132
  # distilled from the vendored teacher library to its critical-rules + default-requirement +
@@ -100,23 +134,53 @@ SETUP_FILES = ("PROJECT.md", "CONVENTIONS.md", "GLOSSARY.md", "MODEL_REGISTRY.md
100
134
  # content quality is the AI's authoring concern, not the engine gate. NO-EXEC: validation is pure.
101
135
  PERSONA_FRONTMATTER_KEYS = ("name", "vibe")
102
136
  PERSONA_REQUIRED_SECTIONS = ("## Identity", "## Critical Rules", "## Default Requirement", "## Success Metrics")
137
+ # persona-schema-hardening: the closed set of apply-surfaces a `flow:` value may name — the
138
+ # single source the quality predicate reads (a value outside this set is loaded by NO surface,
139
+ # so a typo would otherwise fail silently). Findings are WARN-only (measure-not-block).
140
+ PERSONA_FLOW_VALUES = ("design", "build", "advisor", "verify")
141
+ # persona-task-kinds (ADD 2.0 M1 persona-core): the closed task-kind taxonomy — the join key
142
+ # between a persona's routing claim (`task-kinds:` frontmatter) and a task's declared kind
143
+ # (`kind:` header line). Route-outcome traces record it, the persona scoreboard groups by it.
144
+ # Closed on purpose: a free-text kind can't be scored across tasks. Measure-not-block —
145
+ # an unknown kind is a named WARN (quality predicate Finding C), never a refusal.
146
+ TASK_KINDS = ("feature", "refactor", "test", "docs", "ui",
147
+ "security", "data", "infra", "release", "integration")
148
+
149
+ # specs-5dd (ADD 2.0 M3): the closed 5-DD map — dd tag -> (spec file under .add/specs/,
150
+ # title, lens). init renders ONE template (templates/specs/SPEC.md.tmpl) five ways;
151
+ # `delta-append <dd>` routes a lesson to its file. Closed on purpose: the five lenses ARE
152
+ # the method's competency model (DDD·SDD·UDD·TDD·ADD) — an unknown dd is a refusal
153
+ # (delta_dd_unknown), because a delta filed under a sixth ad-hoc lens is a delta lost.
154
+ SPEC_DDS = {
155
+ "ddd": ("domain.md", "Domain",
156
+ "what the system IS: entities, rules, ubiquitous language (DDD)"),
157
+ "sdd": ("system.md", "System",
158
+ "how it is built: architecture, contracts, data shapes (SDD)"),
159
+ "udd": ("experience.md", "Experience",
160
+ "how it feels to use: flows, surfaces, the humans served (UDD)"),
161
+ "tdd": ("quality.md", "Quality",
162
+ "how we know it works: test strategy, floors, evidence (TDD)"),
163
+ "add": ("method.md", "Method",
164
+ "how we work: the loop, autonomy, ceremony budget (ADD)"),
165
+ }
103
166
 
104
167
  # persona-seed-nudge v2: ONE hint, single-sourced — `new-milestone`/`check`/`status` all print
105
168
  # THIS constant (not their own copy) so the wording can never drift across the three surfaces.
106
169
  # Project-scoped (not "this milestone's domain") per the confirmed v2 amendment: the AI should
107
170
  # catch up ALL of a project's missing personas, not draft a single milestone-fit one.
108
- PERSONA_HINT = ("no project-fit persona seeded yet under .add/personas/ — spawn the add-persona "
109
- "agent (or read docs/18-personas.md) to seed the project's persona(s) from "
110
- "PROJECT.md's domain")
171
+ PERSONA_HINT = ("no project-fit persona seeded yet under .add/personas/ — use the persona-author "
172
+ "skill (or read docs/18-personas.md) to author the project's persona(s) "
173
+ "from PROJECT.md's domain")
111
174
 
112
175
  # persona-fit-nudge: the OPPOSITE-branch, mutually-exclusive sibling of PERSONA_HINT — fires only
113
176
  # when ≥1 real persona ALREADY exists, so a brand-new milestone doesn't silently assume one of
114
177
  # them fits its domain. Existence-only (names the persona slugs already seeded); the AI still
115
- # owns the actual fit judgment via add-persona the engine never scores content similarity.
116
- # {slugs} is filled at call time from `.add/personas/*.md` (excluding `_template`).
178
+ # owns the actual fit judgment (add-worker's persona mode, guided by the persona-author skill)
179
+ # the engine never scores content similarity. {slugs} is filled at call time from
180
+ # `.add/personas/*.md` (excluding any `_`-prefixed scaffold).
117
181
  PERSONA_FIT_HINT_TEMPLATE = (
118
- "existing persona(s) seeded — {slugs} — confirm one fits this milestone's domain, or spawn "
119
- "the add-persona agent (or read docs/18-personas.md) to draft a better-fit one"
182
+ "existing persona(s) seeded — {slugs} — confirm one fits this milestone's domain, or use the "
183
+ "persona-author skill (or read docs/18-personas.md) to author a better-fit one"
120
184
  )
121
185
 
122
186
  # Scaffolded into .add/.gitignore at init so the engine's transient LOCAL artifacts
@@ -171,16 +235,11 @@ _RULE_REF_LINE = "- ADD (AI-Driven Development) Workflows rules: ./.claude/rules
171
235
 
172
236
  # Minimal embedded fallback so the tool still works if templates/ is missing
173
237
  # (circuit breaker: never hard-fail just because a template file was deleted).
174
- _FALLBACK_TASK = """# TASK: {title}
238
+ _FALLBACK_TASK = """# PLAN: {title}
175
239
 
176
240
  slug: {slug} · created: {date} · stage: {stage}
177
241
  autonomy: auto
178
- phase: ground
179
-
180
- ## 0 · GROUND
181
- Touches (files · symbols · signatures):
182
- Honors (patterns / conventions):
183
- Anchors the contract cites:
242
+ phase: direction
184
243
 
185
244
  ## 1 · SPECIFY
186
245
  Feature:
@@ -188,12 +247,18 @@ Framings weighed:
188
247
  Must:
189
248
  Reject:
190
249
  After:
191
- Assumptions — lowest-confidence first:
192
- <most likely wrong> — lowest confidence because <why>; if wrong: <cost>
250
+ Boundary:
251
+ <assumptions>
252
+ ⚠ <the ONE assumption most likely to be wrong — if wrong: <cost>>
253
+ </assumptions>
193
254
 
194
255
  ## 2 · SCENARIOS
195
- ## 3 · CONTRACT
256
+ ## 3 · PLAN
257
+ ### Contract
196
258
  Status: DRAFT
259
+ ### Build-strategy
260
+ Scope (may touch):
261
+ Regression floor:
197
262
  ## 4 · TESTS
198
263
  ## 5 · BUILD
199
264
  ## 6 · VERIFY
@@ -205,46 +270,9 @@ Outcome:
205
270
  """
206
271
 
207
272
 
208
- # Fast-lane fallback: the minimal TASK.md variant (sections {0,1,3,4,5,6}; §2 + §7 dropped).
209
- # Mirrors templates/TASK.fast.md.tmpl's section set (circuit-breaker parity); a deleted
210
- # templates/ never hard-fails the fast lane. Keeps the trust floor: §3 freeze-flag + Status,
211
- # §6 GATE RECORD/Outcome, §0 Anchors, §4 red-before-build, §5 Scope.
212
- _FALLBACK_TASK_FAST = """# TASK: {title}
213
-
214
- slug: {slug} · created: {date} · stage: {stage}
215
- autonomy: auto
216
- phase: ground
217
- fast: true
218
-
219
- ## 0 · GROUND
220
- Touches (files · symbols):
221
- Anchors the contract cites:
222
- Ground SHA:
223
-
224
- ## 1 · SPECIFY
225
- Feature:
226
- Must:
227
- Reject:
228
- Accept:
229
- Assumptions: ⚠ <most likely wrong> — why; if wrong: <cost>
230
-
231
- ## 3 · CONTRACT
232
- Least-sure flag surfaced at freeze:
233
- Status: DRAFT
234
-
235
- ## 4 · TESTS
236
- Plan:
237
- Tests live in: `./tests/` · MUST run red before Build.
238
-
239
- ## 5 · BUILD
240
- Scope (may touch): `./src/`
273
+ # atomic-node: the ONE template IS the lean render _FAST_SECTIONS retired with
274
+ # the lane scaffolds (the stripped blocks no longer exist in the template).
241
275
 
242
- ## 6 · VERIFY
243
- Build expectations (from §1 Accept + §3 CONTRACT):
244
- ### GATE RECORD
245
- Outcome:
246
- Reviewed by:
247
- """
248
276
 
249
277
  _DEFAULT_WIDTH = 72 # fixed width for the persisted/canonical render (RETRO.md)
250
278
 
@@ -284,12 +312,39 @@ _TAG_TOKEN_RE = re.compile(r"(M\d+|R:[A-Za-z0-9_]+)")
284
312
  # --- autonomy levels (shared: autonomy resolvers + _AUTONOMY_ORDER/cmd_autonomy) ---
285
313
  _AUTONOMY_LEVELS = ("manual", "conservative", "auto")
286
314
 
287
- # --- streams posture (shared: streams resolvers + cmd_streams) — the parallel-vs-sequential
288
- # half of the run mode (persist-run-mode); project-scoped, persisted in PROJECT.md beside autonomy ---
289
- _STREAMS_POSTURES = ("parallel", "sequential")
290
-
291
315
  # --- sensitivity taxonomy (shared: _task_sensitivity reader + cmd_freeze/status/audit) — the
292
316
  # risk-CLASS the human declares in the TASK header at freeze (risk-sensitivity-taxonomy). The
293
317
  # engine validates + surfaces a HUMAN-declared token; it NEVER classifies. A closed enum, sibling
294
- # of _AUTONOMY_LEVELS/_STREAMS_POSTURES. Consumed downstream by advisor-gate-relax (mechanical). ---
318
+ # of _AUTONOMY_LEVELS. Consumed downstream by advisor-gate-relax (mechanical). ---
295
319
  _SENSITIVITY_VALUES = ("security", "data", "architecture", "mechanical")
320
+
321
+ # --- gate mode (shared: _task_gate_mode reader + cmd_freeze's --ai-plan-verify path) — the
322
+ # two-way DIRECTION-freeze declaration (ai-plan-verify-gate): human (default) | ai-plan-verify.
323
+ # A closed 2-tuple, sibling of _AUTONOMY_LEVELS/_SENSITIVITY_VALUES — but,
324
+ # unlike them, listed in __all__: a NEW trust-loosening capability is deliberately surfaced via
325
+ # `from add_engine.constants import *`, not tucked into the _-prefixed sibling import list.
326
+ # Absent header line -> None from the resolver, treated as "human" by every caller (fail-closed
327
+ # default — never silently upgrades to the loosened path). ---
328
+ _GATE_MODES = ("human", "ai-plan-verify")
329
+
330
+ # --- skippable phases (shared: _task_skip_set reader + cmd_advance's skip pre-pass) — the
331
+ # fast-lane-skips closed tuple: the ONLY set cmd_advance's skip pre-pass ever tests `nxt`
332
+ # against (scenarios left it at phase-merge-specify: merged into specify, the retired
333
+ # header token is tolerated-and-ignored). specify/plan/tests/build/verify can NEVER be
334
+ # skipped — a structural
335
+ # exclusion (this tuple never names them), not a runtime-checked policy. Same relative order
336
+ # as PHASES. Listed in __all__ (mirrors _GATE_MODES): a new trust-loosening capability is
337
+ # deliberately surfaced via `from add_engine.constants import *`, not tucked away. ---
338
+ _SKIPPABLE_PHASES = ()
339
+
340
+ # --- format-dialect registry (shared: _dialect_gaps + the tests->build crossing warning +
341
+ # cmd_check's dialect_gap lint) — quality-floors floor 1. Closed (name, regex) pairs: a
342
+ # class matches only its FULL value shape, never prose fragments (a bare `2026-07-10`
343
+ # date must not match — the aware class requires the T separator + a zone suffix). Born
344
+ # from benchmark WV1 wm2: an arm's own suite stayed green on naive timestamps while the
345
+ # spec's own examples were Z-suffixed; the aware/naive crash shipped green. Listed in
346
+ # __all__ (mirrors _GATE_MODES): a new trust surface is deliberately surfaced. ---
347
+ _DIALECT_CLASSES = (
348
+ ("aware-iso-timestamp",
349
+ r"\d{4}-\d{2}-\d{2}T\d{2}:\d{2}(?::\d{2})?(?:\.\d+)?(?:Z|[+-]\d{2}:\d{2})"),
350
+ )
@@ -41,19 +41,18 @@ def _guideline_block() -> str:
41
41
  "\n"
42
42
  "The flow: INTAKE sizes a request into a milestone; each task runs the **specification bundle**\n"
43
43
  "(Spec+Scenarios+Contract+Tests) — ONE human approval at the frozen contract — then a\n"
44
- "self-driving build→verify run. Non-negotiable for every agent:\n"
45
- "Never weaken a test or edit a frozen contract to make a build pass; a security\n"
46
- "finding is always HARD-STOP never auto-passed.\n"
44
+ "self-driving build→verify run. Non-negotiable for every agent: Never weaken a test or edit a frozen contract\n"
45
+ "to make a build pass; a security finding is always HARD-STOP never auto-passed.\n"
46
+ "PROJECT.md `invariants:` (run/entry contracts) bind EVERY task: the artifact must hold under\n"
47
+ "the BARE declared runtime — a dependency that breaks it is a defect, never \"expected\".\n"
47
48
  "\n"
48
- "Roster (from `add-method/agents/*.md`; adopt per phase point at each phase guide, the floor above binds all):\n"
49
- "- design · setup contract · top\n"
50
- "- build · tests build · mid\n"
51
- "- verify · verify observe · top\n"
52
- "- persona · any phase, cross-cutting service · mid\n"
53
- "- advisor · any phase, cross-cutting service · top\n"
49
+ "Roster (from `add-method/agents/*.md`): TWO agents`add-worker` runs each EXECUTION beat\n"
50
+ "(the spawn names it: direction · build · verify · persona), and `add-advisor` is the second\n"
51
+ "mind it spawns to propose a plan, pressure-test a draft, or decide a delegable ambiguity so\n"
52
+ "the beat never stalls. Each loads that beat's phase guide plus the best-fit `.add/personas/`\n"
53
+ "persona (personas carry the expertise, the agent carries the discipline; the floor binds both).\n"
54
54
  "\n"
55
- "On Claude Code the `add` skill drives this loop; other agents follow the three steps. The\n"
56
- "book is in `.add/docs/`. This block is generated by `add.py sync-guidelines` — edit outside the markers.\n"
55
+ "On Claude Code the `add` skill drives this loop; other agents follow the three steps. Book: https://pilotspace.github.io/ADD/. This block is generated by `add.py sync-guidelines` — edit outside the markers.\n"
57
56
  f"{_GUIDE_END}"
58
57
  )
59
58