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

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 (516) hide show
  1. package/CHANGELOG.md +661 -0
  2. package/README.md +142 -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 +269 -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 +211 -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 +238 -0
  65. package/docs/learning.md +215 -0
  66. package/docs/local-services.md +181 -16
  67. package/docs/obsidian-contract.md +223 -15
  68. package/docs/obsidian-plugin.md +38 -4
  69. package/docs/obsidian.md +613 -51
  70. package/docs/optional-ingestion.md +83 -0
  71. package/docs/personal-workspace.md +257 -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 +49 -0
  77. package/docs/repo-boundary-guard.md +94 -0
  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 +317 -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 +47 -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 +75 -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 +59 -5
  300. package/skills/claude/atelier-build-harness/SKILL.md +59 -0
  301. package/skills/claude/atelier-coordination/SKILL.md +32 -0
  302. package/skills/claude/atelier-discovery-harness/SKILL.md +48 -0
  303. package/skills/claude/atelier-guided-upgrade/SKILL.md +29 -0
  304. package/skills/claude/atelier-interaction/SKILL.md +34 -0
  305. package/skills/claude/atelier-knowledge-harness/SKILL.md +60 -0
  306. package/skills/claude/atelier-knowledge-setup/SKILL.md +72 -0
  307. package/skills/claude/atelier-practical-judgment/SKILL.md +64 -0
  308. package/skills/claude/atelier-research-harness/SKILL.md +43 -0
  309. package/skills/claude/atelier-skill-steward/SKILL.md +53 -0
  310. package/skills/claude/atelier-trackables/SKILL.md +40 -0
  311. package/skills/codex/atelier-build-harness/SKILL.md +59 -0
  312. package/skills/codex/atelier-coordination/SKILL.md +32 -0
  313. package/skills/codex/atelier-discovery-harness/SKILL.md +48 -0
  314. package/skills/codex/atelier-guided-upgrade/SKILL.md +29 -0
  315. package/skills/codex/atelier-interaction/SKILL.md +34 -0
  316. package/skills/codex/atelier-knowledge-harness/SKILL.md +60 -0
  317. package/skills/codex/atelier-knowledge-setup/SKILL.md +72 -0
  318. package/skills/codex/atelier-practical-judgment/SKILL.md +64 -0
  319. package/skills/codex/atelier-research-harness/SKILL.md +43 -0
  320. package/skills/codex/atelier-skill-steward/SKILL.md +53 -0
  321. package/skills/codex/atelier-trackables/SKILL.md +40 -0
  322. package/src/architecture/catalog.mjs +355 -0
  323. package/src/architecture/index.mjs +93 -0
  324. package/src/boundary/content-rules.mjs +4 -2
  325. package/src/boundary/delegation-command.mjs +158 -0
  326. package/src/boundary/delegation.mjs +396 -0
  327. package/src/boundary/policy.mjs +52 -10
  328. package/src/build/git.mjs +18 -0
  329. package/src/build/index.mjs +3 -0
  330. package/src/build/ledger.mjs +88 -0
  331. package/src/capabilities/adoption.mjs +381 -0
  332. package/src/capabilities/evidence.mjs +140 -0
  333. package/src/capabilities/files.mjs +124 -0
  334. package/src/capabilities/index.mjs +4 -0
  335. package/src/capabilities/instructions.mjs +250 -0
  336. package/src/capabilities/package.mjs +136 -0
  337. package/src/cli/command-failure.mjs +36 -0
  338. package/src/cli/execute-command.mjs +16 -2
  339. package/src/cli/run.mjs +65 -9
  340. package/src/coauthor/store.mjs +43 -2
  341. package/src/collaboration/proposals.mjs +189 -0
  342. package/src/commands/architecture.mjs +27 -0
  343. package/src/commands/boundary.mjs +3 -0
  344. package/src/commands/capability.mjs +73 -0
  345. package/src/commands/enroll.mjs +3 -0
  346. package/src/commands/harness.mjs +79 -0
  347. package/src/commands/ingest.mjs +39 -0
  348. package/src/commands/init.mjs +4 -1
  349. package/src/commands/inquiry.mjs +66 -0
  350. package/src/commands/knowledge-semantic.mjs +128 -0
  351. package/src/commands/knowledge.mjs +119 -0
  352. package/src/commands/learn.mjs +61 -0
  353. package/src/commands/obsidian.mjs +754 -63
  354. package/src/commands/practice.mjs +24 -0
  355. package/src/commands/setup.mjs +22 -2
  356. package/src/commands/trackable.mjs +19 -0
  357. package/src/contracts/corpus.mjs +30 -0
  358. package/src/coordination/index.mjs +110 -0
  359. package/src/evidence-navigation/contracts.mjs +60 -0
  360. package/src/evidence-navigation/evaluate.mjs +69 -0
  361. package/src/evidence-navigation/generation.mjs +22 -0
  362. package/src/evidence-navigation/index.mjs +2 -0
  363. package/src/evidence-navigation/local.mjs +167 -0
  364. package/src/evidence-navigation/schema.generated.mjs +604 -0
  365. package/src/evidence-navigation/types.mjs +12 -0
  366. package/src/export/atelier-export-contract.mjs +35 -8
  367. package/src/graph/enroll.mjs +248 -0
  368. package/src/graph/graph.mjs +17 -1
  369. package/src/graph/knowledge-graph.mjs +58 -8
  370. package/src/harnesses/contracts.mjs +41 -0
  371. package/src/harnesses/exchange.mjs +154 -0
  372. package/src/harnesses/feedback.mjs +16 -0
  373. package/src/harnesses/history.mjs +37 -0
  374. package/src/harnesses/index.mjs +4 -0
  375. package/src/harnesses/store.mjs +29 -0
  376. package/src/ingestion/contracts.mjs +41 -0
  377. package/src/ingestion/evaluation.mjs +119 -0
  378. package/src/ingestion/optional/composition/index.mjs +171 -0
  379. package/src/ingestion/optional/evaluation/index.mjs +219 -0
  380. package/src/ingestion/optional/graphify/composition-binding.mjs +60 -0
  381. package/src/ingestion/optional/graphify/composition_receiving.py +185 -0
  382. package/src/ingestion/optional/graphify/graphify_supplier.py +933 -0
  383. package/src/ingestion/optional/graphify/json_bridge.py +163 -0
  384. package/src/ingestion/optional/graphify/query_receiving.py +209 -0
  385. package/src/ingestion/optional/index.mjs +9 -0
  386. package/src/ingestion/optional/jev/bridge.mjs +166 -0
  387. package/src/ingestion/optional/jev/composition-binding.mjs +116 -0
  388. package/src/ingestion/optional/jev/judgments.mjs +174 -0
  389. package/src/ingestion/optional/jev/native-translation.mjs +32 -0
  390. package/src/ingestion/optional/lightrag/atelier_lightrag_supplier/__init__.py +7 -0
  391. package/src/ingestion/optional/lightrag/atelier_lightrag_supplier/adapter.py +966 -0
  392. package/src/ingestion/optional/lightrag/atelier_lightrag_supplier/artifacts.py +101 -0
  393. package/src/ingestion/optional/lightrag/atelier_lightrag_supplier/projection.py +146 -0
  394. package/src/ingestion/optional/lightrag/composition-binding.mjs +67 -0
  395. package/src/ingestion/optional/vanilla/composition-binding.mjs +102 -0
  396. package/src/ingestion/optional/vanilla/index.mjs +218 -0
  397. package/src/ingestion/optional/vanilla/native-normalization.mjs +187 -0
  398. package/src/ingestion/processors.mjs +218 -0
  399. package/src/ingestion/semantic.mjs +203 -0
  400. package/src/ingestion/store.mjs +372 -0
  401. package/src/inquiry/beliefs.mjs +32 -0
  402. package/src/inquiry/contracts.mjs +23 -0
  403. package/src/inquiry/index.mjs +5 -0
  404. package/src/inquiry/ledger.mjs +135 -0
  405. package/src/inquiry/lenses.mjs +15 -0
  406. package/src/inquiry/projection.mjs +77 -0
  407. package/src/inquiry/store.mjs +35 -0
  408. package/src/intake/read-scope.mjs +12 -0
  409. package/src/intake/store.mjs +69 -6
  410. package/src/interaction/index.mjs +91 -0
  411. package/src/judgment/index.mjs +82 -0
  412. package/src/judgment/practice-evaluation.mjs +70 -0
  413. package/src/judgment/practice.mjs +144 -0
  414. package/src/knowledge/context.mjs +217 -0
  415. package/src/knowledge/index.mjs +5 -0
  416. package/src/knowledge/ingestion.mjs +79 -0
  417. package/src/knowledge/intake.mjs +33 -0
  418. package/src/knowledge/ledger.mjs +110 -0
  419. package/src/knowledge/participatory/guidance.mjs +36 -0
  420. package/src/knowledge/participatory/guided-contribution.mjs +44 -0
  421. package/src/knowledge/participatory/index.mjs +2 -0
  422. package/src/knowledge/participatory/installed-workshop.mjs +108 -0
  423. package/src/knowledge/plan.mjs +67 -0
  424. package/src/knowledge/projection.mjs +43 -0
  425. package/src/knowledge/semantic-operation.mjs +567 -0
  426. package/src/knowledge/sessions.mjs +467 -0
  427. package/src/knowledge/workspace.mjs +295 -0
  428. package/src/knowledge-health/assessment.mjs +165 -0
  429. package/src/knowledge-health/capabilities.mjs +350 -0
  430. package/src/knowledge-health/context.mjs +62 -0
  431. package/src/knowledge-health/example.mjs +47 -0
  432. package/src/knowledge-health/index.mjs +10 -0
  433. package/src/knowledge-health/owner-join.mjs +88 -0
  434. package/src/knowledge-health/proof/common.mjs +24 -0
  435. package/src/knowledge-health/proof/installed-check.mjs +100 -0
  436. package/src/knowledge-health/proof/native-readback.mjs +37 -0
  437. package/src/knowledge-health/proof/rehearse.mjs +68 -0
  438. package/src/knowledge-health/proof/validate-participant.mjs +17 -0
  439. package/src/knowledge-health/proof/verify-native-capture.mjs +14 -0
  440. package/src/knowledge-health/proof/workshop-check.mjs +36 -0
  441. package/src/knowledge-health/rule-identity.mjs +44 -0
  442. package/src/knowledge-health/workshop-composition.mjs +19 -0
  443. package/src/knowledge-health/workshop-profile.mjs +176 -0
  444. package/src/knowledge-health/workshop.mjs +99 -0
  445. package/src/learning/adapters.mjs +68 -0
  446. package/src/learning/assistance.mjs +127 -0
  447. package/src/learning/contracts.mjs +65 -0
  448. package/src/learning/store.mjs +272 -0
  449. package/src/personal-workspace/index.mjs +391 -0
  450. package/src/personal-workspace/selection.mjs +385 -0
  451. package/src/project/config.mjs +8 -0
  452. package/src/project/durable-state.mjs +3 -1
  453. package/src/project/file-class.mjs +1 -1
  454. package/src/projection/obsidian/edits/apply.mjs +55 -16
  455. package/src/projection/obsidian/personal-workspace.mjs +436 -0
  456. package/src/projection/obsidian/proposals/adapter.mjs +47 -8
  457. package/src/projection/obsidian/proposals/observation.mjs +10 -2
  458. package/src/projection/obsidian/publication/publisher.mjs +142 -13
  459. package/src/projection/obsidian/publication/vault-list.mjs +4 -3
  460. package/src/projection/obsidian/recovery/index.mjs +4 -1
  461. package/src/projection/obsidian/recovery/store.mjs +160 -7
  462. package/src/projection/obsidian/selection-ui/contribution.mjs +6 -5
  463. package/src/readiness/readiness.mjs +10 -3
  464. package/src/reflection/index.mjs +56 -0
  465. package/src/runtime/obsidian/app-production-seams.mjs +48 -16
  466. package/src/runtime/obsidian/app-registration.mjs +175 -28
  467. package/src/runtime/obsidian/app-restart.mjs +154 -0
  468. package/src/runtime/obsidian/engine.mjs +163 -20
  469. package/src/runtime/obsidian/extension-points.mjs +1 -1
  470. package/src/runtime/obsidian/index.mjs +10 -7
  471. package/src/runtime/obsidian/launch-plan.mjs +7 -4
  472. package/src/runtime/obsidian/lifecycle.mjs +92 -12
  473. package/src/runtime/obsidian/login-item.mjs +332 -0
  474. package/src/runtime/obsidian/machine-settings.mjs +119 -12
  475. package/src/runtime/obsidian/opening.mjs +171 -37
  476. package/src/runtime/obsidian/pipeline.mjs +71 -3
  477. package/src/runtime/obsidian/plugin-channel.mjs +11 -3
  478. package/src/runtime/obsidian/plugin-choice.mjs +16 -4
  479. package/src/runtime/obsidian/plugin-drift.mjs +59 -11
  480. package/src/runtime/obsidian/plugin-presence.mjs +14 -1
  481. package/src/runtime/obsidian/process-identity.mjs +20 -10
  482. package/src/runtime/obsidian/project-views.mjs +282 -0
  483. package/src/runtime/obsidian/questions.mjs +48 -0
  484. package/src/runtime/obsidian/release-watch.mjs +56 -0
  485. package/src/runtime/obsidian/service-main.mjs +99 -16
  486. package/src/runtime/obsidian/service-manager-production.mjs +61 -0
  487. package/src/runtime/obsidian/service-managers.mjs +275 -0
  488. package/src/runtime/obsidian/service-record.mjs +87 -23
  489. package/src/runtime/obsidian/service.mjs +36 -3
  490. package/src/runtime/obsidian/startup-adapters.mjs +59 -21
  491. package/src/runtime/obsidian/unheld-evidence.mjs +84 -0
  492. package/src/runtime/obsidian/vault-location.mjs +300 -0
  493. package/src/runtime/obsidian/view-counts.mjs +34 -0
  494. package/src/server/local-sidecar.mjs +169 -2
  495. package/src/server/server.mjs +28 -2
  496. package/src/template-bindings/project.mjs +92 -0
  497. package/src/templates/profile.mjs +225 -0
  498. package/src/trackables/domain.mjs +175 -0
  499. package/src/trackables/store.mjs +114 -0
  500. package/src/ui/knowledge-page.mjs +1388 -0
  501. package/src/upgrade/explanation.mjs +1 -1
  502. package/src/upgrade/template-participant.mjs +171 -0
  503. package/src/upgrade/transaction.mjs +72 -25
  504. package/src/upgrade/upgrade.mjs +1 -0
  505. package/templates/external-project-workspace/pack-lifecycle.json +6 -1
  506. package/templates/knowledge-workspace/.gitattributes +2 -0
  507. package/templates/knowledge-workspace/AGENTS.md +27 -0
  508. package/templates/knowledge-workspace/README.md +44 -0
  509. package/templates/knowledge-workspace/atelier.project.json +22 -0
  510. package/templates/knowledge-workspace/gitignore +6 -0
  511. package/templates/knowledge-workspace/knowledge-plan.json +111 -0
  512. package/templates/knowledge-workspace/knowledge-plan.schema.json +281 -0
  513. package/templates/knowledge-workspace/records/forecast.md +22 -0
  514. package/templates/knowledge-workspace/records/inspection.md +25 -0
  515. package/templates/knowledge-workspace/records/telescope.md +24 -0
  516. package/templates/knowledge-workspace/repo-access.v1.json +9 -0
package/docs/obsidian.md CHANGED
@@ -282,18 +282,30 @@ below is the shipped `atelier obsidian` usage text; `atelier obsidian --help`
282
282
  prints it. There are three steps, and none of them is done by hand in
283
283
  Obsidian.
284
284
 
285
- 1. Enable the projection in the project configuration. The member
286
- `ext["mnstry.atelier.obsidian"]` is an `atelier-obsidian-ext-settings/v1`
285
+ 1. Declare a view in the project configuration:
286
+ `atelier obsidian view add everything --all`. It adds a view of every note
287
+ the machine may show to `atelier.project.json`, shows the change as a diff
288
+ and how many notes the view would show, and makes it the default view. You
289
+ commit the file; Atelier commits nothing. See
290
+ [Adding a view](#adding-a-view). The member it writes,
291
+ `ext["mnstry.atelier.obsidian"]`, is an `atelier-obsidian-ext-settings/v1`
287
292
  document: `enabled: true`, `scopes` (each with a `scopeId`, a `mode` of
288
293
  `full`, `scoped` or `focus`, a `selector`, and for an expansion an explicit
289
- `depth` and `maxNodes`), and optionally `defaultScopeId`. A project without
290
- this member is `disabled (not-configured)` and nothing is published.
291
- `atelier obsidian scope list` shows what was declared.
294
+ `depth` and `maxNodes`), and optionally `defaultScopeId`. It can also be
295
+ written by hand. A project without this member is
296
+ `disabled (not-configured)` and nothing is published.
297
+ `atelier obsidian view list` (or `scope list`) shows what was declared.
292
298
  2. Set the private machine settings. They live outside every repository and
293
299
  are never committed:
294
- - `atelier obsidian audience set A,B` names the audiences this machine lets
295
- into a view. No audience is admitted by default, so a view is empty until
296
- one is set; `audience clear` empties it again.
300
+ - `atelier obsidian audience set me` lets "only you" into a view: every
301
+ audience of a note but `sensitive`, and the notes that carry no
302
+ classification, which only a vault that is yours alone shows.
303
+ `audience set A,B` names the audiences instead, and never shows notes
304
+ without a classification; `sensitive` is added by name
305
+ (`audience set me,sensitive`, which is such a list). No audience is
306
+ admitted by default, so a view is empty until one is set;
307
+ `audience clear` empties it again. See
308
+ [Notes without a classification](#notes-without-a-classification).
297
309
  - `atelier obsidian mode set manual` keeps every queued edit waiting for a
298
310
  person. `mode set automatic` is refused until an active automatic policy
299
311
  is installed.
@@ -302,11 +314,14 @@ Obsidian.
302
314
  unchanged; `policy revoke` returns the mode to `manual` and stops every
303
315
  later apply.
304
316
  3. Open a view:
305
- `atelier obsidian open --scope ID --consent-actor ID --adapter=obsidian-cli`.
317
+ `atelier obsidian open --scope ID --adapter=obsidian-cli`.
306
318
  That's it. Reaching the installed app is never a default, so
307
- `--adapter=obsidian-cli` is required, and the first open of a workspace
308
- records who allowed the maintenance service to run (`--consent-actor`;
309
- later opens reconnect to it and need no consent). `open` starts or
319
+ `--adapter=obsidian-cli` is needed the first time; the workspace remembers
320
+ it, and later runs need no flag. The first open of a workspace records who
321
+ allowed the maintenance service to run: for a person at a terminal, the
322
+ account's name; for a program, `--consent-actor ID`, which it must pass.
323
+ Later opens reconnect and need neither. `atelier obsidian settings` shows
324
+ what was remembered and how to change it. `open` starts or
310
325
  reconnects maintenance and asks it for a tick, makes Obsidian (version
311
326
  1.13.7 or later) know the view's vault as one of its vaults, opens it,
312
327
  publishes the view, verifies the vault by reading it back, and waits until
@@ -315,25 +330,216 @@ Obsidian.
315
330
  [What `open` does in each state of Obsidian](#what-open-does-in-each-state-of-obsidian).
316
331
 
317
332
  The maintenance service can also be managed on its own:
318
- `atelier obsidian service start --consent-actor ID --adapter=obsidian-cli`,
319
- `service status` and `service stop`; `service unit --print
320
- --adapter=obsidian-cli` prints a startup unit and installs nothing.
333
+ `atelier obsidian service start [--consent-actor ID] [--adapter=obsidian-cli]`,
334
+ `service status` and `service stop`; `service unit --print` prints the login
335
+ item that `service unit --install` would write, and installs nothing (see
336
+ [Start at login](#start-at-login)). The flags are needed only until the
337
+ workspace remembers them, as for `open`.
338
+
339
+ ### Adding a view
340
+
341
+ ```sh
342
+ atelier obsidian view add ID (--all | --folder PATH [--folder PATH ...] [--repo R] | --tag T) [--expand DEPTH:MAX] [--default] [--allow-empty] [--yes]
343
+ ```
344
+
345
+ - `--all` is a view of every note (`full`). `--folder` takes the notes under a
346
+ folder of a repository, written from the repository's root (`docs/notes`),
347
+ and can be given as often as needed; `--repo R` names the repository when
348
+ the project has more than one. `--tag T` takes the notes with a tag. Each of
349
+ these is a `scoped` view, and `--expand DEPTH:MAX` adds the notes they link
350
+ to, following links up to DEPTH steps and adding at most MAX notes.
351
+ - The first view declared is the default; `--default` makes a later one the
352
+ default.
353
+ - Before writing, the command counts the notes the view would show on this
354
+ machine, as the machine decided who may see (as "only you", with the notes
355
+ without a classification it shows, while nobody decided), and names how
356
+ many of the notes it selects are withheld: those without a classification
357
+ (a `kg` block) that the decision does not show, and those whose audience is
358
+ not admitted. A view that would show no note is refused with
359
+ `view-would-be-empty` and the counts; `--allow-empty` declares it anyway.
360
+ When the machine admits no audience at all (`audience clear`), the refusal
361
+ says so and names `atelier obsidian audience set me`.
362
+ - While nobody decided who may see, the maintenance service publishes no
363
+ note, whatever the counts say: the next step `view add` names is then
364
+ `atelier obsidian audience set me`, before `atelier obsidian open` (`next`
365
+ under `--json`, in order).
366
+ - A person at a terminal sees the change and the counts and is asked
367
+ `Write this change? [Y/n]`; `--yes` answers beforehand, and no answer within
368
+ 10 minutes writes nothing (`unanswered`). For anyone else the command is the
369
+ consent: the change is made, and printed (`diff` under `--json`).
370
+ - The file is rewritten only when it is in the form Atelier writes JSON in
371
+ (two-space indentation, LF or CRLF line ends, with or without a final one),
372
+ so the change is the new view and nothing else. A file in another form is
373
+ refused with `project-config-format-unknown`, and the member to add by hand
374
+ is in the refusal's `detail`. The file is replaced atomically, keeps its
375
+ mode, and only while it holds the bytes the change was made from
376
+ (`project-config-changed` otherwise). A link is not followed
377
+ (`project-file-not-regular`).
378
+ - The workspace pointer is only ever written into an ignored `.atelier-local/`.
379
+ When that folder is not ignored, the same change adds `.atelier-local/` to
380
+ the project's `.gitignore`, and shows it.
381
+ - A name that is taken is refused with `view-exists`. Removing a view is done
382
+ by hand for now.
383
+ - The contract's `type` selector matches a note's file type (`markdown`,
384
+ `html`), not its `kg.type`, so `view add` does not offer it; a view by
385
+ `kg.type` needs a contract change.
386
+
387
+ ### Notes without a classification
388
+
389
+ A note whose front matter carries no `kg` block (or that has no front matter)
390
+ is unclassified: the knowledge graph gives it the `private` audience, and by
391
+ default no view shows it. A vault that is only yours shows it: the audience
392
+ decision `only-you` with `unclassified: shown`, which `audience set me`
393
+ records. A list of audiences never shows one, even a list that names every
394
+ audience "only you" stands for, so a vault for anyone else can never carry
395
+ them.
396
+
397
+ A note whose labels cannot be known is never shown, in any vault: front matter
398
+ Atelier cannot read (a block scalar such as `description: |`, a value wrapped
399
+ onto a second line), front matter that is not plain `key: value` lines at its
400
+ top level (a quoted key such as `"kg":`, a one-line flow or JSON mapping, a
401
+ complex key), or any top-level `kg` key that is not a block. Such a note may
402
+ say `sensitive`, which "only you" leaves out. Only a note with no front
403
+ matter, or with front matter of plain top-level keys at the start of the line,
404
+ none of which is `kg`, counts as one without a classification. A plain key is
405
+ written with ASCII letters, digits, `_` and `-`, starting with a letter or
406
+ `_`: a note whose front matter uses a key with a space (`due date:`), other
407
+ letters (`título:`), a dot or a leading digit, or a quoted key, stays withheld
408
+ even when it holds nothing sensitive. Give it a `kg` block to show it.
409
+
410
+ In an "only you" vault such a note is shown only when its bytes read as a note
411
+ the way the emitter reads every note, so one file that cannot be published
412
+ (front matter that opens and never closes, closes at once, or carries a
413
+ trailing space on its first line; bytes that are not UTF-8) never stops the
414
+ vault: it stays withheld, as does a file that cannot be read. A shown note is
415
+ part of the view in every respect: links to it are links inside the view,
416
+ generated text may name it, the selection operation resolves it, and an edit
417
+ to it is applied to its source like any other.
418
+
419
+ A decision recorded before this release, "only you" with those notes
420
+ withheld, keeps them withheld until `audience set me` is run again. Changing
421
+ the decision rebuilds every view at the next tick (the eligibility revision
422
+ changes).
423
+
424
+ ### What this machine remembers
425
+
426
+ A workspace's machine settings (`atelier-obsidian-machine-settings/v2`, owner
427
+ only, under the private data root, never in a repository) hold what a person
428
+ decided once, so no later run asks again or has to be told again. Each
429
+ decision is null until it is made, and otherwise records what was decided,
430
+ when, by whom when that is known (an actor identifier), and how: answered at
431
+ a terminal (`question`), given on the command line (`command`), taken as the
432
+ defaults (`defaults`), or carried over from an earlier release (`v1`).
433
+
434
+ | Decision | Holds | Made today by |
435
+ | --- | --- | --- |
436
+ | `audience` | `only-you` or `custom`, and whether notes that carry no classification are `shown` or `withheld`. Only `only-you` may show them; a list of audiences always withholds them. The admitted list stays in `audienceAllow`, the engine's audience input | `audience set me` (only you, shown) or `audience set A,B` / `audience clear` (withheld) |
437
+ | `location` | the absolute folder that holds this workspace's vaults | `location set DIR` |
438
+ | `loginItem` | `on` or `off` | `service unit --install` (on); `service unit --remove` and `uninstall` (off) |
439
+ | `adapter` | `obsidian-cli` | `--adapter=obsidian-cli` given to `open`, `service start` or `service unit --install` |
440
+
441
+ Who allowed the maintenance service is not a second copy here: it stays the
442
+ consent the service reads from its own settings. `atelier obsidian settings`
443
+ shows all of it, and how each answer is changed.
444
+
445
+ Releases up to 0.2.0-alpha.12 wrote `atelier-obsidian-machine-settings/v1`.
446
+ Such a file is read as the v2 document it stands for, an audience list set
447
+ with it becoming that person's decision, and stays v1 on disk until the next
448
+ write, which writes v2. A release that knows only v1 refuses a v2 file as
449
+ `invalid-machine-settings`: after an upgrade, a maintenance service that
450
+ still runs the earlier release fails its ticks until it is replaced, which
451
+ `atelier obsidian open` and `atelier obsidian service start` do.
452
+
453
+ ### Start at login
454
+
455
+ Without a login item the vault is complete after a restart, but nothing keeps
456
+ it fresh until the next `open`. A login item starts the maintenance service
457
+ when you log in:
458
+
459
+ ```sh
460
+ atelier obsidian service unit --install [--consent-actor ID] [--adapter=obsidian-cli]
461
+ atelier obsidian service unit --print # what --install writes; writes nothing
462
+ atelier obsidian service unit --remove
463
+ atelier obsidian uninstall
464
+ ```
465
+
466
+ - On macOS it is a launchd agent,
467
+ `~/Library/LaunchAgents/ai.mnstry.atelier.<project>.<workspace-id>.plist`.
468
+ macOS says "Background Items Added" and lists it as "node" under System
469
+ Settings → General → Login Items & Extensions, because there is no app to
470
+ name it after. Switched off there, it stays off: `status` reports
471
+ `installed, switched off in System Settings`, and `open` starts the service
472
+ for that session only.
473
+ - On Linux it is a systemd user unit,
474
+ `~/.config/systemd/user/atelier-obsidian-<workspace-id>.service`
475
+ (`$XDG_CONFIG_HOME` when set), enabled with `systemctl --user`. Disabled
476
+ with `systemctl --user disable`, it stays disabled: `status` reports
477
+ `installed, disabled`, and `open` starts the service for that session
478
+ only. Where no user instance of systemd answers (WSL, a container), the
479
+ answer is `login-item-unavailable` and nothing is left behind.
480
+ - Windows is not offered (`startup-platform-unqualified`), as publication
481
+ itself is refused there.
482
+
483
+ It runs the package installed in the project
484
+ (`<project>/node_modules/@mnstry/atelier/…`, named by that path, so the next
485
+ start runs whatever release the project has installed then), with the Node
486
+ that installed it and the search path you had, in the root folder. It names
487
+ the data folder and the workspace it was installed for, so it finds them at
488
+ login whatever variables your shell set. Run from
489
+ `npx` in a project that has no package installed, it refuses with
490
+ `login-item-needs-installed-package`: install `@mnstry/atelier` in the project
491
+ first. Installing records that you allowed the service to run at login (the
492
+ consent then covers startup): `--consent-actor ID` names who allows it; for a
493
+ person at a terminal, the actor already recorded for this workspace, or else
494
+ the account's name. A program that passes no `--consent-actor` for a
495
+ workspace whose consent covers the service alone is refused
496
+ (`startup-consent-required`). The answer is remembered as the `loginItem`
497
+ decision. `--remove` takes the consent back to the service alone, removes the
498
+ item, and starts the service again for this session only, as a process of its
499
+ own (with the adapter given or remembered; otherwise the next `open` starts
500
+ it). Each workspace has its own login item, port, log and consent, and
501
+ projects may pin different releases; `launchctl list | grep ai.mnstry.atelier`
502
+ lists every one on a Mac.
503
+
504
+ Once a login item is installed, the service is started through it: `service
505
+ start`, `open` and the replacement of an outdated service ask launchd or
506
+ systemd to start it, never start a second one beside it, and accept only the
507
+ service that proves itself with the installed entry. When the unit differs from
508
+ what would be written now (the Node it names was removed, say), the next start
509
+ writes it again and says `login item refreshed`. A refusal of the service at
510
+ login (another service already runs, or the consent does not cover startup)
511
+ ends the process cleanly, so it is not retried every minute, and `status` says
512
+ `the login item did not start the service: <code>` with the next step. A crash
513
+ is restarted after a minute.
514
+
515
+ `uninstall` removes the login item and stops the service. It keeps the vaults,
516
+ the private state, the project file and Obsidian's vault list as they are, and
517
+ prints where each is: every vault under the data root and every folder
518
+ allocated to a view where the workspace decided its vaults live, a view no
519
+ longer declared included. It does not start the service again.
321
520
 
322
521
  After an upgrade of Atelier, a maintenance service started earlier still runs
323
- the earlier release. `open` replaces it: when the service of this workspace
324
- proves itself Atelier's own but runs an earlier release than the installed one
325
- (its record names the release it runs: the package version and a digest of
326
- its modules; an earlier version, the same version with other modules, or no
327
- release named), or refuses a tick that names a view as releases up to
328
- 0.2.0-alpha.11 do,
329
- `open` stops it as `service stop` would and starts the installed release under
330
- the consent already recorded, and says `service: restarted (outdated)`. A
331
- service of a later release is never replaced by an earlier one, so two
332
- installations used on one workspace (a global and a project-local one, say)
333
- do not replace each other's service on every open: `open` answers
334
- `service-unavailable` / `service-other-release`; run `atelier obsidian service
335
- stop`, then open again, or open with the later release. A service in a long
336
- tick is not stopped (`open` answers `busy`), and a listener that does not
522
+ the earlier release. One the login item started notices it: after each tick
523
+ it compares the package on disk (read through the path the item names, so a
524
+ re-pointed link or a `file:` install counts) with the release it started
525
+ with, and when they differ it exits after that tick with code 75, and its
526
+ service manager starts the new release within a minute. Otherwise `open` and
527
+ `service start` replace it: when the service of this workspace proves itself
528
+ Atelier's own but runs an earlier release than the installed one (its record
529
+ names the release it runs: the package version and a digest of its modules;
530
+ an earlier version, the same version with other modules, or no release
531
+ named), or refuses a tick that names a view as releases up to 0.2.0-alpha.11
532
+ do, they stop it as `service stop` would and start the installed release under
533
+ the consent already recorded (through the login item when there is one), and
534
+ say `service: restarted (outdated)`. The installed release is read from the
535
+ package of the entry that would be started, so with a login item it is the
536
+ project's own package. A service of a later release is never replaced by an
537
+ earlier one, so two installations used on one workspace (a global and a
538
+ project-local one, say) do not replace each other's service on every open:
539
+ `open` answers `service-unavailable` / `service-other-release`, and `service
540
+ start` answers that it runs, with `release: later`; run `atelier obsidian
541
+ service stop`, then open again, or open with the later release. A service in a
542
+ long tick is not stopped (`open` answers `busy`), and a listener that does not
337
543
  prove itself this workspace's service is never touched.
338
544
 
339
545
  The first time Obsidian opens a view's vault it asks "Do you trust the author
@@ -377,13 +583,79 @@ proposals list` and `proposals show OPERATION` read them, and nothing applies
377
583
  one. A body edit to a note whose source uses CRLF line endings is also a
378
584
  proposal, never an apply, because the app normalizes line endings on save.
379
585
 
380
- The vault itself lives under the private data root, outside every repository:
381
- `~/Library/Application Support/Atelier` on macOS, `$XDG_DATA_HOME/atelier`
382
- (else `~/.local/share/atelier`) on Linux and `%LOCALAPPDATA%\Atelier` on
383
- Windows, under `obsidian/<workspace-id>/`. `--data-root DIR` names another
384
- absolute directory. Private state inside an enrolled repository is refused.
385
- Publication is proven on macOS arm64 only and is refused on Windows; see
386
- [Known limits](#known-limits).
586
+ Atelier's private state lives under the private data root, outside every
587
+ repository: `~/Library/Application Support/Atelier` on macOS,
588
+ `$XDG_DATA_HOME/atelier` (else `~/.local/share/atelier`) on Linux and
589
+ `%LOCALAPPDATA%\Atelier` on Windows, under `obsidian/<workspace-id>/`.
590
+ `--data-root DIR` names another absolute directory. Private state inside an
591
+ enrolled repository is refused. Publication is proven on macOS arm64 only and
592
+ is refused on Windows; see [Known limits](#known-limits).
593
+
594
+ Where the vaults are is decided per workspace. Until a person decides it, a
595
+ view's vault is under the data root too, in `vaults/<view>`, as in every
596
+ earlier release. `atelier obsidian location set DIR` decides a visible folder
597
+ instead (`~/Atelier`, say). Each view that has not been published yet is then
598
+ given its own folder there at its first publication, named
599
+ `<project> (<view>)`: `~/Atelier/harbor-notes (everything)`. That name is also
600
+ the vault's name in Obsidian's vault switcher, so it is readable and unique
601
+ across projects and views. The first name that is free is taken, with a number
602
+ inside the parentheses when needed (`harbor-notes (everything 2)`): free means
603
+ nothing on the disk has it, and no vault Obsidian lists has it in any letter
604
+ case. The folder is created private to this user (mode 0700), and so is `DIR`
605
+ when Atelier creates it; a missing folder on the way to `DIR` is made as any
606
+ other folder is. The allocation is recorded in the workspace's private
607
+ state (`state/allocations/<view>.json`) and is never recomputed: renaming the
608
+ project or deciding another folder later moves no vault, and a vault published
609
+ before under the data root stays there. `location show` says where each
610
+ view's vault is, or will be, or why its record cannot be read.
611
+
612
+ Atelier publishes only into the folder it made. The allocation records the
613
+ folder's real path, device and inode, and the maintenance service checks them
614
+ at every tick, as the publisher does before it writes anything and again
615
+ before each note and before its commit (see Known limits). Another folder
616
+ put where the one made was (moved in, or a link) is not published into
617
+ (`vault-allocation-replaced`), nor is the same folder reached through a link
618
+ put on the way since, into a vault the app lists, say
619
+ (`vault-allocation-moved`). A folder that has gone is made again at the next
620
+ tick, only where its recorded real path leads and only where a location would
621
+ be accepted (not inside a repository, the private state, a vault Atelier
622
+ publishes or one the app lists, and on the data root's volume). A vault
623
+ removed, moved or replaced while it is being published stops that publication
624
+ (`vault-allocation-missing`, `vault-allocation-replaced`, or
625
+ `vault-root-moved` for a vault under the data root). Once the folder is put
626
+ back, or made again, the running service publishes into it again at its next
627
+ tick; no restart is needed. One case waits for the next change at the view's
628
+ sources: a folder made again after a publication that stopped just before its
629
+ commit. That generation is finished by restart recovery, its notes went with
630
+ the folder that went away, and the view reads `vault-note-missing` until then. A
631
+ view that was published and whose vault Atelier cannot find is refused
632
+ (`vault-allocation-lost`) rather than published again into a new, empty vault
633
+ under the data root: its record was lost, or, for a view that never had a
634
+ record (published under the data root), its `vaults/<view>` folder was
635
+ removed. Restore the record from a backup if its vault was allocated
636
+ elsewhere; otherwise make the folder `vaults/<view>` under the data root, and
637
+ the view is published there at the next change at its sources. `status` and
638
+ `open` name that next step for this code, and for `vault-allocation-moved`,
639
+ `vault-allocation-replaced` and `vault-allocation-missing`.
640
+
641
+ `DIR` is refused inside an enrolled repository or the project, inside a vault
642
+ Atelier publishes, inside a folder Obsidian lists as a vault, and on another
643
+ volume than the data root (a note is published by an atomic exchange, which
644
+ cannot cross volumes). A folder a sync client keeps in step (iCloud Drive, a
645
+ cloud storage provider, Dropbox, OneDrive, Google Drive, or a Desktop or
646
+ Documents folder iCloud syncs) is refused unless `--allow-synced-location` is
647
+ given: another machine's Obsidian could hold a vault there unseen. A folder
648
+ macOS protects (Desktop, Documents, Downloads) is accepted with a warning,
649
+ because macOS asks before Obsidian or the maintenance service may read it.
650
+ `~/` is read against the account's home folder, which a shell does not do
651
+ after `--x=`. Each check compares the folder as written and as its real path,
652
+ in any letter case, so a link into a listed or synced vault is refused as
653
+ that vault is. Obsidian's vault list is read through the app when it runs and
654
+ answers, and otherwise from its settings file, never written. When the list
655
+ cannot be read, `location set` says so and accepts the folder, and the
656
+ maintenance service allocates no vault there until it can read the list
657
+ (the view is `stale`, `app-vault-list-unreadable`, and is tried again at
658
+ the next tick).
387
659
 
388
660
  ### What `open` does in each state of Obsidian
389
661
 
@@ -415,28 +687,97 @@ exactly because the folder is listed.
415
687
  reopens every vault it had open, this one included, and once its command
416
688
  line answers (the app itself, not the tool's "unable to find Obsidian")
417
689
  `open` hands it the vault's link through that tool, never through the
418
- operating system. On Linux a plain start is not
690
+ operating system. A vault Obsidian already lists but had closed is not
691
+ reopened by a plain start, so if Obsidian refuses that link just after it
692
+ started, `open` hands it the link once more, again through that tool and
693
+ never through the operating system, before it gives up. On Linux a plain start is not
419
694
  qualified yet, and Obsidian is started with the link (the other vaults'
420
695
  reopen marks are lost there; a known limit).
421
- An Obsidian that never ran on this account has no settings file yet, and
422
- `open` does not create one: start Obsidian once, then open again.
696
+ In the same write, `open` turns Obsidian's command line on (`cli: true`)
697
+ when it is off: publishing into a vault Obsidian holds needs it until
698
+ Atelier's plugin takes over that part, and it is off in a new installation.
699
+ The answer says what was written and where the backup of the file as it
700
+ was is kept.
701
+ - **Obsidian is installed and never started** (no `obsidian.json` yet). When
702
+ the process table says, positively, that no Obsidian runs, `open` creates
703
+ the file, with this vault flagged open and the command line on, and starts
704
+ Obsidian plainly; Obsidian opens the vault. Nothing else is in the file,
705
+ and the settings folder is created private to you when it does not exist
706
+ yet. The file is created exclusively: if Obsidian writes its own first,
707
+ that one is kept and `open` says so. While an Obsidian may run, nothing is
708
+ created (`app-may-be-running`).
423
709
  - **Obsidian runs with no vault open.** Its command line then answers every
424
710
  command with "Vault not found.", so nothing can be asked of it, and its
425
711
  settings file belongs to the running app, so it is only read. A vault the
426
712
  app already lists is opened by path and published through the app as
427
- above. A vault it does not list yet is answered as outcome
428
- `app-version-unsupported` with reason `no-vault-open`: open any vault in
429
- Obsidian, or quit it, and open again. This is the one state of a running
430
- Obsidian that `open` cannot get through alone.
431
- - **Obsidian's command line is turned off** (the default of a new
713
+ above. For a vault it does not list yet, see "Restart, only when you ask"
714
+ below; without that, `open` answers `app-version-unsupported` with reason
715
+ `no-vault-open` and names `--restart-obsidian`.
716
+ - **Obsidian runs with its command line turned off** (the default of a new
432
717
  installation). It then answers every command with "Command line interface
433
- is not enabled", and only a link reaches it. With Obsidian running, `open`
434
- adds and launches nothing. With Obsidian quit, `open` adds the vault to its
435
- settings and starts it, and Obsidian opens the vault. Either way `open` then
436
- answers `app-cli-unavailable` with reason `cli-turned-off` and says where to
437
- turn it on: Settings > General > Advanced > Command line interface.
438
- Publishing into a vault Obsidian holds needs it until Atelier's plugin takes
439
- over that part.
718
+ is not enabled", only a link reaches it, and its settings belong to the
719
+ running app, which keeps the switch in memory and would write it back. See
720
+ "Restart, only when you ask" below; without that, `open` adds and launches
721
+ nothing, and answers `app-cli-unavailable` with reason `cli-turned-off`,
722
+ naming `--restart-obsidian` and where to turn the switch on yourself:
723
+ Settings > General > Advanced > Command line interface.
724
+
725
+ **Restart, only when you ask.** In the two states where Obsidian runs but
726
+ `open` cannot reach it (its command line off, or no vault open and the view's
727
+ vault not in its list), `atelier obsidian open --restart-obsidian` lets `open`
728
+ restart Obsidian once:
729
+
730
+ 1. Before anything is sent, it checks, reading only, that the write the
731
+ restart is for can succeed: the view's vault folder exists, Obsidian's
732
+ settings file can be read and is yours, is no link and has no second
733
+ name, is not a Flatpak or snap build's, is not too large to take the
734
+ vault, and lists no vault at a folder above the view's. An Obsidian that
735
+ has shown only its starter window has written no settings file yet; then
736
+ the folder it goes in must be yours (or be missing inside a folder of
737
+ yours), and the file is created after the quit, as for an Obsidian that
738
+ never started. Otherwise `open` answers that refusal and leaves Obsidian
739
+ running. Right before the first signal, once the process below is proven,
740
+ it keeps a copy of the settings file beside it
741
+ (`obsidian.json.atelier-backup-<time>`), which this run's write does not
742
+ prune, and the answer names it; a copy that cannot be kept sends nothing.
743
+ 2. It sends SIGTERM to Obsidian's main process, and to nothing else. That
744
+ process is found in the process table and must be the only Obsidian main
745
+ process there, one of yours, named by the app bundle's path, with every
746
+ other Obsidian process its child; it is read again just before the signal
747
+ and must be the same process, yours, under the same parent. Anything else
748
+ (two Obsidians, another user's, a helper of another process, a table that
749
+ cannot be read) is answered `app-main-process-unproven`, with the reason in
750
+ `restart.detail`, and nothing is sent.
751
+ 3. Obsidian handles that SIGTERM as a quit: it closes every window, keeping
752
+ the vaults it had open flagged to reopen, and its helper processes end. On
753
+ macOS its main process can then stay, with no window. Electron handles
754
+ only the first SIGTERM as a quit: a second one ends the process at once,
755
+ without its quit handlers. `open` sends that second SIGTERM only when the
756
+ same process has shown no window and no helper at every reading for at
757
+ least 5 seconds (a margin, not a proof that it has nothing left to save). There
758
+ is never a third signal, and never a stronger one: an Obsidian that is not
759
+ gone within 30 seconds is answered `launch-failed` with reason
760
+ `app-did-not-quit`, and nothing is written. The answer says how many
761
+ signals were delivered.
762
+ 4. It adds the vault to Obsidian's settings and turns the command line on, in
763
+ the one write described above.
764
+ 5. It starts Obsidian plainly, and the vaults it had open come back, with this
765
+ one beside them. If the vault could not be added after all, Obsidian is
766
+ still started again, as it was.
767
+
768
+ The answer says that Obsidian was restarted, which process was signalled,
769
+ how, and what was written. The flag is never implied by any other flag or
770
+ answer; every other operation refuses it. The restart is qualified on macOS
771
+ only (on Linux a quit Obsidian is started with a link, which would drop the
772
+ other vaults' reopen flags): elsewhere `open` answers
773
+ `restart-platform-unqualified`.
774
+
775
+ Two limits. `open` asks nothing at a terminal yet: the restart needs the flag
776
+ there too, until the first-run command asks "Obsidian must restart once to add
777
+ this vault … Restart now?" in that state. And if `open` itself is interrupted
778
+ (Ctrl-C, or its process ended) after Obsidian quit and before it was started
779
+ again, Obsidian stays quit: start it yourself, and it reopens its vaults; run
780
+ `open` again to add the view's vault.
440
781
 
441
782
  Only `open` adds a vault to Obsidian: the maintenance service never does, so
442
783
  it never opens a window nobody asked for. A declared view that was never
@@ -464,6 +805,19 @@ the view stays refused until the list names the folder once.
464
805
  While one entry of the folder has a window, `open` reaches only that one and
465
806
  never opens another entry of the same folder beside it.
466
807
 
808
+ A view's first publication into the folder allocated for it is the one
809
+ exception to the rule below. While no list the app keeps names that folder, a
810
+ folder above it or one inside it, the vault is filled even while Obsidian
811
+ runs, by creating files only. When that run completes, `open` adds the vault
812
+ to Obsidian and opens it after the commit. A run that stops partway commits
813
+ nothing and falls back to the coordinated path. That happens when the list
814
+ names the folder meanwhile, a settings file with other bytes is already
815
+ there, or an interrupted run left a replacement or a removal. `open` may then
816
+ add and open the vault before it is complete, and the app publishes the rest.
817
+ Anything that would replace or remove a file waits for the app. See "First publication into a vault no Obsidian lists" in
818
+ [obsidian-contract.md](obsidian-contract.md). The plugin's entry written this
819
+ way counts as offered until the plugin says hello from the vault.
820
+
467
821
  The publisher still writes into a vault only when it can coordinate with every
468
822
  Obsidian that may hold it, or when the process table shows, positively, that
469
823
  none runs. Otherwise it stops, and the view reports `publisher-conflict` with
@@ -500,6 +854,174 @@ command-line interface is turned on). So is a listed vault the command line
500
854
  does not answer for once it is opened, while only the plugin reports the
501
855
  version: `open` says so at once instead of waiting for the app.
502
856
 
857
+ ## Personal workspaces
858
+
859
+ A personal workspace (see [personal-workspace.md](personal-workspace.md)) is
860
+ projected through one route, `bindPersonalWorkspace({ personalHome,
861
+ generationId })` in `src/projection/obsidian/personal-workspace.mjs`. Both
862
+ arguments are explicit; neither is discovered from the environment or the
863
+ working directory. A loader uses `loadBoundProject` with the same arguments,
864
+ or `loadBoundProjectOffThread`, which composes in a worker thread; the engine
865
+ awaits its loader. No command or service binds one yet: that waits for the selection seam that
866
+ keeps one projection configuration per person.
867
+
868
+ - **One graph.** The binding is attached to the generation's resolved
869
+ `atelier.project.json` under one symbol key. When a project carries it, the
870
+ pipeline's `buildGraph` builds the canonical graph with the caller's file
871
+ cache and composition's own rule that no private note is a link target, then
872
+ applies eligibility as for any project. The engine, view counts, source apply,
873
+ the proposal adapter and the selection operation all build through it, so they
874
+ read one graph. A plain build of the generation's configuration would differ:
875
+ there, a shared note's link can name a private note.
876
+ - **Only a confirmed graph is used.** A graph is returned only under a validity
877
+ key that `composePersonalWorkspace` confirmed. The key names:
878
+ - the authored manifest and overlay, as regular files of at most 1 MiB;
879
+ - every file of the generation, as regular files of at most 8 MiB (the
880
+ personal-workspace module's own limits);
881
+ - the private home's own state, any `.git` above it, and a `.git` in its
882
+ `generations` folder;
883
+ - each enrolled root's link status and its Git configuration (its remote and
884
+ its helpers), through a `gitdir:` file and its common directory where `.git`
885
+ is a file;
886
+ - the user's Git configuration (`~/.gitconfig` and the XDG one), through a
887
+ link, and any ambient Git variable;
888
+ - a digest of the graph's facts: nodes, edges, embeds, assets, resolved links
889
+ and every finding.
890
+
891
+ The inputs are read before the composition runs. A key is confirmed only when
892
+ the composition then accepted the inputs and composed a graph with exactly
893
+ those facts, so every graph used is one the composition built too. A single
894
+ change that lands while it runs is either seen by it or leaves the key behind;
895
+ a change and its exact undo during one composition is caught at the next full
896
+ reconciliation. Binding confirms the first key. An authored or generation
897
+ file the key reads is opened without following a link and without waiting on
898
+ it. A FIFO, a device or a link refuses at once, with the composition's code
899
+ (`generation-corrupt`, `malformed-input`). A Git configuration file is read
900
+ through a link, as Git reads it, but never waited on.
901
+
902
+ When a build finds its key unconfirmed, a caller that builds once composes in
903
+ its own thread. The engine, and the proposal adapter it runs, compose in a
904
+ worker, off the event loop, then build again. The adapter builds only when it
905
+ looks at a newly observed edit, as for any project. On a tick whose graph is
906
+ pending (`personal-validation-pending`), it records nothing for the edits it
907
+ reached and reports `observed.deferred`. It offers those edits, and every
908
+ earlier refusal, again next tick, and leaves a due proposal operation as it
909
+ is, without spending one of its attempts. While shared sources change before
910
+ every tick, every tick is pending: the edit is deferred again, with one full
911
+ build per tick, until a tick with no change. A worker that does not answer
912
+ within two minutes is let go of and refuses `personal-composition-unavailable`,
913
+ so the tick does not wait. A worker blocked in a system call (a FIFO opened for
914
+ reading) cannot be stopped until that call returns. Until then it keeps the
915
+ process from exiting, and each such expiry leaves one thread behind: a service
916
+ stopped in that state needs a kill. A graph that still differs refuses
917
+ `personal-graph-unconfirmed`.
918
+ - **A copy is refused.** The settings member names the bound generation. A copy
919
+ of a bound project that lost the binding (a structured clone, a JSON round
920
+ trip) refuses `personal-binding-lost`, and is never built as an ordinary
921
+ project.
922
+ - **Validity.** Composition decides whether the generation may be used, at bind
923
+ time and at every build. Its refusals keep their codes (`stale-generation`,
924
+ `generation-missing`, `generation-corrupt`, `generation-relocated`,
925
+ `retained-removed-reference`, `not-private-location`, `root-symlinked`,
926
+ `ambient-git-environment`, `future-schema`, `ambiguous-binding` and the rest).
927
+ `bindPersonalWorkspace` throws them as `PersonalWorkspaceRefusal`.
928
+ `loadBoundProject` and every build refuse with the same code as a maintenance
929
+ refusal, so the engine and every command report it typed, and no view stays
930
+ current. Nothing is published, and no vault, manifest, journal or private home
931
+ byte is written. A refusal the projection adds (`personal-view-id-reserved`,
932
+ `personal-views-exceed-settings-limit`) is a maintenance refusal from the
933
+ start.
934
+ - **Staleness is noticed at the next tick.** The engine observes the person's
935
+ `atelier.personal.json` and `atelier.overlay.json` and the bound generation's
936
+ `generation.json` as configuration. A change to any of them prepares every
937
+ view again on the next tick, unasked, and a generation that no longer holds
938
+ is refused there. Every full reconciliation composes a bound workspace again,
939
+ in a worker, whatever else it prepares. A cause the key does not name is
940
+ therefore refused within the reconciliation interval (five minutes by
941
+ default). Those causes are:
942
+ - the system Git configuration, and files a Git configuration includes
943
+ (`include.path`, `config.worktree`);
944
+ - an enrolled repository's work tree or top level changing;
945
+ - a change of the authored inputs and its exact undo during one composition;
946
+ - a shared note replaced by a link;
947
+ - an untracked note becoming ignored.
948
+
949
+ The views are prepared again only when that composition refuses or confirms a
950
+ different key: an unchanged workspace is not rebuilt, republished or locked.
951
+ After a refusal the engine
952
+ loads the project again at the next tick, so a loader that binds the next
953
+ generation is followed. The generation's record and the settings member both
954
+ name the generation, so a rebound generation invalidates every view even when
955
+ its configuration file is byte-identical.
956
+ - **Views.** The overlay's saved views become scopes in memory: each is a
957
+ scoped view of the repositories it names, and `everything` is a full view of
958
+ the composed graph. A saved view named `everything` is refused. More than 255
959
+ saved views, or a view of more than 256 repositories, is refused at bind
960
+ (`personal-views-exceed-settings-limit`), within the Obsidian settings
961
+ contract. The preferred view, when it names a saved one, is the default. No
962
+ generation file is written. `view add` refuses `views-from-personal-overlay`;
963
+ `audience set`, `audience clear` and `location set` refuse
964
+ `personal-binding-decision-unavailable`. Each refuses before anything is
965
+ resolved or written.
966
+ - **Preferences and coverage.** `preferences` are returned read only. A theme
967
+ is reported and never written: `appearance.json` stays the person's.
968
+ `coverage` is passed through untouched. No Obsidian code reads it: it states
969
+ what is not enforced, and is never permission.
970
+ - **Workspace identity.** The bound project's folder is the private home, so
971
+ the workspace pointer is `<personal home>/.atelier-local/obsidian.json`. A
972
+ generation is a closed, verified inventory, and an extra file there would
973
+ invalidate it. This is provisional until the per-person projection
974
+ configuration exists.
975
+ - **Edits.** A vault edit to a private note is never applied. Source apply
976
+ refuses it with `personal-overlay-proposals-only`. The proposal adapter does
977
+ not observe, record or propose it either: it answers
978
+ `personal-overlay-not-proposed`. Nothing is written into a generation, and
979
+ the view stays
980
+ `held-for-your-edit` until the edit is undone. Turning such an edit into a
981
+ change of the person's overlay is not built.
982
+ - **Reserved settings key.** The settings member
983
+ `ext["mnstry.atelier.personal-workspace"]` is reserved: the binding writes it
984
+ in memory. A project configuration that declares it itself is refused at
985
+ every build (`personal-binding-lost`, naming the key).
986
+
987
+ Measured once on 2,156 notes in three repositories, with 50 annotations and five
988
+ saved views (six views in all). The production contributions were loaded, as
989
+ the service loads them, so the proposal adapter was registered. The host's load
990
+ average was near 35, slower than an idle one, so read the times as upper
991
+ bounds. "Main-thread compositions" counts the Git probe a composition makes on
992
+ the event loop's thread.
993
+
994
+ | Step | Wall time | Longest event-loop block | Main-thread compositions |
995
+ | --- | --- | --- | --- |
996
+ | Load, composed in a worker (`loadBoundProjectOffThread`) | 3.8 s | 0.03 s | none |
997
+ | Load in the calling thread (`loadBoundProject`) | 3.5 s | 3.5 s | one |
998
+ | One build without a file cache (a caller that builds once) | 1.4 s | 1.3 s | none |
999
+ | First tick: load, build, and first publication of six vaults | 582 s | 574 s | none |
1000
+ | Tick with every view prepared again | 4.5 s | 4.5 s | none |
1001
+ | Idle tick | 0.25 s | 0.23 s | none |
1002
+ | Tick with a vault edit and a graph change: the adapter defers, the engine confirms in a worker | 12.4 s | 2.8 s | none |
1003
+ | Next tick: the adapter observes that edit (one build) | 2.1 s | 2.0 s | none |
1004
+ | Full-reconciliation tick, the edit still open | 5.0 s | 1.0 s | none |
1005
+
1006
+ **What is met.** No composition runs on the engine's event loop, the proposal
1007
+ adapter's included. The load, a confirmation after a change, and the
1008
+ composition at every full reconciliation run in a worker; the tick does not
1009
+ wait on one that misses its deadline. An unchanged workspace is not prepared
1010
+ again. While an edit stays open and shared sources are quiet, the adapter
1011
+ builds nothing more; under continuous change it builds once per tick until a
1012
+ quiet tick.
1013
+
1014
+ **What remains before a service or `open` binds a personal workspace of this
1015
+ size.** The first publication blocks the event loop far longer than the
1016
+ service's five-second health probe: about ten minutes here. That is the
1017
+ publication path every project takes, not this route: an ordinary project of
1018
+ 450 notes, measured the same way, blocked as long as a bound one. Preparing six
1019
+ views again blocked 4.5 s, under the probe. The proposal adapter's build of a
1020
+ newly observed edit, without the engine's file cache, blocked 2.0 s, at a
1021
+ two-second target, as for an ordinary project. A service binding needs the
1022
+ first publication to yield to the event loop (or run off it), or a corpus small
1023
+ enough to stay within the probe.
1024
+
503
1025
  ## Known limits
504
1026
 
505
1027
  These are the limits known at this release. None is hidden behind a skipped
@@ -554,6 +1076,35 @@ test reported as a pass.
554
1076
  own launch `open` waits, bounded, while the app is still opening the vault;
555
1077
  an app whose vault window is still loading answers a command with `Error:
556
1078
  Command "…" not found`, which is read as not up yet, never as a version.
1079
+ - Vault location: consent to a folder a sync client keeps in step
1080
+ (`--allow-synced-location`) is given when `location set` decides the folder,
1081
+ and is not recorded, so the maintenance service does not check for sync
1082
+ clients again. The decision keeps the folder as it was written, so at a
1083
+ view's first allocation a folder on the way that has since become a link
1084
+ into a synced folder is followed, and its vault is allocated there without
1085
+ being asked; a folder that becomes synced without any link (iCloud's
1086
+ "Desktop & Documents Folders" turned on, say) is not refused either, at the
1087
+ first allocation or when a vault is made again. Every other check runs
1088
+ again at both, and a vault made again, or published into, through a link on
1089
+ the way is refused (`vault-allocation-moved`).
1090
+ - Replacing a vault during a publication: the allocated folder is checked
1091
+ before the vault lock is taken and again once its folder is made, after the
1092
+ app is asked about the vault, before each note and before the generation is
1093
+ committed. A program of the same account that puts a link in its place
1094
+ between one check and what follows it can still have that go through the
1095
+ link: one note's writes (the folders on its way and the note), or the vault
1096
+ lock's folder (made there, or made private if it was there already) and, in
1097
+ a folder that already holds one (another Atelier vault), a lock ticket and
1098
+ its release flag. For a note replaced or removed while the app holds the
1099
+ vault, the app is asked about that note between the check and the write, so
1100
+ that window lasts a round trip to the app. The next check refuses the
1101
+ publication, and it is never reported current.
1102
+ - Vault identity: an allocated folder is known by its real path, device and
1103
+ inode. On Linux a folder made at the same path after the allocated one was
1104
+ removed can be given the same inode number (ext4 reuses a freed one), and is
1105
+ then taken for the one made; macOS (APFS) did not reuse one in 200 tries.
1106
+ Such a folder is published into only at the recorded real path, and the
1107
+ plugin's bearer only when this account owns it.
557
1108
  - Obsidian's settings file: `open` adds a view's vault to the app's own list,
558
1109
  `obsidian.json` in its user-data directory: `~/Library/Application
559
1110
  Support/obsidian` on macOS and `$XDG_CONFIG_HOME/obsidian` (else
@@ -646,6 +1197,17 @@ test reported as a pass.
646
1197
  in Obsidian's settings or runs
647
1198
  `atelier obsidian plugin on --scope ID`. Plugin files are never removed from
648
1199
  a vault. See [obsidian-plugin.md](obsidian-plugin.md).
1200
+ - Login items: the tests run the launchd and systemd managers' own code
1201
+ against stand-ins that answer as launchctl and systemctl do, and never
1202
+ against a real session. What `launchctl print-disabled` says for an item
1203
+ switched off in System Settings, and the exit statuses read from
1204
+ `launchctl` and `systemctl`, are the documented ones and are not yet
1205
+ confirmed on a host. A unit whose program cannot be loaded at all (the
1206
+ project's package was removed) is restarted by its manager once a minute,
1207
+ and each attempt adds a few lines to `state/service/login-item.log`, which
1208
+ nothing bounds: `service unit --remove` or `uninstall` ends it. An upgrade
1209
+ in the moment between a service's start and the first reading of its release
1210
+ is not noticed until the next change.
649
1211
  - Acceptance: a schema-valid receipt closes no gate, the package proof closes
650
1212
  no gate, and no adopter acceptance is recorded in this repository.
651
1213