@backbencher/brain 0.0.0-stage → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +298 -0
- package/EMBEDDINGS.md +355 -0
- package/LICENSE +21 -0
- package/README.md +415 -2
- package/bin/bb +13 -0
- package/dist/analysis-exclusions-7ZJDXOVZ.js +35 -0
- package/dist/brain-index-health-KY7K552E.js +17 -0
- package/dist/brain-relationship-enrichment-QH7OOHUF.js +558 -0
- package/dist/brain.sql-EIM4WS4D.js +29 -0
- package/dist/chunk-2BSKD7O3.js +40 -0
- package/dist/chunk-2DE27DVC.js +1314 -0
- package/dist/chunk-2RRBMNBQ.js +322 -0
- package/dist/chunk-2RTN2DFU.js +711 -0
- package/dist/chunk-2WXYNLBA.js +29 -0
- package/dist/chunk-3CTFIJJB.js +17 -0
- package/dist/chunk-3LFTSMIV.js +174 -0
- package/dist/chunk-47HKX4AJ.js +930 -0
- package/dist/chunk-4H22TLOT.js +543 -0
- package/dist/chunk-5SD45FLC.js +818 -0
- package/dist/chunk-66A5ZFYA.js +1758 -0
- package/dist/chunk-6AIRWAO2.js +247 -0
- package/dist/chunk-6WNGD3NN.js +196 -0
- package/dist/chunk-7AN7U5IZ.js +371 -0
- package/dist/chunk-BHB7BYYI.js +626 -0
- package/dist/chunk-BQ3OVQ3P.js +125 -0
- package/dist/chunk-CW4XXSNN.js +1479 -0
- package/dist/chunk-D2Q4Y47A.js +53 -0
- package/dist/chunk-DIYAGQJL.js +34 -0
- package/dist/chunk-DYM4FQEE.js +90 -0
- package/dist/chunk-EWMWK7WN.js +75 -0
- package/dist/chunk-FVVQTSIM.js +3427 -0
- package/dist/chunk-FWSL4VG6.js +1290 -0
- package/dist/chunk-GBI7V7KY.js +69 -0
- package/dist/chunk-GEFFO6O2.js +152 -0
- package/dist/chunk-HOWAQXJO.js +236 -0
- package/dist/chunk-HQSPJDHI.js +613 -0
- package/dist/chunk-IFZNR5UJ.js +2863 -0
- package/dist/chunk-J4PMBXQQ.js +336 -0
- package/dist/chunk-KAET47ZL.js +125 -0
- package/dist/chunk-KCDECRJY.js +440 -0
- package/dist/chunk-KLK3PBTO.js +1119 -0
- package/dist/chunk-L5TDYKYK.js +76 -0
- package/dist/chunk-MLKGABMK.js +9 -0
- package/dist/chunk-OWISBAOF.js +61 -0
- package/dist/chunk-PJTNGD3Z.js +6924 -0
- package/dist/chunk-QLK6ED4Q.js +235 -0
- package/dist/chunk-R2GW4F6R.js +19 -0
- package/dist/chunk-RCMTFSEF.js +87 -0
- package/dist/chunk-RH7KC5HU.js +12050 -0
- package/dist/chunk-RM3PY6TG.js +376 -0
- package/dist/chunk-ROMM6KMC.js +433 -0
- package/dist/chunk-SK6YVHFZ.js +211 -0
- package/dist/chunk-SM7RFQRO.js +214 -0
- package/dist/chunk-UFE77L67.js +782 -0
- package/dist/chunk-UGR4QIGS.js +67 -0
- package/dist/chunk-UUNHHX4M.js +13 -0
- package/dist/chunk-V44PGPA6.js +2104 -0
- package/dist/chunk-VL52PL2T.js +71 -0
- package/dist/chunk-VURYFIHW.js +201 -0
- package/dist/chunk-XJKJYIPP.js +7436 -0
- package/dist/chunk-YI6FF2ZR.js +340 -0
- package/dist/cli/index.js +37 -0
- package/dist/config-HZAAYDP3.js +10 -0
- package/dist/content-search-642F7E5V.js +593 -0
- package/dist/database-TCTZDLE5.js +9 -0
- package/dist/doctor-GXCKSJOX.js +395 -0
- package/dist/edit-engine-KM7MPFEC.js +51 -0
- package/dist/engine-42TZFNIZ.js +11 -0
- package/dist/engine-LO6L4JLQ.js +18 -0
- package/dist/fingerprint-XDXFRWO6.js +33 -0
- package/dist/framework-intelligence-DWFCKV44.js +860 -0
- package/dist/freshness-3K6VU5OT.js +174 -0
- package/dist/graph-engine-PL5YA7BA.js +21 -0
- package/dist/graph_request-MM4REP6H.js +350 -0
- package/dist/impact_request-WDE47IZ5.js +68 -0
- package/dist/index-space-IUUN5WYV.js +15 -0
- package/dist/index-status-6BD7UBHR.js +34 -0
- package/dist/index.js +159 -0
- package/dist/instance-FO6QZRLH.js +19 -0
- package/dist/language-detection-DFCAU5DZ.js +11 -0
- package/dist/lsp/server.js +4301 -0
- package/dist/mcp/server.js +132 -0
- package/dist/onboard-DIQZV2NW.js +161 -0
- package/dist/override-companion-pass-XR7MHTP7.js +117 -0
- package/dist/parallel-indexer-4PW3AFXP.js +88 -0
- package/dist/pool-worker.js +1153 -0
- package/dist/project-health-ZS5TS2Z6.js +94 -0
- package/dist/project-index-5SDPHITE.js +57 -0
- package/dist/project-registry-DGZBIZS7.js +355 -0
- package/dist/real-bash-analyzer-SXSV67E2.js +2201 -0
- package/dist/real-c-analyzer-SY7FTZ6W.js +5942 -0
- package/dist/real-clean-analyzer-IGDHHLZK.js +3470 -0
- package/dist/real-clojure-analyzer-4OH7IWLB.js +2818 -0
- package/dist/real-cpp-analyzer-7LTDRJRJ.js +4101 -0
- package/dist/real-csharp-analyzer-KICU3TLH.js +3298 -0
- package/dist/real-css-analyzer-HPU277Q6.js +15 -0
- package/dist/real-dart-analyzer-7LZ5LCMW.js +3944 -0
- package/dist/real-elixir-analyzer-BE3MEVZO.js +2192 -0
- package/dist/real-erlang-analyzer-BZMAKYBK.js +1731 -0
- package/dist/real-fsharp-analyzer-5QLTOV3E.js +2390 -0
- package/dist/real-go-analyzer-POD7MZQR.js +4126 -0
- package/dist/real-graphql-analyzer-MAQRZ6QW.js +1442 -0
- package/dist/real-groovy-analyzer-MEWSUPMJ.js +2285 -0
- package/dist/real-haskell-analyzer-I5L2GR3Y.js +2533 -0
- package/dist/real-hcl-analyzer-DBOPXSWJ.js +725 -0
- package/dist/real-html-analyzer-O63XZLZD.js +1759 -0
- package/dist/real-java-analyzer-CHCW3EKA.js +4677 -0
- package/dist/real-javascript-analyzer-QAAJQYZE.js +14 -0
- package/dist/real-json-analyzer-UGBR7YQN.js +1640 -0
- package/dist/real-julia-analyzer-35Q4GHOZ.js +2085 -0
- package/dist/real-kotlin-analyzer-GRAYCWW2.js +3956 -0
- package/dist/real-lua-analyzer-5BAPDZDF.js +1957 -0
- package/dist/real-makefile-analyzer-YJKAHNAS.js +920 -0
- package/dist/real-markdown-analyzer-UKUQZO4F.js +1215 -0
- package/dist/real-matlab-analyzer-FVIKQZKG.js +480 -0
- package/dist/real-nim-analyzer-M7FAIABG.js +3603 -0
- package/dist/real-objective-c-analyzer-XMYQIGQI.js +1518 -0
- package/dist/real-perl-analyzer-ZLY6M2DZ.js +1865 -0
- package/dist/real-php-analyzer-KI2ZAM7X.js +9368 -0
- package/dist/real-powershell-analyzer-B3T5ZP6U.js +2915 -0
- package/dist/real-protobuf-analyzer-23OZ75XV.js +867 -0
- package/dist/real-python-analyzer-I4TIUB6D.js +4880 -0
- package/dist/real-r-analyzer-FJZJXXS6.js +2596 -0
- package/dist/real-ruby-analyzer-M3UFIVTQ.js +2429 -0
- package/dist/real-rust-analyzer-LVSONPAN.js +3359 -0
- package/dist/real-scala-analyzer-CWPI33Q2.js +3293 -0
- package/dist/real-scss-analyzer-TGRJQ7TH.js +1515 -0
- package/dist/real-solidity-analyzer-4P2VBVWA.js +2608 -0
- package/dist/real-sql-analyzer-J7DYZOZR.js +3840 -0
- package/dist/real-svelte-analyzer-NHEN2SX5.js +2532 -0
- package/dist/real-swift-analyzer-2NSYULWI.js +2311 -0
- package/dist/real-toml-analyzer-L3C66L7Q.js +929 -0
- package/dist/real-typescript-analyzer-FTC6ETRQ.js +14 -0
- package/dist/real-vb-analyzer-ORY7LAQS.js +3145 -0
- package/dist/real-vba-analyzer-JH2TTUFI.js +466 -0
- package/dist/real-vue-analyzer-OO4FUGBV.js +2680 -0
- package/dist/real-xml-analyzer-6CQVR477.js +2405 -0
- package/dist/real-yaml-analyzer-J6MQG3YX.js +3528 -0
- package/dist/real-zig-analyzer-EFKCPJNU.js +2430 -0
- package/dist/regex-search-OPTLKUN5.js +239 -0
- package/dist/rules-I453JTRC.js +152 -0
- package/dist/scoped-path-MJYWJZQX.js +11 -0
- package/dist/setup-show-Y5GB5KXA.js +15 -0
- package/dist/setup-wizard-G5YYR5T6.js +24 -0
- package/dist/symbol-search-KB4MU4SI.js +16 -0
- package/dist/taint-YOTN5X55.js +202 -0
- package/dist/taint-analyzer-N7YLZU3N.js +163 -0
- package/dist/tool-handlers-G4NAGJIH.js +72 -0
- package/dist/tool-registry-BPEJNSZG.js +17 -0
- package/dist/tool-validation-RF675A3C.js +32 -0
- package/dist/type-inference-4Y7WTMFE.js +13 -0
- package/dist/vector-binary-LMY4QGAN.js +19 -0
- package/dist/version-LXGNFO37.js +9 -0
- package/dist/wasm-NMWO3WXY.js +16 -0
- package/docs/EMBEDDINGS.md +132 -0
- package/docs/README.md +178 -0
- package/docs/data/m10-baseline.json +602 -0
- package/docs/data/m10-benchmark-baseline.json +57 -0
- package/docs/data/m10-benchmark-last-run.json +127 -0
- package/docs/data/m10-final-audit.json +215 -0
- package/docs/data/m12-final-audit.json +138 -0
- package/docs/data/m12-surface-matrix.json +50 -0
- package/docs/data/public-tools.json +1902 -0
- package/docs/indexing/DEAD-ASSETS.md +88 -0
- package/docs/indexing/INDEXER-REVIEW.md +634 -0
- package/docs/indexing/PERFORMANCE-FINDINGS.md +106 -0
- package/docs/indexing/README.md +427 -0
- package/docs/indexing/discovery-matrix.md +41 -0
- package/docs/indexing/embeddings.md +325 -0
- package/docs/indexing/environment-variables.md +77 -0
- package/docs/indexing/performance.md +323 -0
- package/docs/indexing/resume.md +345 -0
- package/docs/indexing/troubleshooting.md +391 -0
- package/docs/man/bb.1 +190 -0
- package/docs/tools/bb_analyze.md +147 -0
- package/docs/tools/bb_annotate.md +110 -0
- package/docs/tools/bb_annotations.md +106 -0
- package/docs/tools/bb_ask.md +101 -0
- package/docs/tools/bb_cross_language.md +103 -0
- package/docs/tools/bb_doc.md +169 -0
- package/docs/tools/bb_edit.md +185 -0
- package/docs/tools/bb_graph.md +169 -0
- package/docs/tools/bb_health.md +156 -0
- package/docs/tools/bb_impact.md +117 -0
- package/docs/tools/bb_index.md +108 -0
- package/docs/tools/bb_migrate.md +135 -0
- package/docs/tools/bb_patterns.md +140 -0
- package/docs/tools/bb_search.md +150 -0
- package/docs/tools/bb_security.md +100 -0
- package/docs/tools/bb_visualize.md +184 -0
- package/grammars/README.md +57 -0
- package/grammars/THIRD-PARTY-NOTICES.md +50 -0
- package/grammars/tree-sitter-c/LICENSE +21 -0
- package/grammars/tree-sitter-clojure/LICENSE.md +21 -0
- package/grammars/tree-sitter-cpp/LICENSE +21 -0
- package/grammars/tree-sitter-csharp/LICENSE +21 -0
- package/grammars/tree-sitter-css/LICENSE +21 -0
- package/grammars/tree-sitter-css/README.md +21 -0
- package/grammars/tree-sitter-dart/LICENSE +20 -0
- package/grammars/tree-sitter-dart-upstream/LICENSE +20 -0
- package/grammars/tree-sitter-dart-upstream/README.md +18 -0
- package/grammars/tree-sitter-elixir/LICENSE +176 -0
- package/grammars/tree-sitter-elixir/README.md +11 -0
- package/grammars/tree-sitter-fsharp/LICENSE +21 -0
- package/grammars/tree-sitter-fsharp/README.md +45 -0
- package/grammars/tree-sitter-graphql/LICENSE +21 -0
- package/grammars/tree-sitter-graphql/README.md +106 -0
- package/grammars/tree-sitter-groovy/LICENSE +21 -0
- package/grammars/tree-sitter-groovy/README.md +4 -0
- package/grammars/tree-sitter-haskell/LICENSE +21 -0
- package/grammars/tree-sitter-haskell/README.md +394 -0
- package/grammars/tree-sitter-hcl/CHANGELOG.md +102 -0
- package/grammars/tree-sitter-hcl/LICENSE +201 -0
- package/grammars/tree-sitter-hcl/README.md +39 -0
- package/grammars/tree-sitter-html/LICENSE +21 -0
- package/grammars/tree-sitter-html/README.md +21 -0
- package/grammars/tree-sitter-julia/LICENSE +21 -0
- package/grammars/tree-sitter-julia/README.md +24 -0
- package/grammars/tree-sitter-kotlin/LICENSE +9 -0
- package/grammars/tree-sitter-lua/LICENSE.md +21 -0
- package/grammars/tree-sitter-lua/README.md +29 -0
- package/grammars/tree-sitter-make/LICENSE +21 -0
- package/grammars/tree-sitter-matlab/LICENSE +19 -0
- package/grammars/tree-sitter-matlab/README.md +99 -0
- package/grammars/tree-sitter-nim/LICENSE +373 -0
- package/grammars/tree-sitter-nim/README.md +46 -0
- package/grammars/tree-sitter-objc/LICENSE +21 -0
- package/grammars/tree-sitter-objc/README.md +20 -0
- package/grammars/tree-sitter-perl/LICENSE +7 -0
- package/grammars/tree-sitter-perl/README.md +100 -0
- package/grammars/tree-sitter-powershell/LICENSE +21 -0
- package/grammars/tree-sitter-powershell/README.md +7 -0
- package/grammars/tree-sitter-proto/LICENSE +21 -0
- package/grammars/tree-sitter-proto/README.md +105 -0
- package/grammars/tree-sitter-r/LICENSE +9 -0
- package/grammars/tree-sitter-r/README.md +66 -0
- package/grammars/tree-sitter-ruby/LICENSE +22 -0
- package/grammars/tree-sitter-scss/LICENSE +21 -0
- package/grammars/tree-sitter-scss/README.md +17 -0
- package/grammars/tree-sitter-solidity/LICENSE +7 -0
- package/grammars/tree-sitter-sql/LICENSE +21 -0
- package/grammars/tree-sitter-typescript/LICENSE +21 -0
- package/grammars/tree-sitter-vba/LICENSE +21 -0
- package/grammars/tree-sitter-vba/README.md +738 -0
- package/grammars/tree-sitter-vbnet/LICENSE +21 -0
- package/grammars/tree-sitter-vbnet/README.md +322 -0
- package/grammars/tree-sitter-xml/LICENSE +19 -0
- package/grammars/tree-sitter-yaml/LICENSE +20 -0
- package/grammars/tree-sitter-yaml/README.md +21 -0
- package/package.json +184 -4
- package/wasm/dart.wasm +0 -0
- package/wasm/tree-sitter-bash.wasm +0 -0
- package/wasm/tree-sitter-c.wasm +0 -0
- package/wasm/tree-sitter-c_sharp.wasm +0 -0
- package/wasm/tree-sitter-clean.wasm +0 -0
- package/wasm/tree-sitter-clojure.wasm +0 -0
- package/wasm/tree-sitter-core_schema.wasm +0 -0
- package/wasm/tree-sitter-cpp.wasm +0 -0
- package/wasm/tree-sitter-css.wasm +0 -0
- package/wasm/tree-sitter-dart.wasm +0 -0
- package/wasm/tree-sitter-elisp.wasm +0 -0
- package/wasm/tree-sitter-elixir.wasm +0 -0
- package/wasm/tree-sitter-elm.wasm +0 -0
- package/wasm/tree-sitter-embedded_template.wasm +0 -0
- package/wasm/tree-sitter-erlang.wasm +0 -0
- package/wasm/tree-sitter-fsharp.wasm +0 -0
- package/wasm/tree-sitter-fsharp_signature.wasm +0 -0
- package/wasm/tree-sitter-go.wasm +0 -0
- package/wasm/tree-sitter-graphql.wasm +0 -0
- package/wasm/tree-sitter-groovy.wasm +0 -0
- package/wasm/tree-sitter-haskell.wasm +0 -0
- package/wasm/tree-sitter-hcl.wasm +0 -0
- package/wasm/tree-sitter-html.wasm +0 -0
- package/wasm/tree-sitter-java.wasm +0 -0
- package/wasm/tree-sitter-javascript.wasm +0 -0
- package/wasm/tree-sitter-json.wasm +0 -0
- package/wasm/tree-sitter-json_schema.wasm +0 -0
- package/wasm/tree-sitter-julia.wasm +0 -0
- package/wasm/tree-sitter-kotlin.wasm +0 -0
- package/wasm/tree-sitter-lua.wasm +0 -0
- package/wasm/tree-sitter-make.wasm +0 -0
- package/wasm/tree-sitter-markdown.wasm +0 -0
- package/wasm/tree-sitter-markdown_inline.wasm +0 -0
- package/wasm/tree-sitter-matlab.wasm +0 -0
- package/wasm/tree-sitter-nim.wasm +0 -0
- package/wasm/tree-sitter-objc.wasm +0 -0
- package/wasm/tree-sitter-ocaml.wasm +0 -0
- package/wasm/tree-sitter-perl.wasm +0 -0
- package/wasm/tree-sitter-php.wasm +0 -0
- package/wasm/tree-sitter-php_only.wasm +0 -0
- package/wasm/tree-sitter-powershell.wasm +0 -0
- package/wasm/tree-sitter-protobuf.wasm +0 -0
- package/wasm/tree-sitter-python.wasm +0 -0
- package/wasm/tree-sitter-ql.wasm +0 -0
- package/wasm/tree-sitter-r.wasm +0 -0
- package/wasm/tree-sitter-rescript.wasm +0 -0
- package/wasm/tree-sitter-ruby.wasm +0 -0
- package/wasm/tree-sitter-rust.wasm +0 -0
- package/wasm/tree-sitter-scala.wasm +0 -0
- package/wasm/tree-sitter-scss.wasm +0 -0
- package/wasm/tree-sitter-solidity.wasm +0 -0
- package/wasm/tree-sitter-sql.wasm +0 -0
- package/wasm/tree-sitter-svelte.wasm +0 -0
- package/wasm/tree-sitter-swift.wasm +0 -0
- package/wasm/tree-sitter-systemrdl.wasm +0 -0
- package/wasm/tree-sitter-terraform.wasm +0 -0
- package/wasm/tree-sitter-tlaplus.wasm +0 -0
- package/wasm/tree-sitter-toml.wasm +0 -0
- package/wasm/tree-sitter-tsx.wasm +0 -0
- package/wasm/tree-sitter-typescript.wasm +0 -0
- package/wasm/tree-sitter-vba.wasm +0 -0
- package/wasm/tree-sitter-vbnet.wasm +0 -0
- package/wasm/tree-sitter-vue.wasm +0 -0
- package/wasm/tree-sitter-xml.wasm +0 -0
- package/wasm/tree-sitter-yaml.wasm +0 -0
- package/wasm/tree-sitter-zig.wasm +0 -0
- package/wasm/tree-sitter.wasm +0 -0
- package/wasm/tsx.wasm +0 -0
- package/wasm/typescript.wasm +0 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,298 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## 0.1.0 — first public release
|
|
4
|
+
|
|
5
|
+
The first public release of Backbencher Brain (`backbencher-brain` on npm, `bb` on
|
|
6
|
+
the command line). Everything below is what a fresh `npm install -g @backbencher/brain`
|
|
7
|
+
gives you. The section still headed **Unreleased** further down was written against
|
|
8
|
+
internal builds and ships in this release; read it as the detailed change record
|
|
9
|
+
behind this summary.
|
|
10
|
+
|
|
11
|
+
### What ships
|
|
12
|
+
|
|
13
|
+
- **16 MCP tools**, served over stdio to any MCP host (Claude Code, Cursor, VS Code,
|
|
14
|
+
Zed, and anything else that speaks MCP): `bb_search`, `bb_ask`, `bb_analyze`,
|
|
15
|
+
`bb_graph`, `bb_impact`, `bb_patterns`, `bb_security`, `bb_doc`, `bb_visualize`,
|
|
16
|
+
`bb_migrate`, `bb_cross_language`, `bb_edit`, `bb_index`, `bb_health`,
|
|
17
|
+
`bb_annotate`, `bb_annotations`. Tool descriptors are the same for the CLI and the
|
|
18
|
+
MCP server, and `docs/data/public-tools.json` is generated from the executable
|
|
19
|
+
registry so the catalog cannot drift from the tool that answers.
|
|
20
|
+
- **50 language analyzers**, from TypeScript/JavaScript, Python, Go,
|
|
21
|
+
Rust, Java/Kotlin/Scala/Groovy and C/C++ through to Haskell, Clojure, Clean, Erlang,
|
|
22
|
+
Julia, Nim, Solidity, HCL/Terraform, Vue, Svelte and more. TSX, Sass and Terraform are
|
|
23
|
+
aliases of the TypeScript, CSS and HCL analyzers, not extra languages; the editor lane
|
|
24
|
+
covers 49 of the 50 (Objective-C is excluded because `.m` is shared with MATLAB) and 48
|
|
25
|
+
carry recorded in-editor evidence. The list is the `SUPPORTED_LANGUAGES` map in
|
|
26
|
+
`src/ast/engine.ts`; the site reads the same map.
|
|
27
|
+
- **A CLI with 14 commands**: `bb index` (build/inspect the index), `bb search`,
|
|
28
|
+
`bb mcp`, `bb setup`, `bb stats`, `bb status`, `bb health`, `bb doctor`,
|
|
29
|
+
`bb projects`, `bb onboard`, `bb tool`, `bb upgrade`, `bb version`, `bb help`.
|
|
30
|
+
- **An LSP server** (`dist/lsp/server.js` over stdio; the editor extension launches it) for the launch languages recorded in
|
|
31
|
+
`src/lsp/launch_languages.ts` — hover, definition, references, document symbols,
|
|
32
|
+
workspace symbols, call hierarchy. The launch set is extended only through the
|
|
33
|
+
recorded wave protocol, so the set here is what the gates prove, not a promise.
|
|
34
|
+
- **Local-first by construction.** The index is SQLite, one database per project,
|
|
35
|
+
outside your repository (`bb stats` prints the path). Nothing is uploaded, there is
|
|
36
|
+
no account, no telemetry and no hosted service; semantic search needs a local
|
|
37
|
+
embedding provider you choose (`bb setup`).
|
|
38
|
+
- **Edits that declare their limits.** `bb_edit` does AST-bounded write/update/
|
|
39
|
+
insert/delete/refactor with pre-image checks, dry runs, batch atomicity and a
|
|
40
|
+
formatter step that reports what it actually did. Every read surface carries a
|
|
41
|
+
freshness block rather than quietly answering from a stale index.
|
|
42
|
+
|
|
43
|
+
### Install
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
npm install -g @backbencher/brain # primary path, Node.js >= 18
|
|
47
|
+
bb --version
|
|
48
|
+
bb setup # optional: semantic search provider
|
|
49
|
+
bb index /path/to/project
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
`curl -fsSL https://backbencher.cc/install.sh | bash` and
|
|
53
|
+
`irm https://backbencher.cc/install.ps1 | iex` remain as alternatives: they install
|
|
54
|
+
the same npm package, and fall back to a checksum-verified GitHub release binary only
|
|
55
|
+
when npm is unavailable. Pin a version with `VERSION=0.1.0` in front of either script.
|
|
56
|
+
Windows, Linux and macOS are supported; the native modules (`better-sqlite3`,
|
|
57
|
+
`web-tree-sitter`) build through npm's normal platform support.
|
|
58
|
+
|
|
59
|
+
### Known limits, stated rather than buried
|
|
60
|
+
|
|
61
|
+
- Node.js 18 or newer is required; there is no bundled runtime.
|
|
62
|
+
- Parsing and analysis are static. Nothing here executes the code it reads, so a
|
|
63
|
+
clean report is not a proof of correctness or security.
|
|
64
|
+
- The LSP serves the languages in the launch set; other indexed languages still get
|
|
65
|
+
the MCP/CLI surfaces but not editor features.
|
|
66
|
+
- Semantic retrieval quality depends on the embedding provider you configure; the
|
|
67
|
+
lexical/graph surfaces work without one.
|
|
68
|
+
- `npm upgrade`/`bb upgrade` move you to the next published release; the index schema
|
|
69
|
+
migrates in place and is never wiped by an upgrade.
|
|
70
|
+
|
|
71
|
+
### Version numbering
|
|
72
|
+
|
|
73
|
+
`0.1.0` is the first public version. Earlier internal builds counted up to `0.3.0`,
|
|
74
|
+
and a separate pre-release binary product used `1.0.x` version numbers; neither is
|
|
75
|
+
continued here. No `1.0.x` artifact was ever published to npm, and the `1.0.x`
|
|
76
|
+
installer line is retired — the installers in this repository install
|
|
77
|
+
`backbencher-brain` from npm.
|
|
78
|
+
|
|
79
|
+
## Unreleased
|
|
80
|
+
|
|
81
|
+
### The editor surfaces stopped disagreeing with each other
|
|
82
|
+
|
|
83
|
+
Four surfaces answer "who uses this symbol": the hover card, `bb/graph` `mode:"usages"`
|
|
84
|
+
(the hub), `textDocument/references`, and the hover's own `connected:` line. Measured on a
|
|
85
|
+
real index over real stdio, one symbol produced four numbers — `greet` reported 6 usages in
|
|
86
|
+
prose while its own connections line listed 3 callers, the hub listed 6 caller groups, and
|
|
87
|
+
references returned 7 locations. Each number was individually defensible: they counted
|
|
88
|
+
different things, and none of them said what.
|
|
89
|
+
|
|
90
|
+
They now count one thing and say so. A **usage site** is a stored relationship row whose
|
|
91
|
+
target is the symbol and whose kind is not a declaration containment, owned in one place
|
|
92
|
+
(`src/lsp/relations.ts`); a **count** is a count of served positions, and the unit sentence is
|
|
93
|
+
the owner's single copy quoted by every surface. The hover's count equals its rendered rows
|
|
94
|
+
plus a declared remainder; zero is stated rather than omitted.
|
|
95
|
+
|
|
96
|
+
Three separate lies were removed to get there, each found only because a human read the
|
|
97
|
+
surface:
|
|
98
|
+
|
|
99
|
+
- **The hover's "usages" list was not usages.** `greetAll` has zero callers and rendered
|
|
100
|
+
"3 usages" listing its own class (`Greeter`) and its own callee (`greet`). Declaration
|
|
101
|
+
containments now render in their own labelled section and never in the usage list or the
|
|
102
|
+
connection summary.
|
|
103
|
+
- **The hub served the owner-family cascade as callers.** A method with **zero** callers
|
|
104
|
+
answered six caller groups — every class member's referrers plus the class's own
|
|
105
|
+
instantiators — so "who calls this" listed symbols that never call it. Cascade rows are now
|
|
106
|
+
excluded **and counted** per bucket (`selfReferentialRows`, `declarationContainments`,
|
|
107
|
+
`ownerFamilyRows`), with `callerCandidateRows` on the payload so every excluded row is
|
|
108
|
+
accounted for. The naive fix — drop everything not adjacent to the root — was measured and
|
|
109
|
+
rejected: it deleted the hub's legitimate transitive call tree. The law that satisfies both
|
|
110
|
+
is that a deeper row is served only when it extends an already-served chain.
|
|
111
|
+
- **The class's caller list carried a member's own call**, re-attributed to the class. It now
|
|
112
|
+
equals the class's usage sites.
|
|
113
|
+
|
|
114
|
+
`script/m55/verify-relations.ts` grew four cross-surface assertions (`R3b`) that pin the
|
|
115
|
+
agreement on the wire: a zero-caller symbol answers zero from hover, references and the hub;
|
|
116
|
+
an empty answer is empty *by a declared filter* whose counts close the row arithmetic; a
|
|
117
|
+
symbol with callers reconciles as groups = usage places + the declared unlocatable referrers.
|
|
118
|
+
|
|
119
|
+
### A position a surface could not know is no longer shown
|
|
120
|
+
|
|
121
|
+
Three classes of invented position, all found by reading rendered surfaces:
|
|
122
|
+
|
|
123
|
+
- **The hover served stored call-site lines past the end of the source.** A three-line file
|
|
124
|
+
with rows stored at lines 40 and 41 rendered two usage links that opened past the file.
|
|
125
|
+
The hover now applies the same line bound `textDocument/references` applies
|
|
126
|
+
(`createPositionMapper(text).lineTexts.length`), refuses to serve such a row, and declares
|
|
127
|
+
the count: *"usages omitted — N stored rows name a call-site line past the end of the source
|
|
128
|
+
file"*, with `data.omittedUsageRows`. Measured before/after: collector sites 2 → 0,
|
|
129
|
+
`omittedUnresolvable` unchanged at 2. The agreement is gated, not described.
|
|
130
|
+
- **Call hierarchy listed the root as its own caller and callee**, pointed every `fromRanges`
|
|
131
|
+
entry at a declaration instead of the call site, and threw `-32603` when a caller was
|
|
132
|
+
expanded. Self-edges are dropped and **declared with their reason**; ranges come from the
|
|
133
|
+
M62 address owner and carry the declared unknown where the store holds no real line.
|
|
134
|
+
- **Outgoing connected/containment links opened the far end's file at the caller's stored
|
|
135
|
+
line** — a link labelled "instantiates [Greeter]" that opened `greeter.ts:4` when the site is
|
|
136
|
+
`app.ts:4`. Outgoing rows now open the far end's declaration and never turn a stored line
|
|
137
|
+
into a link target for a different symbol.
|
|
138
|
+
|
|
139
|
+
A new absence code `no_stored_calls` distinguishes "served symbol with an empty call list" from
|
|
140
|
+
`symbol_not_at_position`, which was false for it — a machine-readable code a client may branch
|
|
141
|
+
on must not contradict the answer.
|
|
142
|
+
|
|
143
|
+
### The hover's relationship denominator was ten kinds against an index that stores fourteen
|
|
144
|
+
|
|
145
|
+
`decorates`, `renders`, `mixes_in` and `part_of` were stored, classified by the hover's own tier
|
|
146
|
+
owner, and could not be rendered or declared because the denominator and the verb table stopped
|
|
147
|
+
at ten. All fourteen now have a denominator entry, both-direction verbs, and — for `part_of` —
|
|
148
|
+
a declared absence instead of a link (a module-level inclusion, like `imports`, is not drawn as
|
|
149
|
+
a symbol link). The drift gate that catches this was itself anchored on a file the kind
|
|
150
|
+
enumeration had moved out of, so it had been reporting a refactor as a pass rather than
|
|
151
|
+
checking a fact.
|
|
152
|
+
|
|
153
|
+
### Warm hover latency: p95 51.31 ms → 9.82 ms
|
|
154
|
+
|
|
155
|
+
The warm budget is 50 ms (§3). One of three busy shapes missed it. The cause was not the parse:
|
|
156
|
+
the hover resolved a full call-site location for **every** row and then discarded it for any row
|
|
157
|
+
whose stored call-site line was real, so a 32-file symbol paid 30 file reads and 60 position
|
|
158
|
+
mappers per request for positions nothing later read. Now a row with a real stored call-site
|
|
159
|
+
line is served from `(caller path, stored line)` validated only by the line-count bound, and
|
|
160
|
+
line counts ride a bounded LRU keyed by `(path, mtimeMs, size)` — stat-only on a warm hit,
|
|
161
|
+
re-read on any mismatch. Measured with load average 20.67 on 8 CPUs: shape A p50 6.62 ms /
|
|
162
|
+
p95 9.82 ms; shapes B and C under 5 ms. No regex was introduced (regex policy: 0 new).
|
|
163
|
+
|
|
164
|
+
### The extension activated on 7 of the 14 languages the server serves
|
|
165
|
+
|
|
166
|
+
`src/lsp/launch_languages.ts` is the single owner of the launch set (14 languages), but
|
|
167
|
+
`package.json` `activationEvents` and the client's `documentSelector` listed 7. On a Go, Rust,
|
|
168
|
+
C, C++, Vue, Svelte or Zig file the extension never activated; in a mixed workspace VS Code
|
|
169
|
+
sent no requests for those files at all. Both lists are now derived from the owner through a
|
|
170
|
+
type-enforced language-id table, and `esbuild-extension.mjs` fails the build if
|
|
171
|
+
`activationEvents` drifts from the launch set.
|
|
172
|
+
|
|
173
|
+
### The status-bar badge was dead on three paths
|
|
174
|
+
|
|
175
|
+
Clicking the `bb` badge opened nothing when there was no workspace folder (a single file
|
|
176
|
+
opened), when the server was not resolved, or when the server version was incompatible — the
|
|
177
|
+
click target was assigned only on the success path. The command is now assigned at creation and
|
|
178
|
+
every command is registered before any early return, so no badge renders without a working
|
|
179
|
+
click.
|
|
180
|
+
|
|
181
|
+
### A claim ladder with three definitions
|
|
182
|
+
|
|
183
|
+
The I0–I5 levels were defined three times and disagreed: the contract said I2
|
|
184
|
+
INDEX-CONFORMANT / I3 EDITOR-VERIFIED / I4 FORK-VERIFIED, the extension README said
|
|
185
|
+
RUNTIME-PASSED / IN-EDITOR / CROSS-EDITOR, and the status model said HARNESS-VERIFIED /
|
|
186
|
+
EDITOR-VERIFIED / PRECISION-VERIFIED. The website rendered two of them side by side. The
|
|
187
|
+
contract is governing; both other copies now defer to it and define no second ladder.
|
|
188
|
+
|
|
189
|
+
### Verification machinery repaired
|
|
190
|
+
|
|
191
|
+
Six gates were red or silently not running, each for a reason unrelated to the product:
|
|
192
|
+
|
|
193
|
+
- `verify-relations.ts` M4 anchored on a source expression M62 had moved behind the
|
|
194
|
+
single-owner constant `STORED_LINE_COLUMN`, so it matched zero times.
|
|
195
|
+
- `verify-call-hierarchy.ts` C1 asserted a store shape the engine stopped producing in
|
|
196
|
+
`2617ac1bd` ("an unresolved target is reported as unresolved, not matched by name"); it is
|
|
197
|
+
now a hermetic planted-row test, and the seven free verdicts it caused are gone.
|
|
198
|
+
- `verify-hover-coverage.ts` V1c read `src/mcp/tool-registry.ts`, where the relationship-kind
|
|
199
|
+
enumeration no longer lives, and its machine metadata shelled out to
|
|
200
|
+
`sysctl -n hw.ncpu`, which crashes on Linux before any result is written.
|
|
201
|
+
- `verify-evidence-tree-clean.ts` counted ~6.7k **deliberately gitignored** research artifacts
|
|
202
|
+
as "scratch" while its own self-check asked git the same question and got a different
|
|
203
|
+
answer; and its EVID-TREE claim declared only verifier paths as coverage, so the fingerprint
|
|
204
|
+
could not discriminate and the gate threw on every run that reached the evidence write.
|
|
205
|
+
- Four gates (`verify-server`, `verify-usage-scope`, `verify-usages-fallback`) did not pin
|
|
206
|
+
`BB_DATA_DIR`, so on a host with a read-only `~/.bb` every absence-carrier path died with
|
|
207
|
+
`-32603 ENOENT` — a red gate about the sandbox. They now pin a temp data dir unless one is
|
|
208
|
+
supplied, and `L1` is 142/142 reproducibly.
|
|
209
|
+
|
|
210
|
+
### Documentation and tree hygiene
|
|
211
|
+
|
|
212
|
+
Documentation now states measured fact rather than narrated decision: the "owner said",
|
|
213
|
+
"his words" and "owner live test" framing is gone from the IDE documents and from the
|
|
214
|
+
analyzer header template that taught it. Thirteen superseded/duplicate documents and twelve
|
|
215
|
+
stray root files (six ad-hoc probes referencing a path that does not exist in this layout, a
|
|
216
|
+
certificate log, two XML probes, two superseded root docs, an unused wasm copy) were removed
|
|
217
|
+
after a reference grep proved nothing cited them. A new `docs/IDE-LANE-BASELINE.md` records,
|
|
218
|
+
per record, what the documents claimed, what the record claimed, what the gate returned at
|
|
219
|
+
HEAD, and what is actually true — four different states that had been collapsed into one.
|
|
220
|
+
|
|
221
|
+
### A `callers` count was not a count of calls
|
|
222
|
+
|
|
223
|
+
The graph engine's default covers every relationship kind the index stores — documented, and
|
|
224
|
+
deliberate, because `contains` is the parent→member edge and excluding it stops a traversal rooted
|
|
225
|
+
at a class from reaching that class's own methods. Three consumers in `src/` read that set while
|
|
226
|
+
making a claim about one kind:
|
|
227
|
+
|
|
228
|
+
- `testImpact` published a depth-0 row from a test file as a DIRECT test without asking what kind
|
|
229
|
+
of row it was, so a test class that *contains* the symbol under test answered as a test that
|
|
230
|
+
depends on it — and `testSuggestions` stamped that `direct_call` at 0.85 confidence.
|
|
231
|
+
- `testSuggestions`'s `blastRadius`, labelled "caller closure", counted containment and lexical
|
|
232
|
+
rows, and it feeds `priorityFor`, so structure inflated a priority.
|
|
233
|
+
- the deprecated `analyzeImpact` (not reachable from any tool since M48) fitted every kind into
|
|
234
|
+
`directSymbols` / `affectedFiles`.
|
|
235
|
+
|
|
236
|
+
Measured on a fixture whose store holds, from the real analyzer, `realTest --calls--> nested` and
|
|
237
|
+
`TestHost --contains--> nested`: the unscoped walk returns both callers, the scoped walk returns
|
|
238
|
+
one, and the tool now reports `directTests: [{ testSymbol: "realTest", relationshipType: "calls",
|
|
239
|
+
evidence: "direct_call" }]`. `TestImpactReport.directTests` / `indirectTests` and
|
|
240
|
+
`AffectedTestEntry` now carry `relationshipType` and `evidence`, so "directly a test" is never
|
|
241
|
+
published as "directly calls". `testSuggestions` walks `bb_impact`'s declared dependency rule
|
|
242
|
+
(`IMPACT_REL_TYPES`, one list, imported from its owner) instead of every kind.
|
|
243
|
+
|
|
244
|
+
`bb_analyze`'s page said nothing about the kind set its `callers`/`callees`/`trace` modes walk; it
|
|
245
|
+
does now, including that mode `impact` walks the declared dependency rule instead — so a `callers`
|
|
246
|
+
count and an `impact` count about the same symbol are not the same question, and both name the rule.
|
|
247
|
+
Pinned by `script/m65/verify-edge-kind-scoping.ts`: an inventory of every graph call site in `src/`
|
|
248
|
+
(an unscoped one must be a declared all-kinds door), a fixture differential against the store, two
|
|
249
|
+
mutations, and source guards so a reverted filter fails the gate.
|
|
250
|
+
|
|
251
|
+
### The public surface grew from ten to sixteen
|
|
252
|
+
|
|
253
|
+
The 0.3.0 section below describes that release's surface, and it was accurate when it
|
|
254
|
+
was written (2026-08-09). Six tools have been added since, so the live surface is
|
|
255
|
+
sixteen — the number is now read from `docs/data/public-tools.json` wherever it is
|
|
256
|
+
needed instead of being restated:
|
|
257
|
+
|
|
258
|
+
- `bb_index` — reindex a file or directory so the index reflects edits immediately,
|
|
259
|
+
plus `mode=post` to re-run derived phases without re-parsing.
|
|
260
|
+
- `bb_graph` — per-symbol callers/callees at a declared depth, with per-edge evidence
|
|
261
|
+
tier and confidence from the canonical graph engine.
|
|
262
|
+
- `bb_impact` — bounded reverse-dependency impact with a declared node budget and an
|
|
263
|
+
echoed relationship-type rule.
|
|
264
|
+
- `bb_cross_language` — stored cross-language facts for one symbol, with absence
|
|
265
|
+
declared rather than inferred when the store holds none.
|
|
266
|
+
- `bb_annotate` — write an agent-authored note with `author_class` enforced at the
|
|
267
|
+
schema level, never spoofable.
|
|
268
|
+
- `bb_annotations` — read notes back with full provenance and a declared bound.
|
|
269
|
+
|
|
270
|
+
Same release window, same defect class: `README.md` and both MCP acceptance harnesses
|
|
271
|
+
(`script/verify-mcp.ts`, `script/verify-mcp-e2e.ts`) had kept the old count in prose and
|
|
272
|
+
in an assertion. The stale assertion failed at command 125 of 358 in `npm run verify`,
|
|
273
|
+
which made the 233 commands after it unreachable — so nothing downstream could notice.
|
|
274
|
+
Both harnesses now derive the expected surface from the contract file, cover all sixteen
|
|
275
|
+
tools (five had no MCP-level test at all, and `bb_index` had never been called as a tool),
|
|
276
|
+
and fail with a named missing/undeclared list rather than a bare number.
|
|
277
|
+
|
|
278
|
+
## 0.3.0
|
|
279
|
+
|
|
280
|
+
### Intelligence Tools Rebuild
|
|
281
|
+
|
|
282
|
+
- Published the final ten-tool MCP surface: `bb_search`, `bb_ask`, `bb_analyze`,
|
|
283
|
+
`bb_patterns`, `bb_security`, `bb_doc`, `bb_visualize`, `bb_migrate`, `bb_edit`,
|
|
284
|
+
and `bb_health`.
|
|
285
|
+
- Removed compatibility aliases after the announced breaking-release window:
|
|
286
|
+
`bb_select`, `bb_relationships`, `bb_refresh`, `bb_write`, `bb_update`,
|
|
287
|
+
`bb_insert`, `bb_delete`, `bb_refactor`, `bb_test_quality`, and
|
|
288
|
+
`bb_test_suggestions`.
|
|
289
|
+
- Replacements are `bb_search mode=symbol`; `bb_analyze` callers/callees/trace and
|
|
290
|
+
test modes; `bb_health refresh=true`; and `bb_edit` write/update/insert/delete/
|
|
291
|
+
refactor modes.
|
|
292
|
+
- Removed alias-only stale-index mutation exceptions. Canonical symbol mutations
|
|
293
|
+
require current indexed AST bounds.
|
|
294
|
+
- Preserved internal indexing, semantic, graph, analysis, test, edit, health,
|
|
295
|
+
documentation, visualization, and migration engines. They are implementation
|
|
296
|
+
layers, not separately advertised MCP tools.
|
|
297
|
+
|
|
298
|
+
Historical migration details remain in `archive/docs-pre-consolidation/MCP_TOOL_MIGRATION.md`.
|
package/EMBEDDINGS.md
ADDED
|
@@ -0,0 +1,355 @@
|
|
|
1
|
+
# Semantic Embeddings — Setup Guide
|
|
2
|
+
|
|
3
|
+
brain-core ships two embedding layers:
|
|
4
|
+
|
|
5
|
+
1. **API embeddings** (best quality) — any OpenAI-compatible `/embeddings`
|
|
6
|
+
endpoint: Google Gemini, NVIDIA NIM, OpenAI, or a self-hosted vLLM /
|
|
7
|
+
llama.cpp server. Off by default — one config file or 3 env vars turns it on.
|
|
8
|
+
2. **Local word vectors** (offline fallback) — always available, no API key.
|
|
9
|
+
Quality is keyword-level, not true semantics.
|
|
10
|
+
|
|
11
|
+
## Interactive setup: `bb setup` (recommended first run)
|
|
12
|
+
|
|
13
|
+
`bb setup` walks you through provider choice with prefilled base URL and model
|
|
14
|
+
so you only paste the API key (input is hidden). It validates the key with one
|
|
15
|
+
live `/embeddings` call before saving, writes `~/.bb/config.json` with mode
|
|
16
|
+
0600 (owner-only), and never stores the key anywhere else. The built-in free
|
|
17
|
+
options are:
|
|
18
|
+
|
|
19
|
+
| Provider | base_url (prefilled) | model (prefilled) |
|
|
20
|
+
|---|---|---|
|
|
21
|
+
| OpenRouter free | `https://openrouter.ai/api/v1` | `liquid/lfm-2.5-embedding-350m:free` |
|
|
22
|
+
| NVIDIA NIM free | `https://integrate.api.nvidia.com/v1` | `nvidia/nemotron-3-embed-1b` |
|
|
23
|
+
| Custom / paid | you supply both | you supply both |
|
|
24
|
+
|
|
25
|
+
If you skip setup or have no key, `bb index` shows exactly this notice (one
|
|
26
|
+
line, non-interactive environments never block on it):
|
|
27
|
+
|
|
28
|
+
```
|
|
29
|
+
note: no embedding key — semantic search will use local vectors (weaker). Setup: bb setup
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
The wizard runs **once**: an explicit skip is remembered (a `setup_skipped`
|
|
33
|
+
marker in the 0600 config), so `bb index` never re-prompts after you chose to
|
|
34
|
+
skip. Entering a key later via `bb setup` replaces the skip automatically.
|
|
35
|
+
|
|
36
|
+
### What a failed key validation means (pre-save, `bb setup`)
|
|
37
|
+
|
|
38
|
+
A key is validated before it is saved. The exact messages users see:
|
|
39
|
+
|
|
40
|
+
- `Key rejected (401). Check the key and provider — copy-paste may have dropped or added characters.`
|
|
41
|
+
- `Rate limit (429). The key looks valid; free-tier limit. It can be saved — indexing backs off and retries.`
|
|
42
|
+
- `Provider error (503). The key may be valid; the provider is temporarily failing. It can be saved — indexing retries automatically.`
|
|
43
|
+
- `Model not found (404). Check the model name: the provider's /embeddings endpoint does not recognize it.`
|
|
44
|
+
- `Provider did not respond (timeout). Check your internet connection and the base URL.`
|
|
45
|
+
- `Could not reach the provider: <error>. Check the base URL.`
|
|
46
|
+
- `Provider returned invalid JSON. The base URL must be a /v1 endpoint.`
|
|
47
|
+
- `Provider returned no embedding. Check the base URL and model name.`
|
|
48
|
+
|
|
49
|
+
429 and 5xx are treated as "key shape accepted" (rate/provider side issue) and
|
|
50
|
+
saved; A 401/403/404 or malformed response is a hard error: the key is NOT saved.
|
|
51
|
+
|
|
52
|
+
**What a saved key actually gets at index time.** The wording above is
|
|
53
|
+
`bb setup`'s pre-save validation, and one of those messages is optimistic about
|
|
54
|
+
what follows: indexing does not re-run key validation, so a 503 seen here is not
|
|
55
|
+
proof that indexing will retry the same way. Concretely, at index time:
|
|
56
|
+
|
|
57
|
+
- A **429** degrades only that batch, per-batch, to local word vectors, and
|
|
58
|
+
further batches are held off by a bounded `Retry-After` window in the engine
|
|
59
|
+
(never a process-wide latch, so the run recovers by itself).
|
|
60
|
+
- A **5xx, timeout, or unreachable provider** degrades that batch to local word
|
|
61
|
+
vectors. The next batch tries again — there is no wait, so a provider that is
|
|
62
|
+
down for a whole run costs one degraded batch per batch, not one at the end.
|
|
63
|
+
- A **401 or 404** stops being retried for the rest of the process: further
|
|
64
|
+
embedding requests fail immediately with the same classified error, and `bb
|
|
65
|
+
doctor` reports the status and what to change. Re-running the command after
|
|
66
|
+
fixing the key picks it up again.
|
|
67
|
+
- **No batch is silently lost**: a batch that cannot be embedded by any provider
|
|
68
|
+
falls back to sparse `tfidf-v1` rows, and the run reports how many were
|
|
69
|
+
embedded, fell back, or failed.
|
|
70
|
+
|
|
71
|
+
If you want a second provider tried when the first one fails, configure
|
|
72
|
+
`BB_EMBEDDING_FALLBACK_*` (below) — that provider is the one with a client-side
|
|
73
|
+
retry loop, bounded by `BB_EMBEDDING_FALLBACK_RETRIES`.
|
|
74
|
+
|
|
75
|
+
## Inspecting and diagnosing: `bb setup show` and `bb doctor` (M32)
|
|
76
|
+
|
|
77
|
+
`bb setup show` prints the effective embedding configuration without ever
|
|
78
|
+
displaying the full key — the key appears only as its last four characters:
|
|
79
|
+
|
|
80
|
+
```
|
|
81
|
+
bb — embedding configuration
|
|
82
|
+
Precedence: env > ~/.bb/config.json > bb.json
|
|
83
|
+
|
|
84
|
+
env : — (not set)
|
|
85
|
+
global : ✓ https://g.example/v1 · g-model · key: ••••2345 · mode: 600
|
|
86
|
+
project: — (not set)
|
|
87
|
+
|
|
88
|
+
Winner: global
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
It names the winning precedence tier, shows incomplete tiers with what is
|
|
92
|
+
missing (an incomplete tier can never win), warns when a config file's mode is
|
|
93
|
+
not 0600, and exits 1 when nothing is configured (scripts can branch on it).
|
|
94
|
+
A corrupt config file is treated as an absent tier — it never crashes.
|
|
95
|
+
|
|
96
|
+
`bb doctor` diagnoses degradation from real local state (config file, file
|
|
97
|
+
permissions, and the embedding models actually stored in the project index —
|
|
98
|
+
read-only, no network). Every finding names the exact fix command:
|
|
99
|
+
|
|
100
|
+
```
|
|
101
|
+
bb doctor — diagnostics
|
|
102
|
+
|
|
103
|
+
✗ No embedding configuration.
|
|
104
|
+
Fix: bb setup
|
|
105
|
+
! global config file has mode 644 — the key may be world-readable.
|
|
106
|
+
Fix: bb doctor --fix
|
|
107
|
+
· No stored vectors for this project (no index or empty). Config model: g-model.
|
|
108
|
+
Fix: bb index .
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
A model mismatch (config says one model, the index was built with another) is
|
|
112
|
+
reported as a hard failure with `Fix: bb index --force` — stored vectors
|
|
113
|
+
from different models are never compared. `bb doctor` exits 1 when a fail-level
|
|
114
|
+
finding exists.
|
|
115
|
+
|
|
116
|
+
### `bb doctor --fix`: the only mutating arm
|
|
117
|
+
|
|
118
|
+
`bb doctor --fix` repairs **only file permissions** of embedding config files
|
|
119
|
+
to 0600. It prints every change it makes; config content, keys, and the index
|
|
120
|
+
are never modified by `--fix`. Everything else remains advice naming the exact
|
|
121
|
+
command — diagnosis never auto-mutates, and `--fix` never touches anything
|
|
122
|
+
beyond permissions:
|
|
123
|
+
|
|
124
|
+
```
|
|
125
|
+
bb doctor --fix — applied
|
|
126
|
+
|
|
127
|
+
✓ /root/.bb/config.json: mode 644 -> 600 (applied)
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
## Discovering these commands
|
|
131
|
+
|
|
132
|
+
Every command documents itself: `bb --help` lists all commands,
|
|
133
|
+
`bb <command> --help` shows that command's options, and `bb -v`,
|
|
134
|
+
`bb version`, and `bb --version` all print the version. A mistyped command
|
|
135
|
+
suggests the closest real one (`bb docter` suggests `doctor`). The full
|
|
136
|
+
manual ships with npm installs and is available as `man bb`.
|
|
137
|
+
|
|
138
|
+
## Quick start (3 environment variables)
|
|
139
|
+
|
|
140
|
+
```bash
|
|
141
|
+
export BB_EMBEDDING_BASE_URL=https://generativelanguage.googleapis.com/v1beta/openai/
|
|
142
|
+
export BB_EMBEDDING_API_KEY=your-google-api-key
|
|
143
|
+
export BB_EMBEDDING_MODEL=text-embedding-004
|
|
144
|
+
|
|
145
|
+
bb index ./my-project # vectors stored under text-embedding-004
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
## Config file (per machine)
|
|
149
|
+
|
|
150
|
+
`~/.bb/config.json`:
|
|
151
|
+
|
|
152
|
+
```json
|
|
153
|
+
{
|
|
154
|
+
"embedding_model": "text-embedding-004",
|
|
155
|
+
"embedding_base_url": "https://generativelanguage.googleapis.com/v1beta/openai/",
|
|
156
|
+
"embedding_api_key": "your-google-api-key"
|
|
157
|
+
}
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
`bb.json` in the project root overrides it per project. Environment variables
|
|
161
|
+
(`BB_EMBEDDING_*`) always win.
|
|
162
|
+
|
|
163
|
+
## Known-good providers
|
|
164
|
+
|
|
165
|
+
| Provider | base_url | model | notes |
|
|
166
|
+
|---|---|---|---|
|
|
167
|
+
| Google Gemini | `https://generativelanguage.googleapis.com/v1beta/openai/` | `text-embedding-004` (768d) or `gemini-embedding-001` (3072d) | OpenAI-compatible endpoint |
|
|
168
|
+
| NVIDIA NIM | `https://integrate.api.nvidia.com/v1` | `nvidia/nv-embedqa-e5-v5` (1024d) or `nvidia/bge-m3` | OpenAI-compatible |
|
|
169
|
+
| OpenAI | `https://api.openai.com/v1` | `text-embedding-3-small` (1536d) or `-3-large` (3072d) | native |
|
|
170
|
+
| Self-hosted vLLM | `http://localhost:8000/v1` | any served model | OpenAI-compatible |
|
|
171
|
+
| Self-hosted llama.cpp | `http://localhost:8080/v1` | any served model | OpenAI-compatible |
|
|
172
|
+
|
|
173
|
+
### Google (Gemini API key from aistudio.google.com)
|
|
174
|
+
|
|
175
|
+
```
|
|
176
|
+
BB_EMBEDDING_BASE_URL=https://generativelanguage.googleapis.com/v1beta/openai/
|
|
177
|
+
BB_EMBEDDING_MODEL=text-embedding-004
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
### NVIDIA NIM (key from build.nvidia.com)
|
|
181
|
+
|
|
182
|
+
```
|
|
183
|
+
BB_EMBEDDING_BASE_URL=https://integrate.api.nvidia.com/v1
|
|
184
|
+
BB_EMBEDDING_MODEL=nvidia/nv-embedqa-e5-v5
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
## Environment variables
|
|
188
|
+
|
|
189
|
+
The three above decide **which** provider is used, and their precedence is
|
|
190
|
+
`env BB_EMBEDDING_*` > config file (`BB_CONFIG_FILE` > `bb.json` > `config.json`)
|
|
191
|
+
> built-in default. Everything below tunes how that provider is called. None of
|
|
192
|
+
them has a config-file equivalent: they are operational knobs, read from the
|
|
193
|
+
environment only.
|
|
194
|
+
|
|
195
|
+
| Variable | Default | What it does |
|
|
196
|
+
|---|---|---|
|
|
197
|
+
| `BB_EMBEDDING_DISABLED` | unset | `1`/`true`/`yes`/`on` turns remote embeddings off entirely. Indexing stores local word vectors and makes no embedding request. An unrecognised value is treated as OFF, so a typo cannot silently drop a provider you pay for. |
|
|
198
|
+
| `BB_EMBEDDING_FALLBACK_BASE_URL` | unset | A second provider to try when the primary fails. Requires `BB_EMBEDDING_FALLBACK_MODEL`. |
|
|
199
|
+
| `BB_EMBEDDING_FALLBACK_MODEL` | unset | Model for the fallback provider. |
|
|
200
|
+
| `BB_EMBEDDING_FALLBACK_API_KEY` | unset | Key for the fallback provider. A loopback fallback needs none. |
|
|
201
|
+
| `BB_EMBEDDING_FALLBACK_RETRIES` | `2` | Retries for the FALLBACK provider only, exponential backoff with jitter. `0` means one attempt, no retry loop. |
|
|
202
|
+
| `BB_EMBEDDING_TIMEOUT_MS` | `30000` | Bound on one embedding request, covering headers **and** body. Floored at 1000ms, so a typo cannot instant-fail every request. |
|
|
203
|
+
| `BB_EMBEDDING_MAX_INPUTS` | `256` | Ceiling on inputs per `/embeddings` request. A ceiling, not a partition: the indexer already batches 100 snippets, so ordinary indexing stays one request. |
|
|
204
|
+
| `BB_EMBEDDING_RETRY_BASE_MS` | `250` | First backoff step; doubles per attempt. Fallback provider only. |
|
|
205
|
+
| `BB_EMBEDDING_RETRY_CAP_MS` | `4000` | Ceiling on one backoff wait. Fallback provider only. |
|
|
206
|
+
| `BB_EMBEDDING_CACHE_MAX` | `128` | How many recent query vectors are cached in memory (LRU). Cached only when they came back non-empty; a config change keys the cache so a different model or endpoint can never serve a vector from another vector space. |
|
|
207
|
+
| `BB_EMBEDDING_CALL_TIMEOUT_MS` | `60000` | Bound on one whole `embedMany` call inside the background drainer, above the client's own per-request bound. Exceeding it counts as a provider failure for that batch, which is what routes it to the local fallback instead of wedging the queue. |
|
|
208
|
+
| `BB_EMBEDDING_DIMENSION` | unset | Assertion, not a request parameter: the vector width you expect from the configured model. A response of a different width is refused rather than written, because vectors of two widths cannot share one `embedding_model` label. Unset it if the real width differs. |
|
|
209
|
+
|
|
210
|
+
Two of these deserve the emphasis, because the defaults are not the only
|
|
211
|
+
sensible choice for everyone:
|
|
212
|
+
|
|
213
|
+
- **`BB_EMBEDDING_DISABLED`** is the switch to reach for when you would rather
|
|
214
|
+
pay the local quality cost than any network call — an air-gapped machine, a CI
|
|
215
|
+
runner with no provider key, or a debugging session where you want indexing to
|
|
216
|
+
stop waiting on someone else's uptime.
|
|
217
|
+
- **`BB_EMBEDDING_MAX_INPUTS`** exists because a failure in any chunk of a
|
|
218
|
+
multi-chunk request discards the whole request, so needless fragmentation turns
|
|
219
|
+
an unrelated later failure into a loss of earlier completed work.
|
|
220
|
+
|
|
221
|
+
## The fallback chain, in order
|
|
222
|
+
|
|
223
|
+
1. `BB_EMBEDDING_DISABLED` on → local word vectors only, no HTTP.
|
|
224
|
+
2. The primary provider (env / config file / default, by the precedence above).
|
|
225
|
+
3. The fallback provider, if `BB_EMBEDDING_FALLBACK_*` is configured. Reached
|
|
226
|
+
only when the primary fails, and the only layer with a client-side retry loop.
|
|
227
|
+
4. Local word vectors (`local-word-vectors-v3`, 50-dimensional) — always
|
|
228
|
+
available, offline, and the reason the chain has no dead end.
|
|
229
|
+
|
|
230
|
+
The chain has no dead end by design: no configuration makes indexing fail to
|
|
231
|
+
produce vectors. What a misconfiguration costs is quality (layer 4 instead of
|
|
232
|
+
layer 2), which is why the diagnosis below is worth reading.
|
|
233
|
+
|
|
234
|
+
## When something is wrong: `bb doctor` and `bb setup show`
|
|
235
|
+
|
|
236
|
+
Both print the chain in the order above with the env var each layer came from,
|
|
237
|
+
so "which provider am I on and what do I change to move off it" is answerable
|
|
238
|
+
without reading a config file. `bb health --verbose` prints the same chain, from
|
|
239
|
+
the same code, so the three surfaces cannot disagree.
|
|
240
|
+
|
|
241
|
+
```
|
|
242
|
+
$ bb doctor
|
|
243
|
+
bb doctor — diagnostics
|
|
244
|
+
|
|
245
|
+
! Embeddings are switched off (BB_EMBEDDING_DISABLED), so indexing stores only local word vectors.
|
|
246
|
+
Fix: unset BB_EMBEDDING_DISABLED
|
|
247
|
+
✗ env tier is incomplete: missing model.
|
|
248
|
+
Fix: bb setup
|
|
249
|
+
embedding provider chain (embeddings disabled — local only):
|
|
250
|
+
1. embeddings disabled: none · none [env:BB_EMBEDDING_DISABLED]
|
|
251
|
+
→2. local word vectors: offline · 50-dim [built in]
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
What each surface adds:
|
|
255
|
+
|
|
256
|
+
- **`bb doctor`** — the findings, each naming the exact command or env var that
|
|
257
|
+
resolves it, and the exit code (1 when a FAIL-level finding exists, so CI can
|
|
258
|
+
branch). It also reports failures the provider has already given this process:
|
|
259
|
+
a 401 and a 404 are FAILs because neither is fixed by waiting, while a 429 or a
|
|
260
|
+
5xx is a WARN because indexing degrades that batch and carries on.
|
|
261
|
+
- **`bb setup show`** — the tier table (base URL, model, and the key as its last
|
|
262
|
+
four characters) plus the chain and any problem found in it.
|
|
263
|
+
- **`bb health --verbose`** — the chain, and `embeddingChain` in the JSON for a
|
|
264
|
+
machine consumer.
|
|
265
|
+
|
|
266
|
+
Diagnosis is read-only and makes no network call, so it is safe in CI and on a
|
|
267
|
+
machine that cannot reach the provider. The one exception is a live probe,
|
|
268
|
+
available as `runDoctorChecksWithProbe` in `src/setup/doctor.ts`: it makes a
|
|
269
|
+
single bounded request through the same client indexing uses, and it does not
|
|
270
|
+
affect what indexing does next. `bb health` never probes.
|
|
271
|
+
|
|
272
|
+
## What changes when it's on
|
|
273
|
+
|
|
274
|
+
- `bb index` stores real embedding vectors (`brain_semantic_embedding`,
|
|
275
|
+
`embedding_model` = your model, `vector_dimension` = the model's dimension)
|
|
276
|
+
- Semantic search ranks by cosine similarity over those vectors
|
|
277
|
+
- No key configured? The index falls back to local word vectors and semantic
|
|
278
|
+
search degrades to keyword-level matching — nothing breaks.
|
|
279
|
+
|
|
280
|
+
## How indexing generates them (background queue)
|
|
281
|
+
|
|
282
|
+
Embedding generation is **non-blocking**: `bb index` completes and returns
|
|
283
|
+
usable code intelligence immediately, while vectors populate lazily on a
|
|
284
|
+
shared background queue (one serialized drainer per process). To wait for the
|
|
285
|
+
queue before reading vectors back programmatically, call
|
|
286
|
+
`flushBackgroundEmbeddings()` from `src/ast/parallel-indexer`. Call it before
|
|
287
|
+
closing or deleting a project database; queued jobs must never outlive their
|
|
288
|
+
SQLite handle.
|
|
289
|
+
|
|
290
|
+
Two knobs bound the work so huge repositories never stall indexing or exhaust
|
|
291
|
+
memory:
|
|
292
|
+
|
|
293
|
+
- `BB_EMBEDDING_BATCH_LIMIT` (default `50000`) — a single storeResults batch
|
|
294
|
+
at or above this limit is skipped entirely (no vectors).
|
|
295
|
+
- `BB_EMBEDDING_QUEUE_LIMIT` (default `25000`) — total queued snippet-items
|
|
296
|
+
across the process. Once the queue is at capacity, further batches are
|
|
297
|
+
dropped with a debug log rather than accumulated in memory.
|
|
298
|
+
|
|
299
|
+
Dropped batches are recoverable: run `bb index --force <project>` (or re-run
|
|
300
|
+
`bb_refresh(force)`) to generate vectors for the whole project at once. For
|
|
301
|
+
measurement harnesses that must not touch the embedding API at all (e.g. the
|
|
302
|
+
M11 corpus benchmarks), set `BB_EMBEDDING_BATCH_LIMIT=0` in the harness scope.
|
|
303
|
+
|
|
304
|
+
## The no-key trade-off, in plain terms
|
|
305
|
+
|
|
306
|
+
Without any embedding key, semantic search uses **local word vectors
|
|
307
|
+
(`local-word-vectors-v3`, keyword-level matching)**. That label is what appears
|
|
308
|
+
in the `embedding_model` column of `brain_semantic_embedding`, so it is the
|
|
309
|
+
string to query when you want the offline vectors:
|
|
310
|
+
|
|
311
|
+
```sql
|
|
312
|
+
SELECT embedding_model, vector_dimension, COUNT(*)
|
|
313
|
+
FROM brain_semantic_embedding
|
|
314
|
+
WHERE embedding_model = 'local-word-vectors-v3'
|
|
315
|
+
GROUP BY 1, 2;
|
|
316
|
+
```
|
|
317
|
+
|
|
318
|
+
(The `-v3` suffix is load-bearing, not decoration: earlier versions of this
|
|
319
|
+
model tokenized and combined words differently, so those vectors occupy a
|
|
320
|
+
different space and are never compared with current ones. Bumping the version is
|
|
321
|
+
how a model change is prevented from producing a confident nonsense score; an
|
|
322
|
+
index built by an older version reports `no-matching-model-embeddings` until it
|
|
323
|
+
is re-embedded with `bb index --force`.) That is a real, declared
|
|
324
|
+
quality cost — not "the same, just offline". It is the honest default: nothing
|
|
325
|
+
is silently degraded, and the notice above says so. Adding a real model later
|
|
326
|
+
**requires `bb index --force <project>`** to re-embed the whole index; old
|
|
327
|
+
vectors are never reused or mixed with new ones.
|
|
328
|
+
|
|
329
|
+
## Vector-space mixing rule
|
|
330
|
+
|
|
331
|
+
Vectors produced by different models live in **different vector spaces** and
|
|
332
|
+
are **never compared or mixed**. Every stored vector records the model that
|
|
333
|
+
produced it (`embedding_model`); the search only compares vectors with the
|
|
334
|
+
same label, and the query vector's producing model
|
|
335
|
+
(`SemanticEngine.getLastEmbeddingModel()`) is authoritative. Changing model or
|
|
336
|
+
dimension therefore requires a forced reindex (`bb index --force`), and a rate
|
|
337
|
+
limit or provider blip degrades one batch to the local fallback — never a
|
|
338
|
+
silent cross-space comparison.
|
|
339
|
+
|
|
340
|
+
## Tool evidence semantics
|
|
341
|
+
|
|
342
|
+
`bb_ask` uses embeddings to discover and rank candidate symbols. Similarity is
|
|
343
|
+
not proof: factual claims should resolve to indexed symbols, source locations,
|
|
344
|
+
and relationships. `bb_doc` follows the same rule and classifies unsupported
|
|
345
|
+
claims as unknown rather than treating semantic proximity as evidence. `bb_health`
|
|
346
|
+
reports the active model, vector dimensions, and coverage; coverage describes
|
|
347
|
+
stored vectors, not answer quality. Changing model or dimensions requires a
|
|
348
|
+
forced reindex because vectors from different spaces are never compared.
|
|
349
|
+
|
|
350
|
+
## Verification
|
|
351
|
+
|
|
352
|
+
```bash
|
|
353
|
+
bun run script/verify-embed.ts # mock API + fallback
|
|
354
|
+
bun run script/m16/verify-embedding-lifecycle.ts # durable vectors + cleanup ordering
|
|
355
|
+
```
|