daftari 1.29.0 → 1.31.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (369) hide show
  1. package/CHANGELOG.md +281 -0
  2. package/README.md +263 -9
  3. package/dist/access/rbac.d.ts +1 -0
  4. package/dist/access/rbac.d.ts.map +1 -1
  5. package/dist/access/rbac.js +7 -0
  6. package/dist/access/rbac.js.map +1 -1
  7. package/dist/asof/git-read.d.ts +17 -0
  8. package/dist/asof/git-read.d.ts.map +1 -0
  9. package/dist/asof/git-read.js +163 -0
  10. package/dist/asof/git-read.js.map +1 -0
  11. package/dist/asof/index.d.ts +2 -0
  12. package/dist/asof/index.d.ts.map +1 -0
  13. package/dist/asof/index.js +151 -0
  14. package/dist/asof/index.js.map +1 -0
  15. package/dist/asof/report.d.ts +11 -0
  16. package/dist/asof/report.d.ts.map +1 -0
  17. package/dist/asof/report.js +119 -0
  18. package/dist/asof/report.js.map +1 -0
  19. package/dist/asof/snapshot.d.ts +72 -0
  20. package/dist/asof/snapshot.d.ts.map +1 -0
  21. package/dist/asof/snapshot.js +207 -0
  22. package/dist/asof/snapshot.js.map +1 -0
  23. package/dist/audit/checks/broken_refs.d.ts +1 -1
  24. package/dist/audit/checks/broken_refs.d.ts.map +1 -1
  25. package/dist/audit/checks/broken_refs.js +77 -22
  26. package/dist/audit/checks/broken_refs.js.map +1 -1
  27. package/dist/audit/collect.d.ts +1 -0
  28. package/dist/audit/collect.d.ts.map +1 -1
  29. package/dist/audit/collect.js +22 -2
  30. package/dist/audit/collect.js.map +1 -1
  31. package/dist/audit/index.d.ts.map +1 -1
  32. package/dist/audit/index.js +9 -3
  33. package/dist/audit/index.js.map +1 -1
  34. package/dist/audit/links.d.ts.map +1 -1
  35. package/dist/audit/links.js +9 -3
  36. package/dist/audit/links.js.map +1 -1
  37. package/dist/audit/report.d.ts.map +1 -1
  38. package/dist/audit/report.js +2 -0
  39. package/dist/audit/report.js.map +1 -1
  40. package/dist/audit/types.d.ts +4 -1
  41. package/dist/audit/types.d.ts.map +1 -1
  42. package/dist/audit/types.js.map +1 -1
  43. package/dist/backfill/apply.js +2 -2
  44. package/dist/backfill/apply.js.map +1 -1
  45. package/dist/backfill/derive.d.ts.map +1 -1
  46. package/dist/backfill/derive.js +1 -0
  47. package/dist/backfill/derive.js.map +1 -1
  48. package/dist/backfill/plan.js +2 -2
  49. package/dist/backfill/plan.js.map +1 -1
  50. package/dist/cli.d.ts.map +1 -1
  51. package/dist/cli.js +36 -0
  52. package/dist/cli.js.map +1 -1
  53. package/dist/consolidate/call-budget.d.ts +3 -0
  54. package/dist/consolidate/call-budget.d.ts.map +1 -0
  55. package/dist/consolidate/call-budget.js +37 -0
  56. package/dist/consolidate/call-budget.js.map +1 -0
  57. package/dist/consolidate/constants.d.ts +1 -0
  58. package/dist/consolidate/constants.d.ts.map +1 -1
  59. package/dist/consolidate/constants.js +5 -0
  60. package/dist/consolidate/constants.js.map +1 -1
  61. package/dist/consolidate/index.d.ts.map +1 -1
  62. package/dist/consolidate/index.js +96 -27
  63. package/dist/consolidate/index.js.map +1 -1
  64. package/dist/court/docket.d.ts +39 -0
  65. package/dist/court/docket.d.ts.map +1 -0
  66. package/dist/court/docket.js +103 -0
  67. package/dist/court/docket.js.map +1 -0
  68. package/dist/court/index.d.ts +2 -0
  69. package/dist/court/index.d.ts.map +1 -0
  70. package/dist/court/index.js +169 -0
  71. package/dist/court/index.js.map +1 -0
  72. package/dist/court/precedent.d.ts +18 -0
  73. package/dist/court/precedent.d.ts.map +1 -0
  74. package/dist/court/precedent.js +89 -0
  75. package/dist/court/precedent.js.map +1 -0
  76. package/dist/court/report.d.ts +10 -0
  77. package/dist/court/report.d.ts.map +1 -0
  78. package/dist/court/report.js +77 -0
  79. package/dist/court/report.js.map +1 -0
  80. package/dist/curation/consumes.d.ts +24 -0
  81. package/dist/curation/consumes.d.ts.map +1 -0
  82. package/dist/curation/consumes.js +122 -0
  83. package/dist/curation/consumes.js.map +1 -0
  84. package/dist/curation/edge-staleness.d.ts +47 -0
  85. package/dist/curation/edge-staleness.d.ts.map +1 -0
  86. package/dist/curation/edge-staleness.js +258 -0
  87. package/dist/curation/edge-staleness.js.map +1 -0
  88. package/dist/curation/edges.d.ts.map +1 -1
  89. package/dist/curation/edges.js +164 -10
  90. package/dist/curation/edges.js.map +1 -1
  91. package/dist/curation/lint.d.ts +4 -1
  92. package/dist/curation/lint.d.ts.map +1 -1
  93. package/dist/curation/lint.js +61 -6
  94. package/dist/curation/lint.js.map +1 -1
  95. package/dist/curation/provenance.d.ts +2 -0
  96. package/dist/curation/provenance.d.ts.map +1 -1
  97. package/dist/curation/provenance.js +2 -0
  98. package/dist/curation/provenance.js.map +1 -1
  99. package/dist/curation/read-log.d.ts +19 -0
  100. package/dist/curation/read-log.d.ts.map +1 -0
  101. package/dist/curation/read-log.js +120 -0
  102. package/dist/curation/read-log.js.map +1 -0
  103. package/dist/curation/review-throughput.d.ts +24 -0
  104. package/dist/curation/review-throughput.d.ts.map +1 -0
  105. package/dist/curation/review-throughput.js +102 -0
  106. package/dist/curation/review-throughput.js.map +1 -0
  107. package/dist/curation/staged-actions.d.ts +11 -1
  108. package/dist/curation/staged-actions.d.ts.map +1 -1
  109. package/dist/curation/staged-actions.js +117 -30
  110. package/dist/curation/staged-actions.js.map +1 -1
  111. package/dist/curation/staleness.js +1 -1
  112. package/dist/curation/staleness.js.map +1 -1
  113. package/dist/curation/structural.d.ts +16 -0
  114. package/dist/curation/structural.d.ts.map +1 -0
  115. package/dist/curation/structural.js +64 -0
  116. package/dist/curation/structural.js.map +1 -0
  117. package/dist/curation/tension-access.d.ts +7 -0
  118. package/dist/curation/tension-access.d.ts.map +1 -0
  119. package/dist/curation/tension-access.js +44 -0
  120. package/dist/curation/tension-access.js.map +1 -0
  121. package/dist/curation/tension-blast.d.ts +6 -1
  122. package/dist/curation/tension-blast.d.ts.map +1 -1
  123. package/dist/curation/tension-blast.js +11 -2
  124. package/dist/curation/tension-blast.js.map +1 -1
  125. package/dist/curation/tension-clusters.d.ts +1 -1
  126. package/dist/curation/tension-clusters.d.ts.map +1 -1
  127. package/dist/curation/tension-clusters.js +5 -2
  128. package/dist/curation/tension-clusters.js.map +1 -1
  129. package/dist/curation/tension.d.ts +6 -2
  130. package/dist/curation/tension.d.ts.map +1 -1
  131. package/dist/curation/tension.js +86 -35
  132. package/dist/curation/tension.js.map +1 -1
  133. package/dist/curation/tier0.d.ts +27 -0
  134. package/dist/curation/tier0.d.ts.map +1 -0
  135. package/dist/curation/tier0.js +196 -0
  136. package/dist/curation/tier0.js.map +1 -0
  137. package/dist/curation/tier1.d.ts +30 -0
  138. package/dist/curation/tier1.d.ts.map +1 -0
  139. package/dist/curation/tier1.js +142 -0
  140. package/dist/curation/tier1.js.map +1 -0
  141. package/dist/curation/tier2.d.ts +43 -0
  142. package/dist/curation/tier2.d.ts.map +1 -0
  143. package/dist/curation/tier2.js +182 -0
  144. package/dist/curation/tier2.js.map +1 -0
  145. package/dist/curation/vault-docs.d.ts +5 -1
  146. package/dist/curation/vault-docs.d.ts.map +1 -1
  147. package/dist/curation/vault-docs.js +15 -1
  148. package/dist/curation/vault-docs.js.map +1 -1
  149. package/dist/eval/generate.js +22 -5
  150. package/dist/eval/generate.js.map +1 -1
  151. package/dist/eval/index.d.ts.map +1 -1
  152. package/dist/eval/index.js +173 -25
  153. package/dist/eval/index.js.map +1 -1
  154. package/dist/eval/llm-openrouter.d.ts +9 -0
  155. package/dist/eval/llm-openrouter.d.ts.map +1 -0
  156. package/dist/eval/llm-openrouter.js +171 -0
  157. package/dist/eval/llm-openrouter.js.map +1 -0
  158. package/dist/eval/llm.js +1 -1
  159. package/dist/eval/llm.js.map +1 -1
  160. package/dist/eval/prune.d.ts +24 -0
  161. package/dist/eval/prune.d.ts.map +1 -0
  162. package/dist/eval/prune.js +83 -0
  163. package/dist/eval/prune.js.map +1 -0
  164. package/dist/eval/storage.d.ts +3 -0
  165. package/dist/eval/storage.d.ts.map +1 -1
  166. package/dist/eval/storage.js +14 -0
  167. package/dist/eval/storage.js.map +1 -1
  168. package/dist/frontmatter/parser.d.ts +1 -0
  169. package/dist/frontmatter/parser.d.ts.map +1 -1
  170. package/dist/frontmatter/parser.js +12 -0
  171. package/dist/frontmatter/parser.js.map +1 -1
  172. package/dist/frontmatter/schema.d.ts.map +1 -1
  173. package/dist/frontmatter/schema.js +38 -3
  174. package/dist/frontmatter/schema.js.map +1 -1
  175. package/dist/frontmatter/types.d.ts +4 -1
  176. package/dist/frontmatter/types.d.ts.map +1 -1
  177. package/dist/frontmatter/types.js +8 -0
  178. package/dist/frontmatter/types.js.map +1 -1
  179. package/dist/import/index.d.ts.map +1 -1
  180. package/dist/import/index.js +44 -9
  181. package/dist/import/index.js.map +1 -1
  182. package/dist/import/langgraph-store.d.ts +53 -0
  183. package/dist/import/langgraph-store.d.ts.map +1 -0
  184. package/dist/import/langgraph-store.js +292 -0
  185. package/dist/import/langgraph-store.js.map +1 -0
  186. package/dist/index.d.ts +5 -0
  187. package/dist/index.d.ts.map +1 -1
  188. package/dist/index.js +56 -18
  189. package/dist/index.js.map +1 -1
  190. package/dist/lifecycle/lock.d.ts +9 -1
  191. package/dist/lifecycle/lock.d.ts.map +1 -1
  192. package/dist/lifecycle/lock.js +34 -9
  193. package/dist/lifecycle/lock.js.map +1 -1
  194. package/dist/okf/export.d.ts +12 -0
  195. package/dist/okf/export.d.ts.map +1 -0
  196. package/dist/okf/export.js +115 -0
  197. package/dist/okf/export.js.map +1 -0
  198. package/dist/okf/import.d.ts +24 -0
  199. package/dist/okf/import.d.ts.map +1 -0
  200. package/dist/okf/import.js +107 -0
  201. package/dist/okf/import.js.map +1 -0
  202. package/dist/okf/index.d.ts +2 -0
  203. package/dist/okf/index.d.ts.map +1 -0
  204. package/dist/okf/index.js +147 -0
  205. package/dist/okf/index.js.map +1 -0
  206. package/dist/okf/map.d.ts +16 -0
  207. package/dist/okf/map.d.ts.map +1 -0
  208. package/dist/okf/map.js +149 -0
  209. package/dist/okf/map.js.map +1 -0
  210. package/dist/okf/types.d.ts +9 -0
  211. package/dist/okf/types.d.ts.map +1 -0
  212. package/dist/okf/types.js +48 -0
  213. package/dist/okf/types.js.map +1 -0
  214. package/dist/search/contested.d.ts +18 -0
  215. package/dist/search/contested.d.ts.map +1 -0
  216. package/dist/search/contested.js +119 -0
  217. package/dist/search/contested.js.map +1 -0
  218. package/dist/search/coverage.d.ts.map +1 -1
  219. package/dist/search/coverage.js +1 -1
  220. package/dist/search/coverage.js.map +1 -1
  221. package/dist/search/hybrid.d.ts +23 -0
  222. package/dist/search/hybrid.d.ts.map +1 -1
  223. package/dist/search/hybrid.js +75 -15
  224. package/dist/search/hybrid.js.map +1 -1
  225. package/dist/search/reindex.d.ts +1 -0
  226. package/dist/search/reindex.d.ts.map +1 -1
  227. package/dist/search/reindex.js +57 -24
  228. package/dist/search/reindex.js.map +1 -1
  229. package/dist/search/watcher.d.ts +2 -0
  230. package/dist/search/watcher.d.ts.map +1 -1
  231. package/dist/search/watcher.js +23 -12
  232. package/dist/search/watcher.js.map +1 -1
  233. package/dist/serve/index.d.ts +36 -0
  234. package/dist/serve/index.d.ts.map +1 -0
  235. package/dist/serve/index.js +507 -0
  236. package/dist/serve/index.js.map +1 -0
  237. package/dist/server.d.ts +10 -1
  238. package/dist/server.d.ts.map +1 -1
  239. package/dist/server.js +91 -12
  240. package/dist/server.js.map +1 -1
  241. package/dist/sleep/cycle.d.ts +59 -0
  242. package/dist/sleep/cycle.d.ts.map +1 -0
  243. package/dist/sleep/cycle.js +127 -0
  244. package/dist/sleep/cycle.js.map +1 -0
  245. package/dist/sleep/index.d.ts +5 -0
  246. package/dist/sleep/index.d.ts.map +1 -0
  247. package/dist/sleep/index.js +320 -0
  248. package/dist/sleep/index.js.map +1 -0
  249. package/dist/sleep/report.d.ts +14 -0
  250. package/dist/sleep/report.d.ts.map +1 -0
  251. package/dist/sleep/report.js +139 -0
  252. package/dist/sleep/report.js.map +1 -0
  253. package/dist/sleep/tension-scan-state.d.ts +19 -0
  254. package/dist/sleep/tension-scan-state.d.ts.map +1 -0
  255. package/dist/sleep/tension-scan-state.js +0 -0
  256. package/dist/sleep/tension-scan-state.js.map +1 -0
  257. package/dist/sleep/tension-scan.d.ts +44 -0
  258. package/dist/sleep/tension-scan.d.ts.map +1 -0
  259. package/dist/sleep/tension-scan.js +0 -0
  260. package/dist/sleep/tension-scan.js.map +1 -0
  261. package/dist/storage/backend.d.ts +12 -0
  262. package/dist/storage/backend.d.ts.map +1 -0
  263. package/dist/storage/backend.js +231 -0
  264. package/dist/storage/backend.js.map +1 -0
  265. package/dist/storage/backends/fs.d.ts +4 -0
  266. package/dist/storage/backends/fs.d.ts.map +1 -0
  267. package/dist/storage/backends/fs.js +99 -0
  268. package/dist/storage/backends/fs.js.map +1 -0
  269. package/dist/storage/fs-walk.d.ts +5 -0
  270. package/dist/storage/fs-walk.d.ts.map +1 -0
  271. package/dist/storage/fs-walk.js +28 -0
  272. package/dist/storage/fs-walk.js.map +1 -0
  273. package/dist/storage/index-db.d.ts +18 -0
  274. package/dist/storage/index-db.d.ts.map +1 -1
  275. package/dist/storage/index-db.js +159 -22
  276. package/dist/storage/index-db.js.map +1 -1
  277. package/dist/storage/local.d.ts +7 -1
  278. package/dist/storage/local.d.ts.map +1 -1
  279. package/dist/storage/local.js +42 -4
  280. package/dist/storage/local.js.map +1 -1
  281. package/dist/storage/sync.d.ts +25 -0
  282. package/dist/storage/sync.d.ts.map +1 -0
  283. package/dist/storage/sync.js +308 -0
  284. package/dist/storage/sync.js.map +1 -0
  285. package/dist/sync/index.d.ts +2 -0
  286. package/dist/sync/index.d.ts.map +1 -0
  287. package/dist/sync/index.js +136 -0
  288. package/dist/sync/index.js.map +1 -0
  289. package/dist/themes/clustering.d.ts +6 -11
  290. package/dist/themes/clustering.d.ts.map +1 -1
  291. package/dist/themes/clustering.js +76 -84
  292. package/dist/themes/clustering.js.map +1 -1
  293. package/dist/tools/consumes.d.ts +14 -0
  294. package/dist/tools/consumes.d.ts.map +1 -0
  295. package/dist/tools/consumes.js +99 -0
  296. package/dist/tools/consumes.js.map +1 -0
  297. package/dist/tools/curation.d.ts +2 -0
  298. package/dist/tools/curation.d.ts.map +1 -1
  299. package/dist/tools/curation.js +102 -7
  300. package/dist/tools/curation.js.map +1 -1
  301. package/dist/tools/edge-staleness.d.ts +28 -0
  302. package/dist/tools/edge-staleness.d.ts.map +1 -0
  303. package/dist/tools/edge-staleness.js +205 -0
  304. package/dist/tools/edge-staleness.js.map +1 -0
  305. package/dist/tools/edges.d.ts.map +1 -1
  306. package/dist/tools/edges.js +28 -22
  307. package/dist/tools/edges.js.map +1 -1
  308. package/dist/tools/read.d.ts +15 -1
  309. package/dist/tools/read.d.ts.map +1 -1
  310. package/dist/tools/read.js +144 -31
  311. package/dist/tools/read.js.map +1 -1
  312. package/dist/tools/receipt.d.ts +65 -0
  313. package/dist/tools/receipt.d.ts.map +1 -0
  314. package/dist/tools/receipt.js +257 -0
  315. package/dist/tools/receipt.js.map +1 -0
  316. package/dist/tools/search.d.ts +1 -0
  317. package/dist/tools/search.d.ts.map +1 -1
  318. package/dist/tools/search.js +186 -12
  319. package/dist/tools/search.js.map +1 -1
  320. package/dist/tools/staged-actions.d.ts +3 -0
  321. package/dist/tools/staged-actions.d.ts.map +1 -1
  322. package/dist/tools/staged-actions.js +228 -23
  323. package/dist/tools/staged-actions.js.map +1 -1
  324. package/dist/tools/themes.d.ts +9 -0
  325. package/dist/tools/themes.d.ts.map +1 -1
  326. package/dist/tools/themes.js +333 -133
  327. package/dist/tools/themes.js.map +1 -1
  328. package/dist/tools/tier1.d.ts +14 -0
  329. package/dist/tools/tier1.d.ts.map +1 -0
  330. package/dist/tools/tier1.js +169 -0
  331. package/dist/tools/tier1.js.map +1 -0
  332. package/dist/tools/tier2.d.ts +27 -0
  333. package/dist/tools/tier2.d.ts.map +1 -0
  334. package/dist/tools/tier2.js +344 -0
  335. package/dist/tools/tier2.js.map +1 -0
  336. package/dist/tools/witness.d.ts +9 -0
  337. package/dist/tools/witness.d.ts.map +1 -0
  338. package/dist/tools/witness.js +66 -0
  339. package/dist/tools/witness.js.map +1 -0
  340. package/dist/tools/write.d.ts +9 -1
  341. package/dist/tools/write.d.ts.map +1 -1
  342. package/dist/tools/write.js +593 -59
  343. package/dist/tools/write.js.map +1 -1
  344. package/dist/utils/config.d.ts +54 -0
  345. package/dist/utils/config.d.ts.map +1 -1
  346. package/dist/utils/config.js +420 -4
  347. package/dist/utils/config.js.map +1 -1
  348. package/dist/utils/paths.d.ts +2 -0
  349. package/dist/utils/paths.d.ts.map +1 -0
  350. package/dist/utils/paths.js +15 -0
  351. package/dist/utils/paths.js.map +1 -0
  352. package/dist/utils/redos.d.ts +2 -0
  353. package/dist/utils/redos.d.ts.map +1 -0
  354. package/dist/utils/redos.js +101 -0
  355. package/dist/utils/redos.js.map +1 -0
  356. package/dist/utils/run-id.d.ts +3 -0
  357. package/dist/utils/run-id.d.ts.map +1 -0
  358. package/dist/utils/run-id.js +19 -0
  359. package/dist/utils/run-id.js.map +1 -0
  360. package/dist/utils/vault-gitignore.d.ts +1 -1
  361. package/dist/utils/vault-gitignore.d.ts.map +1 -1
  362. package/dist/utils/vault-gitignore.js +6 -1
  363. package/dist/utils/vault-gitignore.js.map +1 -1
  364. package/dist/witness/track-record.d.ts +42 -0
  365. package/dist/witness/track-record.d.ts.map +1 -0
  366. package/dist/witness/track-record.js +189 -0
  367. package/dist/witness/track-record.js.map +1 -0
  368. package/package.json +27 -2
  369. package/templates/config.yaml +8 -0
package/CHANGELOG.md CHANGED
@@ -7,6 +7,286 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [1.31.0] - 2026-07-22
11
+
12
+ The self-hosted deployment release: one always-on `daftari serve` instance
13
+ over Streamable HTTP with per-session identity (static tokens and/or OAuth
14
+ 2.1), plus durable object-storage backing (S3/Azure/GCS-interop) behind the
15
+ canonical local git working copy. Design record:
16
+ `docs/superpowers/specs/2026-07-20-self-hosted-server-mode-design.md`.
17
+
18
+ ### Added
19
+
20
+ - **`daftari serve` — server mode over Streamable HTTP (#5).** One always-on
21
+ instance, many MCP clients, per-session RBAC identity resolved at session
22
+ open (zero tool changes — every existence-disclosure invariant applies per
23
+ connection). Static bearer tokens declared in config with values in env
24
+ vars. Fail-loud posture throughout: a non-loopback bind refuses without
25
+ auth AND an explicit `server.transport_security: external` declaration
26
+ (daftari never terminates TLS); with auth configured a bad credential is a
27
+ 401 at session open, never a guest downgrade; loopback binds carry a
28
+ DNS-rebinding guard (Host/Origin validated before routing). The process
29
+ lock learns modes: a stray stdio invocation refuses against a live server,
30
+ a new serve refuses against any live holder, and deliberate replacement is
31
+ `daftari serve --takeover` (stdio-vs-stdio keeps its classic takeover;
32
+ stale locks are still overwritten silently).
33
+ - **OAuth 2.1 resource-server auth for serve (#7).** Bearer JWTs verified
34
+ against your IdP's JWKS (issuer + audience + signature + expiry via
35
+ `jose`), with the subject claim mapped through a config-declared subjects
36
+ table. A valid token with an unmapped subject is 403 — authenticated, not
37
+ authorized — never a guest, never a default role. Composes with static
38
+ tokens (agents on tokens, humans through the IdP). Hardened: https-only
39
+ issuer/JWKS URLs (loopback http for test IdPs only), constant-time static
40
+ token matching, `Object.prototype`-collision-proof subject lookup.
41
+ - **Pluggable storage backends as sync targets (#6).** The local git working
42
+ copy stays canonical; a backend is a dumb `get/put/list/delete` target.
43
+ Backends: `fs` (local/mounted directory), `s3` (S3, MinIO, R2, GCS via its
44
+ S3-interop endpoint), `azure` (Blob/ADLS Gen2) — cloud SDKs are optional
45
+ peer dependencies loaded on demand, credentials come only from the SDKs'
46
+ environment chains, custom endpoints must be https. `daftari sync` pushes
47
+ incrementally against a remote hash manifest (tree + `.git` + durable
48
+ `.daftari` journals; the rebuildable index/locks never sync) and
49
+ `daftari sync --restore` rebuilds a vault into an empty directory with
50
+ per-object hash verification and a reindex. `daftari serve` can push on a
51
+ cadence (`storage.sync_interval_minutes`). Security posture: `.git/config`
52
+ and `.git/hooks` are never synced or restored (git executes what they
53
+ declare — a backup channel must not deliver code), and restore re-enforces
54
+ every exclusion against the untrusted manifest.
55
+ - **Agent-as-judge rerank pool on `vault_search` (#3).** Opt-in
56
+ `rerank_candidates`: the server prepares the fused candidate pool and the
57
+ protocol; the calling agent is the judge.
58
+ - **Per-document theme distributions (#58).** True multi-theme membership via
59
+ chunk-level clustering.
60
+ - **Configurable tool-exposure tiers (#103, #104).** `tools.tier`
61
+ (`core`/`standard`/`full`) plus `include`/`exclude` lists in config.
62
+ - **Resumable reindex (#54).** Per-batch embedding commits so an interrupted
63
+ reindex resumes instead of restarting.
64
+ - **`daftari eval prune` (#100)** — `results/` and `scores/` housekeeping —
65
+ and eval v1 polish (#102): honest exit codes, skipped-run reporting, resume
66
+ validation, tier-aware triviality, intra-call dedupe, `--max-nodes`.
67
+ - **Advisory domain-boundary enforcement (#4)** and inline structural decay
68
+ checks (orphans, deprecated-still-linked) in the curation engine.
69
+ - **Advisory supersede nudge** when overwriting an existing doc, and a YAML
70
+ config error hint for comment lines that lost their `#`.
71
+ - **`daftari okf export|import` — Open Knowledge Format bridge.** OKF is Google
72
+ Cloud's vendor-neutral spec (v0.1) for the LLM-wiki pattern — a directory of
73
+ markdown files with YAML frontmatter — which is exactly Daftari's storage
74
+ model. `okf export` renders a vault as a portable OKF bundle: each doc becomes
75
+ an OKF concept doc carrying the core `type` / `title` / `description` /
76
+ `resource` / `tags` / `timestamp` fields plus a verbatim `daftari` sidecar for
77
+ lossless round-trip, alongside generated `index.md` and `log.md` reserved
78
+ files; the source vault is never mutated. `okf import` adopts an OKF bundle
79
+ into a vault — a bundle from `okf export` round-trips exactly via its sidecar,
80
+ while a foreign bundle is mapped conservatively (docs land as `draft` in the
81
+ `accumulation` domain, the source OKF `type` preserved in `okf_type`); writes
82
+ auto-commit and the index is rebuilt. `--dry-run` previews the import plan.
83
+
84
+ - **The compilation pipeline (#232–#236, #141, #217).** Edge provenance
85
+ classes with type-directed change dispatch (tier 1), structure-first tier-0
86
+ lint checks with a ratify gate, a semantic-review queue with typed verdicts
87
+ (tier 2), the compiled `consumes` dependency graph (run-correlated reads ×
88
+ writes, #233), edge staleness classes and the broken-read rate (#234),
89
+ proposal deltas (write action type, `run_id` provenance, inter-proposal
90
+ tension, a propose-only role, #235), write-protection tiers
91
+ (source/compiled/manual with a demote-then-write escape hatch, #141), a
92
+ review-throughput lint aggregate, and edge-graph existence disclosure
93
+ (blast B′, edges/lint omission) extending the 2026-07-14 RBAC spec (#217).
94
+ - **`sleep` tension-scan dream-type (#228)** closing the day-0 detection gap,
95
+ a langgraph-store adapter with the dedup-is-not-epistemics demo (#227),
96
+ the daftari.dev landing page (#226), and MCP Registry metadata (#222).
97
+ - **Dev maturity (#238–#242):** e2e gate on the built server, tag-driven npm
98
+ release via OIDC trusted publishing, automated code + security review on
99
+ PRs, an `@claude` mention responder, and a nightly maintenance loop.
100
+
101
+ ### Fixed
102
+
103
+ - Canonical-path tension/provenance gates in `vault_status`, `vault_receipt`,
104
+ and precedent lookups (#216), and tier-1 anchors that are unreadable leak
105
+ neither provenance metadata nor existence (#252).
106
+ - `daftari audit` no longer flags on-disk assets and unaudited siblings as
107
+ missing (#255); eval exit codes and resume validation honesty (#102).
108
+
109
+ ### Performance
110
+
111
+ - SQL-authoritative edge reads with write-through and stat-marker self-heal
112
+ (#236), FTS5 `snippet()` for lexical excerpts on the chunk path, and the
113
+ file watcher filters non-markdown events at watch time (#107).
114
+
115
+ ## [1.30.0] - 2026-07-13
116
+
117
+ ### Added
118
+
119
+ - **`vault_receipt` — the epistemic receipt.** A new read-only MCP tool that
120
+ compiles, for the set of documents an answer cites, a single attachable
121
+ artifact: per-source status / confidence / provenance / freshness (decay),
122
+ the exact content-version hash, a filesystem-walked resolution of the
123
+ supersession chain (`resolved` / `restricted` / `dangling` / `cycle`), and
124
+ every unresolved tension touching the source — plus a deterministic summary
125
+ (`byStatus`, `openTensions`, oldest/newest `updated`, sorted
126
+ machine-readable flags such as `cites-stale`, `cites-contested`,
127
+ `cites-superseded`, `supersession-unresolved`; empty flags mean current,
128
+ grounded, and uncontested), the vault's git HEAD as an as-of anchor, and a
129
+ recomputable SHA-256 over the whole receipt. Discipline: the receipt only
130
+ reads (frontmatter, tension log, git); flags are deterministic derivations;
131
+ the optional caller-supplied `claim` rides verbatim and is never
132
+ interpolated into Daftari-authored text. RBAC mirrors the read path: a
133
+ receipt over an unreadable collection is denied, an unreadable supersession
134
+ hop degrades to `restricted`, and a tension is visible only when both
135
+ sources' collections are readable (the `vault_status` precedent). README
136
+ tool list updated to the full 26-tool surface (the "14 tools" count
137
+ predated the edge / staged-action / tension-graph tools).
138
+
139
+ - **`daftari asof` — belief archaeology.** A read-only CLI report over the
140
+ vault's git history: `daftari asof <ref-or-date>` resolves a git ref or a
141
+ `YYYY-MM-DD` date (the last commit on or before that day) and reports the
142
+ vault's belief state at that point plus the drift since — documents
143
+ added/removed, `status`/`confidence` transitions, body-change counts, and
144
+ tensions opened or resolved (the committed `.daftari/tensions.md` is parsed
145
+ at both points with the live parser via the newly exported
146
+ `parseTensionLog`). `--doc <path>` adds a single-document trajectory
147
+ (frontmatter then vs now, every commit touching it since); `--blast <path>`
148
+ adds a **counterfactual replay** — the blast radius of the document
149
+ computed over the tree *as of the commit* (reusing `computeBlast` and the
150
+ reverse source/link maps from `vault_tension_blast`), each downstream
151
+ document annotated with its status today ("this fact turned out wrong — who
152
+ had inherited it, and where are they now?"). Strictly read-only plumbing:
153
+ `git ls-tree` + one `git cat-file --batch` process for the whole historical
154
+ tree — no checkout, no worktree, no index, no API key. Historical trees are
155
+ filtered with the live loader's exclusion rules (dotfiles, `.daftari/`,
156
+ `node_modules`, `.obsidian/`, `.trash/`) so then/now diffs can't report
157
+ phantom drift. Markdown to stdout, `--output` / `--output-json` to files;
158
+ audit-convention exit codes (0 report, 2 config/usage, 3 runtime). Pairs
159
+ with `vault_receipt`: a receipt's `vaultHead` is the anchor to hand back to
160
+ `asof`.
161
+
162
+ - **`daftari court` — the Tension Court.** Common-law memory over the
163
+ tension log. `daftari court` compiles a **docket**: every open tension
164
+ briefed and ranked by priority (aging tier stale→fresh, then blast size,
165
+ then age) — both sides' claims verbatim with the present status and decay
166
+ of their documents ("gone" when a side was deleted), the union blast
167
+ radius a ruling would settle (reusing `computeBlast` and the
168
+ reverse-source/link maps from `vault_tension_blast`), tension-cluster
169
+ membership, and **precedents**: past rulings retrieved by a deterministic
170
+ three-tier match (shared-document > collection-pair > same-kind; newest
171
+ first within a tier, capped at 3, no LLM). `--tension <id>` renders a
172
+ single case's full brief including precedent rationales verbatim.
173
+ `daftari court rule <id> --kind superseded|corrected|accepted|invalid
174
+ [--rationale …] [--references …] [--by …]` records the ruling through the
175
+ same `resolveTension` write path as `vault_tension_resolve`; the rationale
176
+ is recorded verbatim and cited by future dockets — a ruling is precedent
177
+ the moment it lands, because a precedent IS a resolved tension. The court
178
+ retrieves and briefs; it never decides, and a ruling never edits the
179
+ disputed documents. Markdown to stdout, `--output` / `--output-json`;
180
+ audit-convention exit codes (0/2/3).
181
+
182
+ - **`daftari sleep` — circadian memory** (positioning idea 6, gate cleared by
183
+ the CB7 result). A nightly metabolic pass composing machinery that already
184
+ exists — deterministic, LLM-free, and write-free with respect to documents:
185
+ sweeps expired staged actions, scores every document's decay, and builds
186
+ the **wake list** (canonical accumulation docs past TTL with downstream
187
+ dependents, ranked by blast radius via the `vault_tension_blast` reverse
188
+ maps), written to a gitignored `.daftari/wake-queue.jsonl` snapshot for an
189
+ external agent to re-verify against sources — the vault never re-verifies
190
+ on its own. The domain split is honored: generative docs going stale are
191
+ expected — counted, never woken; expired docs with no dependents are
192
+ reported as quiet decay, not woken. The **Morning Report** surfaces tension
193
+ aging and the court docket head, the ratification queue with
194
+ soon-to-expire proposals, and the rubber-stamp monitor (zero rejections
195
+ over ≥10 decisions prints a warning — the circadian design's kill-condition
196
+ instrumentation). Scheduling stays the OS's job (cron example in
197
+ `--help`); daftari ships the cycle, not a daemon. Markdown to stdout,
198
+ `--output` / `--output-json`, `--wake-limit` (report rows only — the queue
199
+ always carries the full list, no silent caps), `--no-queue`;
200
+ audit-convention exit codes. `.daftari/wake-queue.jsonl` added to the vault
201
+ gitignore template.
202
+
203
+ - **`vault_witness` — agent track records + the wager layer** (positioning
204
+ ideas 4 and 9, gate cleared by the CB7 result). A read-only MCP tool that
205
+ aggregates the vault's own ledgers — provenance log, tension log, staged
206
+ actions — into a per-principal track record, priced by a provisional,
207
+ exported wager schedule (`low` 0 / `medium` 1 / `high` 3; survival credit
208
+ 1; gone-doc burn 1 — calibration constants, like the §11.5 impact table).
209
+ Per principal: write volume and span (the longitudinal series for idea 9's
210
+ kill condition), docs authored (first provenance entry wins; authenticated
211
+ `principal` outranks the free-text `agent` claim), live claims with open
212
+ exposure, contested claims with stake at risk, the settled book (claims
213
+ corrected by ruling, retired, or deleted burn their stake; claims
214
+ maintained through a full TTL cycle earn credit; `balance` is the
215
+ difference), proposal outcomes, and tensions logged. Includes the
216
+ flat-curve monitor (idea 4's kill condition): one principal at ≥95% of
217
+ writes flags the records as uninformative instead of reporting them as
218
+ signal. RBAC follows the `vault_status` precedent — everything is scoped
219
+ to readable collections. Advisory and deterministic; nothing is enforced,
220
+ no document is touched, edge-observer attribution is deferred (the edge
221
+ log's collapse keeps observers internal). Tool surface is now 27.
222
+
223
+ - **`vault_search` hits carry unresolved tensions inline** (`contested` /
224
+ `contestedCount`). Each annotation is the full two-sided marker — both
225
+ claims, kind, counterpart, tension id — post-joined from
226
+ `.daftari/tensions.md` in the same enrichment pass as `currentSource`,
227
+ capped at 3 per hit with an honest total. RBAC-gated on the counterpart's
228
+ collection (unreadable ⇒ omitted entirely, and excluded from the count).
229
+ Measured motivation: the tension-graph feud benchmark (2026-07-04) — on
230
+ feuds where retrieval buries one side, agents surface the contradiction
231
+ ~8% baseline vs ~46% with the tension inline; the dedicated-tool shape
232
+ loses to inline across all panel models. Tensions remain advisory and
233
+ never affect ranking.
234
+
235
+ - **OpenRouter LLM transport for `daftari consolidate`** (`--transport
236
+ anthropic|openrouter`, env fallback `DAFTARI_LLM_TRANSPORT`). A second
237
+ model-family client (`createOpenRouterClient`) implementing the same
238
+ `LlmClient` contract as the Anthropic client, promoted from the
239
+ decorrelation shim. On the openrouter transport the CLI gates on
240
+ `OPENROUTER_API_KEY` (not `ANTHROPIC_API_KEY`), defaults the model to
241
+ `anthropic/claude-haiku-4.5`, and accepts any OpenRouter slug via `--model`.
242
+ This is the substrate for the Stage-5 multi-model graduation gate (spec §12
243
+ amendment, 2026-07-02): single-family panel votes are ~92% error-correlated,
244
+ so `k_survived` needs a second model family before any auto-write tier can
245
+ graduate. `completeWithTools` is deliberately unsupported on this transport
246
+ (only `daftari eval` drives tools; eval stays on anthropic).
247
+
248
+ ### Security
249
+
250
+ - **Tension tools now enforce the both-sides visibility rule** (#212).
251
+ `vault_tension_clusters` and `vault_tension_blast` compute over only the
252
+ tensions whose BOTH sides the caller can read — filtered before
253
+ aggregation, so counts, cluster sizes, and blast seeds reveal nothing
254
+ about hidden entries. `vault_tension_log` refuses to record claims naming
255
+ a document the caller cannot read (denial names the caller-supplied path
256
+ only); `vault_tension_resolve` returns the exact not-found error for
257
+ invisible tensions, checked before the loop-authored ratify rule. This
258
+ closes the bypass around #211's contested-annotation gate: one rule
259
+ (`collectionForPath` + `canSeeTension`) now governs every tension
260
+ surface. No-RBAC deployments are unaffected. Known residual (accepted):
261
+ sequential tension ids still reveal the total entry count to callers who
262
+ can log. A follow-up consolidation (`sourceReadable`, exported from
263
+ `tension-access.ts`) then unified the canonicalize → reject-escape →
264
+ `canRead` sequence into a single predicate adopted by all four call
265
+ sites — the tension log/blast gates above and #211's contested-annotation
266
+ filter in `contested.ts` — so one guard now backs every tension-graph tool surface,
267
+ including contested annotations on `vault_search` hits. Further
268
+ residuals (accepted, tracked in follow-ups): `vault_status` /
269
+ `vault_receipt` / court-precedent tension summaries still filter by
270
+ uncanonicalized top-level segment, and `vault_lint`'s tension-health
271
+ aggregates count all entries (counts only, no content).
272
+
273
+ ### Internal
274
+
275
+ - **CB7 decision-divergence bench** (`integrations/consensus-bench`,
276
+ benchmark tooling only). Implements the
277
+ 2026-07-11 CB7 design: instance assembly from existing artifacts (CB6
278
+ tension pairs, CO2 stale-trap diffs, consensus-box supersession chains as
279
+ settled controls — CB6 tension items excluded from the control set),
280
+ condition renderer with locked validity invariants (task text
281
+ byte-identical across memory conditions; the collapsed block carries one
282
+ value and no epistemic language; settled controls give the foil the
283
+ governing value), deterministic enum scorer (divergence, calibration,
284
+ hedge tax — no LLM judge on primary metrics), and `cb7-runner.mjs` for the
285
+ live panel run (`--gate` mode runs the second-rater leakage check).
286
+ M-collapsed for tensions holds the challenger position (recency /
287
+ last-write-wins) rather than the spec's CB6-foil-verdict, a deterministic
288
+ deviation recorded in the module.
289
+
10
290
  ## [1.29.0] - 2026-06-25
11
291
 
12
292
  ### Changed
@@ -1202,6 +1482,7 @@ vault to AI agents, exposing 13 tools over stdio.
1202
1482
  example documents, git history, search index); `daftari --vault` serves it.
1203
1483
  - 160 tests covering all 13 tools and their supporting modules.
1204
1484
 
1485
+ [1.31.0]: https://github.com/mavaali/daftari/releases/tag/v1.31.0
1205
1486
  [1.5.1]: https://github.com/mavaali/daftari/releases/tag/v1.5.1
1206
1487
  [1.4.0]: https://github.com/mavaali/daftari/releases/tag/v1.4.0
1207
1488
  [1.1.1]: https://github.com/mavaali/daftari/releases/tag/v1.1.1
package/README.md CHANGED
@@ -56,7 +56,7 @@ compiles; the vault preserves; *you* keep the judgment. See
56
56
 
57
57
  ## What it is
58
58
 
59
- A directory of markdown files with YAML frontmatter, exposed to agents as 14
59
+ A directory of markdown files with YAML frontmatter, exposed to agents as 27
60
60
  MCP tools over stdio. The vault is plain text: you can read it in any editor,
61
61
  `git log` it, grep it. Daftari adds the machinery agents need to treat it as a
62
62
  shared workspace.
@@ -70,7 +70,10 @@ Point any MCP client (Claude Desktop, Claude Code, an agent SDK) at it.
70
70
 
71
71
  ## The four layers
72
72
 
73
- Storage and access control are table stakes. The moat is layers 3 and 4.
73
+ All four implement one idea *resolve only by discovery, never by invention.*
74
+ Read [**The core idea**](docs/architecture.md#the-core-idea) first and the layers
75
+ become its consequences. Storage and access control are table stakes; the moat is
76
+ layers 3 and 4.
74
77
 
75
78
  |Layer |What it does |Why it matters |
76
79
  |---------------------|------------------------------------------------------------------------------------------------------|-----------------------------------------------------------------------|
@@ -83,16 +86,61 @@ Storage and access control are table stakes. The moat is layers 3 and 4.
83
86
 
84
87
  **Read:** `vault_read`, `vault_index`, `vault_status`
85
88
 
86
- **Search:** `vault_search` (hybrid BM25 + vector), `vault_search_related`, `vault_themes` (thematic clustering), `vault_reindex`
89
+ **Attest:** `vault_receipt` compile an epistemic receipt for the documents
90
+ an answer cites: per-source status, confidence, provenance, freshness, exact
91
+ content-version hash, supersession-chain resolution, and open tensions, plus
92
+ deterministic summary flags, the vault's git HEAD as an as-of anchor, and a
93
+ recomputable hash over the whole receipt. Attach it to the answer so any
94
+ consumer can see what the answer stands on.
87
95
 
88
- **Write:** `vault_write`, `vault_append`, `vault_promote`, `vault_deprecate`
96
+ **Witness:** `vault_witness` per-principal track records from the vault's
97
+ own ledgers, priced by the wager schedule: write volume, live claims with
98
+ open exposure, contested claims with stake at risk, the settled book
99
+ (burned vs credited), proposal outcomes, tensions logged. Advisory and
100
+ deterministic; includes the flat-curve monitor so a single-author vault is
101
+ reported as uninformative rather than as signal.
89
102
 
90
- **Curate:** `vault_tension_log`, `vault_lint`, `vault_provenance`
103
+ **Search:** `vault_search` (hybrid BM25 + vector; hits carry their unresolved
104
+ tensions inline and foreground the current source of superseded documents),
105
+ `vault_search_related`, `vault_themes` (thematic clustering), `vault_reindex`
106
+
107
+ **Write:** `vault_write`, `vault_append`, `vault_promote`, `vault_deprecate`, `vault_supersede`, `vault_merge`, `vault_set_confidence`
108
+
109
+ **Curate:** `vault_tension_log`, `vault_tension_resolve`, `vault_tension_clusters`, `vault_tension_blast`, `vault_lint`, `vault_provenance`
110
+
111
+ **Edges:** `vault_edge_observe`, `vault_edge_contest`, `vault_edges`
112
+
113
+ **Ratify:** `vault_stage_action`, `vault_ratify`
91
114
 
92
115
  The curation engine is advisory: `vault_lint` reports problems and
93
116
  `vault_tension_log` records contradictions. Neither auto-fixes anything. Every
94
117
  change is a deliberate, attributable act.
95
118
 
119
+ ### Tool tiers
120
+
121
+ Every advertised tool costs the agent context tokens and a decision branch.
122
+ The `tools` block in `.daftari/config.yaml` picks how much of the registry
123
+ `tools/list` advertises:
124
+
125
+ ```yaml
126
+ tools:
127
+ tier: standard # core | standard | full (default: full)
128
+ include: # add tools the tier omits
129
+ - vault_tension_log
130
+ exclude: # remove tools the tier includes — exclude wins
131
+ - vault_status
132
+ ```
133
+
134
+ `core` is the search-before-derive loop (`vault_search`, `vault_read`,
135
+ `vault_write`, `vault_index`, `vault_lint`, `vault_status`); `standard` adds
136
+ the full document lifecycle (append/promote/deprecate/supersede/merge,
137
+ confidence and tier setters, propose/ratify) plus diagnostics; `full` is
138
+ everything. `--tools <tier>` overrides the tier for one invocation. Filtering
139
+ only changes what is *advertised* — calls to any registered tool still work,
140
+ so an agent holding a cached tool name keeps working across a tier change.
141
+ Unknown names in `include`/`exclude` warn at startup and are ignored, so a
142
+ config written for a newer daftari still loads.
143
+
96
144
  **Evaluate (opt-in, requires an Anthropic API key):** `daftari eval` — scores how
97
145
  well an LLM can use the curation surface to answer multi-hop questions about the
98
146
  vault. See the [design spec](docs/superpowers/specs/2026-05-31-cortex-quality-metric-design.md)
@@ -220,6 +268,110 @@ daftari backfill --plan
220
268
  daftari backfill --apply --scope specs
221
269
  ```
222
270
 
271
+ ## Open Knowledge Format (OKF)
272
+
273
+ [OKF](https://cloud.google.com/blog/products/data-analytics/how-the-open-knowledge-format-can-improve-data-sharing/)
274
+ is Google Cloud's vendor-neutral spec (v0.1) for the LLM-wiki pattern: a
275
+ directory of markdown files with YAML frontmatter that any producer can emit and
276
+ any consumer can read without translation. A Daftari vault *is* that pattern, so
277
+ `daftari okf` bridges the two directions.
278
+
279
+ **Export** renders the vault as a portable OKF bundle — every doc becomes an OKF
280
+ concept doc (the core `type` / `title` / `description` / `resource` / `tags` /
281
+ `timestamp` fields, plus a verbatim `daftari` sidecar for lossless round-trip),
282
+ with generated `index.md` (progressive-disclosure listing) and `log.md`
283
+ (chronological history). The source vault is never mutated.
284
+
285
+ ```bash
286
+ daftari okf export ./my-vault --out ./okf-bundle
287
+ daftari okf export ./my-vault --out ./okf-bundle --collection pricing
288
+ ```
289
+
290
+ **Import** adopts an OKF bundle into a vault. A bundle produced by `okf export`
291
+ round-trips exactly via its sidecar; a foreign bundle is mapped conservatively
292
+ (docs land as `draft` in the `accumulation` domain, the original OKF `type` is
293
+ preserved in an `okf_type` field). Writes auto-commit and the index is rebuilt.
294
+
295
+ ```bash
296
+ daftari okf import ./okf-bundle --into ./my-vault --dry-run
297
+ daftari okf import ./okf-bundle --into ./my-vault
298
+ ```
299
+
300
+ ## Server mode (self-hosted)
301
+
302
+ By default daftari is a per-user stdio process. `daftari serve` starts the
303
+ same vault as **one always-on instance over Streamable HTTP** — for a team, or
304
+ for clients that can't spawn a local process (claude.ai web/mobile, Cowork):
305
+
306
+ ```bash
307
+ daftari serve --vault ./my-vault # http://127.0.0.1:8787/mcp
308
+ daftari serve --vault ./my-vault --bind 0.0.0.0 --port 9000
309
+ ```
310
+
311
+ Identity is **per MCP session**, resolved when the session opens, so every
312
+ RBAC and existence-disclosure rule applies per connection with zero tool
313
+ changes. Two composable auth schemes, both declared in config:
314
+
315
+ ```yaml
316
+ server:
317
+ transport_security: external # required off-loopback: TLS terminates upstream
318
+ auth:
319
+ tokens: # static bearer tokens (agents, ETL)
320
+ - env: DAFTARI_TOKEN_ETL # the VALUE lives in this env var, never in config
321
+ user: agent:etl
322
+ role: admin
323
+ oauth: # OAuth 2.1 resource server (humans via your IdP)
324
+ issuer: https://idp.example.com
325
+ audience: daftari
326
+ jwks_uri: https://idp.example.com/.well-known/jwks.json
327
+ subjects:
328
+ "alice@example.com": { user: human:alice, role: analyst }
329
+ ```
330
+
331
+ The posture is fail-loud, never silent-downgrade: a non-loopback bind refuses
332
+ to start without auth **and** the explicit `transport_security: external`
333
+ acknowledgment (daftari never terminates TLS itself — put Caddy/nginx/a load
334
+ balancer in front); with any auth configured, a bad or missing credential is
335
+ a 401 at session open and a valid JWT whose subject isn't mapped is a 403 —
336
+ neither ever becomes the guest. Guest sessions exist only in the no-auth
337
+ loopback configuration. A running server also refuses to be silently killed:
338
+ stray stdio invocations against the same vault refuse to start, and replacing
339
+ a live holder requires a deliberate `daftari serve --takeover`.
340
+
341
+ ## Storage backing
342
+
343
+ A self-hosted vault can push to durable object storage (#6). The local git
344
+ working copy stays canonical — reads, writes, auto-commits, locks, and the
345
+ index all stay exactly as above — and the backing is a dumb sync target:
346
+
347
+ ```yaml
348
+ # .daftari/config.yaml
349
+ storage:
350
+ backend: s3 # fs | s3 | azure
351
+ bucket: team-vault
352
+ region: us-east-1
353
+ # endpoint: https://… # MinIO / R2 / GCS S3-interop endpoints
354
+ # sync_interval_minutes: 15 # daftari serve pushes on this cadence
355
+ ```
356
+
357
+ ```bash
358
+ daftari sync --vault ./my-vault # incremental push
359
+ daftari sync --vault ./my-vault --dry-run # show the diff only
360
+ daftari sync --vault ./empty-dir --restore --backend s3 --bucket team-vault
361
+ ```
362
+
363
+ The push covers the markdown tree, the `.git` directory, and durable
364
+ `.daftari` journals; the rebuildable SQLite index and lock files never sync.
365
+ Neither do `.git/config` and `.git/hooks` — git *executes* what those
366
+ declare, and a backup channel must not deliver code (`git clone` refuses to
367
+ transmit them for the same reason), so re-add remotes and local git config
368
+ by hand after a restore.
369
+ Cloud backends load their SDKs (`@aws-sdk/client-s3`, `@azure/storage-blob`)
370
+ as optional dependencies — install the one you use; credentials come from the
371
+ SDK's standard environment chain, never from vault config. GCS is reached via
372
+ its S3-interoperability endpoint. Restore refuses non-empty directories and
373
+ reindexes when done.
374
+
223
375
  ## How it compares
224
376
 
225
377
  | |AGENTS.md |RAG |Daftari |
@@ -234,12 +386,18 @@ daftari backfill --apply --scope specs
234
386
 
235
387
  Deliberately deferred to keep the surface tight:
236
388
 
237
- - **Cloud-hosted multi-tenant server** with S3/GCS backend and token auth
238
- - **Remote MCP transport** for claude.ai web, mobile, and Cowork (v1 is a local desktop extension for Claude Desktop and Claude Code)
389
+ - **Cloud-hosted multi-tenant SaaS** (self-hosted server mode HAS shipped
390
+ see [Server mode](#server-mode-self-hosted) and
391
+ [Storage backing](#storage-backing); the project itself hosts nothing)
239
392
  - **Conflict resolution beyond file-level locks** (CRDTs, semantic merge)
240
393
  - **Background curation agent** running lint on a cadence
241
- - **LLM reranking** of search results
242
- - **Enforced domain separation** (v1 documents the convention; v2 enforces it)
394
+ - **Enforced domain separation** (v1 documents the convention; v2 enforces it —
395
+ advisory boundary warnings shipped in the meantime: `vault_lint`'s
396
+ `domainLeaks` check and write-time `domain_warnings`)
397
+
398
+ (LLM reranking, deferred here originally, has since shipped as the opt-in
399
+ agent-as-judge `rerank_candidates` on `vault_search`: the server prepares the
400
+ fused candidate pool and the protocol; the calling agent is the judge.)
243
401
 
244
402
  Each is a clean increment on a surface that already works.
245
403
 
@@ -402,6 +560,102 @@ fail_on:
402
560
  transitive_staleness: 100 # default: generous; teams tune
403
561
  ```
404
562
 
563
+ ## The vault as witness — and the wager layer
564
+
565
+ Every write already carries an identity, every proposal an outcome, every
566
+ tension a logger and a ruling. `vault_witness` aggregates that ledger into a
567
+ **track record per principal** — and prices it. Confidence is free to claim,
568
+ so the wager schedule makes it cost something: writing at `high` stakes 3
569
+ points, `medium` 1, `low` 0 (hedged claims are the honest default and are
570
+ never taxed). A claim later corrected by a ruling or retired by someone else
571
+ burns the stake; a claim maintained through a full TTL cycle earns credit.
572
+ The balance is arithmetic on recorded facts — advisory, provisional
573
+ constants, nothing enforced: routing a high-stakes write to the agent with
574
+ the earned balance is your policy, not the vault's. Both kill conditions
575
+ from the design travel with the tool: the flat-curve monitor (one author ≥95%
576
+ of writes → curves declared uninformative) and the longitudinal write-volume
577
+ series (if stake-fear suppresses honest claims, it shows up here first).
578
+
579
+ ## Circadian memory
580
+
581
+ The vault sleeps. `daftari sleep` is the nightly metabolic pass — deterministic,
582
+ LLM-free, write-free (documents are never touched):
583
+
584
+ ```bash
585
+ # In cron (any scheduler works; daftari ships the cycle, not a daemon):
586
+ 0 3 * * * cd /path/to/vault && npx daftari sleep --output .daftari/morning-report.md
587
+ ```
588
+
589
+ The cycle sweeps expired staged actions, scores every document's decay, and
590
+ builds the **wake list**: canonical accumulation documents past their TTL
591
+ with downstream dependents, ranked by blast radius. The list is written to
592
+ `.daftari/wake-queue.jsonl` for an external agent to consume — re-verify each
593
+ document against its sources, stage the diff — because the vault never
594
+ re-verifies on its own. Generative documents going stale are expected, not a
595
+ defect: counted, never woken.
596
+
597
+ The **Morning Report** ends where the human begins: tension aging and the
598
+ court docket head, the ratification queue with soon-to-expire proposals, and
599
+ the rubber-stamp monitor — zero rejections over a long decision history is
600
+ printed as a warning, not a compliment. The agent proposes overnight; you
601
+ ratify over coffee.
602
+
603
+ ## Tension Court
604
+
605
+ Tensions wait in a log; the court turns them into decidable cases. `daftari
606
+ court` compiles a **docket** — every open tension briefed and ranked (stale
607
+ first, then by blast radius): both sides' claims, the present state of their
608
+ documents, the downstream stakes, cluster membership, and **precedents** —
609
+ past rulings on disputes that shared a document, a collection pair, or a
610
+ kind.
611
+
612
+ ```bash
613
+ # The docket — a 5-minute weekly ritual
614
+ daftari court --vault ./my-vault
615
+
616
+ # One case's full brief (verbatim rationales from cited precedents)
617
+ daftari court --tension tension-abc123
618
+
619
+ # Rule. The rationale is recorded verbatim and cited by future dockets.
620
+ daftari court rule tension-abc123 --kind corrected \
621
+ --rationale "Vendor pricing page confirmed the entry tier on 2026-07-10."
622
+ ```
623
+
624
+ Rulings go through the same `resolveTension` write path as
625
+ `vault_tension_resolve` — a ruling records the closure, it never edits the
626
+ disputed documents. Precedent retrieval is deterministic (shared-document >
627
+ collection-pair > same-kind; no LLM): the court retrieves how this house has
628
+ resolved similar disputes before, and whether a precedent applies stays the
629
+ human's judgment. Memory grows case law.
630
+
631
+ ## Belief archaeology
632
+
633
+ Git is the version layer, so the vault can answer **"what did we believe on
634
+ March 3?"** `daftari asof` is a read-only report over the repo's history — no
635
+ checkout, no index, no API key:
636
+
637
+ ```bash
638
+ # The vault's belief state at a date (or any git ref), plus the drift since
639
+ daftari asof 2026-03-03 --vault ./my-vault
640
+
641
+ # One document's trajectory: frontmatter then vs now, commits in between
642
+ daftari asof HEAD~20 --doc pricing/helios-consumption-pricing.md
643
+
644
+ # Counterfactual replay: this fact turned out wrong — who had inherited it
645
+ # at the time, and where are they now?
646
+ daftari asof 2026-03-03 --blast pricing/helios-consumption-pricing.md
647
+ ```
648
+
649
+ The default report shows the document and tension state at that point and
650
+ the drift since: documents added/removed, `status`/`confidence` transitions,
651
+ and tensions opened or resolved. `--blast` computes the blast radius of a
652
+ document over the tree *as of the commit* (same source/link edge semantics as
653
+ `vault_tension_blast`), annotating each downstream document with its status
654
+ today — the post-mortem view for a fact that was later corrected. Markdown to
655
+ stdout by default; `--output` / `--output-json` write files. Pairs with
656
+ `vault_receipt`: a receipt's `vaultHead` is exactly the anchor to hand back
657
+ to `asof`.
658
+
405
659
  ## Development
406
660
 
407
661
  ```
@@ -12,6 +12,7 @@ export declare function canRead(role: RoleConfig | null, collection: string): bo
12
12
  export declare function canWrite(role: RoleConfig | null, collection: string): boolean;
13
13
  export declare function canPromote(role: RoleConfig | null): boolean;
14
14
  export declare function canRatify(role: RoleConfig | null): boolean;
15
+ export declare function isProposeOnly(role: RoleConfig | null): boolean;
15
16
  export declare function hasAnyRead(role: RoleConfig | null): boolean;
16
17
  export declare function filterByReadPermission<T extends {
17
18
  collection: string;
@@ -1 +1 @@
1
- {"version":3,"file":"rbac.d.ts","sourceRoot":"","sources":["../../src/access/rbac.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAEpE,eAAO,MAAM,UAAU,UAAU,CAAC;AAClC,eAAO,MAAM,QAAQ,MAAM,CAAC;AAI5B,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,UAAU,GAAG,IAAI,CAAC;CACzB;AAKD,wBAAgB,aAAa,CAC3B,MAAM,EAAE,aAAa,EACrB,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,MAAM,GACf,aAAa,CAEf;AAID,wBAAgB,WAAW,CAAC,IAAI,SAAU,GAAG,aAAa,CAEzD;AAOD,wBAAgB,OAAO,CAAC,IAAI,EAAE,UAAU,GAAG,IAAI,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAE5E;AAGD,wBAAgB,QAAQ,CAAC,IAAI,EAAE,UAAU,GAAG,IAAI,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAE7E;AAGD,wBAAgB,UAAU,CAAC,IAAI,EAAE,UAAU,GAAG,IAAI,GAAG,OAAO,CAE3D;AAMD,wBAAgB,SAAS,CAAC,IAAI,EAAE,UAAU,GAAG,IAAI,GAAG,OAAO,CAE1D;AAID,wBAAgB,UAAU,CAAC,IAAI,EAAE,UAAU,GAAG,IAAI,GAAG,OAAO,CAE3D;AAID,wBAAgB,sBAAsB,CAAC,CAAC,SAAS;IAAE,UAAU,EAAE,MAAM,CAAA;CAAE,EACrE,IAAI,EAAE,UAAU,GAAG,IAAI,EACvB,KAAK,EAAE,CAAC,EAAE,GACT,CAAC,EAAE,CAEL"}
1
+ {"version":3,"file":"rbac.d.ts","sourceRoot":"","sources":["../../src/access/rbac.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAEpE,eAAO,MAAM,UAAU,UAAU,CAAC;AAClC,eAAO,MAAM,QAAQ,MAAM,CAAC;AAI5B,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,UAAU,GAAG,IAAI,CAAC;CACzB;AAKD,wBAAgB,aAAa,CAC3B,MAAM,EAAE,aAAa,EACrB,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,MAAM,GACf,aAAa,CAEf;AAID,wBAAgB,WAAW,CAAC,IAAI,SAAU,GAAG,aAAa,CAEzD;AAOD,wBAAgB,OAAO,CAAC,IAAI,EAAE,UAAU,GAAG,IAAI,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAE5E;AAGD,wBAAgB,QAAQ,CAAC,IAAI,EAAE,UAAU,GAAG,IAAI,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAE7E;AAGD,wBAAgB,UAAU,CAAC,IAAI,EAAE,UAAU,GAAG,IAAI,GAAG,OAAO,CAE3D;AAMD,wBAAgB,SAAS,CAAC,IAAI,EAAE,UAAU,GAAG,IAAI,GAAG,OAAO,CAE1D;AAMD,wBAAgB,aAAa,CAAC,IAAI,EAAE,UAAU,GAAG,IAAI,GAAG,OAAO,CAE9D;AAID,wBAAgB,UAAU,CAAC,IAAI,EAAE,UAAU,GAAG,IAAI,GAAG,OAAO,CAE3D;AAID,wBAAgB,sBAAsB,CAAC,CAAC,SAAS;IAAE,UAAU,EAAE,MAAM,CAAA;CAAE,EACrE,IAAI,EAAE,UAAU,GAAG,IAAI,EACvB,KAAK,EAAE,CAAC,EAAE,GACT,CAAC,EAAE,CAEL"}
@@ -42,6 +42,13 @@ export function canPromote(role) {
42
42
  export function canRatify(role) {
43
43
  return role?.ratify ?? false;
44
44
  }
45
+ // True if the role is propose-only (#235): its writes must land as staged
46
+ // `write` proposals, never as direct mutations. vault_write coerces; every
47
+ // other write tool denies. The write grant still scopes WHICH collections the
48
+ // role may propose into.
49
+ export function isProposeOnly(role) {
50
+ return role?.proposeOnly ?? false;
51
+ }
45
52
  // True if the role has read access to at least one collection. Curation tools
46
53
  // (lint, tension log, provenance) are open to anyone with any read grant.
47
54
  export function hasAnyRead(role) {
@@ -1 +1 @@
1
- {"version":3,"file":"rbac.js","sourceRoot":"","sources":["../../src/access/rbac.ts"],"names":[],"mappings":"AAAA,6BAA6B;AAC7B,EAAE;AACF,6EAA6E;AAC7E,8EAA8E;AAC9E,2EAA2E;AAC3E,EAAE;AACF,8EAA8E;AAC9E,2EAA2E;AAC3E,0EAA0E;AAI1E,MAAM,CAAC,MAAM,UAAU,GAAG,OAAO,CAAC;AAClC,MAAM,CAAC,MAAM,QAAQ,GAAG,GAAG,CAAC;AAU5B,+EAA+E;AAC/E,6EAA6E;AAC7E,2BAA2B;AAC3B,MAAM,UAAU,aAAa,CAC3B,MAAqB,EACrB,IAAY,EACZ,QAAgB;IAEhB,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,IAAI,IAAI,EAAE,CAAC;AAClE,CAAC;AAED,2EAA2E;AAC3E,0BAA0B;AAC1B,MAAM,UAAU,WAAW,CAAC,IAAI,GAAG,OAAO;IACxC,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,UAAU,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC;AACpD,CAAC;AAED,SAAS,OAAO,CAAC,IAAc,EAAE,UAAkB;IACjD,OAAO,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC;AAC9D,CAAC;AAED,uDAAuD;AACvD,MAAM,UAAU,OAAO,CAAC,IAAuB,EAAE,UAAkB;IACjE,OAAO,IAAI,KAAK,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC,IAAI,EAAE,UAAU,CAAC,CAAC;AACzD,CAAC;AAED,gEAAgE;AAChE,MAAM,UAAU,QAAQ,CAAC,IAAuB,EAAE,UAAkB;IAClE,OAAO,IAAI,KAAK,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC,KAAK,EAAE,UAAU,CAAC,CAAC;AAC1D,CAAC;AAED,qDAAqD;AACrD,MAAM,UAAU,UAAU,CAAC,IAAuB;IAChD,OAAO,IAAI,EAAE,OAAO,IAAI,KAAK,CAAC;AAChC,CAAC;AAED,8EAA8E;AAC9E,4EAA4E;AAC5E,wEAAwE;AACxE,kDAAkD;AAClD,MAAM,UAAU,SAAS,CAAC,IAAuB;IAC/C,OAAO,IAAI,EAAE,MAAM,IAAI,KAAK,CAAC;AAC/B,CAAC;AAED,8EAA8E;AAC9E,0EAA0E;AAC1E,MAAM,UAAU,UAAU,CAAC,IAAuB;IAChD,OAAO,IAAI,KAAK,IAAI,IAAI,IAAI,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC;AAC/C,CAAC;AAED,8EAA8E;AAC9E,wBAAwB;AACxB,MAAM,UAAU,sBAAsB,CACpC,IAAuB,EACvB,KAAU;IAEV,OAAO,KAAK,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,EAAE,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC;AAChE,CAAC"}
1
+ {"version":3,"file":"rbac.js","sourceRoot":"","sources":["../../src/access/rbac.ts"],"names":[],"mappings":"AAAA,6BAA6B;AAC7B,EAAE;AACF,6EAA6E;AAC7E,8EAA8E;AAC9E,2EAA2E;AAC3E,EAAE;AACF,8EAA8E;AAC9E,2EAA2E;AAC3E,0EAA0E;AAI1E,MAAM,CAAC,MAAM,UAAU,GAAG,OAAO,CAAC;AAClC,MAAM,CAAC,MAAM,QAAQ,GAAG,GAAG,CAAC;AAU5B,+EAA+E;AAC/E,6EAA6E;AAC7E,2BAA2B;AAC3B,MAAM,UAAU,aAAa,CAC3B,MAAqB,EACrB,IAAY,EACZ,QAAgB;IAEhB,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,IAAI,IAAI,EAAE,CAAC;AAClE,CAAC;AAED,2EAA2E;AAC3E,0BAA0B;AAC1B,MAAM,UAAU,WAAW,CAAC,IAAI,GAAG,OAAO;IACxC,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,UAAU,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC;AACpD,CAAC;AAED,SAAS,OAAO,CAAC,IAAc,EAAE,UAAkB;IACjD,OAAO,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC;AAC9D,CAAC;AAED,uDAAuD;AACvD,MAAM,UAAU,OAAO,CAAC,IAAuB,EAAE,UAAkB;IACjE,OAAO,IAAI,KAAK,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC,IAAI,EAAE,UAAU,CAAC,CAAC;AACzD,CAAC;AAED,gEAAgE;AAChE,MAAM,UAAU,QAAQ,CAAC,IAAuB,EAAE,UAAkB;IAClE,OAAO,IAAI,KAAK,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC,KAAK,EAAE,UAAU,CAAC,CAAC;AAC1D,CAAC;AAED,qDAAqD;AACrD,MAAM,UAAU,UAAU,CAAC,IAAuB;IAChD,OAAO,IAAI,EAAE,OAAO,IAAI,KAAK,CAAC;AAChC,CAAC;AAED,8EAA8E;AAC9E,4EAA4E;AAC5E,wEAAwE;AACxE,kDAAkD;AAClD,MAAM,UAAU,SAAS,CAAC,IAAuB;IAC/C,OAAO,IAAI,EAAE,MAAM,IAAI,KAAK,CAAC;AAC/B,CAAC;AAED,0EAA0E;AAC1E,2EAA2E;AAC3E,8EAA8E;AAC9E,yBAAyB;AACzB,MAAM,UAAU,aAAa,CAAC,IAAuB;IACnD,OAAO,IAAI,EAAE,WAAW,IAAI,KAAK,CAAC;AACpC,CAAC;AAED,8EAA8E;AAC9E,0EAA0E;AAC1E,MAAM,UAAU,UAAU,CAAC,IAAuB;IAChD,OAAO,IAAI,KAAK,IAAI,IAAI,IAAI,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC;AAC/C,CAAC;AAED,8EAA8E;AAC9E,wBAAwB;AACxB,MAAM,UAAU,sBAAsB,CACpC,IAAuB,EACvB,KAAU;IAEV,OAAO,KAAK,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,EAAE,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC;AAChE,CAAC"}