@nurix/etna 0.20.35 → 0.20.37

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 (233) hide show
  1. package/data/catalog/rules/changelog.md +1 -1
  2. package/data/catalog/skills/nustack/SKILL.md +2 -2
  3. package/data/catalog/skills/nustack/references/cli-design.md +35 -35
  4. package/data/catalog/skills/nustack/references/monorepo-master-list.md +6 -6
  5. package/data/catalog/skills/nustack/references/monorepo-setup.md +13 -13
  6. package/data/catalog/skills/nustack/references/publishing.md +40 -39
  7. package/data/harness-index.json +1 -1
  8. package/data/harnesses/code/CLAUDE.md +4 -4
  9. package/data/harnesses/code/agents/brainstorm.md +2 -2
  10. package/data/harnesses/code/agents/lld-mode.md +2 -2
  11. package/data/harnesses/code/agents/maintenance.md +17 -17
  12. package/data/harnesses/code/codex/agents/brainstorm.toml +6 -2
  13. package/data/harnesses/code/codex/agents/lld-mode.toml +2 -2
  14. package/data/harnesses/code/codex/agents/maintenance.toml +18 -17
  15. package/data/harnesses/code/docs/README.md +9 -17
  16. package/data/harnesses/code/docs/history/CHANGELOG.md +19 -18
  17. package/data/harnesses/code/docs/structure.md +60 -45
  18. package/data/harnesses/code/harness.json +2 -2
  19. package/data/harnesses/code/hooks/compliance.mjs +8 -2
  20. package/data/harnesses/code/hooks/lib/sweep.mjs +3 -2
  21. package/data/harnesses/code/rules/changelog.md +1 -1
  22. package/data/harnesses/code/skills/boundary/SKILL.md +33 -22
  23. package/data/harnesses/code/skills/boundary/references/index.md +2 -4
  24. package/data/harnesses/code/skills/boundary/references/mechanisms.md +3 -10
  25. package/data/harnesses/code/skills/boundary/references/packs/frontend.md +17 -17
  26. package/data/harnesses/code/skills/boundary/references/packs/generic-tail.md +1 -1
  27. package/data/harnesses/code/skills/brainstorm/README.md +11 -13
  28. package/data/harnesses/code/skills/brainstorm/SKILL.md +149 -130
  29. package/data/harnesses/code/skills/brainstorm/references/doctrine.md +48 -51
  30. package/data/harnesses/code/skills/brainstorm/references/harvest.md +51 -57
  31. package/data/harnesses/code/skills/brainstorm/references/session-schema.md +48 -42
  32. package/data/harnesses/code/skills/design/SKILL.md +31 -35
  33. package/data/harnesses/code/skills/design/data/iconography.md +2 -2
  34. package/data/harnesses/code/skills/design/references/compose.md +14 -16
  35. package/data/harnesses/code/skills/design/references/foundations.md +5 -5
  36. package/data/harnesses/code/skills/design/references/intake.md +6 -6
  37. package/data/harnesses/code/skills/design/references/object-pass.md +1 -1
  38. package/data/harnesses/code/skills/design/references/ship-gate.md +5 -5
  39. package/data/harnesses/code/skills/design/references/ux-patterns/Readme.md +4 -4
  40. package/data/harnesses/code/skills/design/references/ux-patterns/ai-layer.md +1 -1
  41. package/data/harnesses/code/skills/design/references/ux-patterns/container-choice.md +1 -1
  42. package/data/harnesses/code/skills/design/references/ux-patterns/dashboards.md +1 -1
  43. package/data/harnesses/code/skills/design/references/ux-patterns/modes.md +1 -1
  44. package/data/harnesses/code/skills/design/references/ux-patterns/object-model.md +2 -2
  45. package/data/harnesses/code/skills/design/references/ux-patterns/promotion-demotion.md +1 -1
  46. package/data/harnesses/code/skills/design/references/ux-patterns/settings.md +1 -1
  47. package/data/harnesses/code/skills/design/references/ux-patterns/standard-pages.md +1 -1
  48. package/data/harnesses/code/skills/documentation/SKILL.md +92 -143
  49. package/data/harnesses/code/skills/documentation/references/examples.md +45 -72
  50. package/data/harnesses/code/skills/documentation/references/frontmatter.md +8 -8
  51. package/data/harnesses/code/skills/documentation/references/instruction-style.md +3 -3
  52. package/data/harnesses/code/skills/documentation/references/source-comments.md +19 -0
  53. package/data/harnesses/code/skills/documentation/references/style-guide.md +25 -11
  54. package/data/harnesses/code/skills/documentation/references/untemplated.md +11 -10
  55. package/data/harnesses/code/skills/documentation/scripts/doc-lint.mjs +181 -40
  56. package/data/harnesses/code/skills/documentation/templates/Readme.md +68 -41
  57. package/data/harnesses/code/skills/documentation/templates/acceptance-criteria.md +11 -19
  58. package/data/harnesses/code/skills/documentation/templates/api-reference.md +8 -3
  59. package/data/harnesses/code/skills/documentation/templates/architecture-decision.md +8 -12
  60. package/data/harnesses/code/skills/documentation/templates/backlog.md +2 -2
  61. package/data/harnesses/code/skills/documentation/templates/behavioral-checklist.md +10 -17
  62. package/data/harnesses/code/skills/documentation/templates/bookkeeping.md +2 -2
  63. package/data/harnesses/code/skills/documentation/templates/changelog-entry.md +2 -2
  64. package/data/harnesses/code/skills/documentation/templates/changelog-index.md +21 -29
  65. package/data/harnesses/code/skills/documentation/templates/docs-readme.md +4 -4
  66. package/data/harnesses/code/skills/documentation/templates/doctrine.md +3 -3
  67. package/data/harnesses/code/skills/documentation/templates/domain-model.md +10 -5
  68. package/data/harnesses/code/skills/documentation/templates/environment-registry.md +7 -2
  69. package/data/harnesses/code/skills/documentation/templates/feature.md +6 -6
  70. package/data/harnesses/code/skills/documentation/templates/glossary.md +6 -1
  71. package/data/harnesses/code/skills/documentation/templates/handover.md +17 -17
  72. package/data/harnesses/code/skills/documentation/templates/implementation-map.md +10 -5
  73. package/data/harnesses/code/skills/documentation/templates/journal.md +2 -2
  74. package/data/harnesses/code/skills/documentation/templates/memory-main.md +2 -2
  75. package/data/harnesses/code/skills/documentation/templates/migration-runbook.md +1 -1
  76. package/data/harnesses/code/skills/documentation/templates/non-goals.md +8 -3
  77. package/data/harnesses/code/skills/documentation/templates/operations-procedure.md +8 -3
  78. package/data/harnesses/code/skills/documentation/templates/package.md +5 -9
  79. package/data/harnesses/code/skills/documentation/templates/plan.md +5 -11
  80. package/data/harnesses/code/skills/documentation/templates/protected-files.md +7 -2
  81. package/data/harnesses/code/skills/documentation/templates/root-readme.md +5 -5
  82. package/data/harnesses/code/skills/documentation/templates/security-overview.md +9 -4
  83. package/data/harnesses/code/skills/documentation/templates/setup.md +6 -6
  84. package/data/harnesses/code/skills/documentation/templates/system-overview.md +12 -7
  85. package/data/harnesses/code/skills/documentation/templates/system.md +2 -2
  86. package/data/harnesses/code/skills/documentation/templates/testing-strategy.md +10 -5
  87. package/data/harnesses/code/skills/documentation/templates/ux-behavior.md +14 -5
  88. package/data/harnesses/code/skills/issue-bridge/SKILL.md +51 -16
  89. package/data/harnesses/code/skills/issue-bridge/references/trackers/github.md +5 -5
  90. package/data/harnesses/code/skills/issue-bridge/references/trackers/jira.md +11 -8
  91. package/data/harnesses/code/skills/issue-bridge/references/trackers/linear.md +16 -11
  92. package/data/harnesses/code/skills/nustack-graph/SKILL.md +38 -29
  93. package/data/harnesses/code/skills/polygraph/references/dispatch.md +31 -18
  94. package/data/harnesses/code/skills/polygraph/references/rows.md +11 -6
  95. package/data/harnesses/code/skills/schema-design/SKILL.md +39 -41
  96. package/data/harnesses/code/skills/test/SKILL.md +38 -42
  97. package/data/harnesses/code/skills/testing/SKILL.md +83 -73
  98. package/data/harnesses/code/skills/workflow-mapper/SKILL.md +156 -193
  99. package/data/harnesses/code/skills/workflow-mapper/references/patterns.md +15 -15
  100. package/data/harnesses/delivery/CLAUDE.md +1 -1
  101. package/data/harnesses/delivery/agents/brainstorm.md +2 -2
  102. package/data/harnesses/delivery/agents/lld-mode.md +2 -2
  103. package/data/harnesses/delivery/agents/maintenance.md +17 -17
  104. package/data/harnesses/delivery/codex/agents/brainstorm.toml +6 -2
  105. package/data/harnesses/delivery/codex/agents/lld-mode.toml +2 -2
  106. package/data/harnesses/delivery/codex/agents/maintenance.toml +18 -17
  107. package/data/harnesses/delivery/harness.json +2 -2
  108. package/data/harnesses/delivery/rules/changelog.md +1 -1
  109. package/data/harnesses/delivery/skills/brainstorm/README.md +11 -13
  110. package/data/harnesses/delivery/skills/brainstorm/SKILL.md +149 -130
  111. package/data/harnesses/delivery/skills/brainstorm/references/doctrine.md +48 -51
  112. package/data/harnesses/delivery/skills/brainstorm/references/harvest.md +51 -57
  113. package/data/harnesses/delivery/skills/brainstorm/references/session-schema.md +48 -42
  114. package/data/harnesses/delivery/skills/cost-report/SKILL.md +10 -10
  115. package/data/harnesses/delivery/skills/documentation/SKILL.md +92 -143
  116. package/data/harnesses/delivery/skills/documentation/references/examples.md +45 -72
  117. package/data/harnesses/delivery/skills/documentation/references/frontmatter.md +8 -8
  118. package/data/harnesses/delivery/skills/documentation/references/instruction-style.md +3 -3
  119. package/data/harnesses/delivery/skills/documentation/references/source-comments.md +19 -0
  120. package/data/harnesses/delivery/skills/documentation/references/style-guide.md +25 -11
  121. package/data/harnesses/delivery/skills/documentation/references/untemplated.md +11 -10
  122. package/data/harnesses/delivery/skills/documentation/scripts/doc-lint.mjs +181 -40
  123. package/data/harnesses/delivery/skills/documentation/templates/Readme.md +68 -41
  124. package/data/harnesses/delivery/skills/documentation/templates/acceptance-criteria.md +11 -19
  125. package/data/harnesses/delivery/skills/documentation/templates/api-reference.md +8 -3
  126. package/data/harnesses/delivery/skills/documentation/templates/architecture-decision.md +8 -12
  127. package/data/harnesses/delivery/skills/documentation/templates/backlog.md +2 -2
  128. package/data/harnesses/delivery/skills/documentation/templates/behavioral-checklist.md +10 -17
  129. package/data/harnesses/delivery/skills/documentation/templates/bookkeeping.md +2 -2
  130. package/data/harnesses/delivery/skills/documentation/templates/changelog-entry.md +2 -2
  131. package/data/harnesses/delivery/skills/documentation/templates/changelog-index.md +21 -29
  132. package/data/harnesses/delivery/skills/documentation/templates/docs-readme.md +4 -4
  133. package/data/harnesses/delivery/skills/documentation/templates/doctrine.md +3 -3
  134. package/data/harnesses/delivery/skills/documentation/templates/domain-model.md +10 -5
  135. package/data/harnesses/delivery/skills/documentation/templates/environment-registry.md +7 -2
  136. package/data/harnesses/delivery/skills/documentation/templates/feature.md +6 -6
  137. package/data/harnesses/delivery/skills/documentation/templates/glossary.md +6 -1
  138. package/data/harnesses/delivery/skills/documentation/templates/handover.md +17 -17
  139. package/data/harnesses/delivery/skills/documentation/templates/implementation-map.md +10 -5
  140. package/data/harnesses/delivery/skills/documentation/templates/journal.md +2 -2
  141. package/data/harnesses/delivery/skills/documentation/templates/memory-main.md +2 -2
  142. package/data/harnesses/delivery/skills/documentation/templates/migration-runbook.md +1 -1
  143. package/data/harnesses/delivery/skills/documentation/templates/non-goals.md +8 -3
  144. package/data/harnesses/delivery/skills/documentation/templates/operations-procedure.md +8 -3
  145. package/data/harnesses/delivery/skills/documentation/templates/package.md +5 -9
  146. package/data/harnesses/delivery/skills/documentation/templates/plan.md +5 -11
  147. package/data/harnesses/delivery/skills/documentation/templates/protected-files.md +7 -2
  148. package/data/harnesses/delivery/skills/documentation/templates/root-readme.md +5 -5
  149. package/data/harnesses/delivery/skills/documentation/templates/security-overview.md +9 -4
  150. package/data/harnesses/delivery/skills/documentation/templates/setup.md +6 -6
  151. package/data/harnesses/delivery/skills/documentation/templates/system-overview.md +12 -7
  152. package/data/harnesses/delivery/skills/documentation/templates/system.md +2 -2
  153. package/data/harnesses/delivery/skills/documentation/templates/testing-strategy.md +10 -5
  154. package/data/harnesses/delivery/skills/documentation/templates/ux-behavior.md +14 -5
  155. package/data/harnesses/delivery/skills/escalate/SKILL.md +11 -11
  156. package/data/harnesses/delivery/skills/prompt-eval/SKILL.md +8 -8
  157. package/data/harnesses/delivery/skills/prompt-library/SKILL.md +30 -9
  158. package/data/harnesses/delivery/skills/route/SKILL.md +8 -8
  159. package/data/harnesses/etna/CLAUDE.md +2 -2
  160. package/data/harnesses/etna/agents/brainstorm.md +2 -2
  161. package/data/harnesses/etna/agents/lld-mode.md +2 -2
  162. package/data/harnesses/etna/agents/maintenance.md +17 -17
  163. package/data/harnesses/etna/codex/agents/brainstorm.toml +6 -2
  164. package/data/harnesses/etna/codex/agents/lld-mode.toml +2 -2
  165. package/data/harnesses/etna/codex/agents/maintenance.toml +18 -17
  166. package/data/harnesses/etna/harness.json +2 -2
  167. package/data/harnesses/etna/rules/changelog.md +1 -1
  168. package/data/harnesses/etna/skills/boundary/SKILL.md +33 -22
  169. package/data/harnesses/etna/skills/boundary/references/index.md +2 -4
  170. package/data/harnesses/etna/skills/boundary/references/mechanisms.md +3 -10
  171. package/data/harnesses/etna/skills/boundary/references/packs/frontend.md +17 -17
  172. package/data/harnesses/etna/skills/boundary/references/packs/generic-tail.md +1 -1
  173. package/data/harnesses/etna/skills/brainstorm/README.md +11 -13
  174. package/data/harnesses/etna/skills/brainstorm/SKILL.md +149 -130
  175. package/data/harnesses/etna/skills/brainstorm/references/doctrine.md +48 -51
  176. package/data/harnesses/etna/skills/brainstorm/references/harvest.md +51 -57
  177. package/data/harnesses/etna/skills/brainstorm/references/session-schema.md +48 -42
  178. package/data/harnesses/etna/skills/documentation/SKILL.md +92 -143
  179. package/data/harnesses/etna/skills/documentation/references/examples.md +45 -72
  180. package/data/harnesses/etna/skills/documentation/references/frontmatter.md +8 -8
  181. package/data/harnesses/etna/skills/documentation/references/instruction-style.md +3 -3
  182. package/data/harnesses/etna/skills/documentation/references/source-comments.md +19 -0
  183. package/data/harnesses/etna/skills/documentation/references/style-guide.md +25 -11
  184. package/data/harnesses/etna/skills/documentation/references/untemplated.md +11 -10
  185. package/data/harnesses/etna/skills/documentation/scripts/doc-lint.mjs +181 -40
  186. package/data/harnesses/etna/skills/documentation/templates/Readme.md +68 -41
  187. package/data/harnesses/etna/skills/documentation/templates/acceptance-criteria.md +11 -19
  188. package/data/harnesses/etna/skills/documentation/templates/api-reference.md +8 -3
  189. package/data/harnesses/etna/skills/documentation/templates/architecture-decision.md +8 -12
  190. package/data/harnesses/etna/skills/documentation/templates/backlog.md +2 -2
  191. package/data/harnesses/etna/skills/documentation/templates/behavioral-checklist.md +10 -17
  192. package/data/harnesses/etna/skills/documentation/templates/bookkeeping.md +2 -2
  193. package/data/harnesses/etna/skills/documentation/templates/changelog-entry.md +2 -2
  194. package/data/harnesses/etna/skills/documentation/templates/changelog-index.md +21 -29
  195. package/data/harnesses/etna/skills/documentation/templates/docs-readme.md +4 -4
  196. package/data/harnesses/etna/skills/documentation/templates/doctrine.md +3 -3
  197. package/data/harnesses/etna/skills/documentation/templates/domain-model.md +10 -5
  198. package/data/harnesses/etna/skills/documentation/templates/environment-registry.md +7 -2
  199. package/data/harnesses/etna/skills/documentation/templates/feature.md +6 -6
  200. package/data/harnesses/etna/skills/documentation/templates/glossary.md +6 -1
  201. package/data/harnesses/etna/skills/documentation/templates/handover.md +17 -17
  202. package/data/harnesses/etna/skills/documentation/templates/implementation-map.md +10 -5
  203. package/data/harnesses/etna/skills/documentation/templates/journal.md +2 -2
  204. package/data/harnesses/etna/skills/documentation/templates/memory-main.md +2 -2
  205. package/data/harnesses/etna/skills/documentation/templates/migration-runbook.md +1 -1
  206. package/data/harnesses/etna/skills/documentation/templates/non-goals.md +8 -3
  207. package/data/harnesses/etna/skills/documentation/templates/operations-procedure.md +8 -3
  208. package/data/harnesses/etna/skills/documentation/templates/package.md +5 -9
  209. package/data/harnesses/etna/skills/documentation/templates/plan.md +5 -11
  210. package/data/harnesses/etna/skills/documentation/templates/protected-files.md +7 -2
  211. package/data/harnesses/etna/skills/documentation/templates/root-readme.md +5 -5
  212. package/data/harnesses/etna/skills/documentation/templates/security-overview.md +9 -4
  213. package/data/harnesses/etna/skills/documentation/templates/setup.md +6 -6
  214. package/data/harnesses/etna/skills/documentation/templates/system-overview.md +12 -7
  215. package/data/harnesses/etna/skills/documentation/templates/system.md +2 -2
  216. package/data/harnesses/etna/skills/documentation/templates/testing-strategy.md +10 -5
  217. package/data/harnesses/etna/skills/documentation/templates/ux-behavior.md +14 -5
  218. package/data/harnesses/etna/skills/workflow-mapper/SKILL.md +156 -193
  219. package/data/harnesses/etna/skills/workflow-mapper/references/patterns.md +15 -15
  220. package/data/harnesses/hr/harness.json +1 -1
  221. package/data/harnesses/hr/skills/evaluator/SKILL.md +71 -73
  222. package/data/harnesses/hr/skills/evaluator/criteria/code-quality.md +28 -47
  223. package/data/harnesses/hr/skills/evaluator/criteria/deployment-readiness.md +33 -43
  224. package/data/harnesses/hr/skills/evaluator/criteria/maintainability.md +34 -46
  225. package/data/harnesses/hr/skills/evaluator/criteria/mechanical-ambition.md +13 -13
  226. package/data/harnesses/hr/skills/evaluator/criteria/problem-substantiveness.md +7 -7
  227. package/data/harnesses/hr/skills/evaluator/criteria/testing.md +36 -41
  228. package/data/harnesses/hr/skills/evaluator/criteria/ux-mechanics.md +25 -11
  229. package/data/harnesses/hr/skills/evaluator/criteria/value-articulation.md +7 -7
  230. package/data/harnesses/hr/skills/evaluator/preflight.md +27 -46
  231. package/data/harnesses/hr/skills/interview-eval/SKILL.md +37 -42
  232. package/data/harnesses/hr/skills/interview-eval/rubric.md +21 -23
  233. package/package.json +2 -2
@@ -1,6 +1,6 @@
1
1
  # Changelog
2
2
 
3
- Every unit of work leaves one record — `docs/history/changelog/YYYY-MM-DD-{three-words}.md` (the three words name the work, not the commit) — plus its row in `docs/history/CHANGELOG.md`, appended in the same pass so the index never trails the folder. Entry format, field rules, and the closed exemption list are the `documentation` skill's `templates/changelog-entry.md`; this rule owns when an entry is owed and how it lives. An entry is never a commit summary — it carries the refinement context only the working session holds, which no diff reconstructs.
3
+ Every unit of work leaves one record — `docs/history/changelog/YYYY-MM-DD-{three-words}.md` (the three words name the work, not the commit). `docs/history/CHANGELOG.md` is the folder's guide, never appended to: the entry's own first line is its summary, and listing the folder is the index. Entry format, field rules, and the closed exemption list are the `documentation` skill's `templates/changelog-entry.md`; this rule owns when an entry is owed and how it lives. An entry is never a commit summary — it carries the refinement context only the working session holds, which no diff reconstructs.
4
4
 
5
5
  ## When an entry is owed
6
6
 
@@ -1,11 +1,11 @@
1
1
  ---
2
2
  name: nustack
3
- description: "The @nurix/* packaging and tooling skill — pnpm monorepo setup (workspace file, catalog, root scripts), publishing packages to npm, and distributable @nurix CLIs (npx self-update, managed blocks). Use when scaffolding a workspace, publishing a package, building a CLI, or debugging an npm publish."
3
+ description: "Use when scaffolding a pnpm workspace, publishing an @nurix/* package to npm, building a distributable @nurix CLI (npx self-update, managed blocks), or debugging an npm publish."
4
4
  ---
5
5
 
6
6
  # NuStack
7
7
 
8
- The `@nurix/*` packaging and tooling skill. Always-loaded workspace doctrine — package naming, monorepo boundaries, consuming — is the [`pnpm.md`](../../rules/pnpm.md) rule; this skill carries the on-demand reference material, one area per reference, and grows a new reference as an area is needed.
8
+ The `@nurix/*` packaging and tooling skill. Workspace doctrine that loads every session — package naming, monorepo boundaries, consuming — is the [`pnpm.md`](../../rules/pnpm.md) rule; this skill holds the on-demand material, one area per reference. Read the reference whose trigger matches the task before acting.
9
9
 
10
10
  | Reference | Load when |
11
11
  | --- | --- |
@@ -2,30 +2,28 @@
2
2
 
3
3
  Load when: building or changing a distributable `@nurix/*` command-line tool.
4
4
 
5
- Conventions for building a distributable Nurix command-line tool, distilled from the two we ship: **`@nurix/etna`** (`packages/cli/` in the etna repo — the harness installer, plain ESM JS) and **`@nurix/nustack`** (`~/dev/apollo/packages/cli/` — the service-bootstrap CLI, TypeScript → `dist/`). When you build or change a `@nurix` CLI, follow these. Where the two diverge, both variants are noted as valid.
5
+ Conventions for a distributable `@nurix/*` command-line tool. The two reference CLIs are **`@nurix/etna`** (`packages/cli/` in the etna repo — the harness installer, plain ESM JS) and **`@nurix/nustack`** (`~/dev/apollo/packages/cli/` — the service-bootstrap CLI, TypeScript → `dist/`). Where they diverge, both variants are valid.
6
6
 
7
7
  ## 1. Packaging
8
8
 
9
- The base `package.json` fields — scope, `publishConfig.access: "restricted"`, `files`, build hooks — are [`publishing.md`](publishing.md) §2. CLI-specific on top:
9
+ The base `package.json` fields — scope, `publishConfig.access: "restricted"`, `files`, build hooks — are [`publishing.md`](publishing.md) §2. A CLI adds:
10
10
 
11
11
  - **ESM only** — `"type": "module"`.
12
- - **`bin` maps the command to its entry** — `{ "etna": "bin/etna.js" }` / `{ "nustack": "dist/index.js" }`. The entry has a `#!/usr/bin/env node` shebang.
13
- - **`files` ships only the runnable artifact** — `["bin/", "data/", "README.md"]` (etna) or `["dist"]` (nustack). Never ship `src/`, tests, or the repo.
14
- - **`engines.node` ≥ 22** for new CLIs (matches the workspace Node baseline).
15
- - **One version source** — read the running version from `package.json` at startup; don't hardcode it elsewhere.
16
- - **Minimal deps.** Both ship with essentially one runtime dep (`@clack/prompts`); nustack adds `commander` + `ajv`. Keep the dependency surface tiny — it's installed on every `npx` run.
12
+ - **`bin` maps the command to its entry** — `{ "etna": "bin/etna.js" }` / `{ "nustack": "dist/index.js" }`; the entry carries a `#!/usr/bin/env node` shebang.
13
+ - **`files` ships only the runnable artifact** — `["bin/", "lib/", "data/"]` (etna) or `["dist"]` (nustack). **Never** `src/`, tests, or the repo.
14
+ - **`engines.node` ≥ 22** for a new CLI, the workspace Node baseline.
15
+ - **One version source** — read the running version from `package.json` at startup; never hardcode it elsewhere.
16
+ - **Minimal deps** — essentially one runtime dep (`@clack/prompts`), because the dependency surface installs on every `npx` run; nustack adds `commander` and `ajv`.
17
17
 
18
18
  ## 2. Distribution: `npx`-first, install into the project, never globally
19
19
 
20
- - The canonical entry is **`npx @nurix/<tool>`** — no global install step, no marketplace, no plugin-enablement dance. The user runs `npx`, the tool does its job in the current directory.
21
- - **The CLI writes ONLY inside the folder it was invoked in.** An installer run as `npx @nurix/etna` in a project must touch only that project tree — never `$HOME`, never `~/.claude`, never any shared/user-level location. Reaching outside the target folder is surprising, clobber-prone, and wrong. (This is a hard-won rule: an earlier etna build installed agents to `~/.claude/agents/` and it was reverted precisely for this reason.)
22
- - **Idempotent refresh.** Re-running the CLI re-pulls the latest and overwrites the files it owns (force), while leaving anything the user authored untouched. "Re-run anytime to refresh" must always be safe.
20
+ - The canonical entry is **`npx @nurix/<tool>`** — no global install, no marketplace, no plugin enablement. The tool does its job in the current directory.
21
+ - **The CLI writes only inside the folder it was invoked in.** `npx @nurix/etna` in a project touches only that project tree — **never** `$HOME`, `~/.claude`, or any shared or user-level location, even where a tool conventionally installs globally (`~/.claude/agents/`): a write outside the target folder clobbers state the user never pointed the CLI at.
22
+ - **Idempotent refresh.** Re-running re-pulls the latest and force-overwrites the files the CLI owns, leaving everything the user authored untouched — a re-run is **always** safe.
23
23
 
24
24
  ## 3. Always run the latest — self-update by re-exec
25
25
 
26
- **The problem:** `npx` caches aggressively. A bare `npx @nurix/<tool>` can keep running a *stale* unpacked copy long after a newer version is published (npm's packument cache resolves an old `latest`, and npx reuses the matching install). Users shouldn't have to remember `@latest`.
27
-
28
- **The mechanism** (etna's `selfUpdateOrReexec()`, run before anything else): on startup, ask the registry for the latest version; if this copy is behind, re-exec the latest and hand off.
26
+ A bare `npx @nurix/<tool>` keeps running an outdated unpacked copy long after a newer version publishes — npm's packument cache resolves an old `latest`, and npx reuses the matching install — so the CLI updates itself rather than relying on users to type `@latest`. Before anything else, ask the registry for the latest version; if this copy is behind, re-exec the latest and hand off (etna's `selfUpdateOrReexec()`):
29
27
 
30
28
  ```js
31
29
  function selfUpdateOrReexec() {
@@ -44,43 +42,45 @@ function selfUpdateOrReexec() {
44
42
 
45
43
  Required properties:
46
44
 
47
- - **`--prefer-online`** on both the `npm view` and the `npx` re-exec — defeats the metadata cache so npx fetches the fresh tarball.
48
- - **Loop guard** — set `<TOOL>_SELFUPDATED=1` in the child's env so the re-exec'd process doesn't try to update again.
49
- - **Opt-out** — `<TOOL>_NO_SELFUPDATE=1` skips the whole thing (CI, offline, or running an intentionally pinned/local-dev build). This is also how you test a local build.
50
- - **Degrade gracefully** — *any* failure (offline, unauthed, `npm`/`npx` missing, timeout) falls through to running the current copy. The update is a convenience, never a gate.
51
- - **Reuse existing npm auth** — the `npm view` rides the caller's npm credentials (the same auth that installed the restricted package); never prompt for login.
45
+ - **`--prefer-online`** on both the `npm view` and the `npx` re-exec — it defeats the metadata cache, so npx fetches the fresh tarball.
46
+ - **Loop guard** — set `<TOOL>_SELFUPDATED=1` in the child's env so the re-exec'd process never updates again.
47
+ - **Opt-out** — `<TOOL>_NO_SELFUPDATE=1` skips the check: CI, offline, an intentionally pinned build, and testing a local build.
48
+ - **Degrade gracefully** — *any* failure (offline, unauthed, `npm`/`npx` missing, timeout) falls through to running the current copy; the update is a convenience, **never** a gate.
49
+ - **Reuse existing npm auth** — `npm view` rides the caller's credentials, the same auth that installed the restricted package; **never** prompt for login.
52
50
 
53
51
  ## 4. Editing the user's files: own a delimited block, idempotently
54
52
 
55
- When the CLI must modify a file it doesn't own (`.env`, `settings.json`, `.gitignore`), it **owns only a delimited region** and rewrites that region in place — never the whole file.
53
+ When the CLI modifies a file it doesn't own (`.env`, `settings.json`, `.gitignore`), it **owns only a delimited region** and rewrites that region in place — **never** the whole file.
56
54
 
57
55
  - nustack wraps its `.env` writes in a managed block:
58
- `# >>> nustack:managed — do not edit by hand; the nustack CLI rewrites this block >>>` … `# <<< nustack:managed <<<`. Reads/merges/removes happen *inside* the markers; everything outside belongs to the user.
59
- - etna merges its hooks into `.claude/settings.json` and migrates/retires only its own prior entries.
60
- - Rewrites are **idempotent** (re-running converges to the same block) and **reversible** (logout/uninstall removes exactly the managed region).
61
- - If the block holds secrets, ensure `.gitignore` covers the file so they're never committed.
56
+ `# >>> nustack:managed — do not edit by hand; the nustack CLI rewrites this block >>>` … `# <<< nustack:managed <<<`. Reads, merges, and removals happen *inside* the markers; everything outside belongs to the user.
57
+ - etna merges its hooks into `.claude/settings.json` and migrates or retires only its own entries.
58
+ - Rewrites are **idempotent** (a re-run converges to the same block) and **reversible** (logout or uninstall removes exactly the managed region).
59
+ - A block holding secrets **must** sit in a file `.gitignore` covers.
62
60
 
63
61
  ## 5. Interactive when it can, flag-driven when it can't
64
62
 
65
- - Use **`@clack/prompts`** for the interactive path (TTY): intro/outro, spinners, notes.
66
- - When **not a TTY**, require explicit flags and fail loudly with the correct syntax rather than guessing — e.g. etna needs `--name=<harness>` outside a TTY, and a removed/renamed flag (the dropped positional form in 0.18.0) errors with the new syntax instead of silently misfiring.
67
- - A bare invocation in a TTY may present a menu; the same invocation headless must error, not hang.
63
+ - Use **`@clack/prompts`** for the interactive (TTY) path: intro/outro, spinners, notes.
64
+ - **Outside a TTY**, require explicit flags and fail loudly with the correct syntax rather than guessing — etna requires `--name=<harness>`, and an unsupported flag or argument form errors with the current syntax instead of silently misfiring.
65
+ - A bare invocation in a TTY may present a menu; the same invocation headless **must** error, not hang.
68
66
 
69
67
  ## 6. Detect the package manager from the lockfile
70
68
 
71
- When the CLI installs packages or runs scripts on the user's behalf, detect the manager: `pnpm-lock.yaml` → pnpm, `yarn.lock` → yarn, else npm. Never hardcode one. (nustack's `detectPackageManager()`.)
69
+ When the CLI installs packages or runs scripts for the user, detect the manager from the lockfile — `pnpm-lock.yaml` → pnpm, `yarn.lock` → yarn, else npm (nustack's `detectPackageManager()`); **never** hardcode one.
72
70
 
73
71
  ## 7. Publishing is CI-owned
74
72
 
75
- Publish from CI on push to `dev`/`main`, path-filtered to the CLI package — never `npm publish` by hand for a routine change. The pipeline mechanics — workflow template, tags, skip directives, `registry-url`, monorepo `working-directory` — are [`publishing.md`](publishing.md) §3–5. CLI-specific on top:
73
+ Publish from CI on push to `dev`/`main`, path-filtered to the CLI package — **never** `npm publish` by hand for a routine change. The pipeline mechanics — workflow template, tags, skip directives, `registry-url`, monorepo `working-directory` — are [`publishing.md`](publishing.md) §3–5. A CLI adds:
74
+
75
+ | Version model | How it bumps |
76
+ | --- | --- |
77
+ | **Fingerprint auto-bump** (etna) | The build stamps a content hash (`fingerprint`) of the shipped payload; CI bumps the **patch** when it changes, publishes, and tags. **Never** hand-bump for a content change; hand-edit the version only for a deliberate minor/major |
78
+ | **Manual bump input** (nustack) | A `workflow_dispatch` `bump` input (`patch`/`minor`/`major`) drives `npm version` |
76
79
 
77
- - **Two valid version models:**
78
- - **Fingerprint auto-bump (etna):** the build stamps a content hash (`fingerprint`) of the shipped payload; CI bumps the **patch** automatically when the fingerprint changed, publishes, and tags. Never hand-bump for a content change — let the fingerprint drive it; hand-edit the version only for a deliberate minor/major.
79
- - **Manual bump input (nustack):** a `workflow_dispatch` `bump` input (`patch`/`minor`/`major`) drives `npm version`.
80
- - **`npm version --no-git-tag-version`** (file-only), then commit + tag separately — `npm version` skips the git step when run in a subdirectory of the repo root.
80
+ - **`npm version --no-git-tag-version`** (file-only), then commit and tag separately — `npm version` silently skips its git step in a subdirectory of the repo root.
81
81
 
82
82
  ## 8. Robustness defaults
83
83
 
84
- - **Never hard-block on an advisory/network check.** Version currency, registry lookups, telemetry — all degrade to a one-line notice and continue.
85
- - **Restricted-scope auth is ambient** — the read token in `~/.npmrc` (or `$NODE_AUTH_TOKEN` in CI) authenticates installs and `npm view`. Just attempt the operation; never prompt for `npm login` or reach for a substitute package.
86
- - **Keep the hot path fast** — everything runs on every `npx`, so avoid heavy startup work beyond the self-update check.
84
+ - **Never hard-block on an advisory or network check.** Version currency, registry lookups, telemetry — each degrades to a one-line notice and continues.
85
+ - **Restricted-scope auth is ambient** — the read token in `~/.npmrc` (or `$NODE_AUTH_TOKEN` in CI) authenticates installs and `npm view`. Attempt the operation; **never** prompt for `npm login` or reach for a substitute package.
86
+ - **Keep the hot path fast** — startup runs on every `npx`; do no heavy work beyond the self-update check.
@@ -2,7 +2,7 @@
2
2
 
3
3
  Load when: auditing a workspace's health, reviewing a monorepo PR, scaffolding review gates, or deciding what to enforce next in an existing workspace.
4
4
 
5
- The definitive requirements for a `@nurix/*` monorepo, in three tiers: **required** (every workspace, day one), **trigger-bound** (required the moment its trigger exists), and **deferred** (explicitly not required before scale). Assembly mechanics are [`monorepo-setup.md`](monorepo-setup.md); the publishing pipeline is [`publishing.md`](publishing.md); naming doctrine is [`pnpm.md`](../../../rules/pnpm.md) §1. Every line is auditable — it holds or it doesn't — and names its enforcement mechanism in the closing table.
5
+ The definitive requirements for a `@nurix/*` monorepo, in three tiers: **required** (every workspace, day one), **trigger-bound** (required the moment its trigger exists), and **deferred** (not required before scale). Assembly mechanics are [`monorepo-setup.md`](monorepo-setup.md); the publishing pipeline is [`publishing.md`](publishing.md); naming doctrine is [`pnpm.md`](../../../rules/pnpm.md) §1. Every line holds or it doesn't, and the closing table names how each is enforced.
6
6
 
7
7
  ## Required — every workspace, day one
8
8
 
@@ -17,22 +17,22 @@ The definitive requirements for a `@nurix/*` monorepo, in three tiers: **require
17
17
  9. **Source-first internals, one-way flow** — internal packages export `./src/index.ts` through typed subpaths, no build step; apps depend on packages, never the reverse; anything not exported stays unreachable.
18
18
  10. **Strict hoisting** — no `shamefully-hoist`, no `node-linker=hoisted`; an undeclared import must fail immediately.
19
19
  11. **CI that gates** — a workflow installs with `--frozen-lockfile` and gates merges on the root fan-out. No CI is a compliance failure; a CI that mutates manifests before building is worse than none.
20
- 12. **A real suite behind `pnpm test`** — the canonical-command rule applies to every workspace; toolchain configs (eslint + prettier, root-only) are wired to `lint`/`format` scripts that actually run. A fan-out script with zero targets is decoration, not compliance.
20
+ 12. **A real suite behind `pnpm test`** — the `testing` rule's canonical-command convention applies to every workspace; root-only toolchain configs (eslint + prettier) are wired to `lint`/`format` scripts that actually run. A fan-out script with zero targets is decoration, not compliance.
21
21
 
22
22
  ## Required the moment the trigger exists
23
23
 
24
- - **Native or postinstall deps in the lockfile** → `onlyBuiltDependencies` in `pnpm-workspace.yaml` (never the root `package.json` `pnpm` field), kept current as native deps come and go — pnpm 10 silently skips unlisted builds and the failure surfaces at runtime.
25
- - **A vulnerable transitive** → one `overrides` block in the workspace file; never duplicated into the root manifest.
24
+ - **Native or postinstall deps in the lockfile** → `onlyBuiltDependencies` in `pnpm-workspace.yaml` (**never** the root `package.json` `pnpm` field), kept current as native deps come and go — pnpm 10 silently skips unlisted builds and the failure surfaces at runtime.
25
+ - **A vulnerable transitive** → one `overrides` block in the workspace file; **never** duplicated into the root manifest.
26
26
  - **A member crosses the publish boundary** (`private: false`) → the [`publishing.md`](publishing.md) fields; the build hook **inside** `scripts` (a top-level `prepublishOnly` key silently never runs); `sideEffects: false` (or the CSS-glob variant) so consumers tree-shake; and the parity harness — `pack` → tarball-install into fixtures → build → `publint` + `attw` — re-run on every `exports`-surface change. Dev-mode success proves nothing about what consumers get.
27
27
 
28
28
  ## Deferred until scale — explicitly not required before
29
29
 
30
- - **Affected-filtering and task-graph runners** (`--filter "...[origin/main]"`, turbo, nx) — adopt when full `pnpm -r` runs are slow enough to feel; never day one.
30
+ - **Affected-filtering and task-graph runners** (`--filter "...[origin/main]"`, turbo, nx) — adopt once full `pnpm -r` runs are slow enough to feel; never day one.
31
31
  - **`CODEOWNERS` by directory** — when multiple teams own members; decoration before that.
32
32
 
33
33
  ## Enforcement — every rule names its mechanism
34
34
 
35
- A rule that depends on discipline drifts; a rule the tooling enforces doesn't. When adding a rule to this list, name the mechanism and what happens on violation — prefer the variant that fails loudly at install/CI over the one a reviewer must notice.
35
+ A rule that depends on discipline drifts; a rule the tooling enforces doesn't. A rule added to this list **must** name its mechanism and what happens on violation — prefer the variant that fails loudly at install or CI over one a reviewer must notice.
36
36
 
37
37
  | Rule | Mechanism | On violation |
38
38
  | --- | --- | --- |
@@ -2,11 +2,11 @@
2
2
 
3
3
  Load when: scaffolding a new pnpm workspace, converting a repo to one, adding a workspace member, or wiring the root toolchain (catalog, scripts, build gating).
4
4
 
5
- How a workspace is **assembled** — the root files, layout globs, catalog, and verification. What packages are *named* and how their boundaries work is [`pnpm.md`](../../../rules/pnpm.md) §1–2; how a member *publishes* is [`publishing.md`](publishing.md); the standing invariants to keep true after assembly are [`monorepo-master-list.md`](monorepo-master-list.md). Reference implementations: `~/dev/workflows` (the canonical `packages/*` + catalog shape), `~/dev/starter` (adds `fixtures/*` and the publish-parity harness), `~/dev/robin` and `~/dev/sync-info` (the `packages/*` + `apps/*` split).
5
+ How a workspace is **assembled** — root files, layout globs, catalog, verification. Package naming and boundaries are [`pnpm.md`](../../../rules/pnpm.md) §1–2; how a member publishes is [`publishing.md`](publishing.md); the invariants to keep true after assembly are [`monorepo-master-list.md`](monorepo-master-list.md). Reference implementations: `~/dev/workflows` (the canonical `packages/*` + catalog shape), `~/dev/starter` (adds `fixtures/*` and the publish-parity harness), `~/dev/robin` and `~/dev/sync-info` (the `packages/*` + `apps/*` split).
6
6
 
7
7
  ## 1. Three root files own the workspace
8
8
 
9
- Everything workspace-wide lives in exactly three root files; packages stay thin. Nothing else at root compiles, publishes, or carries policy.
9
+ Everything workspace-wide lives in exactly three root files; packages stay thin, and nothing else at root compiles, publishes, or carries policy.
10
10
 
11
11
  **`pnpm-workspace.yaml`** — membership + shared versions:
12
12
 
@@ -46,11 +46,11 @@ onlyBuiltDependencies: # postinstall allow-list — see §4
46
46
  }
47
47
  ```
48
48
 
49
- - **Fan out with `pnpm -r`; alias with `--filter`.** `--if-present` when not every member has the script; per-app conveniences read `"dev:admin": "pnpm --filter @nurix/nustack-app dev"` (nustack) or `"worker:dev": "pnpm --filter @sync/worker dev"` (sync-info).
50
- - **One toolchain config at root.** `eslint`/`prettier` run from the root over the whole tree — never per-package configs.
51
- - **No turbo/nx.** Plain `pnpm -r` is the baseline; reach for a task-graph runner only when the build graph is slow enough to feel — the same threshold as TS project references (`pnpm.md` §2).
49
+ - **Fan out with `pnpm -r`; alias with `--filter`.** Add `--if-present` when not every member has the script; a per-app convenience reads `"dev:marketplace": "pnpm --filter @nurix/nustack.marketplace dev"`.
50
+ - **One toolchain config at root.** `eslint`/`prettier` run from the root over the whole tree — **never** per-package configs.
51
+ - **No turbo/nx by default.** Plain `pnpm -r` is the baseline; adopt a task-graph runner only once the build graph is slow enough to feel — the same threshold as TS project references (`pnpm.md` §2).
52
52
 
53
- **`tsconfig.base.json`** — the single TS policy owner (`pnpm.md` §2). The workflows repo's base is the model: `strict`, `noUncheckedIndexedAccess`, `noImplicitOverride`, `noFallthroughCasesInSwitch`, `noUnusedLocals` / `noUnusedParameters`, `declaration` + `declarationMap`, `skipLibCheck`. There is **no root `tsconfig.json`** — the base is extended by members, never compiled from.
53
+ **`tsconfig.base.json`** — the single TS policy owner (`pnpm.md` §2). The workflows repo's base is the model: `strict`, `noUncheckedIndexedAccess`, `noImplicitOverride`, `noFallthroughCasesInSwitch`, `noUnusedLocals` / `noUnusedParameters`, `declaration` + `declarationMap`, `skipLibCheck`. There is **no root `tsconfig.json`** — members extend the base; nothing compiles from it.
54
54
 
55
55
  ## 2. Layout — pick the globs by what the repo holds
56
56
 
@@ -62,17 +62,17 @@ onlyBuiltDependencies: # postinstall allow-list — see §4
62
62
  | + `fixtures/*` | consumer-simulation apps for parity testing (§5) | starter |
63
63
 
64
64
  - **Dependency direction is one-way** — `apps/*` depend on `packages/*`, never the reverse; siblings import each other's typed subpath exports, never a deep path into `src/` (`pnpm.md` §2).
65
- - Flat globs are the default; a deep path in the list (`sdk/packages/node/iii`) is for polyglot trees only.
65
+ - Default to flat globs; a deep path in the list (`sdk/packages/node/iii`) is for polyglot trees only.
66
66
 
67
67
  ## 3. `catalog:` — one version per shared dep
68
68
 
69
- Anything two or more members depend on goes in the catalog: the toolchain (`typescript`, `vite`, `vitest`, type packages) and the host singletons (`react`, `react-dom`, `zod`). Members reference it as `"react": "catalog:"` — never a literal version. **A member that pins its own version beside the catalog defeats it** — two `react` copies means two hook dispatchers and runtime errors, not a type error.
69
+ Anything two or more members depend on goes in the catalog: the toolchain (`typescript`, `vite`, `vitest`, type packages) and the host singletons (`react`, `react-dom`, `zod`). Members reference it as `"react": "catalog:"` — **never** a literal version. **A member that pins its own version beside the catalog defeats it** — two `react` copies means two hook dispatchers and runtime errors, not a type error. Set `catalogMode: strict` in `pnpm-workspace.yaml` so such a pin is an install error ([`monorepo-master-list.md`](monorepo-master-list.md) rule 2).
70
70
 
71
- Internal siblings are `"workspace:*"`; both protocols are rewritten to real versions at publish time.
71
+ Internal siblings are `"workspace:*"`; `pnpm publish` rewrites both protocols to real versions.
72
72
 
73
73
  ## 4. pnpm 10 build gating
74
74
 
75
- pnpm 10 refuses to run dependency postinstall scripts unless allow-listed. Keep the allow-list in `pnpm-workspace.yaml` — `onlyBuiltDependencies` (or the map-form `allowBuilds`; `pnpm approve-builds` writes it for you) — for native/codegen deps: `esbuild`, `@swc/core`, `better-sqlite3`. The failure mode is **not** an install error: install succeeds and the missing binary surfaces at runtime.
75
+ pnpm 10 runs no dependency postinstall script unless allow-listed. Keep the allow-list in `pnpm-workspace.yaml` — `onlyBuiltDependencies` (or the map-form `allowBuilds`, which `pnpm approve-builds` writes) — for native and codegen deps: `esbuild`, `@swc/core`, `better-sqlite3`. A missing entry is **not** an install error: install succeeds and the missing binary surfaces at runtime.
76
76
 
77
77
  ## 5. Adding a member
78
78
 
@@ -82,15 +82,15 @@ pnpm 10 refuses to run dependency postinstall scripts unless allow-listed. Keep
82
82
  4. Dependencies: `workspace:*` for siblings, `catalog:` for shared externals.
83
83
  5. Publishable member: dist-based `exports`, `files: ["dist"]`, `publishConfig` — [`publishing.md`](publishing.md) §2 — and cover it with the parity check (§6).
84
84
 
85
- > **Agent guard — never commit a `link:` to a sibling repo on disk** (`"@nurix/contracts": "link:../../../NuStack-contracts"`). The path is machine-specific: every fresh clone and CI run breaks. Consume the published restricted package (`pnpm.md` §3); if the dep must be co-developed, that's the signal it belongs in this workspace.
85
+ > **Agent guard — never commit a `link:` to a sibling repo on disk** (`"@nurix/contracts": "link:../../../NuStack-contracts"`). The path is machine-specific: every fresh clone and CI run breaks. Consume the published restricted package (`pnpm.md` §3); a dep that must be co-developed belongs in this workspace.
86
86
 
87
87
  ## 6. Verify — publish parity
88
88
 
89
- `pnpm install && pnpm -r typecheck` is the smoke test after any membership or catalog change. For workspaces with publishable members, the starter's `scripts/publish-parity.mjs` is the model harness: `npm pack` each publishable member, tarball-install into isolated copies of `fixtures/*`, build them, run `publint` + `attw` — proving consumers of the tarball get what workspace-source dev promises (a deep `src/` import or a missing `exports` entry works in dev and only breaks here). Wire it as the root `parity` script; run before first publish and after any change to an `exports` surface.
89
+ Run `pnpm install && pnpm -r typecheck` after any membership or catalog change. A workspace with publishable members **also** needs a parity harness, because a deep `src/` import or a missing `exports` entry works in workspace-source dev and breaks only in the tarball. The starter's `scripts/publish-parity.mjs` is the model: `npm pack` each publishable member, tarball-install into isolated copies of `fixtures/*`, build them, run `publint` + `attw`. Wire it as the root `parity` script; run it before the first publish and after any change to an `exports` surface.
90
90
 
91
91
  ## 7. Quick checklist for a new workspace
92
92
 
93
- - [ ] `pnpm-workspace.yaml`: globs (§2) + `catalog:` + build allow-list if needed
93
+ - [ ] `pnpm-workspace.yaml`: globs (§2) + `catalog:` + `catalogMode: strict` + build allow-list if needed
94
94
  - [ ] Root `package.json`: `private: true`, exact `packageManager` pin, `engines`, `pnpm -r` scripts
95
95
  - [ ] `tsconfig.base.json` with the strict policy set; no root `tsconfig.json`
96
96
  - [ ] First member added per §5; siblings via `workspace:*`, shared deps via `catalog:`
@@ -2,21 +2,19 @@
2
2
 
3
3
  Load when: creating or publishing a `@nurix/*` package, wiring or debugging a publish workflow, or diagnosing a failed `npm publish`.
4
4
 
5
- How a `@nurix/*` package **ships**: the npm pipeline from `package.json` fields to a published restricted-access version. Naming a package and structuring the workspace it lives in are [`pnpm.md`](../../../rules/pnpm.md) §1–2; consuming an already-published package is `pnpm.md` §3.
5
+ How a `@nurix/*` package **ships**: from `package.json` fields to a published version on **npmjs.org with `restricted` access**, installable only by npm users with read rights to the `nurix` org. Naming a package and structuring its workspace are [`pnpm.md`](../../../rules/pnpm.md) §1–2; consuming a published package is `pnpm.md` §3. Reference implementations: `~/dev/components` (`@nurix/components`, library) and `~/dev/etna/packages/cli` (`@nurix/etna`, CLI).
6
6
 
7
- `@nurix/*` packages publish to **npmjs.org with `restricted` access** — only npm users with read rights to the `nurix` org can install them. Reference implementations: `~/dev/components` (`@nurix/components`, library) and `~/dev/etna/packages/cli` (`@nurix/etna`, CLI).
8
-
9
- npmjs is the source of truth for **both publish and install**. A caching proxy may sit in front of it for reads, but it is **never a publish target** — treat a proxy URL in a publish path as a bug. And publish and install must name the **same** registry: a package published to one and installed from another 404s, and that 404 is indistinguishable from "never published", because a restricted read answers 404 rather than 401 so it doesn't leak which packages exist. (The consumer-side pairing check is [`pnpm.md`](../../../rules/pnpm.md) §3.)
7
+ npmjs is the registry for **both publish and install**. A caching proxy may serve reads, but it is **never a publish target** — a proxy URL in a publish path is a bug. Publish and install **must** name the same registry: a restricted read answers `404`, not `401`, so a package published to one registry and installed from another looks exactly like one never published (the consumer-side pairing check is `pnpm.md` §3).
10
8
 
11
9
  ## 1. Prerequisites (one-time, org-wide)
12
10
 
13
- 1. **npm org `nurix`** exists and you're a member with publish rights — <https://www.npmjs.com/settings/nurix/packages>.
14
- 2. **An npm automation token** with `Read and write` for the `nurix` scope — npm → Generate New Token → Automation.
15
- 3. **The token added as a GitHub Actions secret** named `NPM_PUBLISH_TOKEN` on every publishing repo. `NPM_PUBLISH_TOKEN` is the convention; pick another name only with a strong reason.
11
+ 1. Confirm you are a member of the npm org `nurix` with publish rights — <https://www.npmjs.com/settings/nurix/packages>.
12
+ 2. Generate an npm **Automation** token with `Read and write` on the `nurix` scope (npm → Generate New Token → Automation).
13
+ 3. Add it as the GitHub Actions secret `NPM_PUBLISH_TOKEN` on every publishing repo. Default to that name; use another only with a strong reason.
16
14
 
17
15
  ## 2. `package.json` — required fields
18
16
 
19
- **Private by default.** A package is born `"private": true` and stays there until someone needs it from *another repo*. Publishing is a deliberate act that creates a contract — once published, an export removed or a peer range widened is a breaking change for consumers you cannot see. Internal-to-the-repo packages never publish; they link with `workspace:*` ([`pnpm.md`](../../../rules/pnpm.md) §2). When a package does cross the boundary, the manifest carries:
17
+ **Private by default.** A package is born `"private": true` and stays there until another repo needs it. Publishing creates a contract — once published, a removed export or a widened peer range breaks consumers you cannot see. A package used only inside its repo **never** publishes; it links with `workspace:*` (`pnpm.md` §2). A package crossing the boundary carries:
20
18
 
21
19
  ```jsonc
22
20
  {
@@ -28,12 +26,12 @@ npmjs is the source of truth for **both publish and install**. A caching proxy m
28
26
  }
29
27
  ```
30
28
 
31
- - **`publishConfig.access`** — `"restricted"` (recommended): visible only to `nurix`-org readers. `"public"`: world-readable (free, but only if you mean it). Omitting it on a scoped package defaults to `restricted`; be explicit anyway.
32
- - **`files`** — without it, npm publishes everything not in `.gitignore`, **including source**. Library → `["dist"]`; CLI (etna) → `["bin/", "data/", "README.md"]`. Don't list `package.json`/`README.md` — npm always includes them.
33
- - **Build to `dist` — never ship raw `src`.** A published library compiles with `tsc` (`declaration: true` + `declarationMap: true` come from `tsconfig.base.json`) and points `exports`/`types` at `./dist/*` — `types` first in each subpath block ([`pnpm.md`](../../../rules/pnpm.md) §2 owns the ordering rule). To keep the dev entry on source, use `publishConfig.exports` to swap source→dist at publish time.
34
- - **Build hooks** — `prepack` for build steps that must produce files in `files` (also runs on install-as-git-dep); `prepublishOnly` for publish-only steps. Either alone is fine; `@nurix/components` runs both. With the build hooked here, a publish can never ship a stale `dist`.
29
+ - **`publishConfig.access`** — default `"restricted"`: visible only to `nurix`-org readers. `"public"` is world-readable — use it only when that is the intent. A scoped package without the field defaults to `restricted`; set it explicitly anyway.
30
+ - **`files`** — without it, npm publishes everything not in `.gitignore`, **including source**. Library → `["dist"]`; CLI (etna) → `["bin/", "lib/", "data/"]`. Omit `package.json` and `README.md` — npm always includes them.
31
+ - **Build to `dist` — never ship raw `src`.** A published library compiles with `tsc` (`declaration` and `declarationMap` come from `tsconfig.base.json`) and points `exports`/`types` at `./dist/*`, `types` first in each subpath block (`pnpm.md` §2 owns the ordering). To keep the dev entry on source, swap source→dist at publish time with `publishConfig.exports`.
32
+ - **Build hooks** — `prepack` for build steps that must produce files in `files` (also runs on install-as-git-dep); `prepublishOnly` for publish-only steps. Either alone is fine; `@nurix/components` builds and verifies its types in `prepublishOnly`. With the build hooked here, a publish can never ship a stale `dist`.
35
33
  - **Host singletons are `peerDependencies`** — `react`, `react-dom`, the framework client — so consumers keep exactly one copy; **never** bundle them. Apps depend on them directly.
36
- - **Dependencies carry registry specs only** — **no** `file:`/`link:` (the workspace-root boundary, [`pnpm.md`](../../../rules/pnpm.md) §2). `workspace:*` between workspace members is fine: `pnpm publish` rewrites it into a real range.
34
+ - **Dependencies carry registry specs only** — **no** `file:`/`link:` (the workspace-root boundary, `pnpm.md` §2). `workspace:*` between members is fine: `pnpm publish` rewrites it into a real range.
37
35
  - **Other useful fields** — `type: "module"`, `engines.node`, `bin` (CLIs), `main`/`module`/`types`/`exports` (libraries), `sideEffects: ["**/*.css"]`, `repository` (with `directory` for monorepos), `license: "UNLICENSED"`.
38
36
 
39
37
  ## 3. The publish workflow (generic template)
@@ -75,23 +73,23 @@ jobs:
75
73
  - run: git push --follow-tags # pushes the bump commit AND the v<version> tag npm created
76
74
  ```
77
75
 
78
- **Why dual-trigger is safe** — three safeguards prevent an infinite publish loop: (1) `paths:` scopes the push trigger to artifact-affecting files; (2) `[skip ci]` in the bump commit makes GitHub skip the workflow that bump would otherwise re-trigger; (3) `concurrency: cancel-in-progress: false` queues near-simultaneous merges instead of racing for a version number.
76
+ **Keep all three loop safeguards** — dropping any one lets the dual trigger publish in a loop or race: `paths:` scopes the push trigger to artifact-affecting files; `[skip ci]` in the bump commit stops that commit re-triggering the workflow; `cancel-in-progress: false` queues near-simultaneous merges instead of racing for a version number.
79
77
 
80
- **`registry-url` is load-bearing** — without `registry-url: https://registry.npmjs.org` on `setup-node`, it never writes the `.npmrc` line that uses `$NODE_AUTH_TOKEN`, and the publish falls back to anonymous auth and fails.
78
+ **`registry-url` is load-bearing** — without it on `setup-node`, no `.npmrc` line reads `$NODE_AUTH_TOKEN`, and the publish falls back to anonymous auth and fails.
81
79
 
82
- **The token never enters the repo checkout** — `setup-node` writes its auth `.npmrc` outside the workspace, so the bump commit the job pushes cannot pick it up; a hand-rolled auth line goes to `$HOME/.npmrc` for the same reason, never a repo-path `.npmrc`. Expand the token in the shell step that writes it (`echo "//registry.npmjs.org/:_authToken=$NPM_PUBLISH_TOKEN" >> "$HOME/.npmrc"`) rather than leaving a literal `${VAR}` for the npm client to expand at read time — read-time expansion silently breaks in any later step that lacks the variable.
80
+ **The token never enters the repo checkout** — `setup-node` writes its auth `.npmrc` outside the workspace, so the pushed bump commit cannot pick it up; a hand-rolled auth line goes to `$HOME/.npmrc`, **never** a repo-path `.npmrc`. Expand the token in the shell step that writes it (`echo "//registry.npmjs.org/:_authToken=$NPM_PUBLISH_TOKEN" >> "$HOME/.npmrc"`), never a literal `${VAR}` left for npm to expand at read time — that breaks silently in any later step lacking the variable.
83
81
 
84
- **A pnpm workspace publishes with `pnpm publish --no-git-checks`** — swap it into the publish step above (and into flow C, §4). Only pnpm rewrites `catalog:`/`workspace:` specifiers into real ranges (§6); `--no-git-checks` is required because pnpm otherwise refuses to publish from a non-release branch or from a tree carrying the bump commit the previous step just made. `npm publish` stays correct only for a single-package repo on an npm lockfile.
82
+ **A pnpm workspace publishes with `pnpm publish --no-git-checks`** — swap it into the publish step above and into flow C (§4). Only pnpm rewrites `catalog:`/`workspace:` specifiers into real ranges (§6); without `--no-git-checks`, pnpm refuses to publish from a non-release branch or from a tree carrying the bump commit the previous step made. `npm publish` is correct only for a single-package repo on an npm lockfile.
85
83
 
86
84
  ## 4. The three ways to ship
87
85
 
88
- - **A. Auto on merge (common).** Land on the default branch; if a `paths:`-filtered file changed, the workflow fires and ships a patch.
89
- - **B. Manual dispatch (minor/major/none).** **Actions → Publish to npm → Run workflow**, pick `bump = minor|major` — or `none`, which publishes the current version as-is: the CI-side bootstrap for a first publish when a repo ships exclusively from CI (§7's checklist bootstraps from a local publish instead; both paths are sanctioned).
90
- - **C. Local (CI down / one-off / pipeline bootstrap):** `npm version <patch|minor|major>` → publish → `git push --follow-tags` — sanctioned, at the cost that it bypasses CI's build, lockfile, and version-bump discipline. In a pnpm workspace the publish command is **`pnpm publish --no-git-checks`** (never `npm publish` — the catalog-protocol pitfall in §6; the flag rationale is §3); in a subdirectory of the repo root, `npm version` needs `--no-git-tag-version` plus a manual commit + tag.
86
+ - **A. Auto on merge (default).** Land on the default branch; a change to a `paths:`-filtered file fires the workflow and ships a patch.
87
+ - **B. Manual dispatch (minor/major/none).** **Actions → Publish to npm → Run workflow**, pick `bump = minor|major` — or `none`, which publishes the current version as-is: the first-publish bootstrap for a repo that ships only from CI. §7's checklist bootstraps from a local publish instead; both are sanctioned.
88
+ - **C. Local (CI down, one-off, pipeline bootstrap).** `npm version <patch|minor|major>` → publish → `git push --follow-tags`. Sanctioned, at the price of bypassing CI's build, lockfile, and version-bump discipline. In a pnpm workspace the publish command is **`pnpm publish --no-git-checks`**, **never** `npm publish` (the catalog-protocol pitfall, §6); in a subdirectory of the repo root, `npm version` needs `--no-git-tag-version` plus a manual commit and tag.
91
89
 
92
- Local auth uses two tokens, two homes: a **read** token in `~/.npmrc` (`//registry.npmjs.org/:_authToken=…`) for `npm install`, and `NPM_PUBLISH_TOKEN` as an env var (sourced from `~/.zsh_secrets` or equivalent, **not** in `.npmrc` or the repo) for `npm publish`.
90
+ Local auth uses two tokens in two homes: a **read** token in `~/.npmrc` (`//registry.npmjs.org/:_authToken=…`) for `npm install`, and `NPM_PUBLISH_TOKEN` as an env var (sourced from `~/.zsh_secrets` or equivalent, **never** in `.npmrc` or the repo) for `npm publish`.
93
91
 
94
- > **Agent guard — if `NPM_PUBLISH_TOKEN` isn't in the environment, do not work around it.** No `npm login` to swap the user's auth, no rewriting `~/.npmrc`, no substituting the read token (it lacks publish rights → `403`), no `--registry` overrides, no temp-file token. Instead **stop and report**: "This repo can't publish locally — `NPM_PUBLISH_TOKEN` isn't set. Source `~/.zsh_secrets` (or wherever you keep it) and re-run, or trigger the CI workflow." Some users publish exclusively from CI — that's the default path for a reason.
92
+ > **Agent guard — if `NPM_PUBLISH_TOKEN` isn't in the environment, never work around it.** No `npm login` swapping the user's auth, no rewriting `~/.npmrc`, no substituting the read token (it lacks publish rights → `403`), no `--registry` override, no temp-file token. **Stop and report**: "This repo can't publish locally — `NPM_PUBLISH_TOKEN` isn't set. Source `~/.zsh_secrets` (or wherever you keep it) and re-run, or trigger the CI workflow."
95
93
 
96
94
  Verify after any flow: `https://www.npmjs.com/package/@nurix/<name>` and a clean-dir `npx @nurix/<name>@latest`.
97
95
 
@@ -99,27 +97,30 @@ Verify after any flow: `https://www.npmjs.com/package/@nurix/<name>` and a clean
99
97
 
100
98
  When the package lives in `packages/<pkg>/` of a multi-package repo:
101
99
 
102
- - **`working-directory: packages/<pkg>`** on the bump and publish steps so they operate on the right `package.json`.
100
+ - **`working-directory: packages/<pkg>`** on the bump and publish steps, so they act on the right `package.json`.
103
101
  - **Scoped concurrency** — `group: publish-<pkg>` lets sibling packages publish in parallel.
104
- - **Tag prefix — only with multiple tagging packages.** `npm version --tag-version-prefix="<pkg>-v"` (→ `<pkg>-v0.2.0`) is worth it only when more than one package cuts release tags, so they don't collide. A single publishable package (etna's case, even though it's laid out as a monorepo) uses plain `v0.2.0`.
105
- - **One workflow file per published package** — each `publish-<pkg>.yml` owns its `paths:` filter, `working-directory`, and concurrency group. A single shared workflow couples every package's release cadence and republishes siblings on unrelated changes.
106
- - **Publish dependencies first.** If package `A` depends on `B` by `workspace:^`, `B` must already exist on the registry — otherwise `A`'s rewritten range resolves to nothing for every consumer.
102
+ - **Tag prefix only when more than one package cuts release tags** — `npm version --tag-version-prefix="<pkg>-v"` (→ `<pkg>-v0.2.0`) keeps their tags from colliding.
103
+ - **One workflow file per published package** — each `publish-<pkg>.yml` owns its `paths:` filter, `working-directory`, and concurrency group. One shared workflow couples every package's release cadence and republishes siblings on unrelated changes.
104
+ - **Publish dependencies first.** If `A` depends on `B` by `workspace:^`, `B` **must** already exist on the registry, or `A`'s rewritten range resolves to nothing for every consumer.
107
105
 
108
- A repo with one publishable package only needs `working-directory`; skip the prefix, and concurrency scoping is optional.
106
+ A repo with one publishable package needs only `working-directory`: plain `v0.2.0` tags, concurrency scoping optional.
109
107
 
110
108
  ## 6. Common pitfalls
111
109
 
112
- - **402 Payment Required** — `access: "public"` on an org without a plan for free public scoped packages. Use `"restricted"` (or upgrade the plan).
113
- - **403 Forbidden** — `NPM_PUBLISH_TOKEN` missing/wrong, or its user lacks `nurix` write access, or it's a read-only (not Automation) token.
114
- - **"Cannot publish over previously published version x.y.z"** — a bump ran but publish failed and was re-run without rebasing. `git reset` the bump and let CI re-bump, or `npm version patch && git push --follow-tags && npm publish`.
115
- - **Publish succeeds but `npx @nurix/foo` is "command not found"** — no `bin` field, or `bin` points outside `files`, or the script is missing its `#!/usr/bin/env node` shebang.
116
- - **"Git working directory not clean" on `npm version`** — the checkout has untracked/modified files; build only into `.gitignore`d paths (the components repo builds into `dist/`).
117
- - **Published tarball contains source** — missing `files` in `package.json`. Add `["dist"]` and republish.
118
- - **pnpm consumers fail with "external package declared a dependency using the catalog protocol"** — the package was published with `npm publish` from a pnpm workspace: only **`pnpm publish`** rewrites `catalog:`/`workspace:` specifiers to real versions; npm ships them verbatim. A workspace member must always publish via `pnpm publish` (locally too, not just CI). Deprecate the broken version and republish.
119
- - **Tarball has no `dist/` even though `prepublishOnly` ran clean + build** — a stale `tsconfig.tsbuildinfo` (which `incremental: true` writes *next to tsconfig.json*, outside `dist/`) survived `rm -rf dist`, so `tsc` trusted it and silently emitted nothing. The `clean` script must purge it: `rm -rf dist *.tsbuildinfo`. The parity harness catches this class before it ships.
120
- - **Auto-publish fires too often** — no `paths:` filter or one that's too broad. Tighten it to artifact-affecting files, or drop the push trigger for `workflow_dispatch`-only.
121
- - **Workflow loops forever** — the bump commit lacks `[skip ci]`. Invoke `npm version` with `-m "chore: release v%s [skip ci]"`.
122
- - **A normal commit silently skips its own push** — the inverse trap. GitHub scans the head commit's **whole message** (subject _and_ body) for skip directives (`[skip ci]`, `[ci skip]`, `[no ci]`, `[skip actions]`, `***NO_CI***`). If any hand-written commit merely _mentions_ the literal token in prose, the entire push is skipped and the publish never fires (symptom: branch moved, paths matched, Actions on — yet zero runs for the SHA). Never write the literal token in a commit message or PR body unless you mean it; to ship a push that carried it by accident, re-trigger via **Run workflow** / `gh workflow run … --ref dev`.
110
+ | Symptom | Cause → fix |
111
+ | --- | --- |
112
+ | **402 Payment Required** | `access: "public"` on an org without a plan for free public scoped packages → use `"restricted"` (or upgrade the plan) |
113
+ | **403 Forbidden** | `NPM_PUBLISH_TOKEN` missing or wrong, its user lacks `nurix` write access, or it is a read-only (not Automation) token |
114
+ | **"Cannot publish over previously published version x.y.z"** | a bump ran, the publish failed, and it was re-run without rebasing → `git reset` the bump and let CI re-bump, or `npm version patch && git push --follow-tags && npm publish` |
115
+ | **Publish succeeds but `npx @nurix/foo` is "command not found"** | no `bin` field, `bin` points outside `files`, or the script lacks its `#!/usr/bin/env node` shebang |
116
+ | **"Git working directory not clean" on `npm version`** | the checkout has untracked or modified files → build only into `.gitignore`d paths (`dist/`) |
117
+ | **Published tarball contains source** | `files` missing from `package.json` → add `["dist"]` and republish |
118
+ | **Auto-publish fires too often** | no `paths:` filter, or one too broad → tighten it to artifact-affecting files, or drop the push trigger for `workflow_dispatch` only |
119
+ | **Workflow loops forever** | the bump commit lacks `[skip ci]` → invoke `npm version` with `-m "chore: release v%s [skip ci]"` |
120
+
121
+ - **pnpm consumers fail with "external package declared a dependency using the catalog protocol"** — the package went out via `npm publish` from a pnpm workspace, which ships `catalog:`/`workspace:` specifiers verbatim. A workspace member **always** publishes via `pnpm publish`, locally as well as in CI. Deprecate the broken version and republish.
122
+ - **Tarball has no `dist/` though `prepublishOnly` ran a clean build** — `incremental: true` writes `tsconfig.tsbuildinfo` *next to `tsconfig.json`*, outside `dist/`; a stale one survives `rm -rf dist`, so `tsc` trusts it and emits nothing. The `clean` script **must** purge it: `rm -rf dist *.tsbuildinfo`. The parity harness catches this class before it ships.
123
+ - **A normal commit silently skips its own push** — GitHub scans the head commit's **whole message**, subject _and_ body, for skip directives (`[skip ci]`, `[ci skip]`, `[no ci]`, `[skip actions]`, `***NO_CI***`); a hand-written commit that merely _mentions_ one skips the entire push, and the publish never fires (symptom: branch moved, paths matched, Actions on — zero runs for the SHA). **Never** write a literal skip token in a commit message or PR body unless you mean it; to ship a push that carried one by accident, re-trigger via **Run workflow** / `gh workflow run … --ref dev`.
123
124
 
124
125
  ## 7. Quick checklist for a new `@nurix/*` package
125
126
 
@@ -128,5 +129,5 @@ A repo with one publishable package only needs `working-directory`; skip the pre
128
129
  - [ ] Name follows [`pnpm.md`](../../../rules/pnpm.md) §1; if it's a workspace member, boundaries follow `pnpm.md` §2
129
130
  - [ ] `.github/workflows/publish.yml` from §3
130
131
  - [ ] `NPM_PUBLISH_TOKEN` secret added to the repo
131
- - [ ] First publish from local (flow C, §4) to verify the pipeline end-to-end, then a no-op commit to verify CI — a repo that ships exclusively from CI bootstraps with `bump = none` instead (§4B)
132
+ - [ ] First publish from local (flow C, §4) to verify the pipeline end to end, then a no-op commit to verify CI — or, for a repo that ships only from CI, bootstrap with `bump = none` (§4B)
132
133
  - [ ] README notes the `@nurix` scope so consumers know they need org access
@@ -1,5 +1,5 @@
1
1
  {
2
- "fingerprint": "1099ec325647",
2
+ "fingerprint": "899bed2c91e6",
3
3
  "harnesses": {
4
4
  "code": {
5
5
  "plugin": "code",
@@ -37,7 +37,7 @@ Three peer modes, then a verification gate and a Completion step — enter where
37
37
 
38
38
  > **A build graph overrides all of this, and most sessions never see one.** When `.claude/state/graph.json` exists, a walker decides which document is produced next and when the run is finished: a write reconciles it, an injected line names the next node, and the turn cannot end while the graph can still advance. Produce the file the line names. Never edit the graph or its state — both are refused — and never rewrite a node that has already landed. No such file ⇒ nothing in this paragraph is running.
39
39
 
40
- > **The lightweight lane:** a change touching one module, **at most ~10 files, none on a contract-heavy surface** (db schema, wire envelopes, auth, events, env/config — the `boundary` skill's list), and under about **three days'** work skips the modes above entirely — the ad-hoc regime of `.claude/rules/testing.md` applies: make the change, drive it, then pin it in the same unit of work if it alters promised behavior, cover it with a changelog row. The predicate is mechanical; when in doubt, the `boundary` diff scan is the tiebreak, not self-assessment.
40
+ > **The lightweight lane:** a change touching one module, **at most ~10 files, none on a contract-heavy surface** (db schema, wire envelopes, auth, events, env/config — the `boundary` skill's list), and under about **three days'** work skips the modes above entirely — the ad-hoc regime of `.claude/rules/testing.md` applies: make the change, drive it, then pin it in the same unit of work if it alters promised behavior, cover it with a changelog entry. The predicate is mechanical; when in doubt, the `boundary` diff scan is the tiebreak, not self-assessment.
41
41
 
42
42
  **On Plan Completion:**
43
43
 
@@ -80,7 +80,7 @@ The `lld-mode` agent checks for ownership conflicts during LLD research — two
80
80
 
81
81
  Boundaries are **diagnosed, not documented** — the `boundary` skill derives them fresh from source on every run (the definition and mechanism catalog live in the skill), so nothing is persisted that could go stale.
82
82
 
83
- **Invoke the `boundary` skill while the plan is being written — a plan is not finished until it carries the verdict.** It parses the plan's Proposed Changes, reads the touched source, traces the consumers on the other side, and reports severity-ranked violations with suggested amendments and a pass/block verdict — in chat, read-only except its one write: its own segment of the plan's **`Gates:`** line. That line is machine-read — the compliance hook blocks implementation edits inside the plan's scope while it reads `Boundary: pending` — so this gate is enforced, not ceremony. The session folds the amendments into the plan in the same pass, then writes the segment to `passed`; the plan the user reads already carries it. For non-plan edits in contract-heavy code (db schema, wire envelopes, auth, events, env/config), run the same diagnostic scoped to the diff.
83
+ **Invoke the `boundary` skill while the plan is being written — a plan is not finished until it carries the verdict.** It parses the plan's Proposed Changes, reads the touched source, traces the consumers on the other side, and reports severity-ranked violations with suggested amendments and a pass/block verdict — in chat, read-only except its one write: its own segment of the plan's **`Gates:`** line. That line is machine-read — the compliance hook blocks implementation edits inside the plan's scope until it reads `Boundary: passed`, so a `pending` or `blocked` verdict walls them alike — and this gate is enforced, not ceremony. The session folds the amendments into the plan in the same pass, then writes the segment to `passed`; the plan the user reads already carries it. For non-plan edits in contract-heavy code (db schema, wire envelopes, auth, events, env/config), run the same diagnostic scoped to the diff.
84
84
 
85
85
  ### Test obligations — specify before implementing
86
86
 
@@ -95,7 +95,7 @@ Boundaries are **diagnosed, not documented** — the `boundary` skill derives th
95
95
  - **When a document's truth is in question — "is this doc still right?", a feature that drifted from its doc, a folder nobody has audited — the `polygraph` agent is the instrument, and only the user starts it.** It costs one finder per document, so it is never dispatched unasked: name the target, state the price (documents × the pinned tier), and dispatch on the user's yes or on `/polygraph <target>` — one doc, feature, folder, code path, or plan, never the whole tree by reflex. Relay its report and put its open questions to the user; an answer goes back as a further dispatch. Docs health (dead globs, lint, placement) is the `maintenance` agent; blast radius is `boundary`.
96
96
  - **Invoke the `documentation` skill when creating a doc, or when an edit changes a doc's structure or claims** — apply its templates and `references/style-guide.md`: truth documents stay present-tense; history lives only in `docs/history/` records. Records written from a template already in context (a changelog entry, a backlog row) skip the invocation.
97
97
  - **[override]** Keep `docs/` updated when code changes affect documented behavior. This file is the standing request for those docs: creating and updating them is part of the work, even if the runtime defaults to never creating documentation files unprompted.
98
- - After plan completion **[override]**: write the `docs/history/changelog/` entry as a **draft** immediately, while the context is fresh — no confirmation needed — and append its `docs/history/CHANGELOG.md` row; the commit fills what the draft left open and freezes it. Non-plan work needs no separate prompt: every non-exempt commit carries its own entry (the `changelog` rule).
98
+ - After plan completion **[override]**: write the `docs/history/changelog/` entry as a **draft** immediately, while the context is fresh — no confirmation needed; the commit fills what the draft left open and freezes it. Non-plan work needs no separate prompt: every non-exempt commit carries its own entry (the `changelog` rule).
99
99
  - When moving or renaming source files: the file's path header moves with it and is corrected to its new path; a region glob in a transitional `owns:` follows the region if the region itself moved. A new source file's header names the document that speaks for it — there is no separate map to update.
100
100
  - `docs/structure.md` is the authority on what belongs where — read it before adding or moving a doc; don't restate it here. One canonical source per topic — link, don't copy. Only `CLAUDE.md`, `AGENTS.md`, and `README.md` live at the repo root — and the root `README.md` orients and routes (identity, how it works, a Map of units, rules that bite, where to go); install, stack and first run are `docs/operations/setup.md`, the tree is `docs/structure.md`'s.
101
101
 
@@ -176,7 +176,7 @@ A file's documentation lives in `docs/`. Its comments carry only what a reader n
176
176
  - Add a file-path header comment at the top of each source file, in the file's native comment syntax — `// src/modules/example.js - Module for handling user authentication`. Place it below any shebang line; skip formats with no comment syntax (JSON, lockfiles) and generated files. **The path is repo-relative and names the file's own path**: a header a move left behind is worse than no header, because it reads as current.
177
177
  - **Two or three present-tense sentences, six lines at the ceiling** — what the file is, the invariant a reader must not break, and where the fuller account lives, as a `docs/…` path.
178
178
  - Add a 1-line description above each function whose purpose isn't fully evident from its name and signature: `// Extract JWT token from request based on endpoint type`. **One sentence, third-person indicative** — `Installs the package`, never `Install the package` — and a second sentence only to carry a named invariant. A field, type member, or constant earns a sentence only where its name and type do not already say it; a member of an enum or a constant map earns none. No commented-out code — refactor for clarity instead.
179
- - **Design rationale, alternatives weighed, history, ticket and decision-record references, and dated notes are not comments.** They belong to the owning feature doc, and moving the claim there is part of the same change — cutting one out of a comment without landing it is a deletion, not a cleanup (the `documentation` skill § Where a file's documentation lives).
179
+ - **Design rationale, alternatives weighed, history, ticket and decision-record references, and dated notes are not comments.** They belong to the owning feature doc, and moving the claim there is part of the same change — cutting one out of a comment without landing it is a deletion, not a cleanup (the `documentation` skill's `references/source-comments.md`).
180
180
  - **The ceiling is on what a change adds, not on what it inherits: under a quarter of the lines a change adds are comments.** The measured regression that set this number ran at 28% on new files while the tree it joined sat at 14%, so a whole-file average is the wrong instrument — it grades the density somebody else wrote and passes the prose being added right now. `.claude/skills/documentation/scripts/source-lint.mjs --changed` reports it and the detector raises one row per offending file; a comments-only sweep proves itself with `comment-strip.mjs`, which strips both revisions and diffs what is left, so a code change hiding inside a cleanup cannot pass as one.
181
181
  - **The one comment that earns a paragraph is a booby trap** — an edit that looks obviously safe and is not. It names the version or the measurement that makes it true and the condition under which it stops being true, so the next reader can retire it instead of trusting it. Everything else that wants a paragraph wants a doc.
182
182
 
@@ -122,8 +122,8 @@ Stop is facilitator-orchestrated because approval belongs to the user; you execu
122
122
  ledger and thesis. Gaps → record them in the manifest (`Result: fail`, named gaps), and the fixes
123
123
  re-enter as a new manifest `Round` requiring fresh approval. Pass → record it.
124
124
  4. **Move.** Run `--gate=move`. When clean: delete `ops/` entirely, `git mv` the folder to
125
- `docs/history/brainstorms/{topic}/`, set state `Status: harvested`, update both indexes
126
- (`docs/research/Readme.md` row out, `docs/history/brainstorms/Readme.md` row in). End your
125
+ `docs/history/brainstorms/{topic}/`, set state `Status: harvested` (no index row to move: the folder is
126
+ the record). End your
127
127
  report with the offer the facilitator relays: **delete the moved folder, or commit it** — the
128
128
  user decides; the design assumes deletion.
129
129
 
@@ -21,7 +21,7 @@ Map the documentation landscape — what exists, what is adjacent, how detailed
21
21
  2. Locate the repo's feature-doc layer from `structure.md` — the standard shape is `./docs/features/`, but a repo may document components under their own subject folders. Read that layer's index if it has one; otherwise glob for docs carrying `owns:` frontmatter
22
22
  3. If `./docs/memory/lld-mode.md` exists (or the legacy `./docs/memory/spec-mode.md`), read it for feature doc inventory, ownership conflict zones, and lessons from previous research
23
23
  4. Read 1-2 existing feature LLDs from that layer to calibrate format and depth
24
- 5. Consult the **injected ownership index** (the generated `glob → doc · module · objects · status` map — computed from source headers and the transitional `owns:` region globs) to build the ownership map. It is the source of truth for what code paths are already spoken for; a source file's path header names its document directly. If the index isn't present in context, glob the docs tree (excluding `docs/history/`) and read the `owns:` frontmatter of every doc that declares it.
24
+ 5. Consult the **injected ownership index** (the generated `glob → doc · module · objects · status` map, built from the transitional `owns:` region globs; a source file's path header names its document directly) to build the ownership map. It is the source of truth for what code paths are already spoken for; a source file's path header names its document directly. If the index isn't present in context, glob the docs tree (excluding `docs/history/`) and read the `owns:` frontmatter of every doc that declares it.
25
25
 
26
26
  ## What You Research
27
27
 
@@ -46,7 +46,7 @@ Structure your findings as:
46
46
  - **Invalidated claims**: One row per existing doc this feature makes wrong — doc path, the claim, why it stops being true. This list seeds the plan's **Doc Obligations** ledger, so it is the research finding most likely to survive into an artifact; "none" is a real answer and says the feature is genuinely additive.
47
47
  - **Risks or concerns**: Anything the LLD should address or call out
48
48
 
49
- Structure your findings by the `documentation` skill's style guide — imperative voice, function signatures over implementations, mermaid for flows.
49
+ Write each finding as a bold noun-phrase label and one or two third-person sentences (the `documentation` skill's `references/style-guide.md` § Labels, § Voice); mermaid for a flow worth drawing. Paths, symbols and routes belong in these findings because the author needs them, but these fields are research, not the LLD's sections: the feature doc takes its template's sections and names objects and promises, never the functions listed here.
50
50
 
51
51
  ## Rules
52
52