@dikolab/kbdb 0.3.0 → 0.3.2

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 (428) hide show
  1. package/README.md +89 -120
  2. package/dist/bench/constants/corpus-defaults.constant.d.ts +3 -0
  3. package/dist/bench/functions/format-report.function.d.ts +11 -0
  4. package/dist/bench/functions/generate-corpus.function.d.ts +12 -0
  5. package/dist/bench/functions/measure-operation.function.d.ts +14 -0
  6. package/dist/bench/functions/seeded-rng.function.d.ts +11 -0
  7. package/dist/bench/functions/zipf-word.function.d.ts +13 -0
  8. package/dist/bench/index.d.ts +10 -0
  9. package/dist/bench/typings/bench-result.interface.d.ts +11 -0
  10. package/dist/bench/typings/bench-suite-result.interface.d.ts +10 -0
  11. package/dist/bench/typings/corpus-config.interface.d.ts +11 -0
  12. package/dist/bench/typings/corpus-section.interface.d.ts +9 -0
  13. package/dist/cli.cjs +63 -9
  14. package/dist/cli.cjs.map +2 -2
  15. package/dist/cli.mjs +63 -9
  16. package/dist/cli.mjs.map +2 -2
  17. package/dist/src/shared/auto-capture/classes/auto-capture-controller.class.d.ts +33 -0
  18. package/dist/src/shared/auto-capture/constants/auto-capture-defaults.constant.d.ts +8 -0
  19. package/dist/src/shared/auto-capture/functions/build-capture-prompt.function.d.ts +11 -0
  20. package/dist/src/shared/auto-capture/functions/evaluate-trigger.function.d.ts +12 -0
  21. package/dist/src/shared/auto-capture/index.d.ts +7 -0
  22. package/dist/src/shared/auto-capture/typings/auto-capture-config.interface.d.ts +13 -0
  23. package/dist/src/shared/auto-capture/typings/auto-capture-state.interface.d.ts +13 -0
  24. package/dist/src/shared/auto-capture/typings/auto-capture-trigger.interface.d.ts +7 -0
  25. package/dist/src/shared/cli/constants/global-help.constant.d.ts +8 -0
  26. package/dist/src/shared/cli/constants/leaf-help.constant.d.ts +7 -0
  27. package/dist/src/shared/cli/constants/memory-protocol-body.constant.d.ts +7 -0
  28. package/dist/src/shared/cli/constants/query-guidance-body.constant.d.ts +7 -0
  29. package/dist/src/shared/cli/constants/subcommand-help.constant.d.ts +8 -0
  30. package/dist/src/shared/cli/functions/collect-files.function.d.ts +13 -0
  31. package/dist/src/shared/cli/functions/compute-section-kbid.function.d.ts +15 -0
  32. package/dist/src/shared/cli/functions/format-mcp-output.function.d.ts +9 -0
  33. package/dist/src/shared/cli/functions/format-text-output.function.d.ts +9 -0
  34. package/dist/src/shared/cli/functions/generate-group-help.function.d.ts +11 -0
  35. package/dist/src/shared/cli/functions/handle-data-command.function.d.ts +16 -0
  36. package/dist/src/shared/cli/functions/handle-mcp.function.d.ts +15 -0
  37. package/dist/src/shared/cli/functions/handle-migrate.function.d.ts +15 -0
  38. package/dist/src/shared/cli/functions/hydrate-search-previews.function.d.ts +14 -0
  39. package/dist/src/shared/cli/functions/resolve-skill-names.function.d.ts +16 -0
  40. package/dist/src/shared/cli/functions/run-search.function.d.ts +1 -0
  41. package/dist/src/shared/cli/functions/version-gate.function.d.ts +15 -0
  42. package/dist/src/shared/cli/functions/wrap-command.function.d.ts +15 -0
  43. package/dist/src/shared/cli/typings/agent-create-client.interface.d.ts +42 -0
  44. package/dist/src/shared/cli/typings/agent-get-client.interface.d.ts +36 -0
  45. package/dist/src/shared/cli/typings/check-client.interface.d.ts +58 -0
  46. package/dist/src/shared/cli/typings/cli-deps.interface.d.ts +48 -0
  47. package/dist/src/shared/cli/typings/cli-options.interface.d.ts +2 -0
  48. package/dist/src/shared/cli/typings/disconnectable-client.interface.d.ts +26 -0
  49. package/dist/src/shared/cli/typings/dispatch-client.type.d.ts +27 -0
  50. package/dist/src/shared/cli/typings/learn-client.interface.d.ts +52 -0
  51. package/dist/src/shared/cli/typings/learn-io.interface.d.ts +5 -0
  52. package/dist/src/shared/cli/typings/search-client.interface.d.ts +71 -0
  53. package/dist/src/shared/embedding/classes/null-embedding-provider.class.d.ts +20 -0
  54. package/dist/src/shared/embedding/constants/near-duplicate-thresholds.constant.d.ts +15 -0
  55. package/dist/src/shared/embedding/functions/build-vector-index.function.d.ts +14 -0
  56. package/dist/src/shared/embedding/functions/cosine-similarity.function.d.ts +10 -0
  57. package/dist/src/shared/embedding/functions/detect-near-duplicates.function.d.ts +18 -0
  58. package/dist/src/shared/embedding/functions/jaccard-coefficient.function.d.ts +9 -0
  59. package/dist/src/shared/embedding/functions/read-vector-index-meta.function.d.ts +10 -0
  60. package/dist/src/shared/embedding/functions/rrf-fuse.function.d.ts +14 -0
  61. package/dist/src/shared/embedding/functions/search-vectors.function.d.ts +14 -0
  62. package/dist/src/shared/embedding/index.d.ts +16 -0
  63. package/dist/src/shared/embedding/typings/embedding-config.interface.d.ts +20 -0
  64. package/dist/src/shared/embedding/typings/embedding-provider.interface.d.ts +23 -0
  65. package/dist/src/shared/embedding/typings/near-duplicate-candidate.model.d.ts +23 -0
  66. package/dist/src/shared/embedding/typings/near-duplicate-result.model.d.ts +24 -0
  67. package/dist/src/shared/embedding/typings/vector-index-entry.model.d.ts +12 -0
  68. package/dist/src/shared/embedding/typings/vector-index-meta.model.d.ts +11 -0
  69. package/dist/src/shared/embedding/typings/vector-search-result.model.d.ts +7 -0
  70. package/dist/src/shared/mcp/constants/tool-agent-create.constant.d.ts +3 -0
  71. package/dist/src/shared/mcp/constants/tool-agent-delete.constant.d.ts +3 -0
  72. package/dist/src/shared/mcp/constants/tool-agent-get.constant.d.ts +3 -0
  73. package/dist/src/shared/mcp/constants/tool-agent-list.constant.d.ts +3 -0
  74. package/dist/src/shared/mcp/constants/tool-auto-capture-review.constant.d.ts +8 -0
  75. package/dist/src/shared/mcp/constants/tool-check.constant.d.ts +3 -0
  76. package/dist/src/shared/mcp/constants/tool-content.constant.d.ts +3 -0
  77. package/dist/src/shared/mcp/constants/tool-export.constant.d.ts +3 -0
  78. package/dist/src/shared/mcp/constants/tool-gc.constant.d.ts +3 -0
  79. package/dist/src/shared/mcp/constants/tool-learn.constant.d.ts +3 -0
  80. package/dist/src/shared/mcp/constants/tool-rebuild.constant.d.ts +3 -0
  81. package/dist/src/shared/mcp/constants/tool-recall.constant.d.ts +3 -0
  82. package/dist/src/shared/mcp/constants/tool-retrieve.constant.d.ts +3 -0
  83. package/dist/src/shared/mcp/constants/tool-search.constant.d.ts +3 -0
  84. package/dist/src/shared/mcp/constants/tool-skill-delete.constant.d.ts +3 -0
  85. package/dist/src/shared/mcp/constants/tool-skill-get.constant.d.ts +3 -0
  86. package/dist/src/shared/mcp/constants/tool-skill-learn.constant.d.ts +3 -0
  87. package/dist/src/shared/mcp/constants/tool-skill-list.constant.d.ts +3 -0
  88. package/dist/src/shared/mcp/constants/tool-status.constant.d.ts +3 -0
  89. package/dist/src/shared/mcp/constants/tool-unlearn.constant.d.ts +3 -0
  90. package/dist/src/shared/mcp/functions/as-boolean-or-undefined.function.d.ts +7 -0
  91. package/dist/src/shared/mcp/functions/as-string-array-or-undefined.function.d.ts +7 -0
  92. package/dist/src/shared/mcp/functions/as-string-array.function.d.ts +7 -0
  93. package/dist/src/shared/mcp/functions/as-string.function.d.ts +8 -0
  94. package/dist/src/shared/mcp/functions/build-skills-text.function.d.ts +18 -0
  95. package/dist/src/shared/mcp/functions/handle-agent-prompt.function.d.ts +14 -0
  96. package/dist/src/shared/mcp/functions/handle-mcp-request.function.d.ts +14 -0
  97. package/dist/src/shared/mcp/functions/handle-prompt-get.function.d.ts +4 -3
  98. package/dist/src/shared/mcp/functions/handle-skill-prompt.function.d.ts +16 -0
  99. package/dist/src/shared/mcp/functions/handle-tool-auto-capture-review.function.d.ts +12 -0
  100. package/dist/src/shared/mcp/functions/handle-tool-check.function.d.ts +11 -0
  101. package/dist/src/shared/mcp/functions/handle-tool-content.function.d.ts +12 -0
  102. package/dist/src/shared/mcp/functions/handle-tool-export.function.d.ts +12 -0
  103. package/dist/src/shared/mcp/functions/handle-tool-gc.function.d.ts +11 -0
  104. package/dist/src/shared/mcp/functions/handle-tool-learn.function.d.ts +12 -0
  105. package/dist/src/shared/mcp/functions/handle-tool-rebuild.function.d.ts +11 -0
  106. package/dist/src/shared/mcp/functions/handle-tool-retrieve.function.d.ts +12 -0
  107. package/dist/src/shared/mcp/functions/handle-tool-search.function.d.ts +13 -0
  108. package/dist/src/shared/mcp/functions/handle-tool-skill-delete.function.d.ts +12 -0
  109. package/dist/src/shared/mcp/functions/handle-tool-skill-get.function.d.ts +13 -0
  110. package/dist/src/shared/mcp/functions/handle-tool-skill-learn.function.d.ts +13 -0
  111. package/dist/src/shared/mcp/functions/handle-tool-skill-list.function.d.ts +11 -0
  112. package/dist/src/shared/mcp/functions/handle-tool-status.function.d.ts +11 -0
  113. package/dist/src/shared/mcp/functions/handle-tool-unlearn.function.d.ts +12 -0
  114. package/dist/src/shared/mcp/functions/parse-agent-meta.function.d.ts +14 -0
  115. package/dist/src/shared/mcp/functions/parse-skill-arguments.function.d.ts +11 -0
  116. package/dist/src/shared/mcp/functions/read-agent-meta.function.d.ts +17 -0
  117. package/dist/src/shared/mcp/functions/resolve-skill-refs.function.d.ts +23 -0
  118. package/dist/src/shared/mcp/functions/run-startup-health-check.function.d.ts +14 -0
  119. package/dist/src/shared/mcp/typings/mcp-capabilities.interface.d.ts +16 -0
  120. package/dist/src/shared/mcp/typings/mcp-client.interface.d.ts +2 -0
  121. package/dist/src/shared/mcp/typings/mcp-completion.interface.d.ts +43 -0
  122. package/dist/src/shared/mcp/typings/mcp-content-result.model.d.ts +9 -0
  123. package/dist/src/shared/mcp/typings/mcp-export-result.model.d.ts +11 -0
  124. package/dist/src/shared/mcp/typings/mcp-gc-result.model.d.ts +15 -0
  125. package/dist/src/shared/mcp/typings/mcp-integrity-check-result.model.d.ts +16 -0
  126. package/dist/src/shared/mcp/typings/mcp-integrity-error.model.d.ts +9 -0
  127. package/dist/src/shared/mcp/typings/mcp-notification.interface.d.ts +9 -0
  128. package/dist/src/shared/mcp/typings/mcp-rebuild-result.model.d.ts +9 -0
  129. package/dist/src/shared/mcp/typings/mcp-request.interface.d.ts +11 -0
  130. package/dist/src/shared/mcp/typings/mcp-resource-result.interface.d.ts +12 -0
  131. package/dist/src/shared/mcp/typings/mcp-resource-template.interface.d.ts +11 -0
  132. package/dist/src/shared/mcp/typings/mcp-response.interface.d.ts +18 -0
  133. package/dist/src/shared/mcp/typings/mcp-server-info.interface.d.ts +7 -0
  134. package/dist/src/shared/mcp/typings/mcp-server-state.interface.d.ts +16 -0
  135. package/dist/src/shared/mcp/typings/mcp-tool-annotations.interface.d.ts +32 -0
  136. package/dist/src/shared/mcp/typings/mcp-tool-definition.interface.d.ts +15 -0
  137. package/dist/src/shared/mcp/typings/mcp-tool-result.interface.d.ts +19 -0
  138. package/dist/src/shared/mcp/typings/mcp-worker-client.interface.d.ts +220 -0
  139. package/dist/src/shared/mcp/typings/tool-call-result.model.d.ts +17 -0
  140. package/dist/src/shared/sync/functions/build-import-report.function.d.ts +18 -0
  141. package/dist/src/shared/sync/functions/parse-export-entry.function.d.ts +11 -0
  142. package/dist/src/shared/sync/functions/resolve-conflict.function.d.ts +13 -0
  143. package/dist/src/shared/sync/functions/serialize-export-entry.function.d.ts +8 -0
  144. package/dist/src/shared/sync/index.d.ts +9 -0
  145. package/dist/src/shared/sync/typings/conflict-resolution.type.d.ts +8 -0
  146. package/dist/src/shared/sync/typings/export-entry.interface.d.ts +13 -0
  147. package/dist/src/shared/sync/typings/export-options.interface.d.ts +9 -0
  148. package/dist/src/shared/sync/typings/import-options.interface.d.ts +7 -0
  149. package/dist/src/shared/sync/typings/import-report.interface.d.ts +15 -0
  150. package/dist/src/shared/wasm-codec/functions/decode-one-recall-result.function.d.ts +14 -0
  151. package/dist/src/shared/wasm-codec/functions/decode-option-string.function.d.ts +12 -0
  152. package/dist/src/shared/wasm-codec/functions/decode-recall-document.function.d.ts +14 -0
  153. package/dist/src/shared/wasm-codec/functions/decode-recall-reference.function.d.ts +14 -0
  154. package/dist/src/shared/wasm-codec/functions/decode-recall-sibling.function.d.ts +13 -0
  155. package/dist/src/shared/wasm-codec/functions/decode-section-match.function.d.ts +15 -0
  156. package/dist/src/shared/wasm-codec/functions/decode-section-record-trailing.function.d.ts +14 -0
  157. package/dist/src/shared/wasm-codec/functions/decode-section-record.function.d.ts +14 -0
  158. package/dist/src/shared/wasm-codec/functions/decode-section-type.function.d.ts +13 -0
  159. package/dist/src/shared/wasm-codec/functions/decode-wasm-list.function.d.ts +17 -0
  160. package/dist/src/shared/wasm-codec/typings/add-section-input.model.d.ts +45 -0
  161. package/dist/src/shared/wasm-codec/typings/add-section-result.model.d.ts +27 -0
  162. package/dist/src/shared/wasm-codec/typings/document-manifest.model.d.ts +19 -0
  163. package/dist/src/shared/wasm-codec/typings/document-section.model.d.ts +12 -0
  164. package/dist/src/shared/wasm-codec/typings/item-decoder.type.d.ts +6 -0
  165. package/dist/src/shared/wasm-codec/typings/near-duplicate.model.d.ts +16 -0
  166. package/dist/src/shared/wasm-codec/typings/paged-search-result.model.d.ts +21 -0
  167. package/dist/src/shared/wasm-codec/typings/section-match.model.d.ts +31 -0
  168. package/dist/src/shared/wasm-codec/typings/section-record-trailing.model.d.ts +38 -0
  169. package/dist/src/shared/wasm-codec/typings/section-record.model.d.ts +66 -0
  170. package/dist/src/shared/wasm-codec/typings/section-type-result.model.d.ts +12 -0
  171. package/dist/src/shared/worker-client/functions/handle-ipc-data.function.d.ts +16 -0
  172. package/dist/src/shared/worker-client/functions/send-ipc-request.function.d.ts +19 -0
  173. package/dist/src/shared/worker-client/typings/add-section-result.model.d.ts +2 -0
  174. package/dist/src/shared/worker-client/typings/json-rpc-response.interface.d.ts +16 -0
  175. package/dist/src/shared/worker-client/typings/pending-call.interface.d.ts +7 -0
  176. package/dist/src/shared/worker-client/typings/recall-document.model.d.ts +16 -0
  177. package/dist/src/shared/worker-client/typings/recall-params.model.d.ts +15 -0
  178. package/dist/src/shared/worker-client/typings/recall-reference.model.d.ts +32 -0
  179. package/dist/src/shared/worker-client/typings/recall-sibling.model.d.ts +11 -0
  180. package/dist/src/shared/worker-client/typings/recall-single-result.model.d.ts +40 -0
  181. package/dist/src/shared/worker-daemon/classes/ipc-error.class.d.ts +17 -0
  182. package/dist/src/shared/worker-daemon/constants/wasm-method-map.constant.d.ts +16 -0
  183. package/dist/src/shared/worker-daemon/functions/build-ipc-error-response.function.d.ts +9 -0
  184. package/dist/src/shared/worker-daemon/functions/check-catalog-version.function.d.ts +9 -0
  185. package/dist/src/shared/worker-daemon/functions/check-preconditions.function.d.ts +10 -0
  186. package/dist/src/shared/worker-daemon/functions/detect-stale-pid.function.d.ts +15 -0
  187. package/dist/src/shared/worker-daemon/functions/dispatch-request.function.d.ts +35 -0
  188. package/dist/src/shared/worker-daemon/functions/handle-check-version.function.d.ts +23 -0
  189. package/dist/src/shared/worker-daemon/functions/handle-config-method.function.d.ts +11 -0
  190. package/dist/src/shared/worker-daemon/functions/handle-read-ops.function.d.ts +52 -0
  191. package/dist/src/shared/worker-daemon/functions/handle-write-ops.function.d.ts +44 -0
  192. package/dist/src/shared/worker-daemon/functions/parse-auto-capture-section.function.d.ts +14 -0
  193. package/dist/src/shared/worker-daemon/functions/parse-catalog-version.function.d.ts +10 -0
  194. package/dist/src/shared/worker-daemon/functions/parse-embedding-section.function.d.ts +13 -0
  195. package/dist/src/shared/worker-daemon/functions/parse-worker-toml.function.d.ts +11 -0
  196. package/dist/src/shared/worker-daemon/functions/run-startup-integrity-check.function.d.ts +18 -0
  197. package/dist/src/shared/worker-daemon/functions/scan-near-duplicates.function.d.ts +21 -0
  198. package/dist/src/shared/worker-daemon/functions/wasm-bridge.function.d.ts +51 -0
  199. package/dist/src/shared/worker-daemon/functions/wasm-memory-helpers.function.d.ts +22 -0
  200. package/dist/src/shared/worker-daemon/functions/write-lock.function.d.ts +32 -0
  201. package/dist/src/shared/worker-daemon/typings/allocator-ref.interface.d.ts +16 -0
  202. package/dist/src/shared/worker-daemon/typings/daemon-config.interface.d.ts +6 -0
  203. package/dist/src/shared/worker-daemon/typings/fs-adapter.interface.d.ts +22 -0
  204. package/dist/src/shared/worker-daemon/typings/handler-context.interface.d.ts +18 -0
  205. package/dist/src/shared/worker-daemon/typings/memory-ref.interface.d.ts +13 -0
  206. package/dist/src/shared/worker-daemon/typings/wasm-fn.type.d.ts +2 -0
  207. package/dist/src/shared/worker-daemon/typings/write-lock.interface.d.ts +15 -0
  208. package/dist/wasm/fs-database/kbdb_fs_database_bg.wasm +0 -0
  209. package/dist/wasm/kb-worker/kbdb_worker_bg.wasm +0 -0
  210. package/docs/details/cli.md +9 -0
  211. package/docs/details/mcp-server.md +5 -3
  212. package/docs/details/search-and-ranking.md +55 -0
  213. package/docs/goals/auto-capture.md +378 -0
  214. package/docs/goals/benchmarking.md +296 -0
  215. package/docs/goals/concurrency.md +259 -0
  216. package/docs/goals/hybrid-search.md +436 -0
  217. package/docs/goals/semantic-dedup.md +229 -0
  218. package/docs/goals/sync.md +217 -0
  219. package/docs/modules/rust/fs-database/indexes/vectors.md +110 -0
  220. package/docs/modules/typescript/shared/auto-capture/module.md +73 -0
  221. package/docs/modules/typescript/shared/embedding/functions.md +94 -0
  222. package/docs/modules/typescript/shared/embedding/module.md +71 -0
  223. package/docs/modules/typescript/shared/embedding/typings.md +122 -0
  224. package/docs/overview.md +171 -167
  225. package/docs/release-notes/0.2.0.md +3 -3
  226. package/docs/release-notes/0.3.0.md +89 -0
  227. package/docs/release-notes/0.3.1.md +121 -0
  228. package/docs/release-notes/0.3.2.md +64 -0
  229. package/docs/release-notes/README.md +3 -0
  230. package/package.json +1 -1
  231. package/src/shared/auto-capture/classes/auto-capture-controller.class.ts +62 -0
  232. package/src/shared/auto-capture/constants/auto-capture-defaults.constant.ts +15 -0
  233. package/src/shared/auto-capture/functions/build-capture-prompt.function.ts +27 -0
  234. package/src/shared/auto-capture/functions/evaluate-trigger.function.ts +50 -0
  235. package/src/shared/auto-capture/index.ts +7 -0
  236. package/src/shared/auto-capture/typings/auto-capture-config.interface.ts +13 -0
  237. package/src/shared/auto-capture/typings/auto-capture-state.interface.ts +13 -0
  238. package/src/shared/auto-capture/typings/auto-capture-trigger.interface.ts +7 -0
  239. package/src/shared/cli/constants/global-help.constant.ts +73 -0
  240. package/src/shared/cli/constants/leaf-help.constant.ts +219 -0
  241. package/src/shared/cli/constants/memory-protocol-body.constant.ts +39 -0
  242. package/src/shared/cli/constants/query-guidance-body.constant.ts +37 -0
  243. package/src/shared/cli/constants/subcommand-help.constant.ts +195 -0
  244. package/src/shared/cli/functions/collect-files.function.ts +55 -0
  245. package/src/shared/cli/functions/compute-section-kbid.function.ts +49 -0
  246. package/src/shared/cli/functions/format-mcp-output.function.ts +41 -0
  247. package/src/shared/cli/functions/format-text-output.function.ts +42 -0
  248. package/src/shared/cli/functions/generate-group-help.function.ts +41 -0
  249. package/src/shared/cli/functions/handle-data-command.function.ts +67 -0
  250. package/src/shared/cli/functions/handle-mcp.function.ts +56 -0
  251. package/src/shared/cli/functions/handle-migrate.function.ts +64 -0
  252. package/src/shared/cli/functions/hydrate-search-previews.function.ts +29 -0
  253. package/src/shared/cli/functions/parse-args.function.ts +3 -0
  254. package/src/shared/cli/functions/resolve-skill-names.function.ts +43 -0
  255. package/src/shared/cli/functions/run-search.function.ts +2 -0
  256. package/src/shared/cli/functions/version-gate.function.ts +44 -0
  257. package/src/shared/cli/functions/wrap-command.function.ts +34 -0
  258. package/src/shared/cli/typings/agent-create-client.interface.ts +47 -0
  259. package/src/shared/cli/typings/agent-get-client.interface.ts +39 -0
  260. package/src/shared/cli/typings/check-client.interface.ts +66 -0
  261. package/src/shared/cli/typings/cli-deps.interface.ts +54 -0
  262. package/src/shared/cli/typings/cli-options.interface.ts +2 -0
  263. package/src/shared/cli/typings/disconnectable-client.interface.ts +29 -0
  264. package/src/shared/cli/typings/dispatch-client.type.ts +46 -0
  265. package/src/shared/cli/typings/learn-client.interface.ts +53 -0
  266. package/src/shared/cli/typings/learn-io.interface.ts +5 -0
  267. package/src/shared/cli/typings/search-client.interface.ts +73 -0
  268. package/src/shared/embedding/classes/null-embedding-provider.class.ts +29 -0
  269. package/src/shared/embedding/constants/near-duplicate-thresholds.constant.ts +17 -0
  270. package/src/shared/embedding/functions/build-vector-index.function.ts +79 -0
  271. package/src/shared/embedding/functions/cosine-similarity.function.ts +31 -0
  272. package/src/shared/embedding/functions/detect-near-duplicates.function.ts +69 -0
  273. package/src/shared/embedding/functions/jaccard-coefficient.function.ts +26 -0
  274. package/src/shared/embedding/functions/read-vector-index-meta.function.ts +44 -0
  275. package/src/shared/embedding/functions/rrf-fuse.function.ts +33 -0
  276. package/src/shared/embedding/functions/search-vectors.function.ts +59 -0
  277. package/src/shared/embedding/index.ts +20 -0
  278. package/src/shared/embedding/typings/embedding-config.interface.ts +23 -0
  279. package/src/shared/embedding/typings/embedding-provider.interface.ts +25 -0
  280. package/src/shared/embedding/typings/near-duplicate-candidate.model.ts +25 -0
  281. package/src/shared/embedding/typings/near-duplicate-result.model.ts +26 -0
  282. package/src/shared/embedding/typings/vector-index-entry.model.ts +13 -0
  283. package/src/shared/embedding/typings/vector-index-meta.model.ts +14 -0
  284. package/src/shared/embedding/typings/vector-search-result.model.ts +8 -0
  285. package/src/shared/mcp/classes/mcp-server.class.ts +6 -3
  286. package/src/shared/mcp/constants/tool-agent-create.constant.ts +39 -0
  287. package/src/shared/mcp/constants/tool-agent-delete.constant.ts +26 -0
  288. package/src/shared/mcp/constants/tool-agent-get.constant.ts +24 -0
  289. package/src/shared/mcp/constants/tool-agent-list.constant.ts +18 -0
  290. package/src/shared/mcp/constants/tool-auto-capture-review.constant.ts +32 -0
  291. package/src/shared/mcp/constants/tool-check.constant.ts +21 -0
  292. package/src/shared/mcp/constants/tool-content.constant.ts +29 -0
  293. package/src/shared/mcp/constants/tool-export.constant.ts +27 -0
  294. package/src/shared/mcp/constants/tool-gc.constant.ts +21 -0
  295. package/src/shared/mcp/constants/tool-learn.constant.ts +58 -0
  296. package/src/shared/mcp/constants/tool-rebuild.constant.ts +21 -0
  297. package/src/shared/mcp/constants/tool-recall.constant.ts +36 -0
  298. package/src/shared/mcp/constants/tool-retrieve.constant.ts +31 -0
  299. package/src/shared/mcp/constants/tool-search.constant.ts +51 -0
  300. package/src/shared/mcp/constants/tool-skill-delete.constant.ts +24 -0
  301. package/src/shared/mcp/constants/tool-skill-get.constant.ts +27 -0
  302. package/src/shared/mcp/constants/tool-skill-learn.constant.ts +37 -0
  303. package/src/shared/mcp/constants/tool-skill-list.constant.ts +18 -0
  304. package/src/shared/mcp/constants/tool-status.constant.ts +20 -0
  305. package/src/shared/mcp/constants/tool-unlearn.constant.ts +25 -0
  306. package/src/shared/mcp/functions/as-boolean-or-undefined.function.ts +11 -0
  307. package/src/shared/mcp/functions/as-string-array-or-undefined.function.ts +17 -0
  308. package/src/shared/mcp/functions/as-string-array.function.ts +15 -0
  309. package/src/shared/mcp/functions/as-string.function.ts +10 -0
  310. package/src/shared/mcp/functions/build-skills-text.function.ts +43 -0
  311. package/src/shared/mcp/functions/create-tool-definitions.function.ts +28 -0
  312. package/src/shared/mcp/functions/handle-agent-create.function.ts +1 -1
  313. package/src/shared/mcp/functions/handle-agent-prompt.function.ts +68 -0
  314. package/src/shared/mcp/functions/handle-mcp-request.function.ts +202 -0
  315. package/src/shared/mcp/functions/handle-prompt-get.function.ts +18 -12
  316. package/src/shared/mcp/functions/handle-skill-prompt.function.ts +44 -0
  317. package/src/shared/mcp/functions/handle-tool-auto-capture-review.function.ts +24 -0
  318. package/src/shared/mcp/functions/handle-tool-call.function.ts +18 -0
  319. package/src/shared/mcp/functions/handle-tool-check.function.ts +21 -0
  320. package/src/shared/mcp/functions/handle-tool-content.function.ts +23 -0
  321. package/src/shared/mcp/functions/handle-tool-export.function.ts +25 -0
  322. package/src/shared/mcp/functions/handle-tool-gc.function.ts +21 -0
  323. package/src/shared/mcp/functions/handle-tool-learn.function.ts +69 -0
  324. package/src/shared/mcp/functions/handle-tool-rebuild.function.ts +21 -0
  325. package/src/shared/mcp/functions/handle-tool-retrieve.function.ts +40 -0
  326. package/src/shared/mcp/functions/handle-tool-search.function.ts +47 -0
  327. package/src/shared/mcp/functions/handle-tool-skill-delete.function.ts +34 -0
  328. package/src/shared/mcp/functions/handle-tool-skill-get.function.ts +59 -0
  329. package/src/shared/mcp/functions/handle-tool-skill-learn.function.ts +61 -0
  330. package/src/shared/mcp/functions/handle-tool-skill-list.function.ts +39 -0
  331. package/src/shared/mcp/functions/handle-tool-status.function.ts +21 -0
  332. package/src/shared/mcp/functions/handle-tool-unlearn.function.ts +24 -0
  333. package/src/shared/mcp/functions/parse-agent-meta.function.ts +27 -0
  334. package/src/shared/mcp/functions/parse-skill-arguments.function.ts +36 -0
  335. package/src/shared/mcp/functions/read-agent-meta.function.ts +41 -0
  336. package/src/shared/mcp/functions/resolve-skill-refs.function.ts +50 -0
  337. package/src/shared/mcp/functions/run-startup-health-check.function.ts +34 -0
  338. package/src/shared/mcp/typings/mcp-capabilities.interface.ts +16 -0
  339. package/src/shared/mcp/typings/mcp-client.interface.ts +2 -0
  340. package/src/shared/mcp/typings/mcp-completion.interface.ts +45 -0
  341. package/src/shared/mcp/typings/mcp-content-result.model.ts +9 -0
  342. package/src/shared/mcp/typings/mcp-export-result.model.ts +11 -0
  343. package/src/shared/mcp/typings/mcp-gc-result.model.ts +15 -0
  344. package/src/shared/mcp/typings/mcp-integrity-check-result.model.ts +17 -0
  345. package/src/shared/mcp/typings/mcp-integrity-error.model.ts +15 -0
  346. package/src/shared/mcp/typings/mcp-notification.interface.ts +9 -0
  347. package/src/shared/mcp/typings/mcp-rebuild-result.model.ts +9 -0
  348. package/src/shared/mcp/typings/mcp-request.interface.ts +11 -0
  349. package/src/shared/mcp/typings/mcp-resource-result.interface.ts +12 -0
  350. package/src/shared/mcp/typings/mcp-resource-template.interface.ts +11 -0
  351. package/src/shared/mcp/typings/mcp-response.interface.ts +18 -0
  352. package/src/shared/mcp/typings/mcp-server-info.interface.ts +7 -0
  353. package/src/shared/mcp/typings/mcp-server-state.interface.ts +17 -0
  354. package/src/shared/mcp/typings/mcp-tool-annotations.interface.ts +32 -0
  355. package/src/shared/mcp/typings/mcp-tool-definition.interface.ts +16 -0
  356. package/src/shared/mcp/typings/mcp-tool-result.interface.ts +19 -0
  357. package/src/shared/mcp/typings/mcp-worker-client.interface.ts +243 -0
  358. package/src/shared/mcp/typings/tool-call-result.model.ts +18 -0
  359. package/src/shared/sync/functions/build-import-report.function.ts +40 -0
  360. package/src/shared/sync/functions/parse-export-entry.function.ts +45 -0
  361. package/src/shared/sync/functions/resolve-conflict.function.ts +31 -0
  362. package/src/shared/sync/functions/serialize-export-entry.function.ts +18 -0
  363. package/src/shared/sync/index.ts +9 -0
  364. package/src/shared/sync/typings/conflict-resolution.type.ts +8 -0
  365. package/src/shared/sync/typings/export-entry.interface.ts +13 -0
  366. package/src/shared/sync/typings/export-options.interface.ts +9 -0
  367. package/src/shared/sync/typings/import-options.interface.ts +7 -0
  368. package/src/shared/sync/typings/import-report.interface.ts +15 -0
  369. package/src/shared/wasm-codec/functions/decode-one-recall-result.function.ts +86 -0
  370. package/src/shared/wasm-codec/functions/decode-option-string.function.ts +24 -0
  371. package/src/shared/wasm-codec/functions/decode-recall-document.function.ts +59 -0
  372. package/src/shared/wasm-codec/functions/decode-recall-reference.function.ts +52 -0
  373. package/src/shared/wasm-codec/functions/decode-recall-sibling.function.ts +43 -0
  374. package/src/shared/wasm-codec/functions/decode-section-match.function.ts +80 -0
  375. package/src/shared/wasm-codec/functions/decode-section-record-trailing.function.ts +75 -0
  376. package/src/shared/wasm-codec/functions/decode-section-record.function.ts +85 -0
  377. package/src/shared/wasm-codec/functions/decode-section-type.function.ts +30 -0
  378. package/src/shared/wasm-codec/functions/decode-wasm-list.function.ts +31 -0
  379. package/src/shared/wasm-codec/typings/add-section-input.model.ts +45 -0
  380. package/src/shared/wasm-codec/typings/add-section-result.model.ts +28 -0
  381. package/src/shared/wasm-codec/typings/document-manifest.model.ts +20 -0
  382. package/src/shared/wasm-codec/typings/document-section.model.ts +12 -0
  383. package/src/shared/wasm-codec/typings/item-decoder.type.ts +10 -0
  384. package/src/shared/wasm-codec/typings/near-duplicate.model.ts +16 -0
  385. package/src/shared/wasm-codec/typings/paged-search-result.model.ts +22 -0
  386. package/src/shared/wasm-codec/typings/section-match.model.ts +31 -0
  387. package/src/shared/wasm-codec/typings/section-record-trailing.model.ts +38 -0
  388. package/src/shared/wasm-codec/typings/section-record.model.ts +66 -0
  389. package/src/shared/wasm-codec/typings/section-type-result.model.ts +12 -0
  390. package/src/shared/worker-client/functions/handle-ipc-data.function.ts +49 -0
  391. package/src/shared/worker-client/functions/send-ipc-request.function.ts +39 -0
  392. package/src/shared/worker-client/typings/add-section-result.model.ts +2 -0
  393. package/src/shared/worker-client/typings/json-rpc-response.interface.ts +17 -0
  394. package/src/shared/worker-client/typings/pending-call.interface.ts +7 -0
  395. package/src/shared/worker-client/typings/recall-document.model.ts +16 -0
  396. package/src/shared/worker-client/typings/recall-params.model.ts +15 -0
  397. package/src/shared/worker-client/typings/recall-reference.model.ts +32 -0
  398. package/src/shared/worker-client/typings/recall-sibling.model.ts +11 -0
  399. package/src/shared/worker-client/typings/recall-single-result.model.ts +41 -0
  400. package/src/shared/worker-daemon/classes/ipc-error.class.ts +22 -0
  401. package/src/shared/worker-daemon/constants/wasm-method-map.constant.ts +69 -0
  402. package/src/shared/worker-daemon/functions/build-ipc-error-response.function.ts +16 -0
  403. package/src/shared/worker-daemon/functions/check-catalog-version.function.ts +54 -0
  404. package/src/shared/worker-daemon/functions/check-preconditions.function.ts +28 -0
  405. package/src/shared/worker-daemon/functions/detect-stale-pid.function.ts +33 -0
  406. package/src/shared/worker-daemon/functions/dispatch-request.function.ts +190 -0
  407. package/src/shared/worker-daemon/functions/handle-check-version.function.ts +74 -0
  408. package/src/shared/worker-daemon/functions/handle-config-method.function.ts +27 -0
  409. package/src/shared/worker-daemon/functions/handle-read-ops.function.ts +236 -0
  410. package/src/shared/worker-daemon/functions/handle-write-ops.function.ts +257 -0
  411. package/src/shared/worker-daemon/functions/parse-auto-capture-section.function.ts +51 -0
  412. package/src/shared/worker-daemon/functions/parse-catalog-version.function.ts +20 -0
  413. package/src/shared/worker-daemon/functions/parse-embedding-section.function.ts +38 -0
  414. package/src/shared/worker-daemon/functions/parse-worker-toml.function.ts +104 -0
  415. package/src/shared/worker-daemon/functions/run-startup-integrity-check.function.ts +55 -0
  416. package/src/shared/worker-daemon/functions/scan-near-duplicates.function.ts +92 -0
  417. package/src/shared/worker-daemon/functions/wasm-bridge.function.ts +144 -0
  418. package/src/shared/worker-daemon/functions/wasm-memory-helpers.function.ts +41 -0
  419. package/src/shared/worker-daemon/functions/write-lock.function.ts +49 -0
  420. package/src/shared/worker-daemon/typings/allocator-ref.interface.ts +16 -0
  421. package/src/shared/worker-daemon/typings/daemon-config.interface.ts +7 -0
  422. package/src/shared/worker-daemon/typings/fs-adapter.interface.ts +22 -0
  423. package/src/shared/worker-daemon/typings/handler-context.interface.ts +19 -0
  424. package/src/shared/worker-daemon/typings/memory-ref.interface.ts +13 -0
  425. package/src/shared/worker-daemon/typings/wasm-fn.type.ts +2 -0
  426. package/src/shared/worker-daemon/typings/write-lock.interface.ts +13 -0
  427. package/src/wasm/fs-database/kbdb_fs_database_bg.wasm +0 -0
  428. package/src/wasm/kb-worker/kbdb_worker_bg.wasm +0 -0
@@ -0,0 +1,259 @@
1
+ # Concurrent Write Safety
2
+
3
+ *One writer at a time, unlimited concurrent readers --
4
+ formalizing the locking model, multi-daemon prevention,
5
+ crash recovery, and stress-test methodology.*
6
+
7
+ ## Goal
8
+
9
+ The worker daemon serializes all write operations
10
+ through a single-writer lock. Multiple concurrent
11
+ readers proceed without any lock. This document
12
+ formalizes the locking model, multi-daemon prevention,
13
+ atomic write guarantees, crash recovery, and
14
+ stress-test methodology.
15
+
16
+ This goal addresses gap #3 from the issue
17
+ [2026-06-23 Opus 4.8 Second Brain Review](../issues/2026-06-23-opus-48-second-brain-review.md):
18
+ the single-writer lock in the worker daemon must be
19
+ validated under concurrent load before concurrent
20
+ multi-agent use can be trusted.
21
+
22
+ ## Single-Writer Lock
23
+
24
+ The daemon acquires an exclusive file lock on
25
+ `kbdb-{ctx}.lock` in the OS temporary directory during
26
+ write operations. The lock file uses the same context
27
+ ID as the PID file and IPC socket (see
28
+ [Worker Daemon](worker-daemon.md) for context ID
29
+ derivation).
30
+
31
+ - **Read operations** -- search, recall, retrieve,
32
+ content, dbStatus, and listByType -- proceed without
33
+ acquiring the lock. Concurrent read requests from
34
+ multiple worker client connections are fully parallel.
35
+ - **Write operations** -- addSection, updateSection,
36
+ removeSection, groupSections, removeGrouping,
37
+ initDirectory, gc, rebuildIndexes, and export --
38
+ acquire the exclusive lock before calling the
39
+ corresponding WASM export. If another write is
40
+ already in progress, the new write queues behind the
41
+ lock and waits.
42
+ - The lock is held only for the duration of a single
43
+ write operation. It is released immediately after
44
+ the operation completes. It is never held across
45
+ multiple operations or across client connections.
46
+ - The locking model is implemented in TypeScript inside
47
+ the worker daemon (`src/shared/worker-daemon/`), not
48
+ inside any WASM module.
49
+
50
+ This model is equivalent to SQLite's default locking:
51
+ readers never block, and writers take turns one at a
52
+ time.
53
+
54
+ ### Write Operations Subject to the Lock
55
+
56
+ | IPC Method | WASM Export |
57
+ |--------------------------|----------------------------|
58
+ | `addSection` | `worker_add_section` |
59
+ | `updateSection` | `worker_update_section` |
60
+ | `removeSection` | `worker_remove_section` |
61
+ | `groupSections` | `worker_group_sections` |
62
+ | `removeGrouping` | `worker_remove_grouping` |
63
+ | `initDirectory` | `worker_init_directory` |
64
+ | `gc` | `worker_garbage_collect` |
65
+ | `rebuildIndexes` | `worker_rebuild_indexes` |
66
+ | `export` | `db_export` |
67
+
68
+ ## Multi-Daemon Prevention
69
+
70
+ Each database context gets exactly one daemon process
71
+ at a time, enforced by a PID file keyed to the context
72
+ ID.
73
+
74
+ - The PID file is named `kbdb-{ctx}.pid` and lives in
75
+ the OS temporary directory. Its presence means a
76
+ daemon for that context is either running or died
77
+ without cleaning up.
78
+ - Before spawning a new daemon, the worker client reads
79
+ the PID file (if present) and checks whether the
80
+ recorded process is alive.
81
+ - **PID file absent** -- no running daemon; spawn a
82
+ new one.
83
+ - **PID file present, process alive** -- connect to
84
+ the existing daemon; do not spawn.
85
+ - **PID file present, process dead** -- stale PID
86
+ file from a prior crash; remove the file and spawn
87
+ a new daemon.
88
+ - The daemon writes its PID file only after all startup
89
+ preconditions pass and the WASM module is loaded
90
+ successfully. See [Worker Daemon](worker-daemon.md)
91
+ for the full startup sequence.
92
+ - On graceful shutdown, the daemon removes its PID
93
+ file before exiting.
94
+
95
+ This protocol ensures that the same database directory
96
+ is never served by two concurrent daemon processes.
97
+
98
+ ## Atomic Write Guarantees
99
+
100
+ All file writes in the database use the atomic
101
+ write pattern: content is written to a temporary file
102
+ first, then the temporary file is renamed to the final
103
+ path. Rename is an atomic operation on all supported
104
+ filesystems (POSIX and Windows NTFS).
105
+
106
+ - **Section files** (`sections/{prefix}/{kbid}.sec`)
107
+ are written to `sections/{prefix}/{kbid}.sec.tmp`
108
+ then renamed.
109
+ - **Document manifests** (`documents/{docid}.toml`)
110
+ are written to `documents/{docid}.toml.tmp` then
111
+ renamed.
112
+ - **Index files** (`indexes/terms.idx`, etc.) are
113
+ rebuilt to temporary paths then renamed into place.
114
+ - **Catalog** (`catalog.toml`) is written last,
115
+ after all data files are in place. A crash
116
+ before the catalog rename leaves the catalog
117
+ consistent with the previous complete state.
118
+
119
+ If the daemon crashes mid-write, the temporary file
120
+ is orphaned but the original file is intact. On next
121
+ daemon startup, orphaned temporary files (matching
122
+ `*.tmp`) in the database directory are cleaned up.
123
+
124
+ The atomic write pattern is specified in
125
+ [Database](database.md) under Storage Design.
126
+
127
+ ## Crash Recovery
128
+
129
+ The table below describes every identified failure
130
+ scenario, the resulting disk state, and the recovery
131
+ action.
132
+
133
+ | Scenario | State After Crash | Recovery |
134
+ |---|---|---|
135
+ | Crash during section write | `*.sec.tmp` orphaned, original `.sec` intact | Startup cleans `*.tmp` files |
136
+ | Crash during index rebuild | Partial `*.idx.tmp`, originals intact | Startup cleans `*.tmp`; next `rebuildIndexes` overwrites |
137
+ | Crash during GC | Some unreferenced sections deleted, others not | Re-run `gc`; idempotent |
138
+ | Crash during catalog write | `catalog.toml.tmp` orphaned, original intact | Startup cleans `*.tmp` |
139
+ | PID file not removed | Stale `kbdb-{ctx}.pid` on disk | Worker client detects dead process, removes PID, spawns new daemon |
140
+ | Lock file not released | `kbdb-{ctx}.lock` orphaned | Daemon startup acquires the exclusive lock fresh; OS releases orphaned file locks when the process that held them exits |
141
+ | WASM crash inside write | Partial in-memory state, temp file may exist | Daemon exits; startup cleans `*.tmp`; next operation starts clean |
142
+
143
+ All recovery actions are automatic. No manual
144
+ intervention is required for any scenario in this
145
+ table.
146
+
147
+ ## Stress Test Specification
148
+
149
+ The following test harness validates concurrent write
150
+ safety. It must pass on both Deno and Node.js runtimes
151
+ before a release can claim concurrent safety.
152
+
153
+ ### Setup
154
+
155
+ 1. Create a fresh, empty database directory.
156
+ 2. Prepare N unique documents (N in the range 10--50).
157
+ Each document must have distinct content to avoid
158
+ content-address collisions that would make section
159
+ count verification meaningless.
160
+
161
+ ### Execution
162
+
163
+ 3. Launch N concurrent `kbdb learn` invocations, all
164
+ targeting the same database directory. Each
165
+ invocation learns one of the N unique documents.
166
+ 4. Use a process pool or parallel shell to launch all
167
+ N invocations simultaneously -- not sequentially.
168
+ 5. Wait for all N invocations to complete. Record any
169
+ non-zero exit codes as failures.
170
+
171
+ ### Verification
172
+
173
+ 6. Run `kbdb check` against the database.
174
+ The response must have `ok: true`. Any errors in the
175
+ response are test failures.
176
+ 7. Query the section count. The count must equal the
177
+ expected number of sections derived from the N
178
+ documents (no duplicates from race conditions, no
179
+ losses from interleaved writes).
180
+ 8. Verify that no section has a checksum mismatch.
181
+ A mismatch indicates a torn write -- the atomic
182
+ rename pattern failed or was bypassed.
183
+
184
+ ### Pass Criteria
185
+
186
+ | Check | Expected Result |
187
+ |---|---|
188
+ | All `kbdb learn` exit codes | `0` |
189
+ | `kbdb check` response | `ok: true`, zero errors |
190
+ | Section count | Exactly the expected count |
191
+ | Checksum mismatches | Zero |
192
+
193
+ ### Runtime Matrix
194
+
195
+ Run the full harness on both runtimes:
196
+
197
+ | Runtime | Command prefix |
198
+ |---|---|
199
+ | Node.js >= 20 | `node dist/kbdb.mjs` |
200
+ | Deno | `deno run --allow-all src/cli.ts` |
201
+
202
+ Both must pass. A failure on one runtime but not the
203
+ other indicates a runtime-specific locking bug.
204
+
205
+ ## Edge Cases
206
+
207
+ ### Two CLI Invocations Through the Same Daemon
208
+
209
+ When two `kbdb` CLI processes connect to the same
210
+ daemon (same database directory), their write requests
211
+ share the single-writer lock automatically. No user
212
+ action is required. The second write waits for the
213
+ first to complete.
214
+
215
+ ### MCP Server Connections
216
+
217
+ An MCP server connection routes all requests through
218
+ a worker client to the daemon, the same as a CLI
219
+ invocation. Multiple MCP client connections routed to
220
+ the same daemon share the write lock:
221
+
222
+ - Concurrent read requests from multiple MCP clients
223
+ are served in parallel.
224
+ - Concurrent write requests from multiple MCP clients
225
+ are serialized through the lock one at a time.
226
+
227
+ There is no per-connection or per-client lock; the
228
+ lock is global to the daemon process.
229
+
230
+ ### Direct File Access
231
+
232
+ Accessing or modifying `.kbdb` files directly -- via
233
+ text editor, shell commands, or any process other than
234
+ the daemon -- is not supported. Direct writes bypass
235
+ the single-writer lock and the atomic write pattern,
236
+ and may corrupt the database. All mutations must go
237
+ through the daemon's IPC API.
238
+
239
+ ## Design Constraints
240
+
241
+ - **Per-daemon locking, not per-file** -- The lock
242
+ covers all writes to a database context, not writes
243
+ to individual files. This means writes to unrelated
244
+ sections still serialize behind the same lock. The
245
+ simplicity of a single lock outweighs the throughput
246
+ cost at current scale. If per-section parallelism
247
+ becomes necessary, this constraint is the place to
248
+ revisit.
249
+ - **Single-machine only** -- The locking model
250
+ relies on OS-level file locks and process identity
251
+ on a single machine. It provides no guarantees across
252
+ network filesystems or multiple machines. Cross-machine
253
+ scenarios require an external sync mechanism (see
254
+ [Sync](sync.md) when available).
255
+ - **Lock implemented in TypeScript** -- The write lock
256
+ is managed by the TypeScript worker daemon layer, not
257
+ by any WASM module. WASM modules have no knowledge of
258
+ concurrent callers; they process one call at a time
259
+ through the host.
@@ -0,0 +1,436 @@
1
+ # Hybrid Search -- Lexical + Vector Retrieval
2
+
3
+ *Optional vector retrieval path alongside BM25F, fused
4
+ with RRF for best-of-both ranking.*
5
+
6
+ ## Goal
7
+
8
+ The current retrieval mode is lexical search: BM25F with
9
+ stemming and synonym expansion. It works well for
10
+ structured documentation where terminology is consistent
11
+ -- the agent searches "authentication" and the indexed
12
+ content uses the same word.
13
+
14
+ Lexical search has a ceiling, however. It misses
15
+ associative recall when terminology diverges between the
16
+ time content was stored and the time it is retrieved.
17
+ Example: an agent stores "we chose Postgres because of
18
+ JSONB" and later searches "database rationale" -- lexical
19
+ search misses it because none of the indexed tokens
20
+ (`postgres`, `chose`, `jsonb`) overlap with the query
21
+ tokens (`database`, `rationale`). Vector search finds
22
+ it because the embedding of the query is geometrically
23
+ close to the embedding of the stored sentence.
24
+
25
+ This gap is identified as the critical lexical-only
26
+ ceiling in
27
+ [Opus 4.8 Second Brain Review](../issues/2026-06-23-opus-48-second-brain-review.md)
28
+ (gap #1). Hybrid search closes it by adding an optional
29
+ vector retrieval path alongside the existing lexical
30
+ path, fusing both ranked lists using Reciprocal Rank
31
+ Fusion (RRF) for a final result set that benefits from
32
+ both modes.
33
+
34
+ ## Architecture
35
+
36
+ Two retrieval paths run in parallel. The vector path
37
+ runs entirely in TypeScript. No WASM code is added or
38
+ modified.
39
+
40
+ ```
41
+ Query → ┌─ Lexical path (WASM) ─→ BM25F ranked list ─┐
42
+ │ ├─→ RRF Fusion → Final results
43
+ └─ Vector path (TS) ─→ Cosine ranked list ──┘
44
+ ```
45
+
46
+ The WASM boundary is untouched. `query-parser.wasm`
47
+ remains a pure-computation lexical module. `kb-worker.wasm`
48
+ continues to orchestrate lexical retrieval via
49
+ `fs-database.wasm` exactly as today. No new WASM crate,
50
+ no new WASM export, and no new host import is needed for
51
+ the vector path.
52
+
53
+ The TypeScript daemon layer adds the vector path as an
54
+ independent retrieval step that runs after the lexical
55
+ path completes (or concurrently if the runtime allows).
56
+ The fused list is assembled in TypeScript before the
57
+ response is returned to the worker client.
58
+
59
+ ## EmbeddingProvider Interface
60
+
61
+ ### Why TypeScript, Not WASM
62
+
63
+ Three reasons embeddings are computed in TypeScript
64
+ rather than in WASM:
65
+
66
+ 1. `wasm32-unknown-unknown` has no network I/O. Calling
67
+ an embedding API from WASM is impossible without a
68
+ host bridge that would defeat the purpose of running
69
+ in WASM.
70
+ 2. Embedding models are too large for WASM. A typical
71
+ all-MiniLM-L6-v2 model is ~90 MB. Loading that inside
72
+ the WASM sandbox on every daemon startup is
73
+ impractical.
74
+ 3. TypeScript allows pluggable backends. An interface-based
75
+ design lets the daemon swap providers (local ONNX,
76
+ remote API) without changing any WASM code.
77
+
78
+ ### Interface Specification
79
+
80
+ ```typescript
81
+ interface EmbeddingProvider {
82
+ embed(texts: string[]): Promise<Float32Array[]>;
83
+ dimensions(): number;
84
+ modelName(): string;
85
+ }
86
+ ```
87
+
88
+ | Member | Description |
89
+ |--------------|----------------------------------------------|
90
+ | `embed` | Compute embeddings for a batch of input texts. Returns one `Float32Array` per input, each of length `dimensions()`. |
91
+ | `dimensions` | Fixed embedding dimensionality for this provider. All vectors stored under the same model must have this length. |
92
+ | `modelName` | Stable identifier for the model. Used for stale-detection when the configured model changes. |
93
+
94
+ ### Implementations
95
+
96
+ Three concrete implementations are specified.
97
+
98
+ **`NullEmbeddingProvider`** -- no-op, returns empty
99
+ arrays. The default when no `[embedding]` section is
100
+ present in `worker.toml`. Requesting `vector` or
101
+ `hybrid` search mode with this provider returns a
102
+ structured error rather than silently returning empty
103
+ results. Satisfies POLA: the absence of configuration
104
+ does not silently degrade results.
105
+
106
+ **`OnnxEmbeddingProvider`** -- local offline inference
107
+ using ONNX Runtime. Default model: `all-MiniLM-L6-v2`
108
+ (384 dimensions). The model file is downloaded on first
109
+ use and cached in the OS user-data directory. Works on
110
+ both Deno and Node.js >= 20. No network dependency
111
+ after the initial model download. Suitable for
112
+ air-gapped or cost-sensitive deployments.
113
+
114
+ **`ApiEmbeddingProvider`** -- calls an external HTTP
115
+ embedding API. Compatible with OpenAI, Anthropic, and
116
+ any endpoint that accepts a `POST /embeddings` request
117
+ with a JSON body `{ "input": string[] }` and returns
118
+ `{ "data": [{ "embedding": number[] }] }`. Configured
119
+ via `worker.toml`. The API key is read from an
120
+ environment variable named by `api_key_env`.
121
+
122
+ ## Vector Storage
123
+
124
+ ### New Index Files
125
+
126
+ Two new files are added to `indexes/` alongside the
127
+ existing index files. They follow the same rebuild
128
+ semantics as `terms.idx`, `positions.idx`, and
129
+ `corpus.dat`: derived data, rebuildable from section
130
+ content, excluded from version control.
131
+
132
+ **`vectors.idx`** -- binary, fixed-width records.
133
+
134
+ Header layout:
135
+
136
+ | Bytes | Field | Type | Description |
137
+ |-------|----------------|--------|-------------------------------|
138
+ | 0-3 | magic | u8[4] | `b"KBVX"` -- format sentinel |
139
+ | 4 | version | u8 | Format version, currently `1` |
140
+ | 5-6 | dimensions | u16 | Vector length per record |
141
+ | 7-10 | record_count | u32 | Total number of records |
142
+
143
+ Each record immediately follows the header:
144
+
145
+ | Bytes | Field | Type | Description |
146
+ |----------------|----------------|----------------|-------------------|
147
+ | 0-15 | kbid_hash | u8[16] | First 16 bytes of the section kbid, used as a compact lookup key |
148
+ | 16 onwards | embedding | f32[dimensions]| Raw embedding vector |
149
+
150
+ Record size = `16 + dimensions * 4` bytes. All records
151
+ are the same size, enabling O(1) offset computation by
152
+ record index and binary search by kbid hash.
153
+
154
+ **`vectors-meta.toml`** -- human-readable metadata.
155
+
156
+ ```toml
157
+ [vectors]
158
+ model_name = "all-MiniLM-L6-v2"
159
+ dimensions = 384
160
+ version = 1
161
+ last_built = "2026-06-23T10:00:00Z"
162
+ section_count = 2847
163
+ ```
164
+
165
+ | Field | Description |
166
+ |-----------------|-------------------------------------------|
167
+ | `model_name` | Model name from `EmbeddingProvider.modelName()`. Used for stale detection. |
168
+ | `dimensions` | Must match the `dimensions` header in `vectors.idx`. |
169
+ | `version` | `vectors.idx` format version. |
170
+ | `last_built` | ISO 8601 timestamp of the last rebuild. |
171
+ | `section_count` | Number of sections embedded. |
172
+
173
+ ### Updated Directory Layout
174
+
175
+ ```
176
+ .kbdb/
177
+ └── indexes/
178
+ ├── meta.toml
179
+ ├── terms.idx
180
+ ├── positions.idx
181
+ ├── corpus.dat
182
+ ├── references.idx
183
+ ├── vectors.idx # new -- binary embedding store
184
+ └── vectors-meta.toml # new -- embedding metadata
185
+ ```
186
+
187
+ ## Embedding Lifecycle
188
+
189
+ ### Learn Time
190
+
191
+ When a section is added via `kbdb learn`, the lexical
192
+ indexing pipeline runs first (unchanged). After lexical
193
+ indexing completes, the daemon asynchronously computes
194
+ an embedding for the section using the configured
195
+ `EmbeddingProvider`.
196
+
197
+ The embedding input is the concatenation of the
198
+ section's title and body content:
199
+
200
+ ```
201
+ {title}\n{content}
202
+ ```
203
+
204
+ The title is prepended because it carries strong
205
+ semantic weight (it receives a 2.0x BM25F field weight
206
+ for the same reason). Concatenating both fields gives
207
+ the embedding model the same semantic signal that BM25F
208
+ heading-weight gives to lexical scoring.
209
+
210
+ Sections with no body content (binary sections where
211
+ content is base64) embed only the title and
212
+ description. Sections with neither title nor body
213
+ content are not embedded.
214
+
215
+ Embedding is best-effort at learn time: if the provider
216
+ fails for a section, the section is still stored
217
+ lexically. A warning is emitted in the learn response
218
+ (`vector_embedding_failed: true`).
219
+
220
+ ### Rebuild
221
+
222
+ `kbdb rebuild` regenerates all vector embeddings from
223
+ section content alongside the existing lexical index
224
+ rebuild. Sections are embedded in batches of up to 64
225
+ to respect provider rate limits. The `vectors.idx` and
226
+ `vectors-meta.toml` files are written atomically after
227
+ all embeddings are computed.
228
+
229
+ ### Stale Detection
230
+
231
+ When the daemon starts, it reads `vectors-meta.toml`
232
+ and compares `model_name` to the currently configured
233
+ provider's `modelName()`. If they differ, the vector
234
+ index is marked stale. Stale vector indexes are not
235
+ used for retrieval. Search falls back to lexical-only
236
+ with a warning field in the response:
237
+ `vector_index_stale: true`.
238
+
239
+ The agent or operator must run `kbdb rebuild` to
240
+ regenerate vectors with the new model before hybrid or
241
+ vector search resumes.
242
+
243
+ ## Score Fusion
244
+
245
+ ### Reciprocal Rank Fusion (RRF)
246
+
247
+ RRF combines the lexical ranked list and the vector
248
+ ranked list into a single fused list without requiring
249
+ score normalization. BM25F scores and cosine similarity
250
+ scores live on different scales and cannot be directly
251
+ added -- RRF sidesteps this by working on ranks rather
252
+ than scores.
253
+
254
+ Formula:
255
+
256
+ ```
257
+ score(d) = 1/(k + rank_lexical(d)) + 1/(k + rank_vector(d))
258
+ ```
259
+
260
+ Where:
261
+
262
+ - `k = 60` (standard default, configurable via
263
+ `worker.toml` as `rrf_k`)
264
+ - `rank_lexical(d)` is the 1-based rank of document `d`
265
+ in the BM25F result list, or infinity if `d` does not
266
+ appear in the lexical results
267
+ - `rank_vector(d)` is the 1-based rank of document `d`
268
+ in the cosine similarity result list, or infinity if
269
+ `d` does not appear in the vector results
270
+ - A rank of infinity contributes 0 to the sum (since
271
+ `1/(k + ∞) = 0`)
272
+
273
+ Documents appearing in only one result set receive full
274
+ contribution from that set and zero from the other.
275
+ Documents appearing in both receive a higher combined
276
+ score than either path could produce alone, naturally
277
+ surfacing cross-path agreement.
278
+
279
+ The final result list is sorted by RRF score descending.
280
+
281
+ ### Why RRF
282
+
283
+ - Parameter-light: `k = 60` is the well-established
284
+ default from the original RRF paper (Cormack et al.,
285
+ 2009). It rarely needs tuning.
286
+ - No normalization: BM25F scores and cosine similarity
287
+ are not comparable in magnitude. RRF requires only
288
+ rank order, not the scores themselves.
289
+ - Robust: adding a low-quality second path cannot hurt
290
+ the top results badly because RRF dampens rank
291
+ contributions as `k` is approached.
292
+
293
+ ## Search Mode Parameter
294
+
295
+ A new `search_mode` parameter controls which retrieval
296
+ paths are active for a given search request.
297
+
298
+ | Value | Retrieval behaviour | Embedding provider required |
299
+ |------------|---------------------------------------------|-----------------------------|
300
+ | `lexical` | Lexical path only. Current behaviour. Default. | No |
301
+ | `vector` | Vector path only. Cosine similarity ranking. | Yes |
302
+ | `hybrid` | Both paths, RRF fusion. | Yes |
303
+
304
+ The default is `lexical`. Existing integrations that do
305
+ not supply `search_mode` are unchanged. This is a
306
+ strict backward-compatibility guarantee.
307
+
308
+ Requesting `vector` or `hybrid` when no embedding
309
+ provider is configured (i.e. `NullEmbeddingProvider` is
310
+ active) returns a structured error:
311
+
312
+ ```json
313
+ {
314
+ "error": "Vector search requires a configured embedding provider",
315
+ "code": "EMBEDDING_PROVIDER_NOT_CONFIGURED"
316
+ }
317
+ ```
318
+
319
+ ## CLI and MCP Surface
320
+
321
+ ### CLI
322
+
323
+ The `search` subcommand gains an optional `--mode` flag:
324
+
325
+ ```
326
+ kbdb search "database rationale"
327
+ kbdb search --mode hybrid "database rationale"
328
+ kbdb search --mode vector "database rationale"
329
+ ```
330
+
331
+ Omitting `--mode` defaults to `lexical`. The flag is
332
+ not shown in the short help unless an embedding provider
333
+ is configured.
334
+
335
+ ### MCP
336
+
337
+ The `search` MCP tool gains an optional `mode` parameter
338
+ (string enum: `"lexical" | "vector" | "hybrid"`). The
339
+ parameter is documented as optional in the tool schema
340
+ with a default of `"lexical"`.
341
+
342
+ ### Response Envelope
343
+
344
+ `PagedSearchResult` gains two new fields:
345
+
346
+ | Field | Type | Description |
347
+ |--------------------|--------|---------------------------------|
348
+ | `search_mode` | string | The mode that was requested: `"lexical"`, `"vector"`, or `"hybrid"` |
349
+ | `retrieval_method` | string | The mode that was actually used: `"lexical"`, `"vector"`, or `"hybrid"`. Differs from `search_mode` when a fallback occurred (e.g. stale vector index forced `"lexical"`). |
350
+
351
+ Both fields are always present in the response,
352
+ including when `search_mode` was not supplied (in which
353
+ case both fields are `"lexical"`).
354
+
355
+ ## Configuration
356
+
357
+ `worker.toml` gains an `[embedding]` section:
358
+
359
+ ```toml
360
+ [embedding]
361
+ provider = "onnx" # "onnx" | "api" | "none"
362
+ model = "all-MiniLM-L6-v2"
363
+ dimensions = 384
364
+ rrf_k = 60 # RRF parameter k
365
+
366
+ # API provider only:
367
+ api_url = ""
368
+ api_key_env = "KBDB_API_KEY"
369
+ ```
370
+
371
+ | Key | Default | Description |
372
+ |---------------|----------------------|------------------------------|
373
+ | `provider` | `"none"` | Which `EmbeddingProvider` implementation to use |
374
+ | `model` | `"all-MiniLM-L6-v2"` | Model name, passed to the provider |
375
+ | `dimensions` | `384` | Embedding vector length |
376
+ | `rrf_k` | `60` | RRF constant `k` |
377
+ | `api_url` | `""` | Base URL for API provider |
378
+ | `api_key_env` | `"KBDB_API_KEY"` | Environment variable holding the API key |
379
+
380
+ When `[embedding]` is absent from `worker.toml`,
381
+ `provider` defaults to `"none"` and `NullEmbeddingProvider`
382
+ is used.
383
+
384
+ ## Fallback Behaviour
385
+
386
+ Three fallback conditions are defined. Each is surfaced
387
+ in the search response with a specific warning field
388
+ rather than silently degrading.
389
+
390
+ **No embedding provider configured.**
391
+ `search_mode` defaults to `lexical`. Requesting `hybrid`
392
+ or `vector` returns a structured error with code
393
+ `EMBEDDING_PROVIDER_NOT_CONFIGURED`. No silent fallback
394
+ occurs -- the caller receives an actionable error
395
+ message.
396
+
397
+ **Stale vector index (model mismatch).**
398
+ When `vectors-meta.toml` model name does not match the
399
+ configured provider's `modelName()`, the daemon marks
400
+ the vector index stale. Any search request that would
401
+ use the vector path falls back to `lexical`. The
402
+ response includes `retrieval_method: "lexical"` and
403
+ `vector_index_stale: true`. The correct remediation is
404
+ `kbdb rebuild`.
405
+
406
+ **Embedding failure during learn.**
407
+ If the embedding provider returns an error for a section
408
+ during learn, the section is stored lexically without an
409
+ embedding. The learn response includes
410
+ `vector_embedding_failed: true`. The section will
411
+ appear in lexical results but not in vector or hybrid
412
+ results until a rebuild is run.
413
+
414
+ ## Provider Tradeoffs
415
+
416
+ | Aspect | ONNX (local) | API (cloud) |
417
+ |---------------|---------------------------|------------------------------|
418
+ | Latency | ~10 ms/embed | ~100 ms/embed |
419
+ | Offline | Yes | No |
420
+ | Cost | Free | Per-token |
421
+ | Quality | Good (384 dimensions) | Excellent (1536+ dimensions) |
422
+ | Setup | Model download on first use | API key required |
423
+ | Dual runtime | Deno + Node.js >= 20 | Deno + Node.js >= 20 |
424
+
425
+ Both providers implement the same `EmbeddingProvider`
426
+ interface. The daemon interacts only with the interface.
427
+
428
+ ## Design Constraints
429
+
430
+ | Constraint | Details |
431
+ |-----------------------|------------------------------------------------|
432
+ | WASM purity | `query-parser.wasm` remains pure lexical computation with no I/O. No new WASM crate or export is added. |
433
+ | Backward compatibility | Default `search_mode` is `lexical`. Callers that do not supply the parameter receive identical behaviour to today. |
434
+ | File-based storage | `vectors.idx` and `vectors-meta.toml` follow the same derived-and-rebuildable pattern as all other index files. |
435
+ | Dual runtime | `EmbeddingProvider` and all embedding logic must work on Deno and Node.js >= 20. No Node-specific or Deno-specific APIs in the implementation. |
436
+ | No new WASM deps | All new dependencies are TypeScript-side only. The WASM modules (`fs-database.wasm`, `query-parser.wasm`, `kb-worker.wasm`) are not recompiled for this feature. |