@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.
- package/CLA.md +68 -0
- package/LICENSE +676 -12
- package/LICENSING.md +58 -0
- package/README.md +50 -25
- package/README.md.bak +322 -0
- package/dist/README.md +322 -0
- package/dist/{chunk-BJXEVALU.mjs → chunk-QLJ33C74.mjs} +44 -44
- package/dist/chunk-QLJ33C74.mjs.map +7 -0
- package/dist/cli.cjs +550 -232
- package/dist/cli.cjs.map +4 -4
- package/dist/cli.d.ts +0 -8
- package/dist/cli.mjs +483 -154
- package/dist/cli.mjs.map +4 -4
- package/dist/kbdb-worker.cjs +36 -5
- package/dist/kbdb-worker.cjs.map +3 -3
- package/dist/mod.cjs +89 -30
- package/dist/mod.cjs.map +4 -4
- package/dist/mod.mjs +88 -30
- package/dist/mod.mjs.map +4 -4
- package/dist/src/cli.d.ts +0 -8
- package/dist/src/shared/cli/constants/defaults.constant.d.ts +1 -1
- package/dist/src/shared/cli/constants/recfile-command-field-map.constant.d.ts +8 -0
- package/dist/src/shared/cli/constants/recfile-field-maps.constant.d.ts +21 -0
- package/dist/src/shared/cli/functions/compute-directory-level.function.d.ts +14 -0
- package/dist/src/shared/cli/functions/dispatch-command.function.d.ts +2 -28
- package/dist/src/shared/cli/functions/format-command-output.function.d.ts +14 -0
- package/dist/src/shared/cli/functions/format-db-not-found.function.d.ts +20 -0
- package/dist/src/shared/cli/functions/format-output.function.d.ts +1 -0
- package/dist/src/shared/cli/functions/format-recfile-output.function.d.ts +11 -0
- package/dist/src/shared/cli/functions/render-recfile-value.function.d.ts +11 -0
- package/dist/src/shared/cli/functions/resolve-db-dir.function.d.ts +24 -0
- package/dist/src/shared/cli/functions/resolve-recfile-key.function.d.ts +9 -0
- package/dist/src/shared/cli/functions/run-db-path.function.d.ts +10 -0
- package/dist/src/shared/cli/functions/run-export.function.d.ts +8 -4
- package/dist/src/shared/cli/functions/run-import.function.d.ts +4 -0
- package/dist/src/shared/cli/functions/run-learn.function.d.ts +12 -0
- package/dist/src/shared/cli/index.d.ts +4 -1
- package/dist/src/shared/cli/typings/cli-options.interface.d.ts +9 -2
- package/dist/src/shared/cli/typings/db-resolution.interface.d.ts +9 -0
- package/dist/src/shared/cli/typings/recfile-field-map.type.d.ts +10 -0
- package/dist/src/shared/version/constants/version.constant.d.ts +1 -1
- package/dist/src/shared/wasm-codec/functions/decode-option-u8.function.d.ts +9 -0
- package/dist/src/shared/wasm-codec/functions/decode-section-records.function.d.ts +4 -0
- package/dist/src/shared/wasm-codec/functions/encode-add-section-params.function.d.ts +2 -45
- package/dist/src/shared/wasm-codec/functions/encode-update-section-params.function.d.ts +10 -1
- package/dist/src/shared/wasm-codec/index.d.ts +1 -1
- package/dist/src/shared/wasm-codec/typings/add-section-input.model.d.ts +6 -0
- package/dist/src/shared/wasm-codec/typings/section-record-trailing.model.d.ts +5 -0
- package/dist/src/shared/wasm-codec/typings/section-record.model.d.ts +5 -0
- package/dist/src/shared/worker-client/functions/build-deno-permissions.function.d.ts +11 -0
- package/dist/src/shared/worker-client/functions/read-crash-reason.function.d.ts +9 -0
- package/dist/src/shared/worker-client/functions/resolve-spawn-script.function.d.ts +6 -0
- package/dist/src/shared/worker-client/functions/spawn-daemon.function.d.ts +1 -1
- package/dist/src/shared/worker-client/typings/section.model.d.ts +5 -0
- package/dist/src/shared/worker-client/typings/worker-client-options.interface.d.ts +0 -6
- package/dist/src/shared/worker-daemon/functions/count-files.function.d.ts +12 -0
- package/dist/src/shared/worker-daemon/functions/handle-import.function.d.ts +2 -0
- package/dist/src/shared/worker-daemon/functions/handle-read-ops.function.d.ts +8 -0
- package/dist/src/shared/worker-daemon/functions/validate-daemon-path.function.d.ts +15 -0
- package/dist/src/worker.d.ts +0 -7
- package/dist/wasm/default-embedding/kbdb_default_embedding_bg.wasm +0 -0
- package/dist/wasm/default-embedding/package.json +1 -1
- package/dist/wasm/fs-database/kbdb_fs_database_bg.wasm +0 -0
- package/dist/wasm/fs-database/package.json +1 -1
- package/dist/wasm/fs-migration/package.json +1 -1
- package/dist/wasm/kb-worker/kbdb_worker_bg.wasm +0 -0
- package/dist/wasm/kb-worker/package.json +1 -1
- package/dist/wasm/query-parser/kbdb_query_parser_bg.wasm +0 -0
- package/dist/wasm/query-parser/package.json +1 -1
- package/dist/worker.d.ts +0 -7
- package/dist/worker.mjs +37 -6
- package/dist/worker.mjs.map +3 -3
- package/package.json +11 -10
- package/dist/chunk-BJXEVALU.mjs.map +0 -7
- package/dist/src/shared/cli/functions/resolve-raw-db-path.function.d.ts +0 -10
- package/docs/details/README.md +0 -30
- package/docs/details/agent-tooling.md +0 -132
- package/docs/details/cli.md +0 -777
- package/docs/details/knowledge-base.md +0 -180
- package/docs/details/library-api.md +0 -495
- package/docs/details/mcp-server.md +0 -482
- package/docs/details/search-and-ranking.md +0 -575
- package/docs/details/storage.md +0 -531
- package/docs/goals/agents.md +0 -751
- package/docs/goals/architecture.svg +0 -198
- package/docs/goals/auto-capture.md +0 -378
- package/docs/goals/benchmarking.md +0 -296
- package/docs/goals/cli.md +0 -2654
- package/docs/goals/concurrency.md +0 -259
- package/docs/goals/content-composer.md +0 -609
- package/docs/goals/content-parser.md +0 -279
- package/docs/goals/database.md +0 -1679
- package/docs/goals/document.md +0 -368
- package/docs/goals/hybrid-search.md +0 -465
- package/docs/goals/mcp.md +0 -1541
- package/docs/goals/overview.md +0 -124
- package/docs/goals/query-parser.md +0 -373
- package/docs/goals/query-result.md +0 -860
- package/docs/goals/semantic-dedup.md +0 -233
- package/docs/goals/skills.md +0 -810
- package/docs/goals/sync.md +0 -217
- package/docs/goals/worker-client.md +0 -1005
- package/docs/goals/worker-daemon.md +0 -1547
- package/docs/modules/overview.md +0 -319
- package/docs/modules/rust/embedding/module.md +0 -91
- package/docs/modules/rust/fs-database/functions/document.md +0 -48
- package/docs/modules/rust/fs-database/functions/integrity.md +0 -79
- package/docs/modules/rust/fs-database/functions/io.md +0 -87
- package/docs/modules/rust/fs-database/functions/module.md +0 -22
- package/docs/modules/rust/fs-database/functions/query-exec.md +0 -44
- package/docs/modules/rust/fs-database/functions/section.md +0 -76
- package/docs/modules/rust/fs-database/indexes/btree.md +0 -35
- package/docs/modules/rust/fs-database/indexes/corpus.md +0 -61
- package/docs/modules/rust/fs-database/indexes/inverted.md +0 -60
- package/docs/modules/rust/fs-database/indexes/module.md +0 -64
- package/docs/modules/rust/fs-database/indexes/positional.md +0 -39
- package/docs/modules/rust/fs-database/indexes/vectors.md +0 -110
- package/docs/modules/rust/fs-database/module.md +0 -150
- package/docs/modules/rust/fs-database/types/catalog.md +0 -53
- package/docs/modules/rust/fs-database/types/module.md +0 -12
- package/docs/modules/rust/fs-database/types/section.md +0 -127
- package/docs/modules/rust/kb-worker/functions/compose.md +0 -57
- package/docs/modules/rust/kb-worker/functions/module.md +0 -20
- package/docs/modules/rust/kb-worker/functions/retrieve.md +0 -194
- package/docs/modules/rust/kb-worker/functions/search.md +0 -173
- package/docs/modules/rust/kb-worker/functions/write.md +0 -172
- package/docs/modules/rust/kb-worker/module.md +0 -171
- package/docs/modules/rust/kb-worker/types/cache.md +0 -90
- package/docs/modules/rust/kb-worker/types/context.md +0 -26
- package/docs/modules/rust/kb-worker/types/module.md +0 -16
- package/docs/modules/rust/kb-worker/types/status.md +0 -29
- package/docs/modules/rust/kb-worker/types/token.md +0 -50
- package/docs/modules/rust/overview.md +0 -531
- package/docs/modules/rust/query-parser/functions/extract.md +0 -56
- package/docs/modules/rust/query-parser/functions/module.md +0 -18
- package/docs/modules/rust/query-parser/functions/parse.md +0 -33
- package/docs/modules/rust/query-parser/functions/pipeline.md +0 -9
- package/docs/modules/rust/query-parser/functions/rank.md +0 -85
- package/docs/modules/rust/query-parser/module.md +0 -131
- package/docs/modules/rust/query-parser/types/cache.md +0 -39
- package/docs/modules/rust/query-parser/types/keyphrase.md +0 -71
- package/docs/modules/rust/query-parser/types/module.md +0 -18
- package/docs/modules/rust/query-parser/types/token.md +0 -46
- package/docs/modules/rust/shared/content-composer/functions.md +0 -114
- package/docs/modules/rust/shared/content-composer/module.md +0 -147
- package/docs/modules/rust/shared/content-composer/types.md +0 -93
- package/docs/modules/rust/shared/content-parser/functions.md +0 -72
- package/docs/modules/rust/shared/content-parser/module.md +0 -99
- package/docs/modules/rust/shared/content-parser/types.md +0 -71
- package/docs/modules/rust/shared/corpus/module.md +0 -24
- package/docs/modules/rust/shared/corpus/types.md +0 -141
- package/docs/modules/rust/shared/document/module.md +0 -25
- package/docs/modules/rust/shared/document/types.md +0 -154
- package/docs/modules/rust/shared/encode/module.md +0 -22
- package/docs/modules/rust/shared/encode/traits.md +0 -304
- package/docs/modules/rust/shared/error/module.md +0 -28
- package/docs/modules/rust/shared/error/types.md +0 -302
- package/docs/modules/rust/shared/kbid/module.md +0 -24
- package/docs/modules/rust/shared/kbid/types.md +0 -147
- package/docs/modules/rust/shared/memory/functions.md +0 -209
- package/docs/modules/rust/shared/memory/module.md +0 -24
- package/docs/modules/rust/shared/module.md +0 -196
- package/docs/modules/rust/shared/pipeline/functions.md +0 -141
- package/docs/modules/rust/shared/pipeline/module.md +0 -62
- package/docs/modules/rust/shared/pipeline/types.md +0 -43
- package/docs/modules/rust/shared/query/module.md +0 -27
- package/docs/modules/rust/shared/query/types.md +0 -236
- package/docs/modules/rust/shared/section/module.md +0 -25
- package/docs/modules/rust/shared/section/types.md +0 -294
- package/docs/modules/rust/shared/term/module.md +0 -25
- package/docs/modules/rust/shared/term/types.md +0 -139
- package/docs/modules/typescript/cli.md +0 -131
- package/docs/modules/typescript/kbdb-worker.md +0 -150
- package/docs/modules/typescript/overview.md +0 -400
- package/docs/modules/typescript/shared/auto-capture/module.md +0 -73
- package/docs/modules/typescript/shared/cli/constants.md +0 -23
- package/docs/modules/typescript/shared/cli/functions.md +0 -809
- package/docs/modules/typescript/shared/cli/module.md +0 -138
- package/docs/modules/typescript/shared/cli/typings.md +0 -197
- package/docs/modules/typescript/shared/embedding/functions.md +0 -200
- package/docs/modules/typescript/shared/embedding/module.md +0 -77
- package/docs/modules/typescript/shared/embedding/typings.md +0 -124
- package/docs/modules/typescript/shared/hash/functions.md +0 -20
- package/docs/modules/typescript/shared/hash/module.md +0 -21
- package/docs/modules/typescript/shared/log/constants.md +0 -82
- package/docs/modules/typescript/shared/log/functions.md +0 -131
- package/docs/modules/typescript/shared/log/module.md +0 -153
- package/docs/modules/typescript/shared/log/typings.md +0 -82
- package/docs/modules/typescript/shared/mcp/classes.md +0 -179
- package/docs/modules/typescript/shared/mcp/functions.md +0 -386
- package/docs/modules/typescript/shared/mcp/module.md +0 -160
- package/docs/modules/typescript/shared/mcp/typings.md +0 -529
- package/docs/modules/typescript/shared/module.md +0 -110
- package/docs/modules/typescript/shared/platform/functions.md +0 -42
- package/docs/modules/typescript/shared/platform/module.md +0 -25
- package/docs/modules/typescript/shared/runtime/functions.md +0 -26
- package/docs/modules/typescript/shared/runtime/module.md +0 -27
- package/docs/modules/typescript/shared/runtime/typings.md +0 -13
- package/docs/modules/typescript/shared/version/module.md +0 -27
- package/docs/modules/typescript/shared/wasm-codec/functions.md +0 -391
- package/docs/modules/typescript/shared/wasm-codec/module.md +0 -98
- package/docs/modules/typescript/shared/worker-client/classes.md +0 -264
- package/docs/modules/typescript/shared/worker-client/functions.md +0 -175
- package/docs/modules/typescript/shared/worker-client/module.md +0 -92
- package/docs/modules/typescript/shared/worker-client/typings.md +0 -511
- package/docs/modules/typescript/shared/worker-daemon/classes.md +0 -239
- package/docs/modules/typescript/shared/worker-daemon/constants.md +0 -37
- package/docs/modules/typescript/shared/worker-daemon/functions.md +0 -234
- package/docs/modules/typescript/shared/worker-daemon/module.md +0 -118
- package/docs/modules/typescript/shared/worker-daemon/typings.md +0 -132
- package/docs/overview.md +0 -191
- package/docs/release-notes/0.1.0.md +0 -189
- package/docs/release-notes/0.1.1.md +0 -46
- package/docs/release-notes/0.1.2.md +0 -38
- package/docs/release-notes/0.1.3.md +0 -42
- package/docs/release-notes/0.2.0.md +0 -147
- package/docs/release-notes/0.3.0.md +0 -89
- package/docs/release-notes/0.3.1.md +0 -121
- package/docs/release-notes/0.3.2.md +0 -64
- package/docs/release-notes/0.4.0.md +0 -80
- package/docs/release-notes/0.4.1.md +0 -149
- package/docs/release-notes/0.4.3.md +0 -60
- package/docs/release-notes/0.5.0.md +0 -41
- 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.
|