@mnstry/atelier 0.2.0-alpha.12 → 0.2.0-alpha.14

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 (531) hide show
  1. package/CHANGELOG.md +894 -0
  2. package/README.md +159 -6
  3. package/contracts/atelier-adoption-policy.v2.schema.json +55 -0
  4. package/contracts/atelier-architecture.v1.schema.json +258 -0
  5. package/contracts/atelier-boundary-delegations.v1.schema.json +161 -0
  6. package/contracts/atelier-boundary-owner-keys.v1.schema.json +98 -0
  7. package/contracts/atelier-build.v1.schema.json +1076 -0
  8. package/contracts/atelier-capability.v1.schema.json +1252 -0
  9. package/contracts/atelier-coordination.v1.schema.json +1050 -0
  10. package/contracts/atelier-evidence-navigation.v1.schema.json +603 -0
  11. package/contracts/atelier-harness.v1.schema.json +234 -0
  12. package/contracts/atelier-ingestion.v1.schema.json +806 -0
  13. package/contracts/atelier-inquiry.v1.schema.json +1772 -0
  14. package/contracts/atelier-instruction-adoption.v1.schema.json +490 -0
  15. package/contracts/atelier-interaction.v1.schema.json +553 -0
  16. package/contracts/atelier-judgment.v1.schema.json +690 -0
  17. package/contracts/atelier-knowledge.v1.schema.json +1512 -0
  18. package/contracts/atelier-learning.v1.schema.json +1095 -0
  19. package/contracts/atelier-migration.v3.schema.json +64 -0
  20. package/contracts/atelier-personal-workspace-manifest.v1.schema.json +87 -0
  21. package/contracts/atelier-personal-workspace-overlay.v1.schema.json +299 -0
  22. package/contracts/atelier-template-adoption.v1.schema.json +223 -0
  23. package/contracts/atelier-template-profile.v1.schema.json +1168 -0
  24. package/contracts/atelier-trackable.v1.schema.json +781 -0
  25. package/contracts/atelier-upgrade-plan.v3.schema.json +532 -0
  26. package/docs/architecture.md +89 -0
  27. package/docs/assurance-controls.md +2 -2
  28. package/docs/blocks/capability-stewardship.md +17 -0
  29. package/docs/blocks/claims.md +16 -3
  30. package/docs/blocks/inquiry-harnesses.md +19 -0
  31. package/docs/blocks/learning-harnesses.md +17 -0
  32. package/docs/capability-stewardship.md +267 -0
  33. package/docs/coordination.md +51 -0
  34. package/docs/decision-practices.md +111 -0
  35. package/docs/decisions.md +29 -0
  36. package/docs/evidence-navigation.md +237 -0
  37. package/docs/exact-upgrades.md +3 -2
  38. package/docs/ingestion.md +181 -0
  39. package/docs/inquiry-harnesses.md +210 -0
  40. package/docs/install.md +80 -3
  41. package/docs/intake-and-guides.md +5 -0
  42. package/docs/integration-contract-decisions.md +24 -2
  43. package/docs/interaction-and-reflection.md +72 -0
  44. package/docs/knowledge-graph.md +20 -0
  45. package/docs/knowledge-health/api.md +30 -0
  46. package/docs/knowledge-health/assessment/api.md +96 -0
  47. package/docs/knowledge-health/assessment/capabilities.md +40 -0
  48. package/docs/knowledge-health/assessment/evaluation.md +27 -0
  49. package/docs/knowledge-health/assessment/facilitator.md +30 -0
  50. package/docs/knowledge-health/assessment/quickstart.md +61 -0
  51. package/docs/knowledge-health/assessment/troubleshooting.md +23 -0
  52. package/docs/knowledge-health/devday/facilitator.md +16 -0
  53. package/docs/knowledge-health/devday/participant-response.md +22 -0
  54. package/docs/knowledge-health/devday/public-default.md +107 -0
  55. package/docs/knowledge-health/devday/quickstart.md +18 -0
  56. package/docs/knowledge-health/devday/support.md +22 -0
  57. package/docs/knowledge-health/exercise.md +17 -0
  58. package/docs/knowledge-health/facilitator.md +20 -0
  59. package/docs/knowledge-health/quickstart.md +94 -0
  60. package/docs/knowledge-health/readme.md +15 -0
  61. package/docs/knowledge-health/support.md +34 -0
  62. package/docs/knowledge-setup.md +248 -0
  63. package/docs/knowledge-workspace.md +264 -0
  64. package/docs/learning-harnesses.md +237 -0
  65. package/docs/learning.md +215 -0
  66. package/docs/local-services.md +223 -19
  67. package/docs/obsidian-contract.md +246 -15
  68. package/docs/obsidian-plugin.md +252 -7
  69. package/docs/obsidian.md +874 -52
  70. package/docs/optional-ingestion.md +83 -0
  71. package/docs/personal-workspace.md +266 -0
  72. package/docs/practical-judgment.md +92 -0
  73. package/docs/progressive-ingestion-acceptance.md +89 -0
  74. package/docs/progressive-ingestion.md +235 -0
  75. package/docs/project-command-inventory.md +1 -0
  76. package/docs/release-engineering.md +50 -0
  77. package/docs/repo-boundary-guard.md +120 -3
  78. package/docs/research-starter-quickstart.md +66 -0
  79. package/docs/research-starter.md +114 -0
  80. package/docs/semantic-ingestion.md +198 -0
  81. package/docs/semantic-operation.md +318 -0
  82. package/docs/skill-steward.md +6 -0
  83. package/docs/template-profile.md +164 -0
  84. package/docs/template-upgrades.md +114 -0
  85. package/docs/trackables.md +111 -0
  86. package/docs/upgrade.md +219 -2
  87. package/fixtures/atelier-architecture/binding/invalid/document.json +19 -0
  88. package/fixtures/atelier-architecture/binding/valid/document.json +19 -0
  89. package/fixtures/atelier-architecture/catalog/invalid/document.json +290 -0
  90. package/fixtures/atelier-architecture/catalog/valid/document.json +343 -0
  91. package/fixtures/atelier-build-contract/attempt/invalid/document.json +20 -0
  92. package/fixtures/atelier-build-contract/attempt/valid/document.json +19 -0
  93. package/fixtures/atelier-build-contract/candidate/invalid/document.json +24 -0
  94. package/fixtures/atelier-build-contract/candidate/valid/document.json +23 -0
  95. package/fixtures/atelier-build-contract/decision/invalid/document.json +31 -0
  96. package/fixtures/atelier-build-contract/decision/valid/document.json +30 -0
  97. package/fixtures/atelier-build-contract/delivery/invalid/document.json +18 -0
  98. package/fixtures/atelier-build-contract/delivery/valid/document.json +17 -0
  99. package/fixtures/atelier-build-contract/gate/invalid/document.json +22 -0
  100. package/fixtures/atelier-build-contract/gate/valid/document.json +21 -0
  101. package/fixtures/atelier-build-contract/ledger/invalid/document.json +270 -0
  102. package/fixtures/atelier-build-contract/ledger/valid/document.json +269 -0
  103. package/fixtures/atelier-build-contract/objective/invalid/document.json +73 -0
  104. package/fixtures/atelier-build-contract/objective/valid/document.json +72 -0
  105. package/fixtures/atelier-build-contract/progress/invalid/document.json +18 -0
  106. package/fixtures/atelier-build-contract/progress/valid/document.json +17 -0
  107. package/fixtures/atelier-capability-contract/adoption/invalid/document.json +71 -0
  108. package/fixtures/atelier-capability-contract/adoption/valid/document.json +70 -0
  109. package/fixtures/atelier-capability-contract/event/invalid/document.json +18 -0
  110. package/fixtures/atelier-capability-contract/event/valid/document.json +17 -0
  111. package/fixtures/atelier-capability-contract/journal/invalid/document.json +382 -0
  112. package/fixtures/atelier-capability-contract/journal/valid/document.json +381 -0
  113. package/fixtures/atelier-capability-contract/notice/invalid/document.json +8 -0
  114. package/fixtures/atelier-capability-contract/notice/valid/document.json +7 -0
  115. package/fixtures/atelier-capability-contract/package/invalid/document.json +59 -0
  116. package/fixtures/atelier-capability-contract/package/valid/document.json +58 -0
  117. package/fixtures/atelier-capability-contract/plan/invalid/document.json +107 -0
  118. package/fixtures/atelier-capability-contract/plan/valid/document.json +106 -0
  119. package/fixtures/atelier-capability-contract/release/invalid/document.json +85 -0
  120. package/fixtures/atelier-capability-contract/release/valid/document.json +84 -0
  121. package/fixtures/atelier-capability-contract/state/invalid/document.json +316 -0
  122. package/fixtures/atelier-capability-contract/state/valid/document.json +315 -0
  123. package/fixtures/atelier-coordination/dependency/invalid/document.json +37 -0
  124. package/fixtures/atelier-coordination/dependency/valid/document.json +36 -0
  125. package/fixtures/atelier-coordination/directive/invalid/document.json +25 -0
  126. package/fixtures/atelier-coordination/directive/valid/document.json +24 -0
  127. package/fixtures/atelier-coordination/disposition/invalid/document.json +34 -0
  128. package/fixtures/atelier-coordination/disposition/valid/document.json +33 -0
  129. package/fixtures/atelier-coordination/outcome/invalid/document.json +39 -0
  130. package/fixtures/atelier-coordination/outcome/valid/document.json +38 -0
  131. package/fixtures/atelier-coordination/recovery/invalid/document.json +34 -0
  132. package/fixtures/atelier-coordination/recovery/valid/document.json +33 -0
  133. package/fixtures/atelier-harness-contract/handoff/invalid/document.json +25 -0
  134. package/fixtures/atelier-harness-contract/handoff/valid/document.json +24 -0
  135. package/fixtures/atelier-ingestion/invalid/authority.json +19 -0
  136. package/fixtures/atelier-ingestion/semantic-baseline.json +26 -0
  137. package/fixtures/atelier-ingestion/semantic-operation.json +75 -0
  138. package/fixtures/atelier-ingestion/valid/plan-input.json +18 -0
  139. package/fixtures/atelier-inquiry-contract/assessment/invalid/document.json +41 -0
  140. package/fixtures/atelier-inquiry-contract/assessment/valid/document.json +40 -0
  141. package/fixtures/atelier-inquiry-contract/bundle/invalid/document.json +51 -0
  142. package/fixtures/atelier-inquiry-contract/bundle/valid/document.json +50 -0
  143. package/fixtures/atelier-inquiry-contract/campaign/invalid/document.json +17 -0
  144. package/fixtures/atelier-inquiry-contract/campaign/valid/document.json +16 -0
  145. package/fixtures/atelier-inquiry-contract/decision/invalid/document.json +22 -0
  146. package/fixtures/atelier-inquiry-contract/decision/valid/document.json +21 -0
  147. package/fixtures/atelier-inquiry-contract/feedback/invalid/document.json +19 -0
  148. package/fixtures/atelier-inquiry-contract/feedback/valid/document.json +18 -0
  149. package/fixtures/atelier-inquiry-contract/handoff/invalid/document.json +92 -0
  150. package/fixtures/atelier-inquiry-contract/handoff/valid/document.json +91 -0
  151. package/fixtures/atelier-inquiry-contract/hypothesis/invalid/document.json +20 -0
  152. package/fixtures/atelier-inquiry-contract/hypothesis/valid/document.json +19 -0
  153. package/fixtures/atelier-inquiry-contract/ledger/invalid/document.json +680 -0
  154. package/fixtures/atelier-inquiry-contract/ledger/valid/document.json +679 -0
  155. package/fixtures/atelier-inquiry-contract/legacy-assessment/invalid/document.json +19 -0
  156. package/fixtures/atelier-inquiry-contract/legacy-assessment/valid/document.json +18 -0
  157. package/fixtures/atelier-inquiry-contract/request/invalid/document.json +50 -0
  158. package/fixtures/atelier-inquiry-contract/request/valid/document.json +49 -0
  159. package/fixtures/atelier-inquiry-contract/source/invalid/document.json +18 -0
  160. package/fixtures/atelier-inquiry-contract/source/valid/document.json +17 -0
  161. package/fixtures/atelier-inquiry-contract/withdrawal/invalid/document.json +16 -0
  162. package/fixtures/atelier-inquiry-contract/withdrawal/valid/document.json +15 -0
  163. package/fixtures/atelier-instruction-adoption/context-receipt/invalid/document.json +18 -0
  164. package/fixtures/atelier-instruction-adoption/context-receipt/valid/document.json +17 -0
  165. package/fixtures/atelier-instruction-adoption/plan/invalid/document.json +63 -0
  166. package/fixtures/atelier-instruction-adoption/plan/valid/document.json +62 -0
  167. package/fixtures/atelier-instruction-adoption/receipt/invalid/document.json +22 -0
  168. package/fixtures/atelier-instruction-adoption/receipt/valid/document.json +21 -0
  169. package/fixtures/atelier-instruction-adoption/state/invalid/document.json +30 -0
  170. package/fixtures/atelier-instruction-adoption/state/valid/document.json +29 -0
  171. package/fixtures/atelier-interaction/act/invalid/document.json +25 -0
  172. package/fixtures/atelier-interaction/act/valid/document.json +24 -0
  173. package/fixtures/atelier-interaction/assessment/invalid/document.json +32 -0
  174. package/fixtures/atelier-interaction/assessment/valid/document.json +31 -0
  175. package/fixtures/atelier-interaction/observation/invalid/document.json +22 -0
  176. package/fixtures/atelier-interaction/observation/valid/document.json +21 -0
  177. package/fixtures/atelier-interaction/policy/invalid/document.json +20 -0
  178. package/fixtures/atelier-interaction/policy/valid/document.json +19 -0
  179. package/fixtures/atelier-judgment/case/invalid/document.json +76 -0
  180. package/fixtures/atelier-judgment/case/valid/document.json +75 -0
  181. package/fixtures/atelier-judgment/decision/invalid/document.json +38 -0
  182. package/fixtures/atelier-judgment/decision/valid/document.json +37 -0
  183. package/fixtures/atelier-judgment/native-decision.md +3 -0
  184. package/fixtures/atelier-judgment/practice-reconsideration/definition.json +92 -0
  185. package/fixtures/atelier-judgment/practice-reconsideration/scenario.json +435 -0
  186. package/fixtures/atelier-knowledge-contract/activation/invalid/document.json +26 -0
  187. package/fixtures/atelier-knowledge-contract/activation/valid/document.json +25 -0
  188. package/fixtures/atelier-knowledge-contract/contribution/invalid/document.json +34 -0
  189. package/fixtures/atelier-knowledge-contract/contribution/valid/document.json +33 -0
  190. package/fixtures/atelier-knowledge-contract/domain/invalid/document.json +41 -0
  191. package/fixtures/atelier-knowledge-contract/domain/valid/document.json +40 -0
  192. package/fixtures/atelier-knowledge-contract/domain-revision/invalid/document.json +46 -0
  193. package/fixtures/atelier-knowledge-contract/domain-revision/valid/document.json +45 -0
  194. package/fixtures/atelier-knowledge-contract/evaluation/invalid/document.json +21 -0
  195. package/fixtures/atelier-knowledge-contract/evaluation/valid/document.json +20 -0
  196. package/fixtures/atelier-knowledge-contract/ledger/invalid/document.json +318 -0
  197. package/fixtures/atelier-knowledge-contract/ledger/valid/document.json +317 -0
  198. package/fixtures/atelier-knowledge-contract/relation/invalid/document.json +25 -0
  199. package/fixtures/atelier-knowledge-contract/relation/valid/document.json +24 -0
  200. package/fixtures/atelier-knowledge-contract/review/invalid/document.json +18 -0
  201. package/fixtures/atelier-knowledge-contract/review/valid/document.json +17 -0
  202. package/fixtures/atelier-knowledge-contract/withdrawal/invalid/document.json +16 -0
  203. package/fixtures/atelier-knowledge-contract/withdrawal/valid/document.json +15 -0
  204. package/fixtures/atelier-learning/invalid/authority.json +14 -0
  205. package/fixtures/atelier-learning/valid/capture.json +13 -0
  206. package/fixtures/atelier-personal-workspace-contract/manifest/invalid/authority-key.json +17 -0
  207. package/fixtures/atelier-personal-workspace-contract/manifest/invalid/nonempty-ext.json +25 -0
  208. package/fixtures/atelier-personal-workspace-contract/manifest/invalid/wrong-schema.json +22 -0
  209. package/fixtures/atelier-personal-workspace-contract/manifest/valid/manifest.json +22 -0
  210. package/fixtures/atelier-personal-workspace-contract/overlay/invalid/authority-key.json +25 -0
  211. package/fixtures/atelier-personal-workspace-contract/overlay/invalid/unknown-top-level-field.json +27 -0
  212. package/fixtures/atelier-personal-workspace-contract/overlay/invalid/wrong-schema.json +24 -0
  213. package/fixtures/atelier-trackable/definition/invalid/document.json +15 -0
  214. package/fixtures/atelier-trackable/definition/valid/document.json +14 -0
  215. package/fixtures/atelier-trackable/request/invalid/document.json +23 -0
  216. package/fixtures/atelier-trackable/request/valid/document.json +22 -0
  217. package/fixtures/boundary-delegations/invalid/authority-key.v1.json +30 -0
  218. package/fixtures/boundary-delegations/invalid/push-operation.v1.json +28 -0
  219. package/fixtures/boundary-delegations/invalid/unsigned.v1.json +25 -0
  220. package/fixtures/boundary-delegations/valid/empty.v1.json +4 -0
  221. package/fixtures/boundary-delegations/valid/signed-operator.v1.json +30 -0
  222. package/fixtures/boundary-owner-keys/invalid/wrong-algorithm.v1.json +15 -0
  223. package/fixtures/boundary-owner-keys/invalid/wrong-curve.v1.json +15 -0
  224. package/fixtures/boundary-owner-keys/valid/one-owner.v1.json +17 -0
  225. package/fixtures/capability-packages/adoption.example.json +70 -0
  226. package/fixtures/capability-packages/evidence-review/capability-package.json +58 -0
  227. package/fixtures/capability-packages/evidence-review/capability-release.json +84 -0
  228. package/fixtures/capability-packages/evidence-review/evaluation.md +15 -0
  229. package/fixtures/capability-packages/evidence-review/skills/evidence-review/SKILL.md +22 -0
  230. package/fixtures/capability-packages/evidence-review/skills/evidence-review/references/ledger.md +7 -0
  231. package/fixtures/capability-packages/research/capability-package.json +88 -0
  232. package/fixtures/capability-packages/research/capability-release.json +134 -0
  233. package/fixtures/capability-packages/research/evaluation.md +15 -0
  234. package/fixtures/capability-packages/research/skills/research-integrate/SKILL.md +29 -0
  235. package/fixtures/capability-packages/research/skills/research-integrate/references/integration.md +10 -0
  236. package/fixtures/capability-packages/research/skills/research-plan/SKILL.md +27 -0
  237. package/fixtures/capability-packages/research/skills/research-plan/references/inquiries.md +26 -0
  238. package/fixtures/capability-packages/research/skills/research-synthesize/SKILL.md +23 -0
  239. package/fixtures/capability-packages/research/skills/research-synthesize/references/synthesis.md +12 -0
  240. package/fixtures/evidence-navigation/invalid/duplicate-operation.json +16 -0
  241. package/fixtures/evidence-navigation/invalid/instruction-kind.json +36 -0
  242. package/fixtures/evidence-navigation/invalid/invalid-digest.json +36 -0
  243. package/fixtures/evidence-navigation/invalid/invalid-time.json +36 -0
  244. package/fixtures/evidence-navigation/invalid/missing-attribution.json +35 -0
  245. package/fixtures/evidence-navigation/invalid/reserved-extension.json +19 -0
  246. package/fixtures/evidence-navigation/invalid/unattributed-acceptance.json +36 -0
  247. package/fixtures/evidence-navigation/invalid/uncoerced-version.json +16 -0
  248. package/fixtures/evidence-navigation/invalid/unknown-currency.json +17 -0
  249. package/fixtures/evidence-navigation/invalid/unknown-selector-field.json +37 -0
  250. package/fixtures/evidence-navigation/invalid/unsupported-operation.json +15 -0
  251. package/fixtures/evidence-navigation/valid/claim.json +36 -0
  252. package/fixtures/evidence-navigation/valid/host.json +16 -0
  253. package/fixtures/evidence-navigation/valid/profile.json +16 -0
  254. package/fixtures/evidence-navigation/valid/snapshot.json +17 -0
  255. package/fixtures/harness-packages/build-harness/capability-package.json +61 -0
  256. package/fixtures/harness-packages/build-harness/capability-release.json +82 -0
  257. package/fixtures/harness-packages/build-harness/evaluation.md +3 -0
  258. package/fixtures/harness-packages/build-harness/skills/atelier-build-harness/SKILL.md +59 -0
  259. package/fixtures/harness-packages/knowledge-harness/capability-package.json +61 -0
  260. package/fixtures/harness-packages/knowledge-harness/capability-release.json +82 -0
  261. package/fixtures/harness-packages/knowledge-harness/evaluation.md +3 -0
  262. package/fixtures/harness-packages/knowledge-harness/skills/atelier-knowledge-harness/SKILL.md +60 -0
  263. package/fixtures/harnesses/learning-cycle.json +780 -0
  264. package/fixtures/inquiry/workshop.json +675 -0
  265. package/fixtures/inquiry-packages/discovery-harness/capability-package.json +61 -0
  266. package/fixtures/inquiry-packages/discovery-harness/capability-release.json +82 -0
  267. package/fixtures/inquiry-packages/discovery-harness/evaluation.md +3 -0
  268. package/fixtures/inquiry-packages/discovery-harness/skills/atelier-discovery-harness/SKILL.md +48 -0
  269. package/fixtures/inquiry-packages/research-harness/capability-package.json +61 -0
  270. package/fixtures/inquiry-packages/research-harness/capability-release.json +82 -0
  271. package/fixtures/inquiry-packages/research-harness/evaluation.md +3 -0
  272. package/fixtures/inquiry-packages/research-harness/skills/atelier-research-harness/SKILL.md +43 -0
  273. package/fixtures/knowledge-health/calibration-suite.json +26 -0
  274. package/fixtures/knowledge-health/calibration-trial.json +37 -0
  275. package/fixtures/knowledge-health/corrected/checklist.md +18 -0
  276. package/fixtures/knowledge-health/devday/participant-record.json +19 -0
  277. package/fixtures/knowledge-health/expected-summary.json +27 -0
  278. package/fixtures/knowledge-health/workshop/README.md +20 -0
  279. package/fixtures/knowledge-health/workshop/atelier.project.json +7 -0
  280. package/fixtures/knowledge-health/workshop/knowledge-plan.json +65 -0
  281. package/fixtures/knowledge-health/workshop/records/checklist.md +18 -0
  282. package/fixtures/knowledge-health/workshop/records/workshop.md +18 -0
  283. package/fixtures/knowledge-health/workshop/repo-access.v1.json +5 -0
  284. package/fixtures/knowledge-health/workspace/atelier.project.json +18 -0
  285. package/fixtures/knowledge-health/workspace/knowledge-plan.json +74 -0
  286. package/fixtures/knowledge-health/workspace/records/checklist.md +18 -0
  287. package/fixtures/knowledge-health/workspace/records/pilot.md +16 -0
  288. package/fixtures/knowledge-health/workspace/repo-access.v1.json +9 -0
  289. package/fixtures/personal-workspace/overlay.json +24 -0
  290. package/fixtures/templates/local-library.v1.json +76 -0
  291. package/fixtures/templates/upgrade-contracts/adoption-policy.v2/invalid.json +16 -0
  292. package/fixtures/templates/upgrade-contracts/adoption-policy.v2/valid.json +13 -0
  293. package/fixtures/templates/upgrade-contracts/migration.v3/invalid.json +24 -0
  294. package/fixtures/templates/upgrade-contracts/migration.v3/valid.json +21 -0
  295. package/fixtures/templates/upgrade-contracts/template-adoption.v1/invalid.json +60 -0
  296. package/fixtures/templates/upgrade-contracts/template-adoption.v1/valid.json +57 -0
  297. package/fixtures/templates/upgrade-contracts/upgrade-plan.v3/invalid.json +85 -0
  298. package/fixtures/templates/upgrade-contracts/upgrade-plan.v3/valid.json +82 -0
  299. package/package.json +60 -5
  300. package/plugins/obsidian/main.js +57 -8
  301. package/plugins/obsidian/manifest.json +1 -1
  302. package/skills/claude/atelier-build-harness/SKILL.md +59 -0
  303. package/skills/claude/atelier-coordination/SKILL.md +32 -0
  304. package/skills/claude/atelier-discovery-harness/SKILL.md +48 -0
  305. package/skills/claude/atelier-guided-upgrade/SKILL.md +29 -0
  306. package/skills/claude/atelier-interaction/SKILL.md +34 -0
  307. package/skills/claude/atelier-knowledge-harness/SKILL.md +60 -0
  308. package/skills/claude/atelier-knowledge-setup/SKILL.md +72 -0
  309. package/skills/claude/atelier-practical-judgment/SKILL.md +64 -0
  310. package/skills/claude/atelier-research-harness/SKILL.md +43 -0
  311. package/skills/claude/atelier-skill-steward/SKILL.md +53 -0
  312. package/skills/claude/atelier-trackables/SKILL.md +40 -0
  313. package/skills/codex/atelier-build-harness/SKILL.md +59 -0
  314. package/skills/codex/atelier-coordination/SKILL.md +32 -0
  315. package/skills/codex/atelier-discovery-harness/SKILL.md +48 -0
  316. package/skills/codex/atelier-guided-upgrade/SKILL.md +29 -0
  317. package/skills/codex/atelier-interaction/SKILL.md +34 -0
  318. package/skills/codex/atelier-knowledge-harness/SKILL.md +60 -0
  319. package/skills/codex/atelier-knowledge-setup/SKILL.md +72 -0
  320. package/skills/codex/atelier-practical-judgment/SKILL.md +64 -0
  321. package/skills/codex/atelier-research-harness/SKILL.md +43 -0
  322. package/skills/codex/atelier-skill-steward/SKILL.md +53 -0
  323. package/skills/codex/atelier-trackables/SKILL.md +40 -0
  324. package/src/architecture/catalog.mjs +355 -0
  325. package/src/architecture/index.mjs +93 -0
  326. package/src/boundary/content-rules.mjs +536 -69
  327. package/src/boundary/delegation-command.mjs +158 -0
  328. package/src/boundary/delegation.mjs +396 -0
  329. package/src/boundary/policy.mjs +185 -64
  330. package/src/build/git.mjs +18 -0
  331. package/src/build/index.mjs +3 -0
  332. package/src/build/ledger.mjs +88 -0
  333. package/src/capabilities/adoption.mjs +381 -0
  334. package/src/capabilities/evidence.mjs +140 -0
  335. package/src/capabilities/files.mjs +124 -0
  336. package/src/capabilities/index.mjs +4 -0
  337. package/src/capabilities/instructions.mjs +250 -0
  338. package/src/capabilities/package.mjs +136 -0
  339. package/src/cli/command-failure.mjs +36 -0
  340. package/src/cli/execute-command.mjs +16 -2
  341. package/src/cli/run.mjs +66 -9
  342. package/src/coauthor/store.mjs +43 -2
  343. package/src/collaboration/proposals.mjs +189 -0
  344. package/src/commands/architecture.mjs +27 -0
  345. package/src/commands/boundary.mjs +3 -0
  346. package/src/commands/capability.mjs +73 -0
  347. package/src/commands/enroll.mjs +3 -0
  348. package/src/commands/harness.mjs +79 -0
  349. package/src/commands/ingest.mjs +39 -0
  350. package/src/commands/init.mjs +4 -1
  351. package/src/commands/inquiry.mjs +66 -0
  352. package/src/commands/knowledge-semantic.mjs +128 -0
  353. package/src/commands/knowledge.mjs +119 -0
  354. package/src/commands/learn.mjs +61 -0
  355. package/src/commands/obsidian.mjs +772 -65
  356. package/src/commands/practice.mjs +24 -0
  357. package/src/commands/setup.mjs +22 -2
  358. package/src/commands/trackable.mjs +19 -0
  359. package/src/contracts/corpus.mjs +30 -0
  360. package/src/coordination/index.mjs +110 -0
  361. package/src/evidence-navigation/contracts.mjs +60 -0
  362. package/src/evidence-navigation/evaluate.mjs +69 -0
  363. package/src/evidence-navigation/generation.mjs +22 -0
  364. package/src/evidence-navigation/index.mjs +2 -0
  365. package/src/evidence-navigation/local.mjs +167 -0
  366. package/src/evidence-navigation/schema.generated.mjs +604 -0
  367. package/src/evidence-navigation/types.mjs +12 -0
  368. package/src/export/atelier-export-contract.mjs +35 -8
  369. package/src/graph/enroll.mjs +248 -0
  370. package/src/graph/graph.mjs +30 -6
  371. package/src/graph/knowledge-graph.mjs +77 -9
  372. package/src/harnesses/contracts.mjs +41 -0
  373. package/src/harnesses/exchange.mjs +154 -0
  374. package/src/harnesses/feedback.mjs +16 -0
  375. package/src/harnesses/history.mjs +37 -0
  376. package/src/harnesses/index.mjs +4 -0
  377. package/src/harnesses/store.mjs +29 -0
  378. package/src/ingestion/contracts.mjs +41 -0
  379. package/src/ingestion/evaluation.mjs +119 -0
  380. package/src/ingestion/optional/composition/index.mjs +171 -0
  381. package/src/ingestion/optional/evaluation/index.mjs +219 -0
  382. package/src/ingestion/optional/graphify/composition-binding.mjs +60 -0
  383. package/src/ingestion/optional/graphify/composition_receiving.py +185 -0
  384. package/src/ingestion/optional/graphify/graphify_supplier.py +938 -0
  385. package/src/ingestion/optional/graphify/json_bridge.py +163 -0
  386. package/src/ingestion/optional/graphify/native-closure-pins.json +275 -0
  387. package/src/ingestion/optional/graphify/native-pins.json +306 -0
  388. package/src/ingestion/optional/graphify/query_receiving.py +209 -0
  389. package/src/ingestion/optional/index.mjs +9 -0
  390. package/src/ingestion/optional/jev/bridge.mjs +166 -0
  391. package/src/ingestion/optional/jev/composition-binding.mjs +116 -0
  392. package/src/ingestion/optional/jev/judgments.mjs +174 -0
  393. package/src/ingestion/optional/jev/native-translation.mjs +32 -0
  394. package/src/ingestion/optional/lightrag/atelier_lightrag_supplier/__init__.py +7 -0
  395. package/src/ingestion/optional/lightrag/atelier_lightrag_supplier/adapter.py +966 -0
  396. package/src/ingestion/optional/lightrag/atelier_lightrag_supplier/artifacts.py +101 -0
  397. package/src/ingestion/optional/lightrag/atelier_lightrag_supplier/projection.py +146 -0
  398. package/src/ingestion/optional/lightrag/composition-binding.mjs +67 -0
  399. package/src/ingestion/optional/vanilla/composition-binding.mjs +102 -0
  400. package/src/ingestion/optional/vanilla/index.mjs +218 -0
  401. package/src/ingestion/optional/vanilla/native-normalization.mjs +187 -0
  402. package/src/ingestion/processors.mjs +218 -0
  403. package/src/ingestion/semantic.mjs +203 -0
  404. package/src/ingestion/store.mjs +372 -0
  405. package/src/inquiry/beliefs.mjs +32 -0
  406. package/src/inquiry/contracts.mjs +23 -0
  407. package/src/inquiry/index.mjs +5 -0
  408. package/src/inquiry/ledger.mjs +135 -0
  409. package/src/inquiry/lenses.mjs +15 -0
  410. package/src/inquiry/projection.mjs +77 -0
  411. package/src/inquiry/store.mjs +35 -0
  412. package/src/intake/read-scope.mjs +12 -0
  413. package/src/intake/store.mjs +69 -6
  414. package/src/interaction/index.mjs +91 -0
  415. package/src/judgment/index.mjs +82 -0
  416. package/src/judgment/practice-evaluation.mjs +70 -0
  417. package/src/judgment/practice.mjs +144 -0
  418. package/src/knowledge/context.mjs +217 -0
  419. package/src/knowledge/index.mjs +5 -0
  420. package/src/knowledge/ingestion.mjs +79 -0
  421. package/src/knowledge/intake.mjs +33 -0
  422. package/src/knowledge/ledger.mjs +110 -0
  423. package/src/knowledge/participatory/guidance.mjs +36 -0
  424. package/src/knowledge/participatory/guided-contribution.mjs +44 -0
  425. package/src/knowledge/participatory/index.mjs +2 -0
  426. package/src/knowledge/participatory/installed-workshop.mjs +108 -0
  427. package/src/knowledge/plan.mjs +67 -0
  428. package/src/knowledge/projection.mjs +43 -0
  429. package/src/knowledge/semantic-operation.mjs +567 -0
  430. package/src/knowledge/sessions.mjs +467 -0
  431. package/src/knowledge/workspace.mjs +295 -0
  432. package/src/knowledge-health/assessment.mjs +165 -0
  433. package/src/knowledge-health/capabilities.mjs +350 -0
  434. package/src/knowledge-health/context.mjs +62 -0
  435. package/src/knowledge-health/example.mjs +47 -0
  436. package/src/knowledge-health/index.mjs +10 -0
  437. package/src/knowledge-health/owner-join.mjs +88 -0
  438. package/src/knowledge-health/proof/common.mjs +24 -0
  439. package/src/knowledge-health/proof/installed-check.mjs +100 -0
  440. package/src/knowledge-health/proof/native-readback.mjs +37 -0
  441. package/src/knowledge-health/proof/rehearse.mjs +68 -0
  442. package/src/knowledge-health/proof/validate-participant.mjs +17 -0
  443. package/src/knowledge-health/proof/verify-native-capture.mjs +14 -0
  444. package/src/knowledge-health/proof/workshop-check.mjs +36 -0
  445. package/src/knowledge-health/rule-identity.mjs +49 -0
  446. package/src/knowledge-health/workshop-composition.mjs +19 -0
  447. package/src/knowledge-health/workshop-profile.mjs +176 -0
  448. package/src/knowledge-health/workshop.mjs +99 -0
  449. package/src/learning/adapters.mjs +68 -0
  450. package/src/learning/assistance.mjs +127 -0
  451. package/src/learning/contracts.mjs +65 -0
  452. package/src/learning/store.mjs +272 -0
  453. package/src/personal-workspace/index.mjs +391 -0
  454. package/src/personal-workspace/selection.mjs +401 -0
  455. package/src/project/config.mjs +8 -0
  456. package/src/project/durable-state.mjs +3 -1
  457. package/src/project/file-class.mjs +1 -1
  458. package/src/project/path-match.mjs +2 -1
  459. package/src/projection/obsidian/edits/apply.mjs +55 -16
  460. package/src/projection/obsidian/materialize/prepare-view.mjs +87 -5
  461. package/src/projection/obsidian/personal-workspace.mjs +519 -0
  462. package/src/projection/obsidian/proposals/adapter.mjs +79 -17
  463. package/src/projection/obsidian/proposals/observation.mjs +50 -4
  464. package/src/projection/obsidian/publication/publisher.mjs +214 -18
  465. package/src/projection/obsidian/publication/vault-list.mjs +4 -3
  466. package/src/projection/obsidian/recovery/index.mjs +4 -1
  467. package/src/projection/obsidian/recovery/store.mjs +160 -7
  468. package/src/projection/obsidian/selection-ui/contribution.mjs +6 -5
  469. package/src/projection/project.mjs +3 -2
  470. package/src/readiness/readiness.mjs +10 -3
  471. package/src/reflection/index.mjs +56 -0
  472. package/src/runtime/obsidian/app-production-seams.mjs +48 -16
  473. package/src/runtime/obsidian/app-registration.mjs +175 -28
  474. package/src/runtime/obsidian/app-restart.mjs +154 -0
  475. package/src/runtime/obsidian/engine.mjs +437 -56
  476. package/src/runtime/obsidian/extension-points.mjs +1 -1
  477. package/src/runtime/obsidian/index.mjs +10 -7
  478. package/src/runtime/obsidian/launch-plan.mjs +7 -4
  479. package/src/runtime/obsidian/lifecycle.mjs +108 -23
  480. package/src/runtime/obsidian/login-item.mjs +335 -0
  481. package/src/runtime/obsidian/machine-settings.mjs +119 -12
  482. package/src/runtime/obsidian/observation.mjs +36 -4
  483. package/src/runtime/obsidian/opening.mjs +173 -38
  484. package/src/runtime/obsidian/personal-selection.mjs +125 -0
  485. package/src/runtime/obsidian/pipeline.mjs +115 -6
  486. package/src/runtime/obsidian/plugin-channel.mjs +11 -3
  487. package/src/runtime/obsidian/plugin-choice.mjs +16 -4
  488. package/src/runtime/obsidian/plugin-drift.mjs +59 -11
  489. package/src/runtime/obsidian/plugin-presence.mjs +14 -1
  490. package/src/runtime/obsidian/private-lock.mjs +39 -4
  491. package/src/runtime/obsidian/process-identity.mjs +20 -10
  492. package/src/runtime/obsidian/project-views.mjs +282 -0
  493. package/src/runtime/obsidian/questions.mjs +48 -0
  494. package/src/runtime/obsidian/release-watch.mjs +56 -0
  495. package/src/runtime/obsidian/service-main.mjs +148 -19
  496. package/src/runtime/obsidian/service-manager-production.mjs +61 -0
  497. package/src/runtime/obsidian/service-managers.mjs +275 -0
  498. package/src/runtime/obsidian/service-record.mjs +87 -23
  499. package/src/runtime/obsidian/service.mjs +102 -9
  500. package/src/runtime/obsidian/startup-adapters.mjs +59 -21
  501. package/src/runtime/obsidian/unheld-evidence.mjs +84 -0
  502. package/src/runtime/obsidian/vault-location.mjs +300 -0
  503. package/src/runtime/obsidian/view-counts.mjs +34 -0
  504. package/src/runtime/obsidian/view-permission.mjs +334 -0
  505. package/src/server/local-sidecar.mjs +169 -2
  506. package/src/server/server.mjs +28 -2
  507. package/src/template-bindings/project.mjs +92 -0
  508. package/src/templates/profile.mjs +225 -0
  509. package/src/trackables/domain.mjs +175 -0
  510. package/src/trackables/store.mjs +114 -0
  511. package/src/ui/control-system.mjs +201 -0
  512. package/src/ui/html-primitives.mjs +3 -0
  513. package/src/ui/knowledge-page.mjs +1388 -0
  514. package/src/upgrade/closure-diagnostics.mjs +135 -0
  515. package/src/upgrade/closure.mjs +649 -0
  516. package/src/upgrade/explanation.mjs +1 -1
  517. package/src/upgrade/template-participant.mjs +171 -0
  518. package/src/upgrade/transaction.mjs +72 -25
  519. package/src/upgrade/upgrade.mjs +20 -7
  520. package/templates/external-project-workspace/pack-lifecycle.json +7 -1
  521. package/templates/knowledge-workspace/.gitattributes +2 -0
  522. package/templates/knowledge-workspace/AGENTS.md +27 -0
  523. package/templates/knowledge-workspace/README.md +44 -0
  524. package/templates/knowledge-workspace/atelier.project.json +22 -0
  525. package/templates/knowledge-workspace/gitignore +6 -0
  526. package/templates/knowledge-workspace/knowledge-plan.json +111 -0
  527. package/templates/knowledge-workspace/knowledge-plan.schema.json +281 -0
  528. package/templates/knowledge-workspace/records/forecast.md +22 -0
  529. package/templates/knowledge-workspace/records/inspection.md +25 -0
  530. package/templates/knowledge-workspace/records/telescope.md +24 -0
  531. package/templates/knowledge-workspace/repo-access.v1.json +9 -0
@@ -0,0 +1,248 @@
1
+ import { createHash } from 'node:crypto'
2
+ import fs from 'node:fs'
3
+ import path from 'node:path'
4
+ import { PRIVATE_AUDIENCES, loadBoundaryPolicy } from '../boundary/policy.mjs'
5
+ import { parseProjectOptions } from '../cli/project-options.mjs'
6
+ import { AtelierDiagnosticError, commandProject } from '../project/config.mjs'
7
+ import { VALID_AUDIENCES } from '../projection/policy.mjs'
8
+ import { canonicalGraphOptions } from './graph.mjs'
9
+ import { SOURCE_SIDECAR_SCHEMA, buildKnowledgeGraph, validateSourceSidecar } from './knowledge-graph.mjs'
10
+
11
+ // Document enrollment writes the sidecar the census demands of every
12
+ // non-Markdown document that has none: the smallest classification that lets
13
+ // `atelier graph` pass, never a judgement about the document. It reads the same
14
+ // census as the graph (scope, Git ignore rules and all), writes only where no
15
+ // sidecar exists, and never changes a source.
16
+
17
+ export const DEFAULT_ENROLLMENT_AUDIENCE = 'private'
18
+
19
+ const AUDIENCE_ORDER = ['private', 'sensitive', 'staff', 'operator', 'team', 'public']
20
+ const orderedAudiences = (audiences) => AUDIENCE_ORDER.filter((audience) => audiences.includes(audience))
21
+
22
+ // The audiences a repository's boundary policy lets a node carry, by the same
23
+ // three rules the boundary check applies to every node. Null when the policy
24
+ // does not cover the repository, which the boundary check reports on its own.
25
+ export function enrollableAudiences(repoPolicy) {
26
+ if (!repoPolicy || typeof repoPolicy !== 'object') return null
27
+ const allowed = Array.isArray(repoPolicy.allowedAudiences) ? repoPolicy.allowedAudiences : []
28
+ const forbidden = Array.isArray(repoPolicy.forbiddenAudiences) ? repoPolicy.forbiddenAudiences : []
29
+ return orderedAudiences(
30
+ allowed.filter((audience) => !forbidden.includes(audience) && !(PRIVATE_AUDIENCES.has(audience) && repoPolicy.kind !== 'private_domain')),
31
+ )
32
+ }
33
+
34
+ export function assertEnrollmentAudience(audience) {
35
+ if (typeof audience === 'string' && VALID_AUDIENCES.has(audience)) return audience
36
+ throw new AtelierDiagnosticError('enroll-audience-invalid', `--audience must be one of ${orderedAudiences([...VALID_AUDIENCES]).join(', ')}`, {
37
+ hint: `Omit --audience to enroll documents as ${DEFAULT_ENROLLMENT_AUDIENCE}.`,
38
+ })
39
+ }
40
+
41
+ // Refuses, before anything is written, an audience the boundary policy would
42
+ // reject in any repository that has a document to enroll. A policy in
43
+ // legacy-warning mode only warns about placement, and so does not refuse here.
44
+ export function assertAudienceAllowed({ policy, repoNames, audience }) {
45
+ if (policy?.mode === 'legacy-warning') return
46
+ for (const repoName of repoNames) {
47
+ const repoPolicy = policy?.repos && Object.hasOwn(policy.repos, repoName) ? policy.repos[repoName] : null
48
+ const allowed = enrollableAudiences(repoPolicy)
49
+ if (!allowed || allowed.includes(audience)) continue
50
+ // The message names the allowed audiences itself: adopt prints only the
51
+ // message of a refusal, not its hint.
52
+ const kind = typeof repoPolicy.kind === 'string' ? `${repoPolicy.kind.replaceAll('_', ' ')} ` : ''
53
+ const allows = allowed.length ? `it allows ${allowed.join(', ')}` : 'it allows no audience there'
54
+ throw new AtelierDiagnosticError(
55
+ 'enroll-audience-not-allowed',
56
+ `the boundary policy does not allow audience ${audience} in ${kind}repository ${repoName}; ${allows}`,
57
+ {
58
+ hint: allowed.length
59
+ ? 'Pass --audience with one of the audiences it allows.'
60
+ : 'Review boundary-policy.v1.json before enrolling documents in that repository.',
61
+ },
62
+ )
63
+ }
64
+ }
65
+
66
+ const idSegment = (value) =>
67
+ String(value ?? '')
68
+ .toLowerCase()
69
+ .replace(/[^a-z0-9]+/g, '-')
70
+ .replace(/^-+|-+$/g, '')
71
+
72
+ const pathSegment = (rel) =>
73
+ String(rel)
74
+ .toLowerCase()
75
+ .replace(/[^a-z0-9._/-]+/g, '-')
76
+ .replace(/-+([./])/g, '$1')
77
+ .replace(/([./])-+/g, '$1')
78
+ .replace(/-{2,}/g, '-')
79
+
80
+ const shortDigest = (value) => createHash('sha256').update(value).digest('hex').slice(0, 8)
81
+
82
+ // `<repo>:asset:<path>` keeps the source's folders and file name readable in
83
+ // the id. Two documents whose paths fold to one id (case, spaces) each get a
84
+ // digest of their exact path, as does one whose id is already taken, so the
85
+ // result does not depend on the order documents are found in.
86
+ function assignIds(wanted, taken) {
87
+ const bases = wanted.map((item) => `${idSegment(item.repo) || 'repo'}:asset:${pathSegment(item.path)}`)
88
+ const counts = new Map()
89
+ for (const base of bases) counts.set(base, (counts.get(base) ?? 0) + 1)
90
+ const used = new Set(taken)
91
+ return wanted.map((item, index) => {
92
+ const base = bases[index]
93
+ const id = counts.get(base) > 1 || used.has(base) ? `${base}-${shortDigest(`${item.repo}/${item.path}`)}` : base
94
+ if (used.has(id)) throw new Error('document enrollment could not derive a unique kg.id')
95
+ used.add(id)
96
+ return id
97
+ })
98
+ }
99
+
100
+ function sidecarDocument(node, id, audience) {
101
+ return {
102
+ schema: SOURCE_SIDECAR_SCHEMA,
103
+ asset: path.posix.basename(node.path),
104
+ title: node.title || path.posix.basename(node.path),
105
+ summary: '',
106
+ tags: [],
107
+ kg: {
108
+ id,
109
+ type: node.extension,
110
+ domain: node.domain,
111
+ lifecycle: node.lifecycle,
112
+ status: node.status,
113
+ audience,
114
+ relations: {},
115
+ },
116
+ }
117
+ }
118
+
119
+ // What enrollment would write, and what it leaves alone. `policy` defaults to
120
+ // the project's boundary policy; a missing or unreadable one is not consulted,
121
+ // since the graph itself does not need it.
122
+ export function planDocumentEnrollment(project, { audience = DEFAULT_ENROLLMENT_AUDIENCE, policy = undefined } = {}) {
123
+ assertEnrollmentAudience(audience)
124
+ const { options } = canonicalGraphOptions(project)
125
+ const result = buildKnowledgeGraph(options)
126
+ if (!result.workspaceGraph) {
127
+ throw new AtelierDiagnosticError('enroll-census-unavailable', 'the knowledge graph census could not run, so no document was enrolled', {
128
+ hint: 'Run atelier graph with the same --project path to see why, fix that, then retry.',
129
+ })
130
+ }
131
+ const roots = new Map(options.repoEntries.map((entry) => [entry.name, entry.path]))
132
+ const nodes = result.workspaceGraph.nodes
133
+ // Code-point order, so the report reads the same under every locale.
134
+ const byPath = (a, b) => (`${a.repo}/${a.path}` < `${b.repo}/${b.path}` ? -1 : 1)
135
+ const demanded = nodes.filter((node) => node.extension !== 'md' && !node.hasSidecar).sort(byPath)
136
+
137
+ const wanted = []
138
+ const skipped = []
139
+ for (const node of demanded) {
140
+ const sidecar = `${node.path}.kg.json`
141
+ const target = path.join(roots.get(node.repo), ...sidecar.split('/'))
142
+ const existing = fs.lstatSync(target, { throwIfNoEntry: false })
143
+ // A sidecar that exists but is not visible to the census is Git-ignored,
144
+ // or is a link or folder. Either way it is someone's, and stays as it is.
145
+ if (existing) {
146
+ skipped.push({ repo: node.repo, path: node.path, sidecar, reason: existing.isFile() ? 'sidecar-ignored' : 'sidecar-not-a-file' })
147
+ continue
148
+ }
149
+ wanted.push({ repo: node.repo, path: node.path, sidecar, target, node })
150
+ }
151
+
152
+ if (wanted.length) {
153
+ const loaded = policy === undefined ? loadBoundaryPolicy(project) : { ok: Boolean(policy), policy }
154
+ if (loaded.ok) assertAudienceAllowed({ policy: loaded.policy, repoNames: [...new Set(wanted.map((item) => item.repo))], audience })
155
+ }
156
+
157
+ const enrolling = new Set(wanted.map((item) => item.node))
158
+ const ids = assignIds(wanted, nodes.filter((node) => !enrolling.has(node)).map((node) => node.id))
159
+ const enroll = wanted.map((item, index) => {
160
+ const document = sidecarDocument(item.node, ids[index], audience)
161
+ const errors = validateSourceSidecar(document, document.asset)
162
+ if (errors.length) throw new Error(`document enrollment built an invalid sidecar: ${errors.join('; ')}`)
163
+ return { repo: item.repo, path: item.path, sidecar: item.sidecar, target: item.target, id: ids[index], document }
164
+ })
165
+ return { audience, enroll, skipped }
166
+ }
167
+
168
+ // Writes each planned sidecar with an exclusive create, so a file, link or
169
+ // folder that appeared since the plan is never replaced or followed; it is
170
+ // reported as skipped instead. Sources are never opened.
171
+ export function writeDocumentEnrollment(plan) {
172
+ const written = []
173
+ const skipped = [...plan.skipped]
174
+ for (const item of plan.enroll) {
175
+ try {
176
+ fs.writeFileSync(item.target, `${JSON.stringify(item.document, null, 2)}\n`, { flag: 'wx' })
177
+ written.push(item)
178
+ } catch (error) {
179
+ if (error?.code !== 'EEXIST') throw error
180
+ skipped.push({ repo: item.repo, path: item.path, sidecar: item.sidecar, reason: 'sidecar-exists' })
181
+ }
182
+ }
183
+ return { audience: plan.audience, written, skipped }
184
+ }
185
+
186
+ const SKIP_REASONS = {
187
+ 'sidecar-ignored': 'a sidecar exists but Git ignores it',
188
+ 'sidecar-not-a-file': 'a link or folder has the sidecar name',
189
+ 'sidecar-exists': 'a sidecar appeared while enrolling',
190
+ }
191
+
192
+ export function enrollmentReport({ written = [], skipped = [], audience, dryRun = false }) {
193
+ return {
194
+ ok: true,
195
+ command: 'enroll documents',
196
+ dryRun,
197
+ audience,
198
+ enrolled: written.map((item) => ({ repo: item.repo, path: item.path, sidecar: item.sidecar, id: item.id })),
199
+ skipped: skipped.map((item) => ({ repo: item.repo, path: item.path, sidecar: item.sidecar, reason: item.reason })),
200
+ }
201
+ }
202
+
203
+ function printReport(report) {
204
+ const count = report.enrolled.length
205
+ const noun = count === 1 ? 'document' : 'documents'
206
+ if (count === 0) console.log('No document needs a sidecar.')
207
+ else console.log(`${report.dryRun ? 'Would enroll' : 'Enrolled'} ${count} ${noun} with ${report.audience} sidecars:`)
208
+ for (const item of report.enrolled) console.log(` ${item.repo}/${item.sidecar}`)
209
+ if (report.skipped.length) {
210
+ console.log(`Left ${report.skipped.length} unchanged; the graph still needs a sidecar for each:`)
211
+ for (const item of report.skipped) console.log(` ${item.repo}/${item.path}: ${SKIP_REASONS[item.reason] ?? item.reason}`)
212
+ }
213
+ if (count && !report.dryRun) {
214
+ console.log('Next: review the sidecars (title, audience), then run atelier graph with the same --project path.')
215
+ }
216
+ }
217
+
218
+ const usage = () =>
219
+ new AtelierDiagnosticError('usage', 'enroll has one subcommand, documents', {
220
+ hint: 'Run atelier enroll documents [--audience private] [--dry-run] [--json] [--project ./atelier.project.json].',
221
+ })
222
+
223
+ export function parseEnrollArgs(argv = []) {
224
+ const { remaining } = parseProjectOptions(argv)
225
+ const args = { subcommand: null, audience: DEFAULT_ENROLLMENT_AUDIENCE, dryRun: false, json: false }
226
+ for (let index = 0; index < remaining.length; index += 1) {
227
+ const arg = remaining[index]
228
+ if (arg === '--dry-run') args.dryRun = true
229
+ else if (arg === '--json') args.json = true
230
+ else if (arg === '--audience') args.audience = remaining[++index]
231
+ else if (arg.startsWith('--audience=')) args.audience = arg.slice('--audience='.length)
232
+ else if (!arg.startsWith('-') && args.subcommand === null) args.subcommand = arg
233
+ else throw usage()
234
+ }
235
+ if (args.subcommand !== 'documents') throw usage()
236
+ assertEnrollmentAudience(args.audience)
237
+ return args
238
+ }
239
+
240
+ export function runEnrollCommand(argv = process.argv.slice(2)) {
241
+ const args = parseEnrollArgs(argv)
242
+ const project = commandProject({ argv })
243
+ const plan = planDocumentEnrollment(project, { audience: args.audience })
244
+ const outcome = args.dryRun ? { audience: plan.audience, written: plan.enroll, skipped: plan.skipped } : writeDocumentEnrollment(plan)
245
+ const report = enrollmentReport({ ...outcome, dryRun: args.dryRun })
246
+ if (args.json) console.log(JSON.stringify(report, null, 2))
247
+ else printReport(report)
248
+ }
@@ -5,9 +5,10 @@ import { VALID_AUDIENCES as PROJECTION_AUDIENCES } from '../projection/policy.mj
5
5
  import {
6
6
  REPO_ACCESS_SCHEMA,
7
7
  VALID_RELATION_TYPES,
8
- buildKnowledgeGraph,
8
+ buildKnowledgeGraphSteps,
9
9
  createGraphFileCache,
10
10
  parseYamlSubset,
11
+ runGraphSteps,
11
12
  } from './knowledge-graph.mjs'
12
13
 
13
14
  export { createGraphFileCache }
@@ -19,6 +20,18 @@ export const VALID_AUDIENCES = PROJECTION_AUDIENCES
19
20
  export const VALID_RELATIONS = VALID_RELATION_TYPES
20
21
  export const parseFrontmatterYaml = parseYamlSubset
21
22
 
23
+ // setup.include and setup.exclude scope the census. Both are path patterns
24
+ // relative to the project config's folder, so each repository learns where its
25
+ // root sits relative to that folder.
26
+ function censusScope(project, repoPath) {
27
+ const setup = project.config?.setup
28
+ const include = typeof setup?.include === 'string' && setup.include.trim() ? setup.include : null
29
+ const exclude = typeof setup?.exclude === 'string' && setup.exclude.trim() ? setup.exclude : null
30
+ if (!include && !exclude) return null
31
+ const base = path.relative(project.configDir, repoPath).split(path.sep).join('/')
32
+ return { base, include, exclude }
33
+ }
34
+
22
35
  function canonicalInput(project) {
23
36
  const loadedAccess = loadRepoAccess(project)
24
37
  const managed = []
@@ -31,7 +44,8 @@ function canonicalInput(project) {
31
44
  missing.push(`configured repo is missing or unreadable: ${repo.name ?? '(unnamed)'}`)
32
45
  continue
33
46
  }
34
- managed.push({ name: repo.name, path: repo.path })
47
+ const scope = censusScope(project, repo.path)
48
+ managed.push({ name: repo.name, path: repo.path, ...(scope ? { censusScope: scope } : {}) })
35
49
  accessRepos[repo.name] = {
36
50
  readBoundary:
37
51
  loadedAccess.repos?.[repo.name]?.readBoundary ?? repo.readBoundary ?? loadedAccess.defaultReadBoundary ?? 'team',
@@ -103,11 +117,12 @@ function externalRepos(project) {
103
117
  .sort((a, b) => String(a.name).localeCompare(String(b.name)))
104
118
  }
105
119
 
106
- function canonicalBuild(project, overrides = {}) {
120
+ function* canonicalBuildSteps(project, overrides = {}) {
107
121
  const input = canonicalInput(project)
108
- const result = buildKnowledgeGraph({ ...input.options, ...overrides })
122
+ const result = yield* buildKnowledgeGraphSteps({ ...input.options, ...overrides })
109
123
  return { input, result }
110
124
  }
125
+ const canonicalBuild = (project, overrides = {}) => runGraphSteps(canonicalBuildSteps(project, overrides))
111
126
 
112
127
  // The supported project-to-options seam: the exact buildKnowledgeGraph options
113
128
  // every graph consumer derives from a loaded project, plus the configured
@@ -131,8 +146,14 @@ const canonicalEdgeId = (edge) => JSON.stringify([edge.source, edge.type, edge.t
131
146
  // bytes did not change; the result is the same as without it. `observedDigest`
132
147
  // (see createGraphFileCache) lets a caller that observes sources by digest
133
148
  // spare the read of a source it knows unchanged.
134
- export function buildCanonicalGraph(project, { isLinkTargetEligible, isAssetEligible, fileCache = null, observedDigest = null } = {}) {
135
- const { input, result } = canonicalBuild(project, {
149
+ // buildCanonicalGraphSteps is the same build as steps (see buildKnowledgeGraphSteps), for a caller that waits between
150
+ // them; buildCanonicalGraph runs them through.
151
+ export function buildCanonicalGraph(project, options = {}) {
152
+ return runGraphSteps(buildCanonicalGraphSteps(project, options))
153
+ }
154
+
155
+ export function* buildCanonicalGraphSteps(project, { isLinkTargetEligible, isAssetEligible, fileCache = null, observedDigest = null } = {}) {
156
+ const { input, result } = yield* canonicalBuildSteps(project, {
136
157
  ...(isLinkTargetEligible ? { isLinkTargetEligible } : {}),
137
158
  ...(isAssetEligible ? { isAssetEligible } : {}),
138
159
  ...(fileCache ? { fileCache } : {}),
@@ -211,6 +232,9 @@ export function runGraphCommand(argv = process.argv.slice(2)) {
211
232
  for (const warning of ignoredSidecarWarnings(project)) console.warn(`warning: ${warning.message}`)
212
233
  if (graph.errors.length) {
213
234
  console.error(graph.errors.join('\n'))
235
+ if (graph.errors.some((error) => error.includes(': non-Markdown source requires sidecar '))) {
236
+ console.error('Next: run atelier enroll documents with the same --project path to write private sidecars for documents that have none, review them, then rerun atelier graph.')
237
+ }
214
238
  process.exit(1)
215
239
  }
216
240
  if (check) {
@@ -4,6 +4,7 @@ import path from 'node:path'
4
4
  import { VALID_AUDIENCES } from '../projection/policy.mjs'
5
5
  import { generatedProjectionBasenames, generatedProjectionDirectoryBasenames } from '../project/file-class.mjs'
6
6
  import { gitIgnoreFilter } from '../project/git-ignore.mjs'
7
+ import { matchesPathPattern, normalizeRelPath } from '../project/path-match.mjs'
7
8
 
8
9
  export const KNOWLEDGE_GRAPH_SCHEMA = 'mnstry.knowledge-graph@v1'
9
10
  export const REPO_ACCESS_SCHEMA = 'mnstry.repo-access@v1'
@@ -339,14 +340,58 @@ export function listRepos(workspaceRoot) {
339
340
  .sort()
340
341
  }
341
342
 
343
+ // The project's census scope: `include` and `exclude` are path patterns in the
344
+ // kit's one dialect (src/project/path-match.mjs), relative to the project
345
+ // config's folder, read from the tracked config so every machine walks the
346
+ // same paths. `base` is the repository root relative to that folder. The
347
+ // returned predicate takes a repository-relative path and says whether it is
348
+ // outside the census; `directory` lets a folder that may still hold included
349
+ // files be walked. A path is excluded when it or a folder above it matches
350
+ // `exclude`; with `include`, a file is in the census only when it or a folder
351
+ // above it matches. Exclude wins. A `<file>.kg.json` sidecar belongs to its
352
+ // source and shares the source's scope. Null when the scope restricts nothing.
353
+ export function censusScopeFilter({ base = '', include = null, exclude = null } = {}) {
354
+ // A trailing slash names a folder, which a pattern without one matches too.
355
+ const pattern = (value) => (typeof value === 'string' && value.trim() ? normalizeRelPath(value.trim()).replace(/\/+$/, '') || null : null)
356
+ const includePattern = pattern(include)
357
+ const excludePattern = pattern(exclude)
358
+ if (!includePattern && !excludePattern) return null
359
+ const prefix = normalizeRelPath(base).replace(/\/+$/, '')
360
+ const lineage = (rel) => {
361
+ const parts = path.posix.normalize(prefix ? `${prefix}/${rel}` : rel).split('/')
362
+ return parts.map((_, index) => parts.slice(0, index + 1).join('/'))
363
+ }
364
+ // A folder may lead to an included file when it lies on the pattern's
365
+ // literal leading path, or below it. A slashless pattern matches at any
366
+ // depth, so every folder may.
367
+ const segments = includePattern?.includes('/') ? includePattern.split('/') : null
368
+ const globAt = segments ? segments.findIndex((part) => part.includes('*')) : -1
369
+ const literalLead = segments ? (globAt === -1 ? segments : segments.slice(0, globAt)) : null
370
+ const mayLeadToInclude = (paths) => {
371
+ if (!literalLead) return true
372
+ const parts = paths.at(-1).split('/')
373
+ const shared = Math.min(parts.length, literalLead.length)
374
+ return parts.slice(0, shared).every((part, index) => part.toLowerCase() === literalLead[index].toLowerCase())
375
+ }
376
+ return (rel, { directory = false } = {}) => {
377
+ const paths = lineage(!directory && rel.endsWith('.kg.json') ? rel.slice(0, -'.kg.json'.length) : rel)
378
+ if (excludePattern && paths.some((candidate) => matchesPathPattern(excludePattern, candidate))) return true
379
+ if (!includePattern || paths.some((candidate) => matchesPathPattern(includePattern, candidate))) return false
380
+ return !(directory && mayLeadToInclude(paths))
381
+ }
382
+ }
383
+
342
384
  // Git-ignored paths are machine-local. Counting them makes committed graph
343
385
  // artifacts differ per machine, which turns every sync tick into a conflict.
386
+ // `isIgnored(rel, { directory })` also carries the project's census scope when
387
+ // the builder composes one in (censusScopeFilter); a plain Git filter ignores
388
+ // the second argument.
344
389
  export function walkDocuments(dir, root, acc = [], isIgnored = gitIgnoreFilter(root)) {
345
390
  for (const ent of fs.readdirSync(dir, { withFileTypes: true })) {
346
391
  if (SKIP_DIRS.has(ent.name) || ent.name.startsWith('.')) continue
347
392
  const abs = path.join(dir, ent.name)
348
393
  const rel = relPath(root, abs)
349
- if (isIgnored(rel)) continue
394
+ if (isIgnored(rel, { directory: ent.isDirectory() })) continue
350
395
  if (ent.isDirectory()) {
351
396
  walkDocuments(abs, root, acc, isIgnored)
352
397
  } else if (ent.isFile()) {
@@ -384,7 +429,7 @@ export function ignoredSourceSidecars(repoName, repoRoot, isIgnored = gitIgnoreF
384
429
  const abs = path.join(dir, ent.name)
385
430
  const rel = relPath(repoRoot, abs)
386
431
  if (ent.isDirectory()) {
387
- if (!isIgnored(rel)) visit(abs)
432
+ if (!isIgnored(rel, { directory: true })) visit(abs)
388
433
  continue
389
434
  }
390
435
  if (!ent.isFile() || !ent.name.endsWith('.kg.json') || !isIgnored(rel)) continue
@@ -402,7 +447,7 @@ export function walkSidecars(dir, root, acc = [], isIgnored = gitIgnoreFilter(ro
402
447
  for (const ent of fs.readdirSync(dir, { withFileTypes: true })) {
403
448
  if (SKIP_DIRS.has(ent.name) || ent.name.startsWith('.')) continue
404
449
  const abs = path.join(dir, ent.name)
405
- if (isIgnored(relPath(root, abs))) continue
450
+ if (isIgnored(relPath(root, abs), { directory: ent.isDirectory() })) continue
406
451
  if (ent.isDirectory()) {
407
452
  walkSidecars(abs, root, acc, isIgnored)
408
453
  } else if (ent.isFile() && ent.name.endsWith('.kg.json')) {
@@ -898,7 +943,7 @@ const isMarkdownPath = (rel) => rel.toLowerCase().endsWith('.md')
898
943
  // a path is tested, not the path alone.
899
944
  function ignoredAtAnyDepth(isIgnored, rel) {
900
945
  const parts = rel.split('/')
901
- return parts.some((_, index) => isIgnored(parts.slice(0, index + 1).join('/')))
946
+ return parts.some((_, index) => isIgnored(parts.slice(0, index + 1).join('/'), { directory: index < parts.length - 1 }))
902
947
  }
903
948
 
904
949
  // True only for a regular file whose real location is exactly `rel` under the
@@ -979,7 +1024,7 @@ export function resolveWorkspaceLinks({ repos = [], isLinkTargetEligible = () =>
979
1024
  if (ent.name === '.git') continue
980
1025
  const abs = path.join(dir, ent.name)
981
1026
  const rel = relPath(owner.root, abs)
982
- if (isIgnored(rel)) continue
1027
+ if (isIgnored(rel, { directory: ent.isDirectory() })) continue
983
1028
  // A nested enrolled repository owns its own files.
984
1029
  if (ent.isDirectory()) {
985
1030
  if (!roots.has(abs)) visit(abs)
@@ -1342,7 +1387,24 @@ function markdownCensus({ repoName, repoRoot, coverage, file, accessConfig, cach
1342
1387
  return { node: structuredClone(entry.node), scan: structuredClone(entry.scan), reused: entry === cached, read }
1343
1388
  }
1344
1389
 
1345
- export function buildKnowledgeGraph({
1390
+ // Runs the steps of a graph build through, with no wait, and answers what the build answers.
1391
+ export function runGraphSteps(steps) {
1392
+ for (;;) {
1393
+ const step = steps.next()
1394
+ if (step.done) return step.value
1395
+ }
1396
+ }
1397
+
1398
+ // The knowledge graph of a workspace, in one stretch. Every caller but the maintenance engine's tick builds it this way.
1399
+ export function buildKnowledgeGraph(options) {
1400
+ return runGraphSteps(buildKnowledgeGraphSteps(options))
1401
+ }
1402
+
1403
+ // The same build as steps: one after each Markdown source of the census (its read, hash and parse, or its reuse from
1404
+ // the file cache), named 'graph-census'. A caller that gives the event loop a turn between steps (the maintenance
1405
+ // engine) keeps a large census from holding it; walking the directories, resolving links and assembling the graph
1406
+ // are not split. The answer is the one buildKnowledgeGraph gives.
1407
+ export function* buildKnowledgeGraphSteps({
1346
1408
  workspaceRoot,
1347
1409
  repoAccessConfig,
1348
1410
  repoRoots = null,
@@ -1362,7 +1424,9 @@ export function buildKnowledgeGraph({
1362
1424
  const resolvedWorkspaceRoot = path.resolve(workspaceRoot)
1363
1425
  const external = new Set(externalRepos)
1364
1426
  const discoveredEntries = repoEntries
1365
- ? repoEntries.map((entry) => ({ name: entry.name, path: path.resolve(entry.path) })).sort((a, b) => String(a.name).localeCompare(String(b.name)))
1427
+ ? repoEntries
1428
+ .map((entry) => ({ name: entry.name, path: path.resolve(entry.path), ...(entry.censusScope ? { censusScope: entry.censusScope } : {}) }))
1429
+ .sort((a, b) => String(a.name).localeCompare(String(b.name)))
1366
1430
  : (repoRoots ? repoRoots.map((repoRoot) => path.resolve(repoRoot)) : listRepos(resolvedWorkspaceRoot))
1367
1431
  .sort()
1368
1432
  .map((repoRoot) => ({ name: path.basename(repoRoot), path: repoRoot }))
@@ -1398,8 +1462,11 @@ export function buildKnowledgeGraph({
1398
1462
  for (const entry of roots) {
1399
1463
  const repoRoot = entry.path
1400
1464
  const repoName = entry.name
1401
- // One batched ignore lookup per repo, shared by every walk below.
1402
- const isIgnored = gitIgnoreFilter(repoRoot)
1465
+ // One batched ignore lookup per repo, shared by every walk below. A path
1466
+ // outside the project's census scope is treated exactly as an ignored one.
1467
+ const gitIgnored = gitIgnoreFilter(repoRoot)
1468
+ const outOfScope = censusScopeFilter(entry.censusScope ?? {})
1469
+ const isIgnored = outOfScope ? (rel, info) => gitIgnored(rel) || outOfScope(rel, info) : gitIgnored
1403
1470
  const files = walkDocuments(repoRoot, repoRoot, [], isIgnored)
1404
1471
  workspaceOrphanSidecars.push(...activeOrphanSidecars(repoName, repoRoot, files, isIgnored))
1405
1472
  workspaceIgnoredSidecars.push(...ignoredSourceSidecars(repoName, repoRoot, isIgnored))
@@ -1416,6 +1483,7 @@ export function buildKnowledgeGraph({
1416
1483
  scanned.set(node, entry.scan)
1417
1484
  reuse[entry.reused ? 'reused' : 'derived'] += 1
1418
1485
  if (entry.read) reuse.read += 1
1486
+ yield 'graph-census'
1419
1487
  } else {
1420
1488
  node = nodeForFile(repoName, repoRoot, coverage, file, accessConfig)
1421
1489
  }
@@ -0,0 +1,41 @@
1
+ import fs from 'node:fs'
2
+ import Ajv from 'ajv/dist/2020.js'
3
+ import addFormats from 'ajv-formats'
4
+ import { objectDigest, digest } from '../capabilities/files.mjs'
5
+ export const HARNESS_LIMITS = Object.freeze({ records: 256, bytes: 8 * 1024 * 1024, dependencyVerifications: 256, dependencyDepth: 12 })
6
+ export const harnessDigest = objectDigest
7
+ export const contentDigest = digest
8
+ export const harnessRef = record => ({ id: record.id, digest: objectDigest(record) })
9
+ export const EMPTY_HARNESS_HEAD = objectDigest([])
10
+ const ajv = new Ajv({ allErrors: true, strict: true }); addFormats(ajv)
11
+ const schemas = new Map(['harness', 'knowledge', 'build'].map(name => [name, JSON.parse(fs.readFileSync(new URL(`../../contracts/atelier-${name}.v1.schema.json`, import.meta.url)))]))
12
+ const validators = new Map()
13
+ export function validateHarnessDocument(value, profile, shape = 'record') {
14
+ const schema = schemas.get(profile), key = `${profile}/${shape}`
15
+ if (!schema || !Object.hasOwn(schema.$defs, shape)) return ['unknown harness profile or shape']
16
+ if (!validators.has(key)) validators.set(key, ajv.compile({ $schema: schema.$schema, $defs: schema.$defs, $ref: `#/$defs/${shape}` }))
17
+ const validate = validators.get(key)
18
+ return validate(value) ? [] : validate.errors.map(e => `${e.instancePath || '/'}: ${e.message}`)
19
+ }
20
+ export function assertHarness(value, profile, shape = 'record') {
21
+ const errors = validateHarnessDocument(value, profile, shape)
22
+ if (errors.length) throw new Error(`invalid ${profile} ${shape}: ${errors.slice(0, 5).join('; ')}`)
23
+ return value
24
+ }
25
+ // A private container may receive a public source. An export that includes that
26
+ // container's metadata must retain the more restrictive combined audience.
27
+ export function restrictiveAudience(...values) {
28
+ if (!values.length || values.some(v => !['public', 'team', 'operator', 'staff', 'private', 'sensitive'].includes(v))) throw new Error('unknown audience')
29
+ const restricted = [...new Set(values.filter(v => v !== 'public'))]
30
+ if (restricted.includes('sensitive')) return 'sensitive'
31
+ if (restricted.includes('private') || restricted.length > 1) return 'private'
32
+ return restricted[0] ?? 'public'
33
+ }
34
+ export function assertAudience(receiver, source) {
35
+ if (restrictiveAudience(receiver, source) !== receiver) throw new Error('audience exceeds receiving scope')
36
+ }
37
+ export function assertHandoff(value) {
38
+ assertHarness(value, 'harness', 'handoff')
39
+ if (contentDigest(value.payload) !== value.payloadDigest) throw new Error('handoff payload digest mismatch')
40
+ return value
41
+ }