@dikolab/kbdb 0.5.0 → 0.6.1

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 (224) hide show
  1. package/CLA.md +68 -0
  2. package/LICENSE +676 -12
  3. package/LICENSING.md +58 -0
  4. package/README.md +50 -25
  5. package/README.md.bak +322 -0
  6. package/dist/README.md +322 -0
  7. package/dist/{chunk-BJXEVALU.mjs → chunk-QLJ33C74.mjs} +44 -44
  8. package/dist/chunk-QLJ33C74.mjs.map +7 -0
  9. package/dist/cli.cjs +550 -232
  10. package/dist/cli.cjs.map +4 -4
  11. package/dist/cli.d.ts +0 -8
  12. package/dist/cli.mjs +483 -154
  13. package/dist/cli.mjs.map +4 -4
  14. package/dist/kbdb-worker.cjs +36 -5
  15. package/dist/kbdb-worker.cjs.map +3 -3
  16. package/dist/mod.cjs +89 -30
  17. package/dist/mod.cjs.map +4 -4
  18. package/dist/mod.mjs +88 -30
  19. package/dist/mod.mjs.map +4 -4
  20. package/dist/src/cli.d.ts +0 -8
  21. package/dist/src/shared/cli/constants/defaults.constant.d.ts +1 -1
  22. package/dist/src/shared/cli/constants/recfile-command-field-map.constant.d.ts +8 -0
  23. package/dist/src/shared/cli/constants/recfile-field-maps.constant.d.ts +21 -0
  24. package/dist/src/shared/cli/functions/compute-directory-level.function.d.ts +14 -0
  25. package/dist/src/shared/cli/functions/dispatch-command.function.d.ts +2 -28
  26. package/dist/src/shared/cli/functions/format-command-output.function.d.ts +14 -0
  27. package/dist/src/shared/cli/functions/format-db-not-found.function.d.ts +20 -0
  28. package/dist/src/shared/cli/functions/format-output.function.d.ts +1 -0
  29. package/dist/src/shared/cli/functions/format-recfile-output.function.d.ts +11 -0
  30. package/dist/src/shared/cli/functions/render-recfile-value.function.d.ts +11 -0
  31. package/dist/src/shared/cli/functions/resolve-db-dir.function.d.ts +24 -0
  32. package/dist/src/shared/cli/functions/resolve-recfile-key.function.d.ts +9 -0
  33. package/dist/src/shared/cli/functions/run-db-path.function.d.ts +10 -0
  34. package/dist/src/shared/cli/functions/run-export.function.d.ts +8 -4
  35. package/dist/src/shared/cli/functions/run-import.function.d.ts +4 -0
  36. package/dist/src/shared/cli/functions/run-learn.function.d.ts +12 -0
  37. package/dist/src/shared/cli/index.d.ts +4 -1
  38. package/dist/src/shared/cli/typings/cli-options.interface.d.ts +9 -2
  39. package/dist/src/shared/cli/typings/db-resolution.interface.d.ts +9 -0
  40. package/dist/src/shared/cli/typings/recfile-field-map.type.d.ts +10 -0
  41. package/dist/src/shared/version/constants/version.constant.d.ts +1 -1
  42. package/dist/src/shared/wasm-codec/functions/decode-option-u8.function.d.ts +9 -0
  43. package/dist/src/shared/wasm-codec/functions/decode-section-records.function.d.ts +4 -0
  44. package/dist/src/shared/wasm-codec/functions/encode-add-section-params.function.d.ts +2 -45
  45. package/dist/src/shared/wasm-codec/functions/encode-update-section-params.function.d.ts +10 -1
  46. package/dist/src/shared/wasm-codec/index.d.ts +1 -1
  47. package/dist/src/shared/wasm-codec/typings/add-section-input.model.d.ts +6 -0
  48. package/dist/src/shared/wasm-codec/typings/section-record-trailing.model.d.ts +5 -0
  49. package/dist/src/shared/wasm-codec/typings/section-record.model.d.ts +5 -0
  50. package/dist/src/shared/worker-client/functions/build-deno-permissions.function.d.ts +11 -0
  51. package/dist/src/shared/worker-client/functions/read-crash-reason.function.d.ts +9 -0
  52. package/dist/src/shared/worker-client/functions/resolve-spawn-script.function.d.ts +6 -0
  53. package/dist/src/shared/worker-client/functions/spawn-daemon.function.d.ts +1 -1
  54. package/dist/src/shared/worker-client/typings/section.model.d.ts +5 -0
  55. package/dist/src/shared/worker-client/typings/worker-client-options.interface.d.ts +0 -6
  56. package/dist/src/shared/worker-daemon/functions/count-files.function.d.ts +12 -0
  57. package/dist/src/shared/worker-daemon/functions/handle-import.function.d.ts +2 -0
  58. package/dist/src/shared/worker-daemon/functions/handle-read-ops.function.d.ts +8 -0
  59. package/dist/src/shared/worker-daemon/functions/validate-daemon-path.function.d.ts +15 -0
  60. package/dist/src/worker.d.ts +0 -7
  61. package/dist/wasm/default-embedding/kbdb_default_embedding_bg.wasm +0 -0
  62. package/dist/wasm/default-embedding/package.json +1 -1
  63. package/dist/wasm/fs-database/kbdb_fs_database_bg.wasm +0 -0
  64. package/dist/wasm/fs-database/package.json +1 -1
  65. package/dist/wasm/fs-migration/package.json +1 -1
  66. package/dist/wasm/kb-worker/kbdb_worker_bg.wasm +0 -0
  67. package/dist/wasm/kb-worker/package.json +1 -1
  68. package/dist/wasm/query-parser/kbdb_query_parser_bg.wasm +0 -0
  69. package/dist/wasm/query-parser/package.json +1 -1
  70. package/dist/worker.d.ts +0 -7
  71. package/dist/worker.mjs +37 -6
  72. package/dist/worker.mjs.map +3 -3
  73. package/package.json +11 -10
  74. package/dist/chunk-BJXEVALU.mjs.map +0 -7
  75. package/dist/src/shared/cli/functions/resolve-raw-db-path.function.d.ts +0 -10
  76. package/docs/details/README.md +0 -30
  77. package/docs/details/agent-tooling.md +0 -132
  78. package/docs/details/cli.md +0 -777
  79. package/docs/details/knowledge-base.md +0 -180
  80. package/docs/details/library-api.md +0 -495
  81. package/docs/details/mcp-server.md +0 -482
  82. package/docs/details/search-and-ranking.md +0 -575
  83. package/docs/details/storage.md +0 -531
  84. package/docs/goals/agents.md +0 -751
  85. package/docs/goals/architecture.svg +0 -198
  86. package/docs/goals/auto-capture.md +0 -378
  87. package/docs/goals/benchmarking.md +0 -296
  88. package/docs/goals/cli.md +0 -2654
  89. package/docs/goals/concurrency.md +0 -259
  90. package/docs/goals/content-composer.md +0 -609
  91. package/docs/goals/content-parser.md +0 -279
  92. package/docs/goals/database.md +0 -1679
  93. package/docs/goals/document.md +0 -368
  94. package/docs/goals/hybrid-search.md +0 -465
  95. package/docs/goals/mcp.md +0 -1541
  96. package/docs/goals/overview.md +0 -124
  97. package/docs/goals/query-parser.md +0 -373
  98. package/docs/goals/query-result.md +0 -860
  99. package/docs/goals/semantic-dedup.md +0 -233
  100. package/docs/goals/skills.md +0 -810
  101. package/docs/goals/sync.md +0 -217
  102. package/docs/goals/worker-client.md +0 -1005
  103. package/docs/goals/worker-daemon.md +0 -1547
  104. package/docs/modules/overview.md +0 -319
  105. package/docs/modules/rust/embedding/module.md +0 -91
  106. package/docs/modules/rust/fs-database/functions/document.md +0 -48
  107. package/docs/modules/rust/fs-database/functions/integrity.md +0 -79
  108. package/docs/modules/rust/fs-database/functions/io.md +0 -87
  109. package/docs/modules/rust/fs-database/functions/module.md +0 -22
  110. package/docs/modules/rust/fs-database/functions/query-exec.md +0 -44
  111. package/docs/modules/rust/fs-database/functions/section.md +0 -76
  112. package/docs/modules/rust/fs-database/indexes/btree.md +0 -35
  113. package/docs/modules/rust/fs-database/indexes/corpus.md +0 -61
  114. package/docs/modules/rust/fs-database/indexes/inverted.md +0 -60
  115. package/docs/modules/rust/fs-database/indexes/module.md +0 -64
  116. package/docs/modules/rust/fs-database/indexes/positional.md +0 -39
  117. package/docs/modules/rust/fs-database/indexes/vectors.md +0 -110
  118. package/docs/modules/rust/fs-database/module.md +0 -150
  119. package/docs/modules/rust/fs-database/types/catalog.md +0 -53
  120. package/docs/modules/rust/fs-database/types/module.md +0 -12
  121. package/docs/modules/rust/fs-database/types/section.md +0 -127
  122. package/docs/modules/rust/kb-worker/functions/compose.md +0 -57
  123. package/docs/modules/rust/kb-worker/functions/module.md +0 -20
  124. package/docs/modules/rust/kb-worker/functions/retrieve.md +0 -194
  125. package/docs/modules/rust/kb-worker/functions/search.md +0 -173
  126. package/docs/modules/rust/kb-worker/functions/write.md +0 -172
  127. package/docs/modules/rust/kb-worker/module.md +0 -171
  128. package/docs/modules/rust/kb-worker/types/cache.md +0 -90
  129. package/docs/modules/rust/kb-worker/types/context.md +0 -26
  130. package/docs/modules/rust/kb-worker/types/module.md +0 -16
  131. package/docs/modules/rust/kb-worker/types/status.md +0 -29
  132. package/docs/modules/rust/kb-worker/types/token.md +0 -50
  133. package/docs/modules/rust/overview.md +0 -531
  134. package/docs/modules/rust/query-parser/functions/extract.md +0 -56
  135. package/docs/modules/rust/query-parser/functions/module.md +0 -18
  136. package/docs/modules/rust/query-parser/functions/parse.md +0 -33
  137. package/docs/modules/rust/query-parser/functions/pipeline.md +0 -9
  138. package/docs/modules/rust/query-parser/functions/rank.md +0 -85
  139. package/docs/modules/rust/query-parser/module.md +0 -131
  140. package/docs/modules/rust/query-parser/types/cache.md +0 -39
  141. package/docs/modules/rust/query-parser/types/keyphrase.md +0 -71
  142. package/docs/modules/rust/query-parser/types/module.md +0 -18
  143. package/docs/modules/rust/query-parser/types/token.md +0 -46
  144. package/docs/modules/rust/shared/content-composer/functions.md +0 -114
  145. package/docs/modules/rust/shared/content-composer/module.md +0 -147
  146. package/docs/modules/rust/shared/content-composer/types.md +0 -93
  147. package/docs/modules/rust/shared/content-parser/functions.md +0 -72
  148. package/docs/modules/rust/shared/content-parser/module.md +0 -99
  149. package/docs/modules/rust/shared/content-parser/types.md +0 -71
  150. package/docs/modules/rust/shared/corpus/module.md +0 -24
  151. package/docs/modules/rust/shared/corpus/types.md +0 -141
  152. package/docs/modules/rust/shared/document/module.md +0 -25
  153. package/docs/modules/rust/shared/document/types.md +0 -154
  154. package/docs/modules/rust/shared/encode/module.md +0 -22
  155. package/docs/modules/rust/shared/encode/traits.md +0 -304
  156. package/docs/modules/rust/shared/error/module.md +0 -28
  157. package/docs/modules/rust/shared/error/types.md +0 -302
  158. package/docs/modules/rust/shared/kbid/module.md +0 -24
  159. package/docs/modules/rust/shared/kbid/types.md +0 -147
  160. package/docs/modules/rust/shared/memory/functions.md +0 -209
  161. package/docs/modules/rust/shared/memory/module.md +0 -24
  162. package/docs/modules/rust/shared/module.md +0 -196
  163. package/docs/modules/rust/shared/pipeline/functions.md +0 -141
  164. package/docs/modules/rust/shared/pipeline/module.md +0 -62
  165. package/docs/modules/rust/shared/pipeline/types.md +0 -43
  166. package/docs/modules/rust/shared/query/module.md +0 -27
  167. package/docs/modules/rust/shared/query/types.md +0 -236
  168. package/docs/modules/rust/shared/section/module.md +0 -25
  169. package/docs/modules/rust/shared/section/types.md +0 -294
  170. package/docs/modules/rust/shared/term/module.md +0 -25
  171. package/docs/modules/rust/shared/term/types.md +0 -139
  172. package/docs/modules/typescript/cli.md +0 -131
  173. package/docs/modules/typescript/kbdb-worker.md +0 -150
  174. package/docs/modules/typescript/overview.md +0 -400
  175. package/docs/modules/typescript/shared/auto-capture/module.md +0 -73
  176. package/docs/modules/typescript/shared/cli/constants.md +0 -23
  177. package/docs/modules/typescript/shared/cli/functions.md +0 -809
  178. package/docs/modules/typescript/shared/cli/module.md +0 -138
  179. package/docs/modules/typescript/shared/cli/typings.md +0 -197
  180. package/docs/modules/typescript/shared/embedding/functions.md +0 -200
  181. package/docs/modules/typescript/shared/embedding/module.md +0 -77
  182. package/docs/modules/typescript/shared/embedding/typings.md +0 -124
  183. package/docs/modules/typescript/shared/hash/functions.md +0 -20
  184. package/docs/modules/typescript/shared/hash/module.md +0 -21
  185. package/docs/modules/typescript/shared/log/constants.md +0 -82
  186. package/docs/modules/typescript/shared/log/functions.md +0 -131
  187. package/docs/modules/typescript/shared/log/module.md +0 -153
  188. package/docs/modules/typescript/shared/log/typings.md +0 -82
  189. package/docs/modules/typescript/shared/mcp/classes.md +0 -179
  190. package/docs/modules/typescript/shared/mcp/functions.md +0 -386
  191. package/docs/modules/typescript/shared/mcp/module.md +0 -160
  192. package/docs/modules/typescript/shared/mcp/typings.md +0 -529
  193. package/docs/modules/typescript/shared/module.md +0 -110
  194. package/docs/modules/typescript/shared/platform/functions.md +0 -42
  195. package/docs/modules/typescript/shared/platform/module.md +0 -25
  196. package/docs/modules/typescript/shared/runtime/functions.md +0 -26
  197. package/docs/modules/typescript/shared/runtime/module.md +0 -27
  198. package/docs/modules/typescript/shared/runtime/typings.md +0 -13
  199. package/docs/modules/typescript/shared/version/module.md +0 -27
  200. package/docs/modules/typescript/shared/wasm-codec/functions.md +0 -391
  201. package/docs/modules/typescript/shared/wasm-codec/module.md +0 -98
  202. package/docs/modules/typescript/shared/worker-client/classes.md +0 -264
  203. package/docs/modules/typescript/shared/worker-client/functions.md +0 -175
  204. package/docs/modules/typescript/shared/worker-client/module.md +0 -92
  205. package/docs/modules/typescript/shared/worker-client/typings.md +0 -511
  206. package/docs/modules/typescript/shared/worker-daemon/classes.md +0 -239
  207. package/docs/modules/typescript/shared/worker-daemon/constants.md +0 -37
  208. package/docs/modules/typescript/shared/worker-daemon/functions.md +0 -234
  209. package/docs/modules/typescript/shared/worker-daemon/module.md +0 -118
  210. package/docs/modules/typescript/shared/worker-daemon/typings.md +0 -132
  211. package/docs/overview.md +0 -191
  212. package/docs/release-notes/0.1.0.md +0 -189
  213. package/docs/release-notes/0.1.1.md +0 -46
  214. package/docs/release-notes/0.1.2.md +0 -38
  215. package/docs/release-notes/0.1.3.md +0 -42
  216. package/docs/release-notes/0.2.0.md +0 -147
  217. package/docs/release-notes/0.3.0.md +0 -89
  218. package/docs/release-notes/0.3.1.md +0 -121
  219. package/docs/release-notes/0.3.2.md +0 -64
  220. package/docs/release-notes/0.4.0.md +0 -80
  221. package/docs/release-notes/0.4.1.md +0 -149
  222. package/docs/release-notes/0.4.3.md +0 -60
  223. package/docs/release-notes/0.5.0.md +0 -41
  224. package/docs/release-notes/README.md +0 -16
@@ -1,575 +0,0 @@
1
- # How Search Works
2
-
3
- When you search, kbdb finds the sections that best
4
- match your query and ranks them by relevance. By
5
- default it uses keyword search -- matching terms with
6
- stemming, synonym expansion, and BM25F ranking. Use
7
- `--algo hybrid` to combine keyword matching with
8
- AI-powered similarity for broader recall. The rest
9
- of this page explains how ranking
10
- works under the hood -- you don't need to read it
11
- to use kbdb.
12
-
13
- ---
14
-
15
- kbdb uses field-weighted BM25F ranking to score search
16
- results by relevance. Sections are indexed across
17
- three fields -- heading, body, and code -- each with a
18
- different weight so that a match in a title counts
19
- more than a match buried in body text. Queries
20
- support simple keyword searches, exact phrases,
21
- boolean operators, and term exclusions.
22
-
23
- ## Query Syntax
24
-
25
- Queries are plain text with optional operators.
26
- The query parser tokenizes and normalizes query
27
- terms through the same pipeline used for indexing,
28
- so search terms match consistently regardless of
29
- case or inflection.
30
-
31
- ### Examples
32
-
33
- | Query | Meaning |
34
- |---------------------|----------------------------------|
35
- | `auth flow` | Sections containing both terms |
36
- | `"error handling"` | Exact phrase match |
37
- | `auth -oauth` | "auth" but not "oauth" |
38
- | `auth AND token` | Both terms required |
39
- | `cache OR redis` | Either term matches |
40
-
41
- ### Syntax Reference
42
-
43
- | Syntax | Effect |
44
- |-----------------|------------------------------------|
45
- | `word` | Match normalized/stemmed form |
46
- | `"two words"` | Match exact phrase in order |
47
- | `-word` | Exclude sections containing term |
48
- | `AND` | Both operands required |
49
- | `OR` | Either operand sufficient |
50
-
51
- Operators can be combined. Unquoted multi-word
52
- queries are implicitly ANDed -- `auth flow` matches
53
- sections containing both "auth" and "flow".
54
-
55
- ## Tokenization Pipeline
56
-
57
- Both indexing and search queries pass through the
58
- same nine-stage pipeline. Using identical processing
59
- for both sides guarantees that stored terms match
60
- query terms.
61
-
62
- ```
63
- Raw text
64
- |
65
- v
66
- 1. Strip content markers
67
- |
68
- v
69
- 2. Unicode NFC normalization
70
- |
71
- v
72
- 3. Word boundary detection
73
- |
74
- v
75
- 4. Identifier splitting
76
- |
77
- v
78
- 5. Case folding
79
- |
80
- v
81
- 6. Stop word removal
82
- |
83
- v
84
- 7. Synonym expansion
85
- |
86
- v
87
- 8. Stemming
88
- |
89
- v
90
- 9. N-gram extraction
91
- |
92
- v
93
- Normalized tokens
94
- ```
95
-
96
- 1. **Marker stripping** -- Remove all six content
97
- marker types (`$(image:)`, `$(code:)`, `$(text:)`,
98
- `$(document:)`, `$(link:)`, `$(doc-link:)`) before
99
- processing. Markers are structural references, not
100
- searchable content.
101
-
102
- 2. **Unicode NFC normalization** -- Compose decomposed
103
- Unicode sequences into their canonical form. For
104
- example, `e` + combining acute accent becomes the
105
- single codepoint `e` (U+00E9). Ensures equivalent
106
- Unicode representations produce the same tokens.
107
-
108
- 3. **Word boundary detection** -- Split text at
109
- Unicode-defined word boundaries using the Unicode
110
- Segmentation algorithm. Handles punctuation,
111
- whitespace, and mixed-script text correctly.
112
-
113
- 4. **Identifier splitting** -- Decompose programming
114
- identifiers into constituent words.
115
- `camelCase` becomes `["camel", "case"]`;
116
- `snake_case` becomes `["snake", "case"]`;
117
- `PascalCase` becomes `["pascal", "case"]`.
118
- This stage makes code searchable by individual
119
- words within identifiers.
120
-
121
- 5. **Case folding** -- Convert all tokens to
122
- lowercase. `HTTP`, `Http`, and `http` all become
123
- `http`.
124
-
125
- 6. **Stop word removal** -- Remove common words with
126
- no discriminative value (`the`, `is`, `and`,
127
- etc.). The stop word list is configurable.
128
-
129
- 7. **Synonym expansion** -- Look up each token in a
130
- built-in bidirectional synonym map and insert
131
- synonym tokens alongside the original. Bridges
132
- vocabulary gaps: a document using "sign-in" becomes
133
- findable via "login". The map covers common
134
- IT/development vocabulary (~30-50 entries:
135
- login/sign-in, auth/authentication,
136
- remove/delete, config/configuration, etc.).
137
- Applied symmetrically during both indexing and
138
- querying.
139
-
140
- 8. **Stemming** -- Reduce words to root forms using
141
- the Snowball/Porter2 stemmer. `running` and `runs`
142
- both stem to `run`. Both the stemmed form and the
143
- original are stored so exact-match queries still
144
- work.
145
-
146
- 9. **N-gram extraction** -- Generate bigrams and
147
- trigrams for phrase indexing and multi-word term
148
- matching. Supports phrase queries without requiring
149
- a separate phrase index.
150
-
151
- ### Per-Field Processing
152
-
153
- During indexing, the pipeline runs once per field for
154
- each section:
155
-
156
- | Content source | Field |
157
- |-------------------------|-----------|
158
- | `title` attribute | heading |
159
- | Body text + description | body |
160
- | Code content | code |
161
-
162
- Per-field term frequencies are stored separately in
163
- the inverted index. This separation is what enables
164
- BM25F field weights to be tuned at query time without
165
- rebuilding the indexes.
166
-
167
- ## BM25F Ranking
168
-
169
- BM25F (Field-Weighted Okapi BM25) is the primary
170
- ranking function. It is a probabilistic scoring model
171
- from information retrieval that balances three
172
- factors: how often a term appears in a section, how
173
- rare the term is across the corpus, and how long the
174
- section is relative to average.
175
-
176
- ### The Three Fields
177
-
178
- Each section is indexed across three fields, each
179
- with a default weight:
180
-
181
- | Field | Weight | Content source |
182
- |-----------|--------|----------------------------|
183
- | `heading` | 2.0x | Section `title` attribute |
184
- | `body` | 1.0x | Body text + `description` |
185
- | `code` | 1.5x | Code section content |
186
-
187
- A term match in a heading contributes twice as much
188
- to the score as the same match in body text. A match
189
- in code contributes 1.5 times as much. This reflects
190
- the intuition that titles are the strongest signal of
191
- what a section is about.
192
-
193
- ### How Scoring Works
194
-
195
- For each query term `t` matched in section `d`:
196
-
197
- 1. **IDF (Inverse Document Frequency)** -- Measures
198
- how rare the term is across all sections. Common
199
- terms like "function" get a low IDF; rare terms
200
- like "kademlia" get a high IDF.
201
-
202
- ```
203
- idf(t) = ln((N - df(t) + 0.5) / (df(t) + 0.5) + 1)
204
- ```
205
-
206
- `N` = total indexed sections, `df(t)` = number of
207
- sections containing `t`.
208
-
209
- 2. **Per-field score** -- For each field `f` (heading,
210
- body, code), compute a BM25 score using that
211
- field's term frequency and average length:
212
-
213
- ```
214
- score_f(t, d) = idf(t)
215
- * (tf_f(t,d) * (k1 + 1))
216
- / (tf_f(t,d) + k1 * (1 - b + b * |d_f| / avgdl_f))
217
- ```
218
-
219
- Where:
220
- - `tf_f(t,d)` = term frequency in field `f`
221
- - `|d_f|` = token count of field `f` in section `d`
222
- - `avgdl_f` = average token count of field `f`
223
- across the corpus
224
- - `k1` = 1.2 (term saturation parameter)
225
- - `b` = 0.75 (length normalization parameter)
226
-
227
- 3. **Weighted combination** -- Multiply each field
228
- score by its weight and sum:
229
-
230
- ```
231
- bm25f(t, d) = 2.0 * score_heading(t, d)
232
- + 1.0 * score_body(t, d)
233
- + 1.5 * score_code(t, d)
234
- ```
235
-
236
- 4. **Total section score** -- Sum `bm25f(t, d)`
237
- across all matched query terms.
238
-
239
- ### Key Parameters
240
-
241
- | Parameter | Default | Effect |
242
- |------------------|---------|---------------------------|
243
- | `k1` | 1.2 | Term saturation. Higher = more weight to repeated terms |
244
- | `b` | 0.75 | Length normalization. 0 = none, 1 = full |
245
- | `heading` weight | 2.0 | Title match influence |
246
- | `body` weight | 1.0 | Body text match influence |
247
- | `code` weight | 1.5 | Code match influence |
248
-
249
- ### Why Per-Field Storage Matters
250
-
251
- Per-field term frequencies (`heading_tf`, `body_tf`,
252
- `code_tf`) are stored separately in the inverted
253
- index rather than as a single aggregated value. This
254
- means field weights can be changed at query time --
255
- for example, boosting code matches to 3.0x for a
256
- code-focused search -- without rebuilding any index
257
- files.
258
-
259
- ### Per-Field Length Normalization
260
-
261
- Corpus statistics store per-field average lengths
262
- (`avg_heading_length`, `avg_body_length`,
263
- `avg_code_length`) alongside overall averages. This
264
- prevents unfair comparisons: a 3-word title is
265
- normalized against the average title length, not
266
- against the average body length of 500 words.
267
-
268
- ## Supplementary Scoring Signals
269
-
270
- Three additional signals are added to the BM25F base
271
- score:
272
-
273
- ### Proximity Boost
274
-
275
- Boosts sections where query terms appear close
276
- together. For multi-term queries, the proximity
277
- scorer computes the minimum distance between each
278
- pair of query terms using their stored positions. A
279
- smaller span produces a higher boost. Single-term
280
- queries receive no proximity boost.
281
-
282
- ```
283
- final proximity = inverse of minimum span
284
- across all query term pairs
285
- ```
286
-
287
- ### Zone Scoring
288
-
289
- Structural weighting based on position within a
290
- section. Terms in the first ~20% of a section (the
291
- "heading zone") receive a higher weight than terms in
292
- the rest of the body. The zone boundary is computed
293
- as `0.2 * token_count` using the pre-computed total
294
- token count. This approximates the idea that
295
- headings and opening paragraphs carry more topical
296
- signal.
297
-
298
- ### Freshness Weighting (Optional)
299
-
300
- Time-decay boost that favors recently added sections.
301
- Uses exponential decay with a configurable half-life:
302
- after one half-life period, the freshness score is
303
- halved. Can be disabled entirely by omitting the
304
- freshness weight from score combination.
305
-
306
- ### Score Combination
307
-
308
- ```
309
- final_score = bm25f_score
310
- + proximity_weight * proximity_score
311
- + zone_weight * zone_score
312
- + freshness_weight * freshness_score
313
- ```
314
-
315
- BM25F is always the dominant signal. Proximity, zone,
316
- and freshness are additive boosts with configurable
317
- weights. Results are sorted by `final_score`
318
- descending; ties broken by kbid lexicographic order.
319
-
320
- ### Score Normalization
321
-
322
- Raw BM25F scores are normalized to a 0.0--1.0
323
- `confidence` value within each result set. Each
324
- score is divided by the maximum score in the result
325
- set, so the top result always has confidence 1.0.
326
- This lets agents distinguish strong matches from
327
- weak tail results without interpreting raw score
328
- magnitudes.
329
-
330
- Confidence is exposed in CLI output but omitted from
331
- MCP results (ordering is the signal for agents).
332
-
333
- ## Relaxed-Match Fallback
334
-
335
- When a multi-term AND query returns zero results,
336
- the engine automatically retries with OR semantics
337
- -- any term matches instead of all required. This
338
- prevents silent misses when the query is too
339
- specific for the corpus.
340
-
341
- The fallback is transparent: no special syntax
342
- needed. Results from relaxed matching are flagged
343
- with `relaxed: true` in the response envelope so
344
- the caller knows the match is weaker. Single-term
345
- queries are unaffected (AND and OR are equivalent
346
- for one term). Phrase queries and exclusions are
347
- preserved in both modes.
348
-
349
- ## Keyword Extraction
350
-
351
- When content is added to the knowledge base, the
352
- system extracts searchable terms and computes
353
- weights using statistical methods that require no
354
- training data or external models.
355
-
356
- ### RAKE (Rapid Automatic Keyword Extraction)
357
-
358
- Splits text on stop words to identify candidate
359
- keyphrases. Scores candidates by word degree divided
360
- by frequency ratio -- multi-word phrases with
361
- infrequent component words score highest. Runs on
362
- both text and code content.
363
-
364
- ### N-Gram Scoring
365
-
366
- Bigrams and trigrams are scored by co-occurrence
367
- frequency. High-frequency pairs and triples become
368
- indexed terms, supporting multi-word searches without
369
- exact phrase syntax.
370
-
371
- ### TF-IDF Term Weighting
372
-
373
- For each section, per-field term frequency (TF) is
374
- computed separately for heading, body, and code
375
- fields. These per-field TFs are combined with
376
- corpus-wide inverse document frequency (IDF) to
377
- produce weights reflecting each term's
378
- discriminative value. The per-field TFs are stored in
379
- the inverted index; IDF is computed from corpus
380
- statistics at query time.
381
-
382
- ### What Gets Indexed
383
-
384
- | Section type | Body indexed? | Title indexed? | Description indexed? |
385
- |----------------|---------------|----------------|----------------------|
386
- | `text/*` | Yes (body) | Yes (heading) | Yes (body) |
387
- | `image/*` | No | Yes (heading) | Yes (body) |
388
-
389
- Image binary content is skipped entirely. Image
390
- sections are searchable only through their `title`
391
- (required) and `description` (optional) attributes.
392
-
393
- ## Index Structure
394
-
395
- All index files live in `.kbdb/indexes/`. They are
396
- binary, derived, and rebuildable from source data.
397
- The `.gitignore` at the database root excludes them
398
- from version control.
399
-
400
- ```
401
- indexes/
402
- +-- meta.toml human-readable metadata
403
- +-- terms.idx inverted index (B+ tree)
404
- +-- positions.idx positional index (B+ tree)
405
- +-- references.idx reference graph (B+ tree)
406
- +-- corpus.dat corpus statistics (binary)
407
- ```
408
-
409
- ### `terms.idx` -- Inverted Index
410
-
411
- B+ tree mapping normalized terms to posting lists.
412
- Each posting entry contains:
413
-
414
- | Field | Type | Description |
415
- |--------------|-------|----------------------------|
416
- | `kbid` | bytes | Section identifier |
417
- | `heading_tf` | f32 | Term frequency in heading |
418
- | `body_tf` | f32 | Term frequency in body |
419
- | `code_tf` | f32 | Term frequency in code |
420
-
421
- Supports term lookup, IDF computation (via document
422
- frequency counts), and per-field term frequency
423
- retrieval. O(log n) lookup via B+ tree structure.
424
-
425
- ### `positions.idx` -- Positional Index
426
-
427
- B+ tree mapping `(term, kbid)` pairs to arrays of
428
- zero-based token offsets. Supports three functions:
429
-
430
- - **Phrase queries** -- Verify that terms appear in
431
- the correct order at consecutive positions.
432
- - **Proximity scoring** -- Compute minimum span
433
- between query terms.
434
- - **Zone scoring** -- Determine whether a term falls
435
- in the heading zone (first 20% of the section).
436
-
437
- ### `references.idx` -- Reference Graph Index
438
-
439
- B+ tree mapping section kbids to their content
440
- marker cross-references. Stores bidirectional
441
- edges: for each `$(text:)`, `$(code:)`, `$(image:)`,
442
- `$(link:)`, `$(document:)`, and `$(doc-link:)`
443
- marker, both a forward entry (source -> target) and
444
- a back entry (target -> source) are recorded. This
445
- enables the `recall` command's progressive context
446
- expansion -- depth 1+ retrieves back-references
447
- (sections that point to this one) and depth 2+
448
- retrieves forward references (sections this one
449
- points to).
450
-
451
- ### `corpus.dat` -- Corpus Statistics
452
-
453
- Binary file storing corpus-wide aggregates:
454
-
455
- | Field | Type | Description |
456
- |-----------------------|------|--------------------------|
457
- | `total_sections` | u32 | Indexed section count |
458
- | `total_terms` | u32 | Distinct term count |
459
- | `avg_section_length` | f32 | Average tokens/section |
460
- | `avg_heading_length` | f32 | Average heading tokens |
461
- | `avg_body_length` | f32 | Average body tokens |
462
- | `avg_code_length` | f32 | Average code tokens |
463
- | per-term doc freqs | -- | Per-term section counts |
464
-
465
- Used for IDF computation and per-field BM25 length
466
- normalization.
467
-
468
- ### `meta.toml` -- Index Metadata
469
-
470
- Human-readable TOML file with informational metadata
471
- about the indexes:
472
-
473
- - Last rebuild timestamp
474
- - Total term count
475
- - Corpus statistics summary
476
-
477
- This file is informational only -- the binary index
478
- files are the source of truth for search operations.
479
-
480
- ## Ranking Pipeline (End to End)
481
-
482
- ```
483
- "auth token" (query string)
484
- |
485
- v
486
- Tokenize + parse query (query-parser.wasm)
487
- |
488
- v
489
- QueryPlan: terms=["auth","token"], mode=AND
490
- |
491
- v
492
- Execute plan against indexes (fs-database.wasm)
493
- |
494
- v
495
- Vec<RawMatch>: kbids + per-field TFs + positions
496
- |
497
- v
498
- Fetch corpus statistics (fs-database.wasm)
499
- |
500
- v
501
- Score: BM25F (query-parser.wasm)
502
- Score: proximity (query-parser.wasm)
503
- Score: zone (query-parser.wasm)
504
- Score: freshness (optional) (query-parser.wasm)
505
- |
506
- v
507
- Combine scores, sort descending, truncate
508
- |
509
- v
510
- Shape into result mode (sections/documents/stats)
511
- |
512
- v
513
- Ranked results
514
- ```
515
-
516
- `kb-worker.wasm` orchestrates the entire flow,
517
- calling `query-parser.wasm` for text processing and
518
- scoring, and `fs-database.wasm` for storage lookups.
519
- Neither standalone module calls the other directly.
520
-
521
- ## Result Modes
522
-
523
- | Mode | Returns |
524
- |-------------|-------------------------------------|
525
- | `sections` | Individual matching sections with scores, snippets, and matched terms |
526
- | `documents` | Documents containing matches, with aggregated scores and per-section details |
527
- | `stats` | Match counts and top terms without content bodies |
528
-
529
- ## Search Algorithms
530
-
531
- kbdb supports three search algorithms, selected
532
- with `--algo` (CLI) or the `algo` parameter (MCP).
533
-
534
- ### Lexical
535
-
536
- Keyword matching with stemming and synonym
537
- expansion, scored by BM25F as described above.
538
- Fast, works offline, and gives consistent results.
539
-
540
- ### Vector
541
-
542
- Embedding-based similarity search. Each section's
543
- content is converted into a numeric vector (an
544
- "embedding") by an AI model. Search finds sections
545
- whose vectors are closest to the query's vector
546
- using cosine similarity.
547
-
548
- Vector search catches matches that keyword search
549
- misses -- for example, searching "database
550
- rationale" finds a section about "we chose Postgres
551
- because of JSONB" even though none of the words
552
- overlap.
553
-
554
- Requires an embedding provider to be configured.
555
- Without one, vector mode returns an error.
556
-
557
- ### Hybrid
558
-
559
- Runs both lexical and vector searches in parallel,
560
- then merges the two ranked lists using Reciprocal
561
- Rank Fusion (RRF). This combines the precision of
562
- keyword matching with the associative recall of
563
- embeddings. Use `--algo hybrid` to enable.
564
-
565
- RRF works by converting each result's rank position
566
- into a score (`1 / (k + rank)` with k=60), then
567
- summing scores across both lists. Results that rank
568
- well in both lists get the highest combined scores.
569
-
570
- Hybrid mode uses a built-in TF-IDF embedding provider
571
- by default. Configure `provider = "onnx"` or
572
- `provider = "api"` in `worker.toml` for higher
573
- quality embeddings. Setting `provider = "none"`
574
- explicitly disables embeddings and returns an error
575
- for hybrid and vector searches.