codebase-index 1.7.0__tar.gz → 1.9.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (335) hide show
  1. codebase_index-1.9.0/.claude/skills/codebase-index/.skill_version +1 -0
  2. {codebase_index-1.7.0 → codebase_index-1.9.0}/.claude-plugin/plugin.json +1 -1
  3. codebase_index-1.9.0/.codex/skills/codebase-index/.skill_version +1 -0
  4. codebase_index-1.9.0/.opencode/skills/codebase-index/.skill_version +1 -0
  5. {codebase_index-1.7.0 → codebase_index-1.9.0}/CHANGELOG.md +105 -1
  6. {codebase_index-1.7.0 → codebase_index-1.9.0}/PKG-INFO +16 -8
  7. {codebase_index-1.7.0 → codebase_index-1.9.0}/README.md +15 -7
  8. {codebase_index-1.7.0 → codebase_index-1.9.0}/docs/ARCHITECTURE.md +4 -3
  9. {codebase_index-1.7.0 → codebase_index-1.9.0}/docs/BENCHMARKS.md +23 -4
  10. {codebase_index-1.7.0 → codebase_index-1.9.0}/docs/FAQ.md +6 -5
  11. {codebase_index-1.7.0 → codebase_index-1.9.0}/docs/INSTALLATION.md +3 -3
  12. codebase_index-1.9.0/docs/RETRIEVAL.md +229 -0
  13. codebase_index-1.9.0/docs/RETRIEVAL_PIPELINE.md +179 -0
  14. {codebase_index-1.7.0 → codebase_index-1.9.0}/docs/SEO.md +2 -2
  15. {codebase_index-1.7.0 → codebase_index-1.9.0}/docs/installer.md +2 -3
  16. {codebase_index-1.7.0 → codebase_index-1.9.0}/pyproject.toml +1 -1
  17. {codebase_index-1.7.0 → codebase_index-1.9.0}/requirements.lock +1 -1
  18. {codebase_index-1.7.0 → codebase_index-1.9.0}/src/codebase_index/__init__.py +1 -1
  19. {codebase_index-1.7.0 → codebase_index-1.9.0}/src/codebase_index/graph/expand.py +123 -13
  20. codebase_index-1.9.0/src/codebase_index/graph/retrieval.py +456 -0
  21. {codebase_index-1.7.0 → codebase_index-1.9.0}/src/codebase_index/mcp/server.py +1 -1
  22. codebase_index-1.9.0/src/codebase_index/retrieval/diversity.py +324 -0
  23. {codebase_index-1.7.0 → codebase_index-1.9.0}/src/codebase_index/retrieval/fusion.py +38 -0
  24. codebase_index-1.9.0/src/codebase_index/retrieval/fuzzy.py +278 -0
  25. {codebase_index-1.7.0 → codebase_index-1.9.0}/src/codebase_index/retrieval/intent.py +1 -1
  26. codebase_index-1.9.0/src/codebase_index/retrieval/lexical.py +409 -0
  27. {codebase_index-1.7.0 → codebase_index-1.9.0}/src/codebase_index/retrieval/pipeline.py +69 -18
  28. codebase_index-1.9.0/src/codebase_index/retrieval/priors.py +227 -0
  29. {codebase_index-1.7.0 → codebase_index-1.9.0}/src/codebase_index/retrieval/rerank.py +15 -1
  30. codebase_index-1.9.0/src/codebase_index/retrieval/searchers.py +573 -0
  31. codebase_index-1.9.0/src/codebase_index/retrieval/tuning.py +146 -0
  32. {codebase_index-1.7.0 → codebase_index-1.9.0}/src/codebase_index/storage/repo.py +7 -3
  33. codebase_index-1.9.0/tests/eval/README.md +99 -0
  34. codebase_index-1.9.0/tests/eval/__init__.py +1 -0
  35. codebase_index-1.9.0/tests/eval/gen_queries.py +253 -0
  36. codebase_index-1.9.0/tests/eval/harness.py +419 -0
  37. codebase_index-1.9.0/tests/eval/metrics.py +207 -0
  38. codebase_index-1.9.0/tests/eval/queries/self_repo.yml +204 -0
  39. codebase_index-1.9.0/tests/eval/queries/self_repo_git.yml +627 -0
  40. codebase_index-1.9.0/tests/eval/run_eval.py +186 -0
  41. codebase_index-1.9.0/tests/golden/explain_auth.json +54 -0
  42. codebase_index-1.9.0/tests/golden/mcp_explain_code.json +56 -0
  43. {codebase_index-1.7.0 → codebase_index-1.9.0}/tests/golden/mcp_search_code.json +4 -4
  44. {codebase_index-1.7.0 → codebase_index-1.9.0}/tests/golden/search_token.json +4 -4
  45. codebase_index-1.9.0/tests/test_diversity.py +120 -0
  46. codebase_index-1.9.0/tests/test_fusion.py +145 -0
  47. codebase_index-1.9.0/tests/test_fuzzy.py +42 -0
  48. codebase_index-1.9.0/tests/test_gen_queries.py +152 -0
  49. codebase_index-1.9.0/tests/test_graph_retrieval.py +100 -0
  50. codebase_index-1.9.0/tests/test_impact_decay.py +110 -0
  51. codebase_index-1.9.0/tests/test_lexical.py +66 -0
  52. codebase_index-1.9.0/tests/test_priors.py +82 -0
  53. {codebase_index-1.7.0 → codebase_index-1.9.0}/tests/test_search_cli.py +13 -0
  54. codebase_index-1.9.0/tests/test_symbol_ranking.py +264 -0
  55. codebase_index-1.9.0/tests/test_tuning_contract.py +141 -0
  56. codebase_index-1.7.0/.claude/skills/codebase-index/.skill_version +0 -1
  57. codebase_index-1.7.0/.codex/skills/codebase-index/.skill_version +0 -1
  58. codebase_index-1.7.0/.opencode/skills/codebase-index/.skill_version +0 -1
  59. codebase_index-1.7.0/docs/RETRIEVAL.md +0 -164
  60. codebase_index-1.7.0/docs/RETRIEVAL_PIPELINE.md +0 -147
  61. codebase_index-1.7.0/src/codebase_index/retrieval/searchers.py +0 -291
  62. codebase_index-1.7.0/tests/golden/explain_auth.json +0 -21
  63. codebase_index-1.7.0/tests/golden/mcp_explain_code.json +0 -23
  64. codebase_index-1.7.0/tests/test_fusion.py +0 -66
  65. codebase_index-1.7.0/tests/test_symbol_ranking.py +0 -91
  66. {codebase_index-1.7.0 → codebase_index-1.9.0}/.claude/skills/codebase-index/SKILL.md +0 -0
  67. {codebase_index-1.7.0 → codebase_index-1.9.0}/.claude/skills/codebase-index/examples/hooks/settings.json +0 -0
  68. {codebase_index-1.7.0 → codebase_index-1.9.0}/.claude/skills/codebase-index/references/commands.md +0 -0
  69. {codebase_index-1.7.0 → codebase_index-1.9.0}/.claude/skills/codebase-index/references/response-contract.md +0 -0
  70. {codebase_index-1.7.0 → codebase_index-1.9.0}/.claude/skills/codebase-index/scripts/cbx +0 -0
  71. {codebase_index-1.7.0 → codebase_index-1.9.0}/.claude/skills/codebase-index/scripts/cbx.ps1 +0 -0
  72. {codebase_index-1.7.0 → codebase_index-1.9.0}/.claude-plugin/marketplace.json +0 -0
  73. {codebase_index-1.7.0 → codebase_index-1.9.0}/.codex/skills/codebase-index/SKILL.md +0 -0
  74. {codebase_index-1.7.0 → codebase_index-1.9.0}/.codex/skills/codebase-index/examples/hooks/settings.json +0 -0
  75. {codebase_index-1.7.0 → codebase_index-1.9.0}/.codex/skills/codebase-index/references/commands.md +0 -0
  76. {codebase_index-1.7.0 → codebase_index-1.9.0}/.codex/skills/codebase-index/references/response-contract.md +0 -0
  77. {codebase_index-1.7.0 → codebase_index-1.9.0}/.codex/skills/codebase-index/scripts/cbx +0 -0
  78. {codebase_index-1.7.0 → codebase_index-1.9.0}/.codex/skills/codebase-index/scripts/cbx.ps1 +0 -0
  79. {codebase_index-1.7.0 → codebase_index-1.9.0}/.editorconfig +0 -0
  80. {codebase_index-1.7.0 → codebase_index-1.9.0}/.gitattributes +0 -0
  81. {codebase_index-1.7.0 → codebase_index-1.9.0}/.github/FUNDING.yml +0 -0
  82. {codebase_index-1.7.0 → codebase_index-1.9.0}/.github/ISSUE_TEMPLATE/bug_report.yml +0 -0
  83. {codebase_index-1.7.0 → codebase_index-1.9.0}/.github/ISSUE_TEMPLATE/feature_request.yml +0 -0
  84. {codebase_index-1.7.0 → codebase_index-1.9.0}/.github/ISSUE_TEMPLATE/skill_listing_request.yml +0 -0
  85. {codebase_index-1.7.0 → codebase_index-1.9.0}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
  86. {codebase_index-1.7.0 → codebase_index-1.9.0}/.github/workflows/ci.yml +0 -0
  87. {codebase_index-1.7.0 → codebase_index-1.9.0}/.github/workflows/release.yml +0 -0
  88. {codebase_index-1.7.0 → codebase_index-1.9.0}/.gitignore +0 -0
  89. {codebase_index-1.7.0 → codebase_index-1.9.0}/.opencode/agents/codebase-index.md +0 -0
  90. {codebase_index-1.7.0 → codebase_index-1.9.0}/.opencode/commands/codebase-index.md +0 -0
  91. {codebase_index-1.7.0 → codebase_index-1.9.0}/.opencode/skills/codebase-index/SKILL.md +0 -0
  92. {codebase_index-1.7.0 → codebase_index-1.9.0}/.opencode/skills/codebase-index/examples/hooks/settings.json +0 -0
  93. {codebase_index-1.7.0 → codebase_index-1.9.0}/.opencode/skills/codebase-index/references/commands.md +0 -0
  94. {codebase_index-1.7.0 → codebase_index-1.9.0}/.opencode/skills/codebase-index/references/response-contract.md +0 -0
  95. {codebase_index-1.7.0 → codebase_index-1.9.0}/.opencode/skills/codebase-index/scripts/cbx +0 -0
  96. {codebase_index-1.7.0 → codebase_index-1.9.0}/.opencode/skills/codebase-index/scripts/cbx.ps1 +0 -0
  97. {codebase_index-1.7.0 → codebase_index-1.9.0}/AGENTS.md +0 -0
  98. {codebase_index-1.7.0 → codebase_index-1.9.0}/CODE_OF_CONDUCT.md +0 -0
  99. {codebase_index-1.7.0 → codebase_index-1.9.0}/CONTRIBUTING.md +0 -0
  100. {codebase_index-1.7.0 → codebase_index-1.9.0}/LICENSE +0 -0
  101. {codebase_index-1.7.0 → codebase_index-1.9.0}/ROADMAP.md +0 -0
  102. {codebase_index-1.7.0 → codebase_index-1.9.0}/SECURITY.md +0 -0
  103. {codebase_index-1.7.0 → codebase_index-1.9.0}/adapters/claude.ps1 +0 -0
  104. {codebase_index-1.7.0 → codebase_index-1.9.0}/adapters/claude.sh +0 -0
  105. {codebase_index-1.7.0 → codebase_index-1.9.0}/adapters/codex.ps1 +0 -0
  106. {codebase_index-1.7.0 → codebase_index-1.9.0}/adapters/codex.sh +0 -0
  107. {codebase_index-1.7.0 → codebase_index-1.9.0}/adapters/opencode.ps1 +0 -0
  108. {codebase_index-1.7.0 → codebase_index-1.9.0}/adapters/opencode.sh +0 -0
  109. {codebase_index-1.7.0 → codebase_index-1.9.0}/assets/demo.png +0 -0
  110. {codebase_index-1.7.0 → codebase_index-1.9.0}/assets/mark.png +0 -0
  111. {codebase_index-1.7.0 → codebase_index-1.9.0}/assets/social-preview.png +0 -0
  112. {codebase_index-1.7.0 → codebase_index-1.9.0}/bin/cbx +0 -0
  113. {codebase_index-1.7.0 → codebase_index-1.9.0}/bin/cbx.ps1 +0 -0
  114. {codebase_index-1.7.0 → codebase_index-1.9.0}/bin/codebase-index +0 -0
  115. {codebase_index-1.7.0 → codebase_index-1.9.0}/bin/codebase-index.ps1 +0 -0
  116. {codebase_index-1.7.0 → codebase_index-1.9.0}/docs/COMPARISON.md +0 -0
  117. {codebase_index-1.7.0 → codebase_index-1.9.0}/docs/DATABASE_SCHEMA.md +0 -0
  118. {codebase_index-1.7.0 → codebase_index-1.9.0}/docs/LANGUAGES.md +0 -0
  119. {codebase_index-1.7.0 → codebase_index-1.9.0}/docs/MCP.md +0 -0
  120. {codebase_index-1.7.0 → codebase_index-1.9.0}/docs/PRODUCT_UPGRADE_PLAN.md +0 -0
  121. {codebase_index-1.7.0 → codebase_index-1.9.0}/docs/QUICKSTART.md +0 -0
  122. {codebase_index-1.7.0 → codebase_index-1.9.0}/docs/RELEASE_CHECKLIST.md +0 -0
  123. {codebase_index-1.7.0 → codebase_index-1.9.0}/docs/ROADMAP.md +0 -0
  124. {codebase_index-1.7.0 → codebase_index-1.9.0}/docs/SCHEMA.md +0 -0
  125. {codebase_index-1.7.0 → codebase_index-1.9.0}/docs/SECURITY.md +0 -0
  126. {codebase_index-1.7.0 → codebase_index-1.9.0}/docs/SECURITY_MODEL.md +0 -0
  127. {codebase_index-1.7.0 → codebase_index-1.9.0}/docs/SKILL_DESIGN.md +0 -0
  128. {codebase_index-1.7.0 → codebase_index-1.9.0}/docs/superpowers/plans/2026-05-29-benchmark-index-improvements.md +0 -0
  129. {codebase_index-1.7.0 → codebase_index-1.9.0}/docs/superpowers/plans/2026-05-29-generalize-skill-research-discipline.md +0 -0
  130. {codebase_index-1.7.0 → codebase_index-1.9.0}/docs/superpowers/plans/2026-05-29-m1-storage-discovery.md +0 -0
  131. {codebase_index-1.7.0 → codebase_index-1.9.0}/docs/superpowers/plans/2026-05-29-m2-fts-lexical.md +0 -0
  132. {codebase_index-1.7.0 → codebase_index-1.9.0}/docs/superpowers/plans/2026-05-29-m3-treesitter-symbols.md +0 -0
  133. {codebase_index-1.7.0 → codebase_index-1.9.0}/docs/superpowers/plans/2026-05-29-m4-hybrid-search.md +0 -0
  134. {codebase_index-1.7.0 → codebase_index-1.9.0}/docs/superpowers/plans/2026-05-29-m5-graph-impact.md +0 -0
  135. {codebase_index-1.7.0 → codebase_index-1.9.0}/docs/superpowers/plans/2026-05-29-m6-embeddings-vector.md +0 -0
  136. {codebase_index-1.7.0 → codebase_index-1.9.0}/docs/superpowers/plans/2026-05-29-m7-5-plugin-one-command-install.md +0 -0
  137. {codebase_index-1.7.0 → codebase_index-1.9.0}/docs/superpowers/plans/2026-05-29-m7-skill-packaging.md +0 -0
  138. {codebase_index-1.7.0 → codebase_index-1.9.0}/docs/superpowers/plans/2026-05-29-m8-hooks-watch.md +0 -0
  139. {codebase_index-1.7.0 → codebase_index-1.9.0}/docs/superpowers/plans/2026-05-29-m9-release.md +0 -0
  140. {codebase_index-1.7.0 → codebase_index-1.9.0}/docs/superpowers/plans/2026-05-29-multilang-symbols-make-skill-win.md +0 -0
  141. {codebase_index-1.7.0 → codebase_index-1.9.0}/docs/superpowers/plans/2026-06-24-snippet-skeletonization.md +0 -0
  142. {codebase_index-1.7.0 → codebase_index-1.9.0}/docs/superpowers/specs/2026-05-29-plugin-one-command-install-design.md +0 -0
  143. {codebase_index-1.7.0 → codebase_index-1.9.0}/docs/superpowers/specs/2026-06-14-typed-framework-edges-design.md +0 -0
  144. {codebase_index-1.7.0 → codebase_index-1.9.0}/docs/superpowers/specs/2026-06-24-snippet-skeletonization-design.md +0 -0
  145. {codebase_index-1.7.0 → codebase_index-1.9.0}/examples/config.example.json +0 -0
  146. {codebase_index-1.7.0 → codebase_index-1.9.0}/examples/demo-project/README.md +0 -0
  147. {codebase_index-1.7.0 → codebase_index-1.9.0}/examples/hooks/settings.json +0 -0
  148. {codebase_index-1.7.0 → codebase_index-1.9.0}/examples/queries.md +0 -0
  149. {codebase_index-1.7.0 → codebase_index-1.9.0}/examples/sample-queries.md +0 -0
  150. {codebase_index-1.7.0 → codebase_index-1.9.0}/examples/sample-retrieval-output.md +0 -0
  151. {codebase_index-1.7.0 → codebase_index-1.9.0}/hooks/hooks.json +0 -0
  152. {codebase_index-1.7.0 → codebase_index-1.9.0}/install.ps1 +0 -0
  153. {codebase_index-1.7.0 → codebase_index-1.9.0}/install.sh +0 -0
  154. {codebase_index-1.7.0 → codebase_index-1.9.0}/lib/common.ps1 +0 -0
  155. {codebase_index-1.7.0 → codebase_index-1.9.0}/lib/common.sh +0 -0
  156. {codebase_index-1.7.0 → codebase_index-1.9.0}/scripts/bootstrap.ps1 +0 -0
  157. {codebase_index-1.7.0 → codebase_index-1.9.0}/scripts/bootstrap.sh +0 -0
  158. {codebase_index-1.7.0 → codebase_index-1.9.0}/scripts/gen_assets.py +0 -0
  159. {codebase_index-1.7.0 → codebase_index-1.9.0}/scripts/release_smoke.py +0 -0
  160. {codebase_index-1.7.0 → codebase_index-1.9.0}/scripts/sync_skill_copies.py +0 -0
  161. {codebase_index-1.7.0 → codebase_index-1.9.0}/skill/SKILL.md +0 -0
  162. {codebase_index-1.7.0 → codebase_index-1.9.0}/skill/examples/basic-usage.md +0 -0
  163. {codebase_index-1.7.0 → codebase_index-1.9.0}/skill/examples/claude-md-example.md +0 -0
  164. {codebase_index-1.7.0 → codebase_index-1.9.0}/skill/examples/hooks-example.json +0 -0
  165. {codebase_index-1.7.0 → codebase_index-1.9.0}/skill/references/commands.md +0 -0
  166. {codebase_index-1.7.0 → codebase_index-1.9.0}/skill/references/response-contract.md +0 -0
  167. {codebase_index-1.7.0 → codebase_index-1.9.0}/skill/scripts/bootstrap.py +0 -0
  168. {codebase_index-1.7.0 → codebase_index-1.9.0}/skill/scripts/cbx +0 -0
  169. {codebase_index-1.7.0 → codebase_index-1.9.0}/skill/scripts/cbx.ps1 +0 -0
  170. {codebase_index-1.7.0 → codebase_index-1.9.0}/skill/scripts/doctor.py +0 -0
  171. {codebase_index-1.7.0 → codebase_index-1.9.0}/skill/scripts/install.py +0 -0
  172. {codebase_index-1.7.0 → codebase_index-1.9.0}/skill/scripts/smoke_test.py +0 -0
  173. {codebase_index-1.7.0 → codebase_index-1.9.0}/skills/codebase-index/SKILL.md +0 -0
  174. {codebase_index-1.7.0 → codebase_index-1.9.0}/skills/codebase-index/references/commands.md +0 -0
  175. {codebase_index-1.7.0 → codebase_index-1.9.0}/skills/codebase-index/references/response-contract.md +0 -0
  176. {codebase_index-1.7.0 → codebase_index-1.9.0}/src/codebase_index/__main__.py +0 -0
  177. {codebase_index-1.7.0 → codebase_index-1.9.0}/src/codebase_index/cli.py +0 -0
  178. {codebase_index-1.7.0 → codebase_index-1.9.0}/src/codebase_index/config.py +0 -0
  179. {codebase_index-1.7.0 → codebase_index-1.9.0}/src/codebase_index/discovery/__init__.py +0 -0
  180. {codebase_index-1.7.0 → codebase_index-1.9.0}/src/codebase_index/discovery/classify.py +0 -0
  181. {codebase_index-1.7.0 → codebase_index-1.9.0}/src/codebase_index/discovery/ignore.py +0 -0
  182. {codebase_index-1.7.0 → codebase_index-1.9.0}/src/codebase_index/discovery/walker.py +0 -0
  183. {codebase_index-1.7.0 → codebase_index-1.9.0}/src/codebase_index/doctor.py +0 -0
  184. {codebase_index-1.7.0 → codebase_index-1.9.0}/src/codebase_index/embeddings/__init__.py +0 -0
  185. {codebase_index-1.7.0 → codebase_index-1.9.0}/src/codebase_index/embeddings/backend.py +0 -0
  186. {codebase_index-1.7.0 → codebase_index-1.9.0}/src/codebase_index/embeddings/external.py +0 -0
  187. {codebase_index-1.7.0 → codebase_index-1.9.0}/src/codebase_index/embeddings/local.py +0 -0
  188. {codebase_index-1.7.0 → codebase_index-1.9.0}/src/codebase_index/embeddings/noop.py +0 -0
  189. {codebase_index-1.7.0 → codebase_index-1.9.0}/src/codebase_index/graph/__init__.py +0 -0
  190. {codebase_index-1.7.0 → codebase_index-1.9.0}/src/codebase_index/graph/analysis.py +0 -0
  191. {codebase_index-1.7.0 → codebase_index-1.9.0}/src/codebase_index/graph/builder.py +0 -0
  192. {codebase_index-1.7.0 → codebase_index-1.9.0}/src/codebase_index/graph/export.py +0 -0
  193. {codebase_index-1.7.0 → codebase_index-1.9.0}/src/codebase_index/graph/navigate.py +0 -0
  194. {codebase_index-1.7.0 → codebase_index-1.9.0}/src/codebase_index/indexer/__init__.py +0 -0
  195. {codebase_index-1.7.0 → codebase_index-1.9.0}/src/codebase_index/indexer/doc_chunks.py +0 -0
  196. {codebase_index-1.7.0 → codebase_index-1.9.0}/src/codebase_index/indexer/freshness.py +0 -0
  197. {codebase_index-1.7.0 → codebase_index-1.9.0}/src/codebase_index/indexer/pipeline.py +0 -0
  198. {codebase_index-1.7.0 → codebase_index-1.9.0}/src/codebase_index/mcp/__init__.py +0 -0
  199. {codebase_index-1.7.0 → codebase_index-1.9.0}/src/codebase_index/models.py +0 -0
  200. {codebase_index-1.7.0 → codebase_index-1.9.0}/src/codebase_index/output/__init__.py +0 -0
  201. {codebase_index-1.7.0 → codebase_index-1.9.0}/src/codebase_index/output/json.py +0 -0
  202. {codebase_index-1.7.0 → codebase_index-1.9.0}/src/codebase_index/output/markdown.py +0 -0
  203. {codebase_index-1.7.0 → codebase_index-1.9.0}/src/codebase_index/output/redact.py +0 -0
  204. {codebase_index-1.7.0 → codebase_index-1.9.0}/src/codebase_index/parsers/__init__.py +0 -0
  205. {codebase_index-1.7.0 → codebase_index-1.9.0}/src/codebase_index/parsers/base.py +0 -0
  206. {codebase_index-1.7.0 → codebase_index-1.9.0}/src/codebase_index/parsers/languages.py +0 -0
  207. {codebase_index-1.7.0 → codebase_index-1.9.0}/src/codebase_index/parsers/line_chunker.py +0 -0
  208. {codebase_index-1.7.0 → codebase_index-1.9.0}/src/codebase_index/parsers/symbol_chunks.py +0 -0
  209. {codebase_index-1.7.0 → codebase_index-1.9.0}/src/codebase_index/parsers/treesitter.py +0 -0
  210. {codebase_index-1.7.0 → codebase_index-1.9.0}/src/codebase_index/retrieval/__init__.py +0 -0
  211. {codebase_index-1.7.0 → codebase_index-1.9.0}/src/codebase_index/retrieval/budget.py +0 -0
  212. {codebase_index-1.7.0 → codebase_index-1.9.0}/src/codebase_index/retrieval/skeleton.py +0 -0
  213. {codebase_index-1.7.0 → codebase_index-1.9.0}/src/codebase_index/retrieval/types.py +0 -0
  214. {codebase_index-1.7.0 → codebase_index-1.9.0}/src/codebase_index/scaffold.py +0 -0
  215. {codebase_index-1.7.0 → codebase_index-1.9.0}/src/codebase_index/service.py +0 -0
  216. {codebase_index-1.7.0 → codebase_index-1.9.0}/src/codebase_index/skill_template/SKILL.md +0 -0
  217. {codebase_index-1.7.0 → codebase_index-1.9.0}/src/codebase_index/skill_template/examples/hooks/settings.json +0 -0
  218. {codebase_index-1.7.0 → codebase_index-1.9.0}/src/codebase_index/skill_template/references/commands.md +0 -0
  219. {codebase_index-1.7.0 → codebase_index-1.9.0}/src/codebase_index/skill_template/references/response-contract.md +0 -0
  220. {codebase_index-1.7.0 → codebase_index-1.9.0}/src/codebase_index/skill_template/scripts/cbx +0 -0
  221. {codebase_index-1.7.0 → codebase_index-1.9.0}/src/codebase_index/skill_template/scripts/cbx.ps1 +0 -0
  222. {codebase_index-1.7.0 → codebase_index-1.9.0}/src/codebase_index/skill_update.py +0 -0
  223. {codebase_index-1.7.0 → codebase_index-1.9.0}/src/codebase_index/storage/__init__.py +0 -0
  224. {codebase_index-1.7.0 → codebase_index-1.9.0}/src/codebase_index/storage/db.py +0 -0
  225. {codebase_index-1.7.0 → codebase_index-1.9.0}/src/codebase_index/storage/schema.sql +0 -0
  226. {codebase_index-1.7.0 → codebase_index-1.9.0}/src/codebase_index/watch/__init__.py +0 -0
  227. {codebase_index-1.7.0 → codebase_index-1.9.0}/src/codebase_index/watch/watcher.py +0 -0
  228. {codebase_index-1.7.0 → codebase_index-1.9.0}/tests/__init__.py +0 -0
  229. {codebase_index-1.7.0 → codebase_index-1.9.0}/tests/benchmark_honest.py +0 -0
  230. {codebase_index-1.7.0 → codebase_index-1.9.0}/tests/benchmark_honest_RESULTS.md +0 -0
  231. {codebase_index-1.7.0 → codebase_index-1.9.0}/tests/benchmark_honest_newtowny.txt +0 -0
  232. {codebase_index-1.7.0 → codebase_index-1.9.0}/tests/benchmark_public.py +0 -0
  233. {codebase_index-1.7.0 → codebase_index-1.9.0}/tests/benchmark_public_RESULTS.md +0 -0
  234. {codebase_index-1.7.0 → codebase_index-1.9.0}/tests/benchmark_real_repo.py +0 -0
  235. {codebase_index-1.7.0 → codebase_index-1.9.0}/tests/conftest.py +0 -0
  236. {codebase_index-1.7.0 → codebase_index-1.9.0}/tests/fixtures/README.md +0 -0
  237. {codebase_index-1.7.0 → codebase_index-1.9.0}/tests/fixtures/expected_answers.yml +0 -0
  238. {codebase_index-1.7.0 → codebase_index-1.9.0}/tests/fixtures/multilang/sample.go +0 -0
  239. {codebase_index-1.7.0 → codebase_index-1.9.0}/tests/fixtures/multilang/sample.java +0 -0
  240. {codebase_index-1.7.0 → codebase_index-1.9.0}/tests/fixtures/multilang/sample.rs +0 -0
  241. {codebase_index-1.7.0 → codebase_index-1.9.0}/tests/fixtures/sample_repo/.env +0 -0
  242. {codebase_index-1.7.0 → codebase_index-1.9.0}/tests/fixtures/sample_repo/.gitignore +0 -0
  243. {codebase_index-1.7.0 → codebase_index-1.9.0}/tests/fixtures/sample_repo/huge.json +0 -0
  244. {codebase_index-1.7.0 → codebase_index-1.9.0}/tests/fixtures/sample_repo/logo.png +0 -0
  245. {codebase_index-1.7.0 → codebase_index-1.9.0}/tests/fixtures/sample_repo/node_modules/leftpad/index.js +0 -0
  246. {codebase_index-1.7.0 → codebase_index-1.9.0}/tests/fixtures/sample_repo/secrets.pem +0 -0
  247. {codebase_index-1.7.0 → codebase_index-1.9.0}/tests/fixtures/sample_repo/src/api/service.py +0 -0
  248. {codebase_index-1.7.0 → codebase_index-1.9.0}/tests/fixtures/sample_repo/src/auth/token.py +0 -0
  249. {codebase_index-1.7.0 → codebase_index-1.9.0}/tests/fixtures/sample_repo/src/models/user.py +0 -0
  250. {codebase_index-1.7.0 → codebase_index-1.9.0}/tests/fixtures/sample_repo/src/schema.generated.ts +0 -0
  251. {codebase_index-1.7.0 → codebase_index-1.9.0}/tests/fixtures/sample_repo/web/app.ts +0 -0
  252. {codebase_index-1.7.0 → codebase_index-1.9.0}/tests/golden/architecture.json +0 -0
  253. {codebase_index-1.7.0 → codebase_index-1.9.0}/tests/golden/describe_refresh.json +0 -0
  254. {codebase_index-1.7.0 → codebase_index-1.9.0}/tests/golden/impact_user_model.json +9 -9
  255. {codebase_index-1.7.0 → codebase_index-1.9.0}/tests/golden/mcp_architecture.json +0 -0
  256. {codebase_index-1.7.0 → codebase_index-1.9.0}/tests/golden/mcp_describe_symbol.json +0 -0
  257. {codebase_index-1.7.0 → codebase_index-1.9.0}/tests/golden/mcp_find_refs.json +0 -0
  258. {codebase_index-1.7.0 → codebase_index-1.9.0}/tests/golden/mcp_find_symbol.json +0 -0
  259. {codebase_index-1.7.0 → codebase_index-1.9.0}/tests/golden/mcp_healthcheck.json +0 -0
  260. {codebase_index-1.7.0 → codebase_index-1.9.0}/tests/golden/mcp_impact_of.json +9 -9
  261. {codebase_index-1.7.0 → codebase_index-1.9.0}/tests/golden/mcp_impact_of_diff.json +0 -0
  262. {codebase_index-1.7.0 → codebase_index-1.9.0}/tests/golden/mcp_index_stats.json +0 -0
  263. {codebase_index-1.7.0 → codebase_index-1.9.0}/tests/golden/mcp_path_between.json +0 -0
  264. {codebase_index-1.7.0 → codebase_index-1.9.0}/tests/golden/path_renew_to_token.json +0 -0
  265. {codebase_index-1.7.0 → codebase_index-1.9.0}/tests/golden/refs_refresh_access_token.json +0 -0
  266. {codebase_index-1.7.0 → codebase_index-1.9.0}/tests/golden/stats.json +0 -0
  267. {codebase_index-1.7.0 → codebase_index-1.9.0}/tests/golden/symbol_user.json +0 -0
  268. {codebase_index-1.7.0 → codebase_index-1.9.0}/tests/golden_utils.py +0 -0
  269. {codebase_index-1.7.0 → codebase_index-1.9.0}/tests/installer/smoke.ps1 +0 -0
  270. {codebase_index-1.7.0 → codebase_index-1.9.0}/tests/installer/smoke.sh +0 -0
  271. {codebase_index-1.7.0 → codebase_index-1.9.0}/tests/test_analysis.py +0 -0
  272. {codebase_index-1.7.0 → codebase_index-1.9.0}/tests/test_benchmark_comparison.py +0 -0
  273. {codebase_index-1.7.0 → codebase_index-1.9.0}/tests/test_bootstrap.py +0 -0
  274. {codebase_index-1.7.0 → codebase_index-1.9.0}/tests/test_budget.py +0 -0
  275. {codebase_index-1.7.0 → codebase_index-1.9.0}/tests/test_chunker.py +0 -0
  276. {codebase_index-1.7.0 → codebase_index-1.9.0}/tests/test_classify.py +0 -0
  277. {codebase_index-1.7.0 → codebase_index-1.9.0}/tests/test_clean_cli.py +0 -0
  278. {codebase_index-1.7.0 → codebase_index-1.9.0}/tests/test_cli.py +0 -0
  279. {codebase_index-1.7.0 → codebase_index-1.9.0}/tests/test_cli_golden.py +0 -0
  280. {codebase_index-1.7.0 → codebase_index-1.9.0}/tests/test_config.py +0 -0
  281. {codebase_index-1.7.0 → codebase_index-1.9.0}/tests/test_diff_impact.py +0 -0
  282. {codebase_index-1.7.0 → codebase_index-1.9.0}/tests/test_discovery.py +0 -0
  283. {codebase_index-1.7.0 → codebase_index-1.9.0}/tests/test_doc_chunks.py +0 -0
  284. {codebase_index-1.7.0 → codebase_index-1.9.0}/tests/test_doctor.py +0 -0
  285. {codebase_index-1.7.0 → codebase_index-1.9.0}/tests/test_embeddings_backend.py +0 -0
  286. {codebase_index-1.7.0 → codebase_index-1.9.0}/tests/test_embeddings_external.py +0 -0
  287. {codebase_index-1.7.0 → codebase_index-1.9.0}/tests/test_embeddings_local.py +0 -0
  288. {codebase_index-1.7.0 → codebase_index-1.9.0}/tests/test_freshness.py +0 -0
  289. {codebase_index-1.7.0 → codebase_index-1.9.0}/tests/test_graph.py +0 -0
  290. {codebase_index-1.7.0 → codebase_index-1.9.0}/tests/test_graph_coverage.py +0 -0
  291. {codebase_index-1.7.0 → codebase_index-1.9.0}/tests/test_graph_export_cli.py +0 -0
  292. {codebase_index-1.7.0 → codebase_index-1.9.0}/tests/test_hooks_merge.py +0 -0
  293. {codebase_index-1.7.0 → codebase_index-1.9.0}/tests/test_hybrid_ranking.py +0 -0
  294. {codebase_index-1.7.0 → codebase_index-1.9.0}/tests/test_ignore.py +0 -0
  295. {codebase_index-1.7.0 → codebase_index-1.9.0}/tests/test_impact_cli.py +0 -0
  296. {codebase_index-1.7.0 → codebase_index-1.9.0}/tests/test_index_cli.py +0 -0
  297. {codebase_index-1.7.0 → codebase_index-1.9.0}/tests/test_init_cli.py +0 -0
  298. {codebase_index-1.7.0 → codebase_index-1.9.0}/tests/test_intent.py +0 -0
  299. {codebase_index-1.7.0 → codebase_index-1.9.0}/tests/test_languages.py +0 -0
  300. {codebase_index-1.7.0 → codebase_index-1.9.0}/tests/test_mcp_golden.py +0 -0
  301. {codebase_index-1.7.0 → codebase_index-1.9.0}/tests/test_mcp_server.py +0 -0
  302. {codebase_index-1.7.0 → codebase_index-1.9.0}/tests/test_multilang_symbols.py +0 -0
  303. {codebase_index-1.7.0 → codebase_index-1.9.0}/tests/test_navigate.py +0 -0
  304. {codebase_index-1.7.0 → codebase_index-1.9.0}/tests/test_output.py +0 -0
  305. {codebase_index-1.7.0 → codebase_index-1.9.0}/tests/test_packaging.py +0 -0
  306. {codebase_index-1.7.0 → codebase_index-1.9.0}/tests/test_parse_guardrails.py +0 -0
  307. {codebase_index-1.7.0 → codebase_index-1.9.0}/tests/test_perf_smoke.py +0 -0
  308. {codebase_index-1.7.0 → codebase_index-1.9.0}/tests/test_pipeline.py +0 -0
  309. {codebase_index-1.7.0 → codebase_index-1.9.0}/tests/test_pipeline_search.py +0 -0
  310. {codebase_index-1.7.0 → codebase_index-1.9.0}/tests/test_pipeline_vectors.py +0 -0
  311. {codebase_index-1.7.0 → codebase_index-1.9.0}/tests/test_plugin_manifest.py +0 -0
  312. {codebase_index-1.7.0 → codebase_index-1.9.0}/tests/test_plugin_skill_parity.py +0 -0
  313. {codebase_index-1.7.0 → codebase_index-1.9.0}/tests/test_plugin_wrappers.py +0 -0
  314. {codebase_index-1.7.0 → codebase_index-1.9.0}/tests/test_public_benchmark.py +0 -0
  315. {codebase_index-1.7.0 → codebase_index-1.9.0}/tests/test_quality_benchmark.py +0 -0
  316. {codebase_index-1.7.0 → codebase_index-1.9.0}/tests/test_redact.py +0 -0
  317. {codebase_index-1.7.0 → codebase_index-1.9.0}/tests/test_repo_search.py +0 -0
  318. {codebase_index-1.7.0 → codebase_index-1.9.0}/tests/test_rerank.py +0 -0
  319. {codebase_index-1.7.0 → codebase_index-1.9.0}/tests/test_retrieval_types.py +0 -0
  320. {codebase_index-1.7.0 → codebase_index-1.9.0}/tests/test_scaffold.py +0 -0
  321. {codebase_index-1.7.0 → codebase_index-1.9.0}/tests/test_searchers.py +0 -0
  322. {codebase_index-1.7.0 → codebase_index-1.9.0}/tests/test_seeded_index.py +0 -0
  323. {codebase_index-1.7.0 → codebase_index-1.9.0}/tests/test_service.py +0 -0
  324. {codebase_index-1.7.0 → codebase_index-1.9.0}/tests/test_skeleton.py +0 -0
  325. {codebase_index-1.7.0 → codebase_index-1.9.0}/tests/test_skill_update.py +0 -0
  326. {codebase_index-1.7.0 → codebase_index-1.9.0}/tests/test_storage.py +0 -0
  327. {codebase_index-1.7.0 → codebase_index-1.9.0}/tests/test_symbol_cli.py +0 -0
  328. {codebase_index-1.7.0 → codebase_index-1.9.0}/tests/test_symbol_refs.py +0 -0
  329. {codebase_index-1.7.0 → codebase_index-1.9.0}/tests/test_sync_skill_copies.py +0 -0
  330. {codebase_index-1.7.0 → codebase_index-1.9.0}/tests/test_treesitter.py +0 -0
  331. {codebase_index-1.7.0 → codebase_index-1.9.0}/tests/test_update.py +0 -0
  332. {codebase_index-1.7.0 → codebase_index-1.9.0}/tests/test_update_cli.py +0 -0
  333. {codebase_index-1.7.0 → codebase_index-1.9.0}/tests/test_vector_search.py +0 -0
  334. {codebase_index-1.7.0 → codebase_index-1.9.0}/tests/test_vectors_storage.py +0 -0
  335. {codebase_index-1.7.0 → codebase_index-1.9.0}/tests/test_watcher.py +0 -0
@@ -3,7 +3,7 @@
3
3
  "name": "codebase-index",
4
4
  "displayName": "Codebase Index",
5
5
  "description": "Give Claude a precise local map of your codebase: find implementations, trace behavior, and predict change impact with file-line evidence.",
6
- "version": "1.7.0",
6
+ "version": "1.9.0",
7
7
  "author": {
8
8
  "name": "codebase-index contributors"
9
9
  },
@@ -6,6 +6,109 @@ All notable changes to this project are documented here. The format is based on
6
6
 
7
7
  ## [Unreleased]
8
8
 
9
+ ## [1.9.0] - 2026-09-02
10
+
11
+ ### Added
12
+
13
+ - **Objective ground truth from git history.** `tests/eval/gen_queries.py` mints a
14
+ retrieval benchmark from any git repository by pairing a human-written commit
15
+ subject with the files that commit actually changed. Unlike docstring-derived
16
+ benchmarks the query text is not copied into the document being retrieved, so the
17
+ set is leak-free by construction; merges, reverts, releases, version bumps,
18
+ sweeping refactors, changelog-style answers and benchmark scaffolding are all
19
+ filtered out.
20
+ - **Multi-corpus, multi-language evaluation.** `run_eval.py --corpus REPO:QUERIES`
21
+ pools several repositories into one benchmark so ranking changes are validated
22
+ outside this repository and outside Python. The 1.9.0 defaults were measured on
23
+ 305 queries across Python, Java and TypeScript corpora.
24
+ - **Significance testing.** Every non-baseline row now reports a paired bootstrap
25
+ 95% confidence interval and a paired permutation p-value (both seeded, therefore
26
+ reproducible). Query sets of this size have a noise floor of several MRR points;
27
+ signals now ship on the strength of that test rather than the sign of a delta.
28
+ - **Context-noise metrics.** The report adds mean emitted snippet tokens, duplicate
29
+ rate of returned results, and p99 latency alongside the existing IR metrics.
30
+
31
+ ### Changed
32
+
33
+ - **Fusion now scores cross-retriever agreement.** RRF fuses on
34
+ `(path, line-bucket)`, so a symbol definition at line 40 and a lexical hit at line
35
+ 120 in the same file fused as two unrelated candidates — two retrievers agreeing
36
+ on a file produced two weak results instead of one strong one, and cross-source
37
+ agreement never reached the score. Each candidate now also receives, at
38
+ `file_agreement_weight` (0.4), the RRF mass of every retriever that found its file
39
+ at another locator, excluding retrievers already counted at that locator.
40
+ Ablatable via `RetrievalTuning(file_agreement=False)`.
41
+ - **Documentation demotion deepened** from -0.05 to -0.20. Prose describing a
42
+ feature matches a natural-language question more literally than the code
43
+ implementing it, so design notes and plans were displacing the modules they
44
+ describe. Because this only reorders prose relative to code, documentation-seeking
45
+ queries improved as well (category MRR 0.579 → 0.612). Generated/vendor paths move
46
+ to -0.25 so they remain the least-preferred role, and `MAX_ABS_PRIOR` now pins the
47
+ invariant that priors stay tiebreakers.
48
+ - **Fuzzy identifier matching is now a recall fallback.** It runs only when the
49
+ precise symbol lookup named no symbol and returned fewer than
50
+ `fuzzy_fallback_min` (3) rows. It moved no ranking metric across 305 queries while
51
+ accounting for ~20% of query latency; typo and acronym recall is unchanged because
52
+ those are exactly the queries where the precise lookup comes up empty.
53
+ - **Candidate over-fetch is explicit.** `candidate_pool_multiplier` (default 2)
54
+ replaces the implicit widening that happened whenever dedup or MMR was enabled.
55
+ Making it explicit revealed that the quality previously credited to SimHash dedup
56
+ was really the wider pool; dedup is retained for what it does measurably do, which
57
+ is cutting the duplicate rate of returned snippets from ~1.6% to ~0%.
58
+
59
+ ### Fixed
60
+
61
+ - **Synonym matches were reported as exact symbol matches.** `is_exact` came from
62
+ SQL and was relative to whichever needle retrieved the row, so a synonym
63
+ expansion ("config" for "configuration") marked an unrelated symbol as an exact
64
+ match — worth a +0.20 rerank bonus and an unconditional `high` confidence.
65
+ Exactness is now judged against the terms the user actually typed.
66
+ - **Duplicate suppression was order-dependent on ties.** Equal-scoring duplicates
67
+ handed the slot to whichever copy arrived last, contradicting the documented
68
+ "ties favor input order" and making the retained snippet depend on retriever
69
+ emission order.
70
+
71
+ ### Performance
72
+
73
+ - Query latency roughly halves: p50 78.6 ms → 51.2 ms, p95 193.2 ms → 94.9 ms,
74
+ p99 277.1 ms → 152.2 ms on the pooled three-repository benchmark, from the fuzzy
75
+ fallback plus a SimHash fingerprint that folds repeated tokens by multiplicity and
76
+ caches token digests. Fingerprint output is bit-for-bit unchanged.
77
+ - Mean emitted snippet tokens fall 1183 → 1091 per query.
78
+
79
+ ### Retrieval quality
80
+
81
+ Pooled over 305 queries (Python, Java, TypeScript), v1.8.0 → 1.9.0:
82
+
83
+ | Metric | v1.8.0 | 1.9.0 | Δ | p |
84
+ |---|---|---|---|---|
85
+ | MRR | 0.564 | 0.591 | +0.027 | <0.001 |
86
+ | MAP | 0.433 | 0.461 | +0.028 | <0.001 |
87
+ | nDCG@10 | 0.503 | 0.527 | +0.024 | <0.001 |
88
+ | recall@5 | 0.529 | 0.560 | +0.031 | <0.001 |
89
+ | P@5 | 0.182 | 0.192 | +0.009 | 0.001 |
90
+ | hit@3 | 0.649 | 0.666 | +0.016 | 0.124 |
91
+
92
+ ## [1.8.0] - 2026-09-02
93
+
94
+ ### Added
95
+
96
+ - **Reproducible retrieval evaluation.** Added a self-repository ground-truth
97
+ query suite with Recall@K, MRR, nDCG, hit rate, precision, MAP, useful-context,
98
+ latency percentiles, and one-signal ablations.
99
+
100
+ ### Changed
101
+
102
+ - **Hybrid retrieval quality.** Natural-language lexical queries now use safe,
103
+ down-weighted identifier/synonym expansion and soft term coverage; exact symbol
104
+ lookup preserves framing-word tolerance and bounded fuzzy matching.
105
+ - **Packaging compatibility.** Cap the build backend below the Metadata 2.5
106
+ default until the release validation toolchain supports that metadata version.
107
+ - **Ranking defaults are evidence-driven.** Implementation/test/documentation
108
+ source priors are calibrated from the benchmark. Graph propagation is bounded
109
+ and intent-directed; graph and MMR signals remain opt-in because ablations
110
+ reduced direct retrieval quality on the reproducible corpus.
111
+
9
112
  ## [1.7.0] - 2026-07-29
10
113
 
11
114
  ### Added
@@ -401,7 +504,8 @@ All notable changes to this project are documented here. The format is based on
401
504
  - Hooks example + `watch` mode for keeping the index fresh without blocking the edit loop (M8).
402
505
  - `doctor`, `stats`, `clean` diagnostics/maintenance commands.
403
506
 
404
- [Unreleased]: https://github.com/denfry/codebase-index/compare/v1.7.0...HEAD
507
+ [Unreleased]: https://github.com/denfry/codebase-index/compare/v1.8.0...HEAD
508
+ [1.8.0]: https://github.com/denfry/codebase-index/compare/v1.7.0...v1.8.0
405
509
  [1.7.0]: https://github.com/denfry/codebase-index/compare/v1.6.0...v1.7.0
406
510
  [1.6.0]: https://github.com/denfry/codebase-index/compare/v1.5.0...v1.6.0
407
511
  [1.5.0]: https://github.com/denfry/codebase-index/compare/v1.4.0...v1.5.0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: codebase-index
3
- Version: 1.7.0
3
+ Version: 1.9.0
4
4
  Summary: A precise local codebase map for AI coding agents: find, trace, and predict with file-line evidence.
5
5
  Project-URL: Homepage, https://github.com/denfry/codebase-index
6
6
  Project-URL: Documentation, https://github.com/denfry/codebase-index/tree/main/docs
@@ -321,7 +321,7 @@ See [MCP.md](docs/MCP.md) for client configuration.
321
321
 
322
322
  ## Project status
323
323
 
324
- The latest released line is **1.7.0**. It includes:
324
+ The latest released line is **1.9.0**. It includes:
325
325
 
326
326
  - hybrid and optional vector retrieval;
327
327
  - Tree-sitter symbol extraction across the documented language tiers;
@@ -329,14 +329,22 @@ The latest released line is **1.7.0**. It includes:
329
329
  - architecture communities, central nodes, and surprising cross-module links;
330
330
  - shortest dependency paths and node descriptions;
331
331
  - token-budgeted and skeletonized retrieval packets;
332
+ - benchmark-calibrated lexical expansion, fuzzy identifier matching, and source-aware ranking;
333
+ - rank fusion that scores cross-retriever agreement at file level, not just at a locator;
334
+ - bounded, intent-directed graph discovery with optional diversity and duplicate suppression;
332
335
  - CLI, Skill, plugin, and MCP delivery;
333
336
  - incremental updates, watch hooks, diagnostics, skill rollback, and diff-aware
334
- impact analysis.
335
-
336
- Planned work is deliberately separated from shipped capability. The next
337
- product priorities are stronger real-repository evaluations, typed framework
338
- edges, and an even more direct task-context workflow. See the
339
- [roadmap](docs/ROADMAP.md).
337
+ impact analysis;
338
+ - a multi-repository retrieval evaluation with leak-free git-derived ground truth,
339
+ one-signal ablations, and paired significance tests
340
+ ([tests/eval](tests/eval/README.md)).
341
+
342
+ Every shipped ranking signal has to survive that evaluation: 1.9.0 removed the
343
+ cost of two signals that could not demonstrate a benefit and rejected several
344
+ plausible ones outright (IDF-weighted coverage, stemming, graph propagation, MMR,
345
+ a file-length prior). Planned work is deliberately separated from shipped
346
+ capability. The next product priorities are typed framework edges and an even more
347
+ direct task-context workflow. See the [roadmap](docs/ROADMAP.md).
340
348
 
341
349
  ## Documentation
342
350
 
@@ -271,7 +271,7 @@ See [MCP.md](docs/MCP.md) for client configuration.
271
271
 
272
272
  ## Project status
273
273
 
274
- The latest released line is **1.7.0**. It includes:
274
+ The latest released line is **1.9.0**. It includes:
275
275
 
276
276
  - hybrid and optional vector retrieval;
277
277
  - Tree-sitter symbol extraction across the documented language tiers;
@@ -279,14 +279,22 @@ The latest released line is **1.7.0**. It includes:
279
279
  - architecture communities, central nodes, and surprising cross-module links;
280
280
  - shortest dependency paths and node descriptions;
281
281
  - token-budgeted and skeletonized retrieval packets;
282
+ - benchmark-calibrated lexical expansion, fuzzy identifier matching, and source-aware ranking;
283
+ - rank fusion that scores cross-retriever agreement at file level, not just at a locator;
284
+ - bounded, intent-directed graph discovery with optional diversity and duplicate suppression;
282
285
  - CLI, Skill, plugin, and MCP delivery;
283
286
  - incremental updates, watch hooks, diagnostics, skill rollback, and diff-aware
284
- impact analysis.
285
-
286
- Planned work is deliberately separated from shipped capability. The next
287
- product priorities are stronger real-repository evaluations, typed framework
288
- edges, and an even more direct task-context workflow. See the
289
- [roadmap](docs/ROADMAP.md).
287
+ impact analysis;
288
+ - a multi-repository retrieval evaluation with leak-free git-derived ground truth,
289
+ one-signal ablations, and paired significance tests
290
+ ([tests/eval](tests/eval/README.md)).
291
+
292
+ Every shipped ranking signal has to survive that evaluation: 1.9.0 removed the
293
+ cost of two signals that could not demonstrate a benefit and rejected several
294
+ plausible ones outright (IDF-weighted coverage, stemming, graph propagation, MMR,
295
+ a file-length prior). Planned work is deliberately separated from shipped
296
+ capability. The next product priorities are typed framework edges and an even more
297
+ direct task-context workflow. See the [roadmap](docs/ROADMAP.md).
290
298
 
291
299
  ## Documentation
292
300
 
@@ -2,7 +2,7 @@
2
2
 
3
3
  ## 1. Overview
4
4
 
5
- `codebase-index` is a **local-first** code intelligence layer for AI coding agents. In `1.7.0`
5
+ `codebase-index` is a **local-first** code intelligence layer for AI coding agents. In `1.9.0`
6
6
  it has two shipped faces:
7
7
 
8
8
  1. **A Claude Code Skill** (`.claude/skills/codebase-index/SKILL.md`) that Claude auto-invokes for
@@ -97,8 +97,9 @@ codebase-index/
97
97
  ├── graph/ # builder.py (edge resolution), expand.py (impact),
98
98
  │ # export.py (HTML graph)
99
99
  ├── storage/ # db.py (pragmas, schema, version guard), schema.sql, repo.py
100
- ├── retrieval/ # intent.py, searchers.py, fusion.py, rerank.py,
101
- │ # budget.py, pipeline.py, types.py
100
+ ├── retrieval/ # intent.py, searchers.py, fusion.py, rerank.py, priors.py,
101
+ │ # lexical.py, fuzzy.py, diversity.py, skeleton.py,
102
+ │ # tuning.py (ablation contract), budget.py, pipeline.py, types.py
102
103
  ├── embeddings/ # backend.py, noop.py (default), local.py, external.py — opt-in
103
104
  ├── output/ # markdown.py, json.py, redact.py
104
105
  ├── watch/ # watcher.py (optional, watchdog-based)
@@ -1,10 +1,11 @@
1
1
  # Benchmarks
2
2
 
3
- `codebase-index` has three benchmark surfaces. Read them with their status in
3
+ `codebase-index` has four benchmark surfaces. Read them with their status in
4
4
  mind — the whole point of this page is to keep evidence and aspiration separate.
5
5
 
6
6
  | Surface | What it is | Status | Use it as |
7
7
  |---|---|---|---|
8
+ | Retrieval eval (`tests/eval/`) | Ranking quality vs a fixed baseline across multiple real repositories, with significance tests | **Proven (relative)** | The gate for ranking changes; measures *deltas*, not absolute superiority |
8
9
  | Public suite (`tests/benchmark_public.py`) | Deterministic synthetic multi-language fixture with the full metric framework | **Toy/synthetic** | CI regression gate + metric shape, **not** product-quality evidence |
9
10
  | Smoke/perf (`test_perf_smoke.py`, `test_benchmark_comparison.py`) | Latency + output-size guards on a tiny fixture | **Toy/smoke** | Regression checks only |
10
11
  | Honest real-repo (`tests/benchmark_honest.py`) | 55k LOC Java repo, recall@3 vs disciplined `rg` baseline, symmetric token accounting | **Proven (one repo)** | The only headline product-quality number we stand behind today |
@@ -15,15 +16,33 @@ Do not write, imply, or ship any of these until a run with published logs exists
15
16
 
16
17
  - Any 10k / 100k / 1M LOC scale or speed claim (no real run at that size).
17
18
  - "Beats Cursor / Sourcegraph / Codebase-Memory MCP" — no head-to-head exists.
18
- - Per-language quality claims beyond Java (the honest run is Java-only).
19
+ - Per-language *absolute* quality claims beyond Java. The retrieval eval covers
20
+ Python, Java and TypeScript, but it measures this system against its own earlier
21
+ versions — it says a change helped, not that the product beats an alternative.
19
22
  - Generic "Nx faster" / "Nx fewer tokens" without naming the baseline and repo.
20
- - Latency claims — the honest run explicitly does not headline latency
21
- (Python process start dominates; real `rg` is tens of ms).
23
+ - Latency claims against external tools — the honest run explicitly does not
24
+ headline latency (Python process start dominates; real `rg` is tens of ms).
25
+ Version-over-version latency from the retrieval eval is in-process and is only
26
+ comparable to other runs of that harness.
22
27
 
23
28
  The defensible headline today is exactly: **on one 55k LOC Java repo, recall@3 was
24
29
  70% (index) vs 40% (`rg`+window), using ~13× fewer answer tokens.** Everything
25
30
  else is roadmap.
26
31
 
32
+ ## Retrieval evaluation (ranking gate)
33
+
34
+ See [tests/eval/README.md](../tests/eval/README.md) for the full protocol. In short:
35
+ ground truth comes from hand-written queries verified against the source tree and
36
+ from commit-subject → changed-files pairs mined from git history (leak-free: the
37
+ query text is not in the indexed corpus). Corpora are pooled across languages, one
38
+ index per corpus is shared by every variant, and every non-baseline row carries a
39
+ paired bootstrap CI and permutation p-value.
40
+
41
+ `1.9.0` was measured over 305 queries across Python, Java and TypeScript corpora
42
+ against `1.8.0`: MRR +0.027, MAP +0.028, nDCG@10 +0.024, recall@5 +0.031 (all
43
+ p < 0.001), with p50 latency 78.6 ms → 51.2 ms. These are version-over-version
44
+ ranking deltas on those corpora, not a universal quality claim.
45
+
27
46
  ## Public benchmark suite
28
47
 
29
48
  Run:
@@ -14,7 +14,7 @@ pip install codebase-index # or: pipx install codebase-index
14
14
  ```
15
15
 
16
16
  To pin an exact version or grab an unreleased commit, install from a GitHub tag
17
- instead: `pip install "codebase-index @ git+https://github.com/denfry/codebase-index.git@v1.7.0"`.
17
+ instead: `pip install "codebase-index @ git+https://github.com/denfry/codebase-index.git@v1.8.0"`.
18
18
 
19
19
  Then run `codebase-index init` inside your project and `codebase-index index` to build
20
20
  the first index. In Claude Code you can instead install the plugin
@@ -162,11 +162,12 @@ Yes. Use any of these methods:
162
162
 
163
163
  ## Is it production-ready?
164
164
 
165
- Yes — `codebase-index` is released as **v1.7.0**. The core indexing and search
166
- functionality is implemented and tested. The current `1.7.0` package includes:
165
+ Yes — `codebase-index` is released as **v1.8.0**. The core indexing and search
166
+ functionality is implemented and tested. The current `1.8.0` package includes:
167
167
 
168
- - Hybrid FTS/path/symbol/vector retrieval
169
- - Import/call/reference graph expansion and `impact`
168
+ - Hybrid FTS/path/symbol/vector retrieval with benchmark-calibrated lexical expansion
169
+ and bounded fuzzy identifier matching
170
+ - Import/call/reference graph expansion, intent-directed graph discovery, and `impact`
170
171
  - Diff-aware blast-radius analysis for tracked working-tree changes
171
172
  - Optional local embeddings, with external embeddings gated behind explicit opt-in
172
173
  - Hooks and watch mode for freshness
@@ -67,7 +67,7 @@ pipx install codebase-index # isolated environment
67
67
  uv tool install codebase-index # uv-managed tool
68
68
 
69
69
  # Pin to a GitHub tag for an exact or unreleased version
70
- pip install "codebase-index @ git+https://github.com/denfry/codebase-index.git@v1.7.0"
70
+ pip install "codebase-index @ git+https://github.com/denfry/codebase-index.git@v1.8.0"
71
71
 
72
72
  # From source (editable mode)
73
73
  git clone https://github.com/denfry/codebase-index.git
@@ -90,7 +90,7 @@ pip install -e ".[embeddings-local,watch,dev]"
90
90
 
91
91
  ### uvx / Homebrew status
92
92
 
93
- As of `1.7.0`, **PyPI is shipped** — `pip install codebase-index` and
93
+ As of `1.8.0`, **PyPI is shipped** — `pip install codebase-index` and
94
94
  `pipx install codebase-index` are the verified paths. `uvx codebase-index init`,
95
95
  Homebrew tap installation, signed checksums, and SBOMs remain distribution
96
96
  targets for a more complete release story.
@@ -130,7 +130,7 @@ Expected output:
130
130
  === codebase-index Doctor ===
131
131
 
132
132
  [OK] Python 3.12 (requires 3.11+)
133
- [OK] codebase-index package installed (v1.7.0)
133
+ [OK] codebase-index package installed (v1.8.0)
134
134
  [OK] tree-sitter is available
135
135
  [INFO] Cache directory not yet created: ...
136
136
  [INFO] Skill not installed in .claude/skills/
@@ -0,0 +1,229 @@
1
+ # Retrieval Pipeline
2
+
3
+ The retrieval engine turns a natural-language or symbolic query into a **compact, ranked,
4
+ token-budgeted** set of file/line ranges for Claude to read. It is hybrid: multiple independent
5
+ retrievers run, their results are fused and reranked, then trimmed. Graph expansion and MMR are
6
+ available as bounded opt-in signals; the shipped default prioritizes direct evidence.
7
+
8
+ ```
9
+ query
10
+ │
11
+ ▼
12
+ [1] intent detection ──────────────┐
13
+ │ │ selects retrievers + weights + graph strategy
14
+ ▼ ▼
15
+ [2] retrievers (run in parallel)
16
+ ├─ exact path (glob/path LIKE)
17
+ ├─ symbol (symbols table, exact + fuzzy)
18
+ ├─ FTS keyword (FTS5 bm25 over chunks + symbols + summaries)
19
+ └─ vector (opt-in) (sqlite-vec / local embeddings)
20
+ │
21
+ ▼
22
+ [3] rank fusion ── Reciprocal Rank Fusion (RRF) across retriever result lists
23
+ │
24
+ ▼
25
+ [4] rerank ── feature-based score (symbol-kind, path, source role, centrality)
26
+ │
27
+ ▼
28
+ [5] optional graph expansion ── pull in imports/callers/callees per intent (bounded)
29
+ │
30
+ ▼
31
+ [6] diversity / duplicate filtering (MMR opt-in, SimHash duplicate guard)
32
+ │
33
+ ▼
34
+ [7] token budgeting ── greedy fill under --token-budget; snippets trimmed + secret-redacted
35
+ │
36
+ ▼
37
+ ranked results + recommended_reads + fallback_suggestions
38
+ ```
39
+
40
+ ## 1. Intent detection (`retrieval/intent.py`)
41
+
42
+ Cheap, rule-first classifier (regex/keyword heuristics; optionally a tiny local model later). Each
43
+ intent maps to a retriever mix, a graph strategy, and an output shape.
44
+
45
+ | Intent | Trigger examples | Retriever emphasis | Graph strategy |
46
+ |---|---|---|---|
47
+ | `locate_impl` | "where is X implemented", "find the X function" | symbol > path > fts | none / defs only |
48
+ | `how_it_works` | "how does X work", "explain X flow" | fts + symbol + vector | expand callees 1–2 hops |
49
+ | `impact` | "what breaks if I change X", "what depends on X" | symbol + path | expand callers/importers (up) |
50
+ | `find_refs` | "find references to X", "who calls X" | symbol | edges where target=X |
51
+ | `data_flow` | "trace data flow of X", "where does X get set" | symbol + fts | follow assignments/calls both ways |
52
+ | `debug_error` | pasted stack trace / "error: ...", "why does X fail" | fts (error string) + symbol | expand around match |
53
+ | `architecture` | "explain the architecture", "high-level overview" | summaries + graph centrality | package/module summaries |
54
+ | `keyword` | fallback when nothing matches above | fts + vector | none |
55
+
56
+ Each intent also sets a **default token budget** and whether to return module/package summaries
57
+ instead of code (e.g. `architecture` returns summaries first).
58
+
59
+ ## 2. Retrievers (`retrieval/searchers.py`)
60
+
61
+ All retrievers return a uniform `Candidate(id, kind, path, line_start, line_end, symbol, score,
62
+ source)` list so fusion is source-agnostic.
63
+
64
+ - **Path** — exact and glob path matches (`src/auth/*.py`, `auth.py`). Highest precision; surfaced
65
+ first when the query clearly names a path.
66
+ - **Symbol** — query against `symbols` (exact, identifier parts, bounded fuzzy matching). Carries
67
+ `kind` (function/class/method/...) and signature. Primary for `locate_impl` / `find_refs`.
68
+ Fuzzy identifier matching (acronym / concatenation / edit distance) runs only as a **recall
69
+ fallback**, when the precise lookup named no symbol and returned fewer than
70
+ `fuzzy_fallback_min` rows. Measured over 305 queries on three repositories it moved no ranking
71
+ metric while costing ~20% of query latency, so it is kept for typos and abbreviations but no
72
+ longer runs when the query already spelled its identifier correctly.
73
+ - **FTS** — FTS5 `bm25()` over the `fts_chunks` virtual table (chunk text + symbol names +
74
+ summaries indexed). Query-time camelCase/snake_case splitting, small down-weighted synonym
75
+ expansion, and soft coverage scoring make natural-language questions robust without weakening
76
+ exact terms.
77
+ - **Vector** *(opt-in)* — cosine similarity over chunk embeddings via `sqlite-vec`. Only runs if
78
+ `embeddings.enabled = true`. Adds semantic recall for paraphrased queries. Absent → pipeline
79
+ degrades gracefully to FTS+symbol.
80
+
81
+ ## 3. Rank fusion (`retrieval/fusion.py`)
82
+
83
+ **Reciprocal Rank Fusion** combines the per-retriever ranked lists without needing comparable raw
84
+ scores:
85
+
86
+ ```
87
+ RRF(d) = Σ_r w_r · k / (k + rank_r(d)) # k ≈ 60, w_r = per-intent retriever weight
88
+ ```
89
+
90
+ - Robust to scale differences between BM25 and cosine.
91
+ - Per-intent weights `w_r` let `locate_impl` favor the symbol list and `how_it_works` favor FTS.
92
+ - Scaled by `k` so fused scores and the reranker's bounded bonuses share an O(1) scale. This is a
93
+ monotonic rescale; fusion order is unchanged.
94
+ - Ties broken by rerank features (next step).
95
+
96
+ ### Cross-locator file agreement
97
+
98
+ Fusion keys on `(path, line-bucket)`, not `(path, start, end)`, because different retrievers report
99
+ different line ranges for the same place. Bucketing alone was not enough: a symbol defined at line
100
+ 40 and a lexical hit at line 120 are genuinely different locators, so a file that **two retrievers
101
+ agreed on** still fused as two separate candidates, each carrying one retriever's evidence — and
102
+ cross-source agreement, the entire point of RRF, never fired.
103
+
104
+ Each candidate therefore also receives, at weight `file_agreement_weight`, the RRF mass of every
105
+ retriever that found its *file* at some other locator:
106
+
107
+ ```
108
+ score(d) = RRF(d) + α · Σ_{r ∉ sources(d)} w_r · k / (k + best_rank_r(path(d)))
109
+ ```
110
+
111
+ Retrievers already counted at the candidate's own locator are excluded, so nothing double-counts,
112
+ and the term is bounded by the same weights as fusion itself. `α = 0.4`; the 0.3–0.6 plateau peaks
113
+ there. Set `RetrievalTuning(file_agreement=False)` to recover plain locator-only RRF.
114
+
115
+ ## 4. Reranking (`retrieval/rerank.py`)
116
+
117
+ A lightweight, explainable feature score (no external model required) layered on the fused order.
118
+ Every term is bounded, so reranking reorders near-neighbours rather than overruling retrieval:
119
+
120
+ | Feature | Effect | Intuition |
121
+ |---|---:|---|
122
+ | Exact symbol match | +0.20 | the user named a specific symbol |
123
+ | Symbol definition kind | +0.05 | a `def`/`class` outranks an incidental mention |
124
+ | Symbol name among query terms | +0.05 | the name was asked for, not just matched |
125
+ | Path term match | +0.05 | the user supplied a location clue |
126
+ | Graph centrality (`in_degree`) | ≤ +0.08 | `log1p`-damped, so a god class cannot dominate |
127
+ | Reference-count fallback | ≤ +0.04 | for names too common to resolve a precise `in_degree` |
128
+ | Source role prior | −0.25…+0.08 | see below |
129
+ | Generated, or test on a non-test query | −0.15 | supporting evidence, not the answer |
130
+
131
+ ### Source role priors (`retrieval/priors.py`)
132
+
133
+ | Role | Prior | Rationale |
134
+ |---|---:|---|
135
+ | Implementation | +0.08 | the answer to a code question is usually code |
136
+ | Test | −0.06 | flips to +0.05 when the query or intent is test-oriented |
137
+ | Documentation | −0.20 | prose *about* a feature matches a natural-language question more literally than the code implementing it, so design notes and plans crowded out the modules they describe |
138
+ | Generated / vendor / build | −0.25 | never the answer; kept strictly below documentation |
139
+
140
+ The documentation prior deepened from −0.05 in 1.8.0. Because it only reorders prose relative to
141
+ code — never below other prose — documentation-seeking queries improved too (MRR 0.579 → 0.612).
142
+ At −0.35 that reverses and the `docs` category collapses, so the optimum is interior, not a
143
+ "more is better" knob. `MAX_ABS_PRIOR` caps every prior so this stays a tiebreaker.
144
+
145
+ The reranker also produces the human-readable **`reason`** string per result
146
+ (e.g. *"exact symbol match · 4 callers · in src/auth/"*).
147
+
148
+ ## 5. Graph expansion (`graph/retrieval.py`; `graph/expand.py` for impact APIs)
149
+
150
+ Graph expansion runs only when the tuning enables `graph_source` and the intent plan requests a
151
+ graph strategy. It is disabled by default because the reproducible self-repository ablation
152
+ reduced direct-hit MRR when related nodes displaced lexical hits.
153
+
154
+ When enabled, it is bounded by depth and node cap:
155
+
156
+ - `impact` → walk **up** edges (callers, importers) = blast radius.
157
+ - `how_it_works` → walk **down** edges (callees, imported defs) = mechanism.
158
+ - `find_refs` → walk **up** edges to callers/importers.
159
+ - `data_flow` → walk **both** directions along call/assignment edges.
160
+
161
+ Expanded nodes retain edge confidence and receive distance-decayed scores so seeds stay on top.
162
+
163
+ ## 6. Diversity and duplicate control
164
+
165
+ `retrieval.diversity` provides bounded MMR selection and SimHash near-duplicate suppression.
166
+
167
+ MMR is disabled in the shipped default: it moved no ranking metric on the benchmark and roughly
168
+ doubled p50 latency. Callers that need broader snippet coverage can enable
169
+ `RetrievalTuning(mmr=True)`.
170
+
171
+ SimHash duplicate suppression stays on, but on noise grounds rather than ranking grounds: it does
172
+ not move MRR, and it takes the duplicate rate of returned snippets from ~1.6% to ~0%. The
173
+ over-fetch that feeds selection is now an explicit `candidate_pool_multiplier` rather than an
174
+ implicit side effect of enabling dedup — an earlier ablation credited dedup with a quality win that
175
+ was really the wider pool doing the work.
176
+
177
+ ## 7. Token budgeting (`retrieval/budget.py`)
178
+
179
+ Results are trimmed to fit `--token-budget` (default per intent, e.g. 1500 tokens):
180
+
181
+ 1. Always include result metadata (path, line range, symbol, reason) — cheap.
182
+ 2. Greedily attach snippets to the highest-ranked results until budget is hit.
183
+ 3. Snippets are trimmed to the relevant line range (± a few context lines), not whole functions.
184
+ 4. Lower-ranked results become **`recommended_reads`** (path + range, no snippet) so Claude can
185
+ choose to read them itself.
186
+ 5. Snippet text passes through secret redaction (see SECURITY.md) before emission.
187
+
188
+ The point: Claude gets enough to decide, and a precise list of what to read next — never a dump.
189
+
190
+ ## 8. Confidence & fallback
191
+
192
+ A `confidence` score (high/medium/low) is derived from: top RRF score, score gap between #1 and #2,
193
+ number of agreeing retrievers, and whether a symbol matched exactly.
194
+
195
+ - **high** → Claude reads `recommended_reads` and answers.
196
+ - **medium** → Claude reads, but may verify with one Grep.
197
+ - **low** → skill instructs Claude to **fall back** to `ripgrep`/Grep/Glob with suggested patterns
198
+ emitted in `fallback_suggestions` (derived from query terms + detected symbols).
199
+
200
+ ## 9. Output payload (shared by Markdown + JSON)
201
+
202
+ ```jsonc
203
+ {
204
+ "query": "where is auth token refresh implemented",
205
+ "intent": "locate_impl",
206
+ "confidence": "high",
207
+ "results": [
208
+ {
209
+ "rank": 1,
210
+ "path": "src/auth/token.py",
211
+ "line_start": 88, "line_end": 134,
212
+ "symbols": ["refresh_access_token"],
213
+ "score": 0.91,
214
+ "reason": "exact symbol match · 4 callers · in src/auth/",
215
+ "snippet": "def refresh_access_token(...):\n ..."
216
+ }
217
+ ],
218
+ "recommended_reads": [
219
+ { "path": "src/auth/token.py", "line_start": 88, "line_end": 134 },
220
+ { "path": "src/auth/middleware.py", "line_start": 40, "line_end": 72 }
221
+ ],
222
+ "fallback_suggestions": {
223
+ "ripgrep": ["rg -n \"refresh_access_token\" src/", "rg -n \"token.*refresh\""]
224
+ }
225
+ }
226
+ ```
227
+
228
+ The Markdown renderer (`output/markdown.py`) prints the same data as a tight table + fenced
229
+ snippets so it's compact in Claude's context. See SKILL.md for how Claude is told to read it.