@tenkara/afm-linux-arm64 0.0.0-stage → 4.0.0-alpha.10

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 (277) hide show
  1. package/bin/afm +4 -0
  2. package/content/.coupling-baseline.tsv +1 -0
  3. package/content/.pending-commands.txt +2 -0
  4. package/content/CHANGELOG-archive.md +806 -0
  5. package/content/CHANGELOG.md +4320 -0
  6. package/content/PRINCIPLES.md +119 -0
  7. package/content/README-light.md +158 -0
  8. package/content/README.md +150 -0
  9. package/content/code-style/_any/file-size.md +62 -0
  10. package/content/code-style/_any/imports.md +68 -0
  11. package/content/code-style/_any/naming.md +72 -0
  12. package/content/code-style/_any/test-placement.md +57 -0
  13. package/content/code-style/nextjs-app-router/imports.md +50 -0
  14. package/content/code-style/nextjs-app-router/naming.md +50 -0
  15. package/content/code-style/prisma-postgres/error-boundary.md +55 -0
  16. package/content/code-style/prisma-postgres/imports.md +61 -0
  17. package/content/code-style/shadcn-ui/naming.md +48 -0
  18. package/content/code-style/stripe-billing/naming.md +76 -0
  19. package/content/code-style/trigger-dev-v4/imports.md +58 -0
  20. package/content/code-style/trigger-dev-v4/naming.md +49 -0
  21. package/content/code-style/trigger-dev-v4/test-placement.md +61 -0
  22. package/content/code-style/trpc-v11/error-boundary.md +51 -0
  23. package/content/code-style/trpc-v11/file-size.md +44 -0
  24. package/content/code-style/trpc-v11/naming.md +60 -0
  25. package/content/code-style/trpc-v11/test-placement.md +52 -0
  26. package/content/core/ach.md +260 -0
  27. package/content/core/afm.md +514 -0
  28. package/content/core/gotchas.md +18 -0
  29. package/content/core/prd.md +141 -0
  30. package/content/core/protocol.md +158 -0
  31. package/content/core/ust.md +65 -0
  32. package/content/guardrails/README.md +55 -0
  33. package/content/guardrails/dsl-com-ordem-obrigatoria.md +47 -0
  34. package/content/guardrails/exaustividade-de-union.md +48 -0
  35. package/content/guardrails/fronteira-de-import.md +57 -0
  36. package/content/hooks/README.md +70 -0
  37. package/content/interview/bootstrap.md +417 -0
  38. package/content/interview/promotion.md +115 -0
  39. package/content/interview/refactor.md +379 -0
  40. package/content/interview/triggers.md +107 -0
  41. package/content/modules/nextjs-app-router/ach.patch.md +44 -0
  42. package/content/modules/nextjs-app-router/gotchas.seed.md +78 -0
  43. package/content/modules/nextjs-app-router/rules.patch.md +35 -0
  44. package/content/modules/prisma-postgres/ach.patch.md +65 -0
  45. package/content/modules/prisma-postgres/rules.patch.md +28 -0
  46. package/content/modules/shadcn-ui/ach.patch.md +42 -0
  47. package/content/modules/stripe-billing/ach.patch.md +46 -0
  48. package/content/modules/stripe-billing/gotchas.seed.md +73 -0
  49. package/content/modules/stripe-billing/rules.patch.md +30 -0
  50. package/content/modules/trigger-dev-v4/ach.patch.md +64 -0
  51. package/content/modules/trigger-dev-v4/gotchas.seed.md +53 -0
  52. package/content/modules/trigger-dev-v4/rules.patch.md +35 -0
  53. package/content/modules/trpc-v11/ach.patch.md +56 -0
  54. package/content/modules/trpc-v11/rules.patch.md +34 -0
  55. package/content/modules/vireya-ui/ach.patch.md +85 -0
  56. package/content/modules/vireya-ui/gotchas.seed.md +98 -0
  57. package/content/modules/vireya-ui/rules.patch.md +36 -0
  58. package/content/ops/adr.md +54 -0
  59. package/content/ops/analyze.md +130 -0
  60. package/content/ops/clarify.md +86 -0
  61. package/content/ops/deliver.md +209 -0
  62. package/content/ops/diagnose.md +143 -0
  63. package/content/ops/evolve.md +366 -0
  64. package/content/ops/export-template.md +97 -0
  65. package/content/ops/generalize.md +117 -0
  66. package/content/ops/gotcha.md +46 -0
  67. package/content/ops/plan.md +61 -0
  68. package/content/ops/policy.md +61 -0
  69. package/content/ops/promote.md +72 -0
  70. package/content/ops/protocol.md +51 -0
  71. package/content/ops/reconcile.md +44 -0
  72. package/content/ops/reflect.md +182 -0
  73. package/content/ops/remediate.md +143 -0
  74. package/content/ops/restructure.md +142 -0
  75. package/content/ops/rule.md +170 -0
  76. package/content/ops/specify.md +62 -0
  77. package/content/ops/tasks.md +67 -0
  78. package/content/ops/update.md +252 -0
  79. package/content/ops/verify.md +67 -0
  80. package/content/patterns/adapter.md +46 -0
  81. package/content/patterns/facade.md +47 -0
  82. package/content/patterns/factory.md +46 -0
  83. package/content/patterns/null-object.md +55 -0
  84. package/content/patterns/result-vs-exception.md +52 -0
  85. package/content/patterns/strategy.md +45 -0
  86. package/content/patterns/template-method-vs-composition.md +50 -0
  87. package/content/questions/adr.questions.yaml +14 -0
  88. package/content/questions/analyze.questions.yaml +12 -0
  89. package/content/questions/bootstrap-mapping.questions.yaml +14 -0
  90. package/content/questions/bootstrap-rules.questions.yaml +10 -0
  91. package/content/questions/bootstrap-stack.questions.yaml +23 -0
  92. package/content/questions/clarify.questions.yaml +10 -0
  93. package/content/questions/code-style.questions.yaml +12 -0
  94. package/content/questions/confirm.questions.yaml +12 -0
  95. package/content/questions/deliver.questions.yaml +23 -0
  96. package/content/questions/evolve.questions.yaml +15 -0
  97. package/content/questions/export-template-apply.questions.yaml +11 -0
  98. package/content/questions/export-template.questions.yaml +23 -0
  99. package/content/questions/gates.questions.yaml +27 -0
  100. package/content/questions/generalize.questions.yaml +13 -0
  101. package/content/questions/gotcha.questions.yaml +11 -0
  102. package/content/questions/init-template.questions.yaml +10 -0
  103. package/content/questions/init.questions.yaml +41 -0
  104. package/content/questions/plan.questions.yaml +14 -0
  105. package/content/questions/refactor.questions.yaml +23 -0
  106. package/content/questions/reflect.questions.yaml +13 -0
  107. package/content/questions/remediate.questions.yaml +27 -0
  108. package/content/questions/restructure.questions.yaml +15 -0
  109. package/content/questions/rf-mapping.questions.yaml +12 -0
  110. package/content/questions/rule-scope.questions.yaml +12 -0
  111. package/content/questions/rule.questions.yaml +12 -0
  112. package/content/questions/specify.questions.yaml +23 -0
  113. package/content/questions/update-artifacts.questions.yaml +10 -0
  114. package/content/questions/update-strings.questions.yaml +14 -0
  115. package/content/questions/update.questions.yaml +10 -0
  116. package/content/questions/verify.questions.yaml +9 -0
  117. package/content/roles/executor.md +18 -0
  118. package/content/roles/explorer.md +22 -0
  119. package/content/roles/reviewer.md +23 -0
  120. package/content/rubrics/enum-vs-union-vs-branded.md +40 -0
  121. package/content/rubrics/episodic-vs-semantic-boundary.md +37 -0
  122. package/content/rubrics/error-classification.md +98 -0
  123. package/content/rubrics/failure-classification.md +111 -0
  124. package/content/rubrics/negative-filters.md +38 -0
  125. package/content/rubrics/solid-triggers.md +119 -0
  126. package/content/rubrics/template-vs-streaming-precedence.md +34 -0
  127. package/content/rubrics/validation-boundary.md +94 -0
  128. package/content/rubrics/when-to-create-dsl.md +65 -0
  129. package/content/rubrics/when-to-create-lib.md +49 -0
  130. package/content/rubrics/when-to-create-module.md +39 -0
  131. package/content/rubrics/when-to-evolve-methodology.md +62 -0
  132. package/content/skills/adr.md +42 -0
  133. package/content/skills/analyze.md +28 -0
  134. package/content/skills/clarify.md +28 -0
  135. package/content/skills/deliver.md +26 -0
  136. package/content/skills/diagnose.md +42 -0
  137. package/content/skills/evolve.md +43 -0
  138. package/content/skills/export-template.md +37 -0
  139. package/content/skills/generalize.md +31 -0
  140. package/content/skills/gotcha.md +40 -0
  141. package/content/skills/init.md +77 -0
  142. package/content/skills/plan.md +28 -0
  143. package/content/skills/policy.md +25 -0
  144. package/content/skills/promote.md +39 -0
  145. package/content/skills/protocol.md +41 -0
  146. package/content/skills/reconcile.md +45 -0
  147. package/content/skills/refactor.md +79 -0
  148. package/content/skills/reflect.md +43 -0
  149. package/content/skills/remediate.md +33 -0
  150. package/content/skills/restructure.md +46 -0
  151. package/content/skills/rule.md +43 -0
  152. package/content/skills/specify.md +28 -0
  153. package/content/skills/tasks.md +24 -0
  154. package/content/skills/update.md +58 -0
  155. package/content/skills/verify.md +29 -0
  156. package/content/templates/adr.template.md +51 -0
  157. package/content/templates/evolution-report.template.md +132 -0
  158. package/content/templates/feature-plan.template.md +84 -0
  159. package/content/templates/feature-research.template.md +56 -0
  160. package/content/templates/feature-spec.template.md +86 -0
  161. package/content/templates/feature-tasks.induced.template.md +91 -0
  162. package/content/templates/feature-tasks.template.md +82 -0
  163. package/content/templates/focus.template.md +30 -0
  164. package/content/templates/gotcha.template.md +31 -0
  165. package/content/templates/guardrail-runner.template.md +97 -0
  166. package/content/templates/guardrail.template.md +63 -0
  167. package/content/templates/learning.template.md +40 -0
  168. package/content/templates/procedure.template.md +47 -0
  169. package/content/templates/protocols/p1.md +29 -0
  170. package/content/templates/protocols/p2.md +28 -0
  171. package/content/templates/protocols/p3.md +47 -0
  172. package/content/templates/research.template.md +50 -0
  173. package/content/templates/session-handoff.template.md +58 -0
  174. package/content/templates/us.template.md +39 -0
  175. package/content/tools/gate/core-rules/PLUGIN-13-secrets.sh +36 -0
  176. package/content/tools/gate/core-rules/PLUGIN-21-code-language.sh +27 -0
  177. package/content/tools/gate/core-rules/PLUGIN-35-gate-complete.sh +19 -0
  178. package/content/tools/gate/core-rules/PLUGIN-36-absolute-path.sh +38 -0
  179. package/content/tools/gate/core-rules/PLUGIN-37-prose-language.sh +56 -0
  180. package/content/tools/gate/core-rules/PLUGIN-38-parser-marker.sh +82 -0
  181. package/content/tools/gate/core-rules/PLUGIN-39-frontmatter-ops.sh +325 -0
  182. package/content/tools/gate/core-rules/PLUGIN-40-dead-reference.sh +74 -0
  183. package/content/tools/gate/core-rules/README.md +55 -0
  184. package/content/tools/gate/guardrails.sh +740 -0
  185. package/content/tools/gate/lib/ratchet.sh +119 -0
  186. package/content/tools/gate/lib/scope.sh +85 -0
  187. package/content/tools/gate/ratchet.seed.tsv +1 -0
  188. package/content/tools/gate/rules/README.md +50 -0
  189. package/package.json +19 -5
  190. package/plugin/agy/hooks.json +29 -0
  191. package/plugin/agy/mcp_config.json +7 -0
  192. package/plugin/agy/plugin.json +6 -0
  193. package/plugin/agy/skills/afm-adr/SKILL.md +48 -0
  194. package/plugin/agy/skills/afm-analyze/SKILL.md +34 -0
  195. package/plugin/agy/skills/afm-clarify/SKILL.md +34 -0
  196. package/plugin/agy/skills/afm-deliver/SKILL.md +30 -0
  197. package/plugin/agy/skills/afm-diagnose/SKILL.md +46 -0
  198. package/plugin/agy/skills/afm-evolve/SKILL.md +49 -0
  199. package/plugin/agy/skills/afm-export-template/SKILL.md +43 -0
  200. package/plugin/agy/skills/afm-generalize/SKILL.md +37 -0
  201. package/plugin/agy/skills/afm-gotcha/SKILL.md +46 -0
  202. package/plugin/agy/skills/afm-init/SKILL.md +81 -0
  203. package/plugin/agy/skills/afm-plan/SKILL.md +34 -0
  204. package/plugin/agy/skills/afm-policy/SKILL.md +29 -0
  205. package/plugin/agy/skills/afm-promote/SKILL.md +43 -0
  206. package/plugin/agy/skills/afm-protocol/SKILL.md +45 -0
  207. package/plugin/agy/skills/afm-reconcile/SKILL.md +49 -0
  208. package/plugin/agy/skills/afm-refactor/SKILL.md +83 -0
  209. package/plugin/agy/skills/afm-reflect/SKILL.md +49 -0
  210. package/plugin/agy/skills/afm-remediate/SKILL.md +39 -0
  211. package/plugin/agy/skills/afm-restructure/SKILL.md +52 -0
  212. package/plugin/agy/skills/afm-rule/SKILL.md +49 -0
  213. package/plugin/agy/skills/afm-specify/SKILL.md +34 -0
  214. package/plugin/agy/skills/afm-tasks/SKILL.md +28 -0
  215. package/plugin/agy/skills/afm-update/SKILL.md +64 -0
  216. package/plugin/agy/skills/afm-verify/SKILL.md +35 -0
  217. package/plugin/claude-code/.claude-plugin/marketplace.json +15 -0
  218. package/plugin/claude-code/.claude-plugin/plugin.json +9 -0
  219. package/plugin/claude-code/.mcp.json +7 -0
  220. package/plugin/claude-code/agents/afm-executor.md +18 -0
  221. package/plugin/claude-code/agents/afm-explorer.md +20 -0
  222. package/plugin/claude-code/agents/afm-reviewer.md +21 -0
  223. package/plugin/claude-code/hooks/hooks.json +85 -0
  224. package/plugin/claude-code/skills/adr/SKILL.md +48 -0
  225. package/plugin/claude-code/skills/analyze/SKILL.md +34 -0
  226. package/plugin/claude-code/skills/clarify/SKILL.md +34 -0
  227. package/plugin/claude-code/skills/deliver/SKILL.md +30 -0
  228. package/plugin/claude-code/skills/diagnose/SKILL.md +46 -0
  229. package/plugin/claude-code/skills/evolve/SKILL.md +49 -0
  230. package/plugin/claude-code/skills/export-template/SKILL.md +43 -0
  231. package/plugin/claude-code/skills/generalize/SKILL.md +37 -0
  232. package/plugin/claude-code/skills/gotcha/SKILL.md +46 -0
  233. package/plugin/claude-code/skills/init/SKILL.md +81 -0
  234. package/plugin/claude-code/skills/plan/SKILL.md +34 -0
  235. package/plugin/claude-code/skills/policy/SKILL.md +29 -0
  236. package/plugin/claude-code/skills/promote/SKILL.md +43 -0
  237. package/plugin/claude-code/skills/protocol/SKILL.md +45 -0
  238. package/plugin/claude-code/skills/reconcile/SKILL.md +49 -0
  239. package/plugin/claude-code/skills/refactor/SKILL.md +83 -0
  240. package/plugin/claude-code/skills/reflect/SKILL.md +49 -0
  241. package/plugin/claude-code/skills/remediate/SKILL.md +39 -0
  242. package/plugin/claude-code/skills/restructure/SKILL.md +52 -0
  243. package/plugin/claude-code/skills/rule/SKILL.md +49 -0
  244. package/plugin/claude-code/skills/specify/SKILL.md +34 -0
  245. package/plugin/claude-code/skills/tasks/SKILL.md +28 -0
  246. package/plugin/claude-code/skills/update/SKILL.md +64 -0
  247. package/plugin/claude-code/skills/verify/SKILL.md +35 -0
  248. package/plugin/opencode/afm/index.js +245 -0
  249. package/plugin/opencode/afm/tui.js +21 -0
  250. package/plugin/opencode/agents/afm-executor.md +39 -0
  251. package/plugin/opencode/agents/afm-explorer.md +92 -0
  252. package/plugin/opencode/agents/afm-reviewer.md +93 -0
  253. package/plugin/opencode/skills/afm-adr/SKILL.md +48 -0
  254. package/plugin/opencode/skills/afm-analyze/SKILL.md +34 -0
  255. package/plugin/opencode/skills/afm-clarify/SKILL.md +34 -0
  256. package/plugin/opencode/skills/afm-deliver/SKILL.md +30 -0
  257. package/plugin/opencode/skills/afm-diagnose/SKILL.md +46 -0
  258. package/plugin/opencode/skills/afm-evolve/SKILL.md +49 -0
  259. package/plugin/opencode/skills/afm-export-template/SKILL.md +43 -0
  260. package/plugin/opencode/skills/afm-generalize/SKILL.md +37 -0
  261. package/plugin/opencode/skills/afm-gotcha/SKILL.md +46 -0
  262. package/plugin/opencode/skills/afm-init/SKILL.md +81 -0
  263. package/plugin/opencode/skills/afm-plan/SKILL.md +34 -0
  264. package/plugin/opencode/skills/afm-policy/SKILL.md +29 -0
  265. package/plugin/opencode/skills/afm-promote/SKILL.md +43 -0
  266. package/plugin/opencode/skills/afm-protocol/SKILL.md +45 -0
  267. package/plugin/opencode/skills/afm-reconcile/SKILL.md +49 -0
  268. package/plugin/opencode/skills/afm-refactor/SKILL.md +83 -0
  269. package/plugin/opencode/skills/afm-reflect/SKILL.md +49 -0
  270. package/plugin/opencode/skills/afm-remediate/SKILL.md +39 -0
  271. package/plugin/opencode/skills/afm-restructure/SKILL.md +52 -0
  272. package/plugin/opencode/skills/afm-rule/SKILL.md +49 -0
  273. package/plugin/opencode/skills/afm-specify/SKILL.md +34 -0
  274. package/plugin/opencode/skills/afm-tasks/SKILL.md +28 -0
  275. package/plugin/opencode/skills/afm-update/SKILL.md +64 -0
  276. package/plugin/opencode/skills/afm-verify/SKILL.md +35 -0
  277. package/README.md +0 -3
@@ -0,0 +1,417 @@
1
+ ---
2
+ type: interview
3
+ description: The greenfield interview that materializes a new instance.
4
+ load: cold
5
+ ---
6
+
7
+ # Bootstrap — interview script
8
+
9
+ > This doc is an instruction **for the agent** when the operator runs `afm init` (or asks for something
10
+ > equivalent, like "set up the project doc"). The CLI materializes everything a repository can answer; this
11
+ > script runs the interview for what only the operator knows, a 7-step one, and fills the result into `docs/`.
12
+
13
+ ---
14
+
15
+ ## Invariant principles (do not violate)
16
+
17
+ **AFM universals**: see the single canonical source, `afm path PRINCIPLES` § Universals (§1-8). They apply
18
+ here. In particular:
19
+
20
+ - **#2** (discover-first): `afm init --mechanical` already scanned the repo. Where it found a signal (a
21
+ manifest with real dependencies, existing CI or hooks), bring it as the recommendation BEFORE you offer
22
+ options. Do not ask a blank question about what the repo already shows.
23
+ - **#4** (`[TBD]` beats invention): bootstrap never guesses the operator's answer.
24
+ - **#5** (do not invent an entity, rule or module): write only what the operator said.
25
+ - **#8** (questions are data, recommendation-first): every confirmation or selection with closed options
26
+ goes through `afm ask <op>`, whose questions live in `content/questions/<op>.questions.yaml` and carry
27
+ the recommended option. Free text is only for genuinely open questions (describe the product or the pain,
28
+ list entities, describe a flow).
29
+
30
+ **Specific to the bootstrap interview** (rules for *running* the interview, not for the methodology):
31
+
32
+ 1. **A pre-filled suggestion beats a blank question, wherever a signal exists (#2 + #8).** The report of
33
+ `afm init --mechanical` is the signal. Every suggestion still needs the operator's confirmation: the
34
+ stack is the operator's decision, so nothing is final without their agreement. Open free-text
35
+ questions are only for what you cannot infer: product, pain, persona, entities, flows. Ask one thing
36
+ at a time.
37
+ 2. **Validate before you move on.** After each free-text answer, restate it in one line, then
38
+ `afm ask confirm --scope <step-slug>` (for example `step0-product`). Move on only after `Yes, exact`
39
+ (or after you process the fix).
40
+ 3. **Record what the operator said, nothing more.** If they described 3 RFs, write 3 RFs. Do not add
41
+ "RF-04 security" because "every project needs it" (universal #5 in the interview context).
42
+ 4. **At the end, list every `[TBD]`.** The operator decides whether to fill them in now or later.
43
+
44
+ ---
45
+
46
+ ## Initial setup (before step 1)
47
+
48
+ 1. `afm preflight`. Exit 3 means there is no `docs/.afm-version`: a real greenfield, continue. Any other
49
+ exit means the project is already bootstrapped: **do not run bootstrap again**. The atomic ops stay
50
+ available (`afm gotcha`, `afm adr`, `afm rule`), and a newer version is `afm update`.
51
+ 2. **Detect the `docs/.template` marker.** If it exists, go to § Alternate branch below.
52
+ 3. **Ask the two decisions the mechanical pass needs:** `afm ask init` (harnesses whose instruction files
53
+ the project covers, and the product's string language). The language is a **product** decision, not a
54
+ rule: it goes to `prd.md § 11.1`, is declared and never enforced, and is what makes the english-first
55
+ exception mechanical. Without it, a later language migration (`afm update`) cannot tell an artifact
56
+ from a string the user reads, and it would translate the UI. `Decide later` records `[TBD]`.
57
+ The same `afm ask init` asks the artifact language (`en`, `pt-BR`, `es`, `other`), and
58
+ `afm init --mechanical` records a tag itself through `afm config set language.artifacts <tag>` (the
59
+ CLI validates the tag and edits `.afm/config.toml`). On `other` it prints that command: run it with the
60
+ tag the owner names. Never write the key by hand.
61
+ 4. **Materialize:** `afm init --mechanical` (add `--dry-run` first to preview). It creates, and never
62
+ overwrites a file the operator already has:
63
+ - `docs/{prd,ach,afm,ust}.md` from the shipped skeletons, the project name from the manifest and every
64
+ placeholder filled by what the code answers, `[TBD]` where it does not;
65
+ - the five rule constants **measured, not assumed**: the source root and extension (the root with the
66
+ most non-test files), the file-size limit, the domain-function prefix and its subfolder. The report
67
+ prints each as `measured<TAB><constant><TAB><value><TAB><evidence>`;
68
+ - empty `docs/gotchas/` and `docs/rules/`, `docs/adr/0000-template.md`, every rubric and every pattern
69
+ the index lists (no hand-written list of names: `afm index --type rubric` is the list);
70
+ - `AGENTS.md` (the tool-agnostic file, canonical) and one stub per answered harness that imports it;
71
+ - `docs/.afm-version` last, so a run that stops half way can simply be run again.
72
+ The gate is the CLI (`afm gate`): nothing is copied into `docs/tools/` for it.
73
+ 5. **Read the report back to the operator** and go to step 0. A project that maintains the plugin itself
74
+ calls the shipped content through `afm path` instead of copying it (hard rule 34, one canonical source).
75
+
76
+ ---
77
+
78
+ ## Alternate branch — from-template (active only if setup detected `docs/.template`)
79
+
80
+ Scenario: the project comes from an architectural template (a clone of a starter with an inherited
81
+ `ach.md`, `afm.md` and `gotchas/`). Stack, rules and architecture are already decided. The interview
82
+ covers only the product.
83
+
84
+ 1. **Read the metadata** from `docs/.template` (JSON). Accept an empty file with the fallback
85
+ `{"template-name": "<unknown>", "template-version": "<unknown>", "exported-from-afm": "<unknown>"}`.
86
+ If metadata is missing, record it as unknown; do not invent it (#5).
87
+ 2. **Confirm the branch:** `afm ask init-template`. `Product only` runs steps 0, 3, 6 short and 7 adapted;
88
+ `Full interview` follows the standard flow and ignores the marker for this session (it stays on disk).
89
+ 3. On `Product only`, run `afm ask init` and `afm init --mechanical` as in setup: it writes the product
90
+ docs and the version marker and leaves the inherited `ach.md`, `afm.md` and `gotchas/` untouched. Then
91
+ **load the technical context** by reading those three inherited files (read-only). Note the stack
92
+ internally, to cite component types from `ach.md § 3.1` at closing.
93
+ 4. Tell the operator: *"Stack, architecture and rules are already set in the template. I will ask only
94
+ about the product."* Go to step 0.
95
+
96
+ ### Step subset in from-template mode
97
+
98
+ - **Step 0** (product, pain, persona, metric): full, materializes `prd.md`.
99
+ - **Step 3** (critical flows): full, materializes `ust.md`.
100
+ - **Step 6**, **short version**: one question, `afm ask gates` pre-checked from the inherited DoD in
101
+ `afm.md § 6`. The operator keeps it or lists the edits.
102
+ - **Step 7**, **adapted**: if the inherited `gotchas/` has entries, keep them unchanged and offer to add a
103
+ file (do not erase prior discovery, #5). If it is empty, follow the standard flow. Inherited `adr/`
104
+ files stay. New ADRs are born on demand through `afm adr`.
105
+
106
+ **Explicit skip:** steps 1 (stack), 2 (data model), 4 (component mapping) and 5 (inherited rules). All of
107
+ that is in the template. Asking again is redundant, and it would break principle #5 if the agent tried to
108
+ "validate" what was already decided.
109
+
110
+ ### Adapted closing (when from-template)
111
+
112
+ 1. **List the pending `[TBD]` items** (usually few: only steps 0 and 3). The operator replies with the ones
113
+ to fill in now.
114
+ 2. **Quick check:** the PRD has §1 + §2 + §3 + at least one RF. The UST has at least US-001. The inherited
115
+ `ach.md`, `afm.md` and `gotchas/` are unchanged. `docs/rubrics/` exists: if it is missing (a template
116
+ exported before 3.0.0-rc.5), `afm init --mechanical` copies it without touching what is inherited.
117
+ 3. **Add the inheritance line** under the version `afm init` wrote into `docs/.afm-version`:
118
+ ```
119
+ <version of the afm in use>
120
+
121
+ Inherited from template "<template-name>" v<template-version> (exported with afm v<exported-from-afm>)
122
+ ```
123
+ 4. **Origin note.** Add one bullet in the `## Canonical documentation` section of `AGENTS.md`: the project
124
+ started from architectural template `<template-name>` v<template-version>; stack, rules and
125
+ architecture are inherited (`docs/ach.md`, `docs/afm.md`, `docs/gotchas/`).
126
+ 5. **Generate the indexes:** `afm index --materialize`, then `afm index --check`.
127
+ 6. **Suggested commit:**
128
+ ```
129
+ docs(afm): bootstrap from-template — template "<template-name>" v<template-version>
130
+
131
+ Materializes PRD/UST from a product-focused interview.
132
+ Architecture and rules inherited from the template, untouched.
133
+ Open [TBD] items: <list>.
134
+ ```
135
+ 7. **Reminder for the operator:** the bootstrap is done; `docs/` is now a living source that evolves
136
+ through passive reconcile (every session watches the signals in `afm path interview/triggers` and
137
+ proposes edits); the atomic ops (`afm gotcha`, `afm adr`, `afm rule`, `afm promote`, `afm specify`,
138
+ `afm plan`, `afm tasks`, `afm clarify`, `afm analyze`) stay available on demand. The
139
+ single test for memory versus doc: *if another dev needs it to avoid breaking something, it is a doc.*
140
+
141
+ ### Anti-patterns of the from-template branch
142
+
143
+ - ❌ Re-check the inherited stack or rules through a re-ask. It breaks trust in the template; the operator
144
+ is responsible for keeping the template current.
145
+ - ❌ Modify the inherited `ach.md`, `afm.md` or `gotchas/` during this branch. They are read-only in this
146
+ session. Changes come through passive reconcile or the on-demand ops.
147
+ - ❌ Invent product details if the operator did not answer step 0 or 3. Use `[TBD]` (#4 and #5).
148
+ - ❌ Skip marker detection in setup: the branch only activates if setup confirmed that `docs/.template`
149
+ exists.
150
+
151
+ ---
152
+
153
+ ## Step 0 — Problem context (becomes PRD §1, §2, §3)
154
+
155
+ **Goal:** understand the product, the pain point and the persona. Materializes into `prd.md`.
156
+
157
+ **Questions (free text; a genuine description does not fit closed options):**
158
+
159
+ 1. *"In 3 sentences, what product are you building, and who is the user?"*
160
+ 2. *"What hurts today in this user's flow, without your product?"*
161
+ 3. *"What is the success criterion for a session? How do you know the user's job is done?"*
162
+
163
+ **Validation after each answer:** restate it ("I restated it as: «X»"), then `afm ask confirm --scope step0-q<N>`. Move to the next question only after `Yes, exact` (or after you process the fix).
164
+
165
+ **Materializes into `prd.md`:**
166
+
167
+ - §1 Summary: 1 paragraph drawn from answer 1.
168
+ - §2 Problem & Opportunity: the pain (answer 2) plus why now (`[TBD]` if the operator did not say).
169
+ - §3 Persona: extracted from answer 1.
170
+ - §6 MVP acceptance criteria + metric: derived from answer 3.
171
+ - §11.1 App-facing string language: the answer of `afm ask init` from setup, or `[TBD]`.
172
+
173
+ **Do not invent:** market size; target companies, if none was named; "why now", if no reason was given.
174
+
175
+ ---
176
+
177
+ ## Step 1 — Tech stack (becomes ACH §1, §2)
178
+
179
+ ### 1.0 — The stack scan is already done (gap-driven #2: infer before you ask)
180
+
181
+ `afm init --mechanical` enumerated the manifests, read each one and printed the stacks per manifest, **and
182
+ where each was found**. Do not re-derive it. A workspace root declares the tooling and none of the stacks,
183
+ so a root-only scan answers "no stacks here" for a repository full of them; the report is per manifest for
184
+ that reason. A stack present in one package out of eight is a true finding and a different fact from a
185
+ stack present everywhere: the operator needs the second half to judge the first. Report the union of the
186
+ stacks and say **where** each was found. `afm detect --stacks` repeats the scan on demand.
187
+
188
+ - **Signal found:** each layer comes with its evidence (the installed dependency), not with popularity.
189
+ The question becomes a **confirmation of a suggestion**, not a blank choice. A layer with no signal gets
190
+ no guessed recommendation: it stays blank for the operator.
191
+ - **Nothing found** (empty repo, no stack named in step 0): ask the layers as open questions in plain
192
+ conversation (web framework, API layer, DB + ORM, async tasks), with sensible defaults offered where one
193
+ exists.
194
+
195
+ ### 1.1 — Confirm the stack and the modules
196
+
197
+ Ask `afm ask bootstrap-stack` (questions in `content/questions/bootstrap-stack.questions.yaml`): the stack
198
+ as reported, and whether to apply the detected opt-in modules. `Leave as TBD` marks the layer `[TBD]` in
199
+ `ach.md` and says: *"I leave the pending layers as `[TBD]` instead of recommending now; a recommendation
200
+ works better once you have also defined what you do NOT want."* An answer outside the options is recorded
201
+ as given, without inventing a module.
202
+
203
+ **Materializes into `ach.md`:** §1 Macro architecture (an ASCII diagram of the layers based on the fixed
204
+ stack; an open component is a `[TBD]` box) and §2 Folders (a tree following the stack's conventions).
205
+
206
+ **Opt-in modules.** `afm index --triggers` lists one row per module with its stack and its `detect`
207
+ command; a zero exit means the stack is present. Apply every file under `modules/<stack>/` (read each
208
+ with `afm path modules/<stack>/<file>`) for each hit, unless the operator opted the module out. Do not
209
+ maintain a list of modules here: it was a hand-written list of six stacks until 3.31.0 while seven
210
+ existed, because the prose that named the modules was not the directory that held them. A stack with no
211
+ module (Nest, FastAPI, BullMQ) is `[TBD]` in the component types of `core/ach`. **Do not invent a
212
+ module**: promote it to the shipped content later (`afm promote`) once the learning is proven. A
213
+ `gotchas.seed` is a **commented reference** only, never an active gotcha: the project's `docs/gotchas/`
214
+ starts empty.
215
+
216
+ **Code-style seeds are opt-in item by item, never wholesale.** For each stack that hit, list the files
217
+ `afm index --type code-style` reports under `code-style/<stack>/` and `code-style/_any/`. Unlike a module
218
+ (applied whole, opt-out), a code-style file is one house convention its author observed in a single
219
+ project: naming, test placement, a file-size ceiling, an error-boundary shape, an import order. It is never
220
+ a fact of the stack. Applying it wholesale would rebuild the defect the split fixed, a `(mandatory)`
221
+ naming convention the operator never got a say in. State what each file decides in one line, then ask
222
+ `afm ask code-style`. **Materialize only what the operator marks**, verbatim, into
223
+ `docs/code-style/<stack>/<concern>.md`. An unmarked item is written nowhere: not as a note, not as a
224
+ commented-out stub. **Default = nothing marked, nothing applies**: the opposite default from modules and
225
+ rubrics, and deliberately so. Silent opt-in is the defect, not a shortcut around it.
226
+
227
+ ---
228
+
229
+ ## Step 2 — Core data model (becomes PRD §10 + ACH §1)
230
+
231
+ **Question (free text):** *"List the 3-5 core entities of the product and the relation between them, one
232
+ sentence each."*
233
+
234
+ **Materializes:** a mini ER diagram in ASCII into ACH §1, and one PRD §10 Glossary entry per entity.
235
+
236
+ **Validate:** show the restated ASCII ER diagram, then `afm ask confirm --scope step2-er`.
237
+
238
+ **Do not invent** attributes the operator did not mention, nor a relation they did not describe.
239
+
240
+ ---
241
+
242
+ ## Step 3 — Critical flows (becomes UST + PRD §4)
243
+
244
+ **Questions (one at a time):**
245
+
246
+ 1. *"Describe the main user flow, from the first click to the success state."* Materializes as **US-001**
247
+ in `ust.md`, with a happy-path Gherkin scenario.
248
+ 2. *"And the most likely error flow?"* Materializes as **US-002** or an extra scenario in US-001
249
+ (depending on scope).
250
+
251
+ **For each US written, ask** `afm ask rf-mapping --scope <us-id>` (for example `us-001`): which PRD RF it
252
+ implements. A new RF is drafted from the story as RF-01, RF-02 and so on in PRD §4; an existing one is
253
+ named by the operator; `Not yet` records `[TBD]`.
254
+
255
+ ---
256
+
257
+ ## Step 4 — Mapping to the meta-framework (becomes ACH §3)
258
+
259
+ **Present the generic component types:**
260
+
261
+ > "AFM works with 5 component types:
262
+ > 1. **Procedure-like**: sync request/response, under 5s.
263
+ > 2. **Domain-like**: a pure business-rule function.
264
+ > 3. **Task-like**: async, retry-safe.
265
+ > 4. **Lib-like**: an isolated, publishable package.
266
+ > 5. **Adapter-like**: a typed port implementation (registries, storages, etc).
267
+ >
268
+ > In your stack:
269
+ > - Procedure-like = {{tool inferred from step 1, e.g. a tRPC procedure}}
270
+ > - Domain-like = {{e.g. an exported TS function with the measured domain prefix}}
271
+ > - Task-like = {{e.g. a Trigger.dev v4 task}}
272
+ > - Lib-like = {{e.g. a folder under the source root with no framework import}}
273
+ > - Adapter-like = {{e.g. a port implementation under `<src-path>/lib/<provider>/<adapter>`}}"
274
+
275
+ **Confirm:** `afm ask bootstrap-mapping`. **Materializes into `ach.md` §3.1** with the stack's concrete
276
+ naming convention.
277
+
278
+ ---
279
+
280
+ ## Step 5 — Inherited and new rules (becomes AFM §3)
281
+
282
+ **The inherited rules are already in `afm.md § 3`**: `afm init --mechanical` copied every one. List them
283
+ for the operator with the numbers and headlines **read from `afm.md § 3`**, not from memory. The file
284
+ numbers slots up to 21; four of them (3, 8, 9, 14) are **demoted principles** that live in § 1.3 and carry
285
+ no trigger, so there is nothing to opt out of, and slot 21 is **INALIENABLE**. **Do not renumber to close
286
+ the gap**: the number is the rule's identity, and `afm doctor` compares the instance against the plugin by
287
+ number.
288
+
289
+ Ask `afm ask bootstrap-rules`. **Default = keep all.** For each rule the operator opts out of, ask why in
290
+ free text and record it with `afm rule na <id> --reason "<why>"`: the index line in `afm.md § 3` becomes
291
+ "N/A — <reason>" and the number stays. **Rules marked `INALIENABLE` do NOT enter this question.** They are
292
+ not silently omitted: list them, with a note that they apply to every project and are not opt-out. Offering
293
+ an opt-out and then refusing it would be worse than not offering one at all (`afm rule na` refuses them).
294
+
295
+ ### Rule constants: measured first, then proposed, never assumed
296
+
297
+ Five values belong to the **operator, not the framework**: the line limit (rule 6), the domain-function
298
+ prefix (rule 7), the source root, the domain-function subfolder inside it and the source-file extension. A
299
+ default disguised as best practice is invention (#5), and a rule whose constant the owner did not choose is
300
+ a rule the owner turns off at first friction. `afm init --mechanical` already **measured** them from the
301
+ code, and its report carries each value with the evidence. Propose each one with that measurement
302
+ attached: *"your file p90 is N lines, I propose a limit of N rounded up"*; *"your code already uses
303
+ `<prefix>` in X files, I propose it as the domain prefix"*; *"domain-prefixed functions already live under
304
+ `<subfolder>`"*. The operator accepts or changes each.
305
+
306
+ - **Greenfield project (nothing to measure):** the report proposes `300`, `domain_`, `src`, `ts` (or the
307
+ extension the chosen stack generates) and `domain`. **State that these are template defaults**, not a
308
+ measurement. The difference between an assumed default and a chosen default decides whether the rule
309
+ survives.
310
+ - **The operator does not answer, for any of the five:** the constant stays `[TBD]`. **Say that the rule
311
+ or path has no trigger until someone fills it in** (#4). Do not invent a value "to make it work": a
312
+ wrong literal replaced by an unfilled placeholder still fails silently.
313
+
314
+ **Free-text question:** *"Does your team have a specific rule that applies from day one?"* Examples:
315
+ "every PR needs 2 reviewers", "commits are always in English", "no direct commits to main". A ready-made
316
+ trigger for the last one: `git rev-parse --abbrev-ref HEAD | grep -qE '^(main|master)$'`. If yes, write it
317
+ with `afm rule` (numbers 18–29 are reserved for the template's universal rules; the command picks the next
318
+ free number). Each new rule MUST have a mechanical trigger; without one it becomes a principle in §1.3.
319
+
320
+ ---
321
+
322
+ ## Step 6 — Validation rituals (becomes AFM §6 + §6.1)
323
+
324
+ **Signal first (gap-driven #2).** The `afm init` report lists the checks the repo already runs (CI on a
325
+ PR, a pre-push hook, a lint-staged entry, a script, a Makefile target) as `check<TAB><check><TAB><stage>`.
326
+ Bring them **pre-marked**: CI on a PR maps to the merge DoD, a pre-push hook to pre-push. The question
327
+ becomes a confirmation. No signal means nothing is pre-marked.
328
+
329
+ **Ask `afm ask gates`** (two multi-selects, because DoD and pre-push are independent lists). Marking
330
+ nothing in either leaves that section `[TBD]` with the note "define before the first merge". If the
331
+ pre-push sequence needs a specific order or a custom command, ask a follow-up in free text: *"Any extra
332
+ command or specific order for pre-push?"*
333
+
334
+ **Materializes into `afm.md`:**
335
+
336
+ - §6 Definition of Done: the options marked for the merge DoD.
337
+ - §6.1 Pre-push validation: the command sequence for a push (for example tests, then the type check, then
338
+ the build) from the pre-push answer plus the optional free text.
339
+
340
+ ---
341
+
342
+ ## Step 7 — Gotchas and ADRs (start empty)
343
+
344
+ `afm init --mechanical` already created the structure; this step only decides what stays empty:
345
+
346
+ - `gotchas/`: empty. A gotcha is one file per entry, and `afm gotcha` writes the first.
347
+ - `rules/`: empty. A hard rule is one file per rule; section 3 of `afm.md` carries one index line per rule
348
+ in the `N. **title**` shape two hooks parse, and `afm rule` writes both sides.
349
+ - `adr/0000-template.md` exists; `adr/` is otherwise empty. ADRs are born when a real decision happens.
350
+ - `rubrics/` and `patterns/` hold every file the index lists, copied verbatim. They are runnable,
351
+ stack-agnostic decision tables, the highest-value content at apply time, and the placeholders in them
352
+ (the source root, domain path and extension) were filled by the measurement of step 5. A pattern only
353
+ ever *suggests*: it becomes a project norm solely when the operator accepts it, and only then does it
354
+ materialize into `code-style/`, `ach.md` or an ADR. The copy is not that acceptance.
355
+ - `evolution/` is **not** materialized now. It is born on demand at the first `afm evolve` cycle.
356
+ `docs/research/` is born the same way, at the first research.
357
+
358
+ **Do not write a retroactive ADR during the interview.** An ADR is a real decision with a concrete
359
+ symptom. If one comes up during development and is non-obvious, create the ADR at that moment (see
360
+ `afm path interview/triggers`).
361
+
362
+ ---
363
+
364
+ ## Closing
365
+
366
+ After the 7 steps:
367
+
368
+ 1. **List every `[TBD]`** (file and section, for example `prd.md § 3 Persona`) and let the operator reply
369
+ with the ones to fill in now. Marked items become free-text questions, one at a time. Unmarked items
370
+ stay `[TBD]` in the doc and are recorded in the commit note.
371
+ 2. **Generate the indexes:** `afm index --materialize`, then `afm index --check`. It writes an `index.md` in
372
+ every documentation directory plus the bundle-root `index.md` that declares `okf_version`. Hard rule 39
373
+ fails on a missing or stale index, so a bootstrap that skips this step hands the owner a red gate on the
374
+ first commit.
375
+ 3. **Quick check** with `afm doctor` and `afm gate --worktree`: the PRD has §1 + §2 + §3 + at least RF-01;
376
+ the ACH has a diagram plus component types mapped to the stack; the AFM has hard rules plus DoD plus
377
+ pre-push; the UST has at least US-001; `.afm-version` points to the version in use.
378
+ 4. **Instruction files.** `AGENTS.md` and the per-harness stubs were written by the mechanical pass. Add
379
+ the libraries detected in step 1 where the block asks for them. If the repo already had an
380
+ `AGENTS.md`, only the managed AFM block was merged in, never a duplicated rule.
381
+ 5. **Suggested commit:**
382
+ ```
383
+ docs(afm): initial bootstrap — afm version <version>
384
+
385
+ Creates PRD/ACH/AFM/UST/gotchas/adr from a guided interview.
386
+ Open [TBD] items: <list>.
387
+ ```
388
+ 6. **Reminder for the operator:** the bootstrap is done. `docs/` is now a living source that evolves with
389
+ the project through passive reconcile: every session watches the signals in
390
+ `afm path interview/triggers` (architectural decision, runtime surprise 2x, correction with a reusable
391
+ rule, gotcha, etc.) and proposes an edit to the right file. There is no need to run `afm init` again.
392
+ The ops `afm gotcha`, `afm adr`, `afm rule` and `afm promote` stay available on demand, for when the
393
+ operator wants to be explicit. The single test for memory versus doc: *if another dev needs it to avoid
394
+ breaking something, it is a doc.*
395
+
396
+ ---
397
+
398
+ ## Interview anti-patterns
399
+
400
+ - ❌ Fire 5+ free-text questions in the same turn: the operator loses context. (`afm ask` renders several
401
+ structured questions together, and that is fine: each one is a click, not typing.)
402
+ - ❌ "Do you want X or Y?" without having heard the problem first: a premature recommendation.
403
+ - ❌ Ask about the stack blank when the report shows one, or when the operator already named it in step 0.
404
+ Bring the inference as the recommendation to confirm (#2). An inference anchored in an installed
405
+ dependency is not a premature recommendation: the first has evidence, the second does not.
406
+ - ❌ Materialize before you validate: it produces a wrong doc the operator has to fix.
407
+ - ❌ Invent an RF "because it is best practice": write only what the operator asked for.
408
+ - ❌ Add a gotcha proactively: gotchas start empty and get discovered over time.
409
+ - ❌ Skip a `[TBD]` by guessing: invention is worse than a pending item.
410
+ - ❌ Write a retroactive ADR during the interview: an ADR is a real decision, not proactive documentation.
411
+
412
+ ## Interview success criteria
413
+
414
+ - The generated doc is useful **without** the operator having to edit it by hand (except to fill in `[TBD]`).
415
+ - No section contains invention that goes beyond what the operator said.
416
+ - Another dev who clones the repo and reads `docs/` can understand the product, the architecture and how
417
+ to contribute, with no need to ask.
@@ -0,0 +1,115 @@
1
+ ---
2
+ type: interview
3
+ description: The criteria that move a local learning into the plugin.
4
+ load: cold
5
+ ---
6
+
7
+ # Promotion — when to promote `/docs` to `framework-template/`
8
+
9
+ > This doc gives instructions **to Claude**. It detects a promotion candidate and proposes a PR.
10
+
11
+
12
+ ---
13
+
14
+ ## Principle
15
+
16
+ A learning in the project's `/docs/` can be:
17
+ - **Specific to the project** → it stays in `/docs/`.
18
+ - **Valid for any project with the same stack** → promote it to `framework-template/modules/<stack>/`.
19
+ - **Valid for any project, regardless of stack** → promote it to `framework-template/core/`.
20
+
21
+ **Promotion here means registering a candidate. It does not mean writing to the plugin.** The table below decides the finding's `target:` field. The maintainer applies the change, in the plugin's own repo, from the `afm_findings` entries. The boundary is absolute (`PRINCIPLES.md` #7). From inside an adopting project, the reachable `framework-template/` is only the **install cache** — a copy the next `plugin update` discards.
22
+
23
+ ---
24
+
25
+ ## Decision table
26
+
27
+ | Learning in the project's `/docs/` | Promote? | Where to |
28
+ | --- | --- | --- |
29
+ | Depends on a project entity (`SdkSource`, `App`, `Order`) | ❌ | Stays in `/docs/` |
30
+ | Local naming convention ("we prefix routes with X") | ❌ | Stays in `/docs/` |
31
+ | Current project status (auth wired? RFs pending?) | ❌ | Stays in `/docs/` |
32
+ | Valid for any project with the same stack (tRPC, Trigger, Stripe, etc.) | ✅ | `modules/<stack>/` |
33
+ | SDK or external library gotcha (Stripe Schedule, tsdown subprocess) | ✅ | `modules/<lib>/gotchas.seed.md` |
34
+ | Universal hard rule (valid in any project, any stack) | ✅ | `core/afm.md` §3 |
35
+ | Universal anti-pattern (a Lib that imports an ORM, a Domain that imports TRPCError) | ✅ | `core/ach.md` or `rubrics/` |
36
+ | Universal principle (saga ordering, error classification) | ✅ | `core/afm.md` §1.3 or §3 |
37
+ | Decision rubric (when to create X, which type to use) | ✅ | `rubrics/<name>.md` |
38
+
39
+ ---
40
+
41
+ ## Promotion flow
42
+
43
+ When Claude detects a candidate:
44
+
45
+ ### 1. Ask the user
46
+
47
+ > "I just added X to `/docs/{{file}}.md`. Does this learning **apply to any project {{with tRPC | with Stripe | universally}}**, not just this one? Do you want me to register it as a finding for the AFM plugin? `afm findings record` stores it in the project state for the maintainer to collect. This project does not change."
48
+
49
+ ### 2. If the user approves:
50
+
51
+ a. Check the **mechanical evidence**. Find the command that proves the learning: a passing test, `tsc`, or a `grep`/`test -e` that shows the defect. With no reproducible command, do not register it (#5).
52
+
53
+ b. Decide the `target:` field with the table above (`core/` vs. `modules/<stack>/`).
54
+
55
+ c. Append the entry to the session file's `afm_findings`. Use the issue-body format from `ops/promote.md` step 4. Include an imperative title, `target:`, `evidence:`, and `origin:` — project plus the version pinned in `docs/.afm-version`. Add 1-3 sentences on why the learning applies to any instance.
56
+
57
+ d. Report where the entry went. **Do not bump `VERSION`/`CHANGELOG`, and do not open a PR or commit in the plugin.** That is maintenance work. It happens in the plugin's repo.
58
+
59
+ ### 3. If the user declines:
60
+
61
+ The learning stays in the project's `/docs/`. Add an internal note ("X is specific to {{project}}").
62
+
63
+ ---
64
+
65
+ ## Criterion for "valid for any project"
66
+
67
+ Validation questions to ask before proposing:
68
+
69
+ 1. **Does the rule or gotcha reference a project-specific entity or model?**
70
+ If yes → it stays. If no → it might promote.
71
+ 2. **Does the solution depend on stack-specific tech?**
72
+ If yes → it goes to `modules/<stack>/`, not `core/`.
73
+ 3. **Would another project without this stack break without this rule?**
74
+ If yes → `core/`. If no → `modules/`.
75
+ 4. **Would the rule still hold if we changed the language?**
76
+ If yes → it is universal, and goes to `core/`.
77
+ 5. **Can I describe the rule without naming anything specific to the project?**
78
+ If yes → universal. If no → rewrite it as generic before promoting.
79
+
80
+ ---
81
+
82
+ ## Anti-patterns
83
+
84
+ - ❌ **Writing to `framework-template/`.** The boundary is absolute (#7). From here you can only register a candidate. The reachable path is the install cache. The edit dies at the next `plugin update`, with no error and no signal.
85
+ - ❌ **Registering a candidate without confirming with the user.** It might be specific to the project.
86
+ - ❌ **Registering a rule that names a project entity** ("App.healthStatus must...") without generalizing it first.
87
+ - ❌ **Registering an ADR.** An ADR is a decision for this project. A learning from that decision (a gotcha, a rule) can become a finding. The ADR itself cannot.
88
+ - ❌ **Registering a candidate with no reproducible mechanical evidence.** A finding with no command is just an impression (#5). The maintainer needs to be able to rerun it and see the same result.
89
+ - ❌ **Registering a candidate ahead of need** ("it will be useful later"). Register on demand, with a real case.
90
+
91
+ ---
92
+
93
+ ## Concrete example
94
+
95
+ ### Scenario
96
+
97
+ The `sdk.mapree.dev` project found that `package.json.type` must be `"module"` even in `format=cjs`, because of a tsdown subprocess.
98
+
99
+ ### Decision
100
+
101
+ - Goes to the project's `/docs/gotchas/`, one file per entry. ✅
102
+ - Goes to `framework-template/modules/trigger-dev-v4/gotchas.seed.md`? **Not directly** — it is not a Trigger.dev gotcha.
103
+ - Goes to `framework-template/modules/sdk-generator/`? **This module does not exist.** It is specific to this project.
104
+ - **Conclusion:** it stays in `/docs/`. No promotion (this learning lives in the project, not in the template).
105
+
106
+ ### Scenario 2
107
+
108
+ The `sdk.mapree.dev` project found that a Stripe webhook can arrive twice, and needs an idempotent UPSERT.
109
+
110
+ ### Decision
111
+
112
+ - Goes to the project's `/docs/gotchas/`, one file per entry. ✅
113
+ - `target: modules/stripe-billing/gotchas.seed.md`? **Yes** — every Stripe project runs into this.
114
+ - Register it in `afm_findings`. Use the title "Gotcha: Stripe webhook is at-least-once — needs an idempotent UPSERT". Add `evidence:` the test that reproduced the repeated delivery. Add `origin:` sdk.mapree.dev plus the pinned version.
115
+ - The `VERSION` bump and the `CHANGELOG` entry happen **in the plugin's repo**, when the maintainer collects the finding. Not here.