contextual-engine 0.9.5__tar.gz → 0.9.6__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 (287) hide show
  1. {contextual_engine-0.9.5 → contextual_engine-0.9.6}/.gitignore +4 -0
  2. {contextual_engine-0.9.5 → contextual_engine-0.9.6}/PKG-INFO +7 -11
  3. {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/cli/commands/doctor.py +4 -9
  4. contextual_engine-0.9.6/contextual/cli/commands/fetch.py +158 -0
  5. {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/cli/commands/index.py +0 -5
  6. {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/cli/commands/install.py +1 -2
  7. {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/config/__init__.py +0 -2
  8. {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/config/base.py +1 -1
  9. {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/config/global_/mcp_config.py +15 -7
  10. {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/config/indexing.py +15 -57
  11. {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/config/paths.py +18 -17
  12. {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/config/workspace/__init__.py +0 -2
  13. {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/config/workspace/retrieval_config.py +0 -8
  14. {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/core/errors.py +1 -2
  15. contextual_engine-0.9.6/contextual/core/memory.py +46 -0
  16. {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/incremental/daemon_embed.py +6 -5
  17. {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/incremental/file_watcher.py +2 -30
  18. {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/incremental/incremental_indexer.py +132 -7
  19. {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/indexing/__init__.py +0 -37
  20. {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/indexing/_config.py +0 -5
  21. {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/indexing/index_writer.py +2 -1
  22. {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/indexing/pipeline.py +76 -14
  23. {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/indexing/processor.py +0 -86
  24. {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/mcp/__main__.py +6 -0
  25. {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/mcp/memory_monitor.py +4 -25
  26. {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/mcp/middleware/auth.py +0 -2
  27. {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/mcp/middleware/ratelimit.py +9 -0
  28. {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/mcp/middleware/warmup.py +3 -3
  29. {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/mcp/middleware/workspace.py +11 -0
  30. {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/mcp/router.py +12 -6
  31. {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/mcp/server.py +34 -65
  32. {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/mcp/session_manager.py +79 -56
  33. {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/mcp/shim.py +95 -34
  34. {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/mcp/tools/graph.py +49 -6
  35. {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/mcp/tools/nexus.py +4 -0
  36. {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/mcp/tools/semantic.py +31 -3
  37. {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/mcp/tools/system.py +3 -12
  38. contextual_engine-0.9.6/contextual/models/__init__.py +353 -0
  39. contextual_engine-0.9.6/contextual/models/_inference.py +15 -0
  40. {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/models/allowlist.py +2 -3
  41. contextual_engine-0.9.6/contextual/models/base_embedder.py +23 -0
  42. contextual_engine-0.9.6/contextual/models/unified_embedder.py +353 -0
  43. {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/retrieval/__init__.py +3 -24
  44. {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/retrieval/mmr.py +1 -46
  45. {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/retrieval/pipeline.py +271 -137
  46. {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/retrieval/ranker.py +2 -34
  47. contextual_engine-0.9.6/contextual/retrieval/structural_similarity.py +150 -0
  48. {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/storage/connection.py +11 -0
  49. {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/storage/fts.py +38 -1
  50. {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/storage/lancedb_provider.py +84 -16
  51. contextual_engine-0.9.6/contextual/storage/migrations/m015_symbol_ngram.py +1 -0
  52. {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/storage/migrations/runner.py +18 -1
  53. contextual_engine-0.9.6/contextual/storage/migrations/solo/m015_symbol_ngram.py +154 -0
  54. {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/storage/schema.py +15 -4
  55. {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/temporal/blame_pipeline.py +9 -82
  56. contextual_engine-0.9.6/docs/SECURITY.md +116 -0
  57. {contextual_engine-0.9.5 → contextual_engine-0.9.6}/pyproject.toml +12 -14
  58. contextual_engine-0.9.6/scripts/benchmark_golden.json +56 -0
  59. contextual_engine-0.9.6/scripts/run_benchmark.py +161 -0
  60. {contextual_engine-0.9.5 → contextual_engine-0.9.6}/tests/conftest.py +0 -15
  61. contextual_engine-0.9.6/tests/test_accuracy.py +90 -0
  62. contextual_engine-0.9.6/tests/test_async.py +121 -0
  63. contextual_engine-0.9.6/tests/test_mcp.py +155 -0
  64. {contextual_engine-0.9.5 → contextual_engine-0.9.6}/tests/test_retrieval.py +8 -54
  65. contextual_engine-0.9.6/tests/test_security.py +153 -0
  66. {contextual_engine-0.9.5 → contextual_engine-0.9.6}/tests/test_storage.py +171 -0
  67. contextual_engine-0.9.5/.cursor/rules/contextual.mdc +0 -87
  68. contextual_engine-0.9.5/contextual/cli/commands/fetch.py +0 -221
  69. contextual_engine-0.9.5/contextual/models/__init__.py +0 -575
  70. contextual_engine-0.9.5/contextual/models/_inference.py +0 -21
  71. contextual_engine-0.9.5/contextual/models/base_embedder.py +0 -72
  72. contextual_engine-0.9.5/contextual/models/reranker_model.py +0 -386
  73. contextual_engine-0.9.5/contextual/models/unified_embedder.py +0 -429
  74. contextual_engine-0.9.5/docs/SECURITY.md +0 -0
  75. contextual_engine-0.9.5/pytest.ini +0 -80
  76. contextual_engine-0.9.5/tests/test_accuracy.py +0 -23
  77. contextual_engine-0.9.5/tests/test_async.py +0 -23
  78. contextual_engine-0.9.5/tests/test_mcp.py +0 -33
  79. contextual_engine-0.9.5/tests/test_security.py +0 -23
  80. {contextual_engine-0.9.5 → contextual_engine-0.9.6}/.contextualignore +0 -0
  81. {contextual_engine-0.9.5 → contextual_engine-0.9.6}/.github/workflows/ci.yml +0 -0
  82. {contextual_engine-0.9.5 → contextual_engine-0.9.6}/.github/workflows/release.yml +0 -0
  83. {contextual_engine-0.9.5 → contextual_engine-0.9.6}/.mcp.json +0 -0
  84. {contextual_engine-0.9.5 → contextual_engine-0.9.6}/LICENSE +0 -0
  85. {contextual_engine-0.9.5 → contextual_engine-0.9.6}/README.md +0 -0
  86. {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/__init__.py +0 -0
  87. {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/__main__.py +0 -0
  88. {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/cli/__init__.py +0 -0
  89. {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/cli/commands/__init__.py +0 -0
  90. {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/cli/commands/auth.py +0 -0
  91. {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/cli/commands/client.py +0 -0
  92. {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/cli/commands/config.py +0 -0
  93. {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/cli/commands/initialisation.py +0 -0
  94. {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/cli/commands/mcp.py +0 -0
  95. {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/cli/commands/stats.py +0 -0
  96. {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/cli/commands/workspace.py +0 -0
  97. {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/cli/core/__init__.py +0 -0
  98. {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/cli/core/context.py +0 -0
  99. {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/cli/core/decorators.py +0 -0
  100. {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/cli/core/editor.py +0 -0
  101. {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/cli/core/output.py +0 -0
  102. {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/config/global_/__init__.py +0 -0
  103. {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/config/global_/security_config.py +0 -0
  104. {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/config/global_/storage_config.py +0 -0
  105. {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/config/workspace/cache_config.py +0 -0
  106. {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/config/workspace/indexing_config.py +0 -0
  107. {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/config/workspace/observability_config.py +0 -0
  108. {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/config/workspace/workspace_config.py +0 -0
  109. {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/core/__init__.py +0 -0
  110. {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/core/models.py +0 -0
  111. {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/git/__init__.py +0 -0
  112. {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/git/blame.py +0 -0
  113. {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/git/hooks.py +0 -0
  114. {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/git/incremental_git.py +0 -0
  115. {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/graph/__init__.py +0 -0
  116. {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/graph/dedup.py +0 -0
  117. {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/graph/extractor.py +0 -0
  118. {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/graph/integrator.py +0 -0
  119. {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/graph/resolver.py +0 -0
  120. {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/graph/staleness.py +0 -0
  121. {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/graph/store.py +0 -0
  122. {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/graph/traversal.py +0 -0
  123. {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/incremental/__init__.py +0 -0
  124. {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/indexing/_ignore.py +0 -0
  125. {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/indexing/chunker.py +0 -0
  126. {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/indexing/docs_pipeline.py +0 -0
  127. {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/indexing/merkle_tree.py +0 -0
  128. {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/indexing/symbol_extractor.py +0 -0
  129. {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/integrations/__init__.py +0 -0
  130. {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/integrations/client_content.py +0 -0
  131. {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/integrations/client_writer.py +0 -0
  132. {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/mcp/__init__.py +0 -0
  133. {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/mcp/_platform.py +0 -0
  134. {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/mcp/access.py +0 -0
  135. {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/mcp/bootstrap.py +0 -0
  136. {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/mcp/config.py +0 -0
  137. {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/mcp/daemon.py +0 -0
  138. {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/mcp/middleware/__init__.py +0 -0
  139. {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/mcp/middleware/audit.py +0 -0
  140. {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/mcp/middleware/identity.py +0 -0
  141. {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/mcp/tools/__init__.py +0 -0
  142. {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/mcp/tools/_gcf.py +0 -0
  143. {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/mcp/tools/temporal.py +0 -0
  144. {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/mcp/workspace_registry.py +0 -0
  145. {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/observability/__init__.py +0 -0
  146. {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/observability/config.py +0 -0
  147. {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/observability/exporters.py +0 -0
  148. {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/observability/logging.py +0 -0
  149. {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/observability/retention.py +0 -0
  150. {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/observability/tracer.py +0 -0
  151. {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/retrieval/context_assembler.py +0 -0
  152. {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/retrieval/tokenizer.py +0 -0
  153. {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/security/__init__.py +0 -0
  154. {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/security/paths.py +0 -0
  155. {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/security/sanitize.py +0 -0
  156. {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/security/workspace.py +0 -0
  157. {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/storage/__init__.py +0 -0
  158. {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/storage/cache.py +0 -0
  159. {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/storage/migrations/__init__.py +0 -0
  160. {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/storage/migrations/enterprise/me001_orgs.py +0 -0
  161. {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/storage/migrations/enterprise/me002_org_members.py +0 -0
  162. {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/storage/migrations/enterprise/me003_teams.py +0 -0
  163. {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/storage/migrations/enterprise/me004_team_members.py +0 -0
  164. {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/storage/migrations/enterprise/me005_org_workspaces.py +0 -0
  165. {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/storage/migrations/enterprise/me006_workspace_permissions.py +0 -0
  166. {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/storage/migrations/enterprise/me007_idp_sync_log.py +0 -0
  167. {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/storage/migrations/enterprise/me008_org_policies.py +0 -0
  168. {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/storage/migrations/enterprise/me009_api_keys.py +0 -0
  169. {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/storage/migrations/enterprise/me010_org_audit_log.py +0 -0
  170. {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/storage/migrations/enterprise/me011_workspace_traceability.py +0 -0
  171. {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/storage/migrations/m001_global.py +0 -0
  172. {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/storage/migrations/m002_embeddings.py +0 -0
  173. {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/storage/migrations/m003_temporal.py +0 -0
  174. {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/storage/migrations/m004_graph.py +0 -0
  175. {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/storage/migrations/m005_cache.py +0 -0
  176. {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/storage/migrations/m006_logs.py +0 -0
  177. {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/storage/migrations/m007_terminal_sessions.py +0 -0
  178. {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/storage/migrations/m008_queue.py +0 -0
  179. {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/storage/migrations/m009_swarm.py +0 -0
  180. {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/storage/migrations/m010_task_force.py +0 -0
  181. {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/storage/migrations/m011_reminders.py +0 -0
  182. {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/storage/migrations/m013_temporal_l2.py +0 -0
  183. {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/storage/migrations/m014_nexus_foundation.py +0 -0
  184. {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/storage/migrations/solo/m001_global.py +0 -0
  185. {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/storage/migrations/solo/m002_embeddings.py +0 -0
  186. {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/storage/migrations/solo/m003_temporal.py +0 -0
  187. {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/storage/migrations/solo/m004_graph.py +0 -0
  188. {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/storage/migrations/solo/m005_cache.py +0 -0
  189. {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/storage/migrations/solo/m006_logs.py +0 -0
  190. {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/storage/migrations/solo/m007_terminal_sessions.py +0 -0
  191. {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/storage/migrations/solo/m008_queue.py +0 -0
  192. {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/storage/migrations/solo/m009_swarm.py +0 -0
  193. {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/storage/migrations/solo/m010_task_force.py +0 -0
  194. {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/storage/migrations/solo/m011_reminders.py +0 -0
  195. {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/storage/migrations/solo/m012_workspace_metadata.py +0 -0
  196. {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/storage/migrations/solo/m013_temporal_l2.py +0 -0
  197. {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/storage/migrations/solo/m014_nexus_foundation.py +0 -0
  198. {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/storage/migrations/teams/mt001_orgs.py +0 -0
  199. {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/storage/migrations/teams/mt002_org_members.py +0 -0
  200. {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/storage/migrations/teams/mt003_teams.py +0 -0
  201. {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/storage/migrations/teams/mt004_team_members.py +0 -0
  202. {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/storage/migrations/teams/mt005_team_workspaces.py +0 -0
  203. {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/storage/migrations/teams/mt006_workspace_permissions.py +0 -0
  204. {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/storage/migrations/teams/mt007_team_audit_log.py +0 -0
  205. {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/storage/migrations/teams/mt008_workspace_traceability.py +0 -0
  206. {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/storage/schema_base.py +0 -0
  207. {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/storage/schema_ent.py +0 -0
  208. {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/storage/schema_team.py +0 -0
  209. {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/temporal/__init__.py +0 -0
  210. {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/temporal/adr.py +0 -0
  211. {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/temporal/context.py +0 -0
  212. {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/temporal/query.py +0 -0
  213. {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/temporal/velocity.py +0 -0
  214. {contextual_engine-0.9.5 → contextual_engine-0.9.6}/docs/ADRs/ADR-001-lancedb-over-vec0.md +0 -0
  215. {contextual_engine-0.9.5 → contextual_engine-0.9.6}/docs/ADRs/ADR-002-retry-exponential-backoff.md +0 -0
  216. {contextual_engine-0.9.5 → contextual_engine-0.9.6}/docs/ADRs/ADR-003-blake3-deduplication.md +0 -0
  217. {contextual_engine-0.9.5 → contextual_engine-0.9.6}/docs/ADRs/ADR-004-async-first-architecture.md +0 -0
  218. {contextual_engine-0.9.5 → contextual_engine-0.9.6}/docs/ADRs/ADR-005-model-lineup.md +0 -0
  219. {contextual_engine-0.9.5 → contextual_engine-0.9.6}/docs/ADRs/ADR-006-remove-bm25-k1-b-dead-config.md +0 -0
  220. {contextual_engine-0.9.5 → contextual_engine-0.9.6}/docs/ARCHITECTURE.md +0 -0
  221. {contextual_engine-0.9.5 → contextual_engine-0.9.6}/docs/CHANGELOG.md +0 -0
  222. {contextual_engine-0.9.5 → contextual_engine-0.9.6}/docs/DATABASE.md +0 -0
  223. {contextual_engine-0.9.5 → contextual_engine-0.9.6}/docs/DEPLOYMENT.md +0 -0
  224. {contextual_engine-0.9.5 → contextual_engine-0.9.6}/docs/DISTRIBUTIONS.md +0 -0
  225. {contextual_engine-0.9.5 → contextual_engine-0.9.6}/docs/DRs/CHATGPT-DR-mcp-cli-security-testing-distribution.md +0 -0
  226. {contextual_engine-0.9.5 → contextual_engine-0.9.6}/docs/DRs/CHATGPT-DR-web-ui-experience.md +0 -0
  227. {contextual_engine-0.9.5 → contextual_engine-0.9.6}/docs/DRs/CLAUDE-DR-ai-agents-teams.md +0 -0
  228. {contextual_engine-0.9.5 → contextual_engine-0.9.6}/docs/DRs/CLAUDE-DR-competitive-landscape-market-analysis.md +0 -0
  229. {contextual_engine-0.9.5 → contextual_engine-0.9.6}/docs/DRs/CLAUDE-DR-core-architecture.md +0 -0
  230. {contextual_engine-0.9.5 → contextual_engine-0.9.6}/docs/DRs/CLAUDE-DR-mvp-phase0-technical-plan.md +0 -0
  231. {contextual_engine-0.9.5 → contextual_engine-0.9.6}/docs/DRs/CLAUDE-DR-strategic-briefing.md +0 -0
  232. {contextual_engine-0.9.5 → contextual_engine-0.9.6}/docs/DRs/GEMINI-DR-analysis-extraction.md +0 -0
  233. {contextual_engine-0.9.5 → contextual_engine-0.9.6}/docs/DRs/GEMINI-DR-graph-implementation.md +0 -0
  234. {contextual_engine-0.9.5 → contextual_engine-0.9.6}/docs/DRs/GEMINI-DR-hybrid-retrieval-local-optimization.md +0 -0
  235. {contextual_engine-0.9.5 → contextual_engine-0.9.6}/docs/DRs/GEMINI-DR-infrastructure-security.md +0 -0
  236. {contextual_engine-0.9.5 → contextual_engine-0.9.6}/docs/DRs/GEMINI-DR-lance-specs.md +0 -0
  237. {contextual_engine-0.9.5 → contextual_engine-0.9.6}/docs/DRs/GEMINI-DR-nexus-graph-architecture.md +0 -0
  238. {contextual_engine-0.9.5 → contextual_engine-0.9.6}/docs/DRs/GEMINI-DR-nexus-graph-engineering.md +0 -0
  239. {contextual_engine-0.9.5 → contextual_engine-0.9.6}/docs/DRs/GEMINI-DR-vec0-vs-lancedb.md +0 -0
  240. {contextual_engine-0.9.5 → contextual_engine-0.9.6}/docs/DRs/GEMINI_DR_extraction-optimisation.md +0 -0
  241. {contextual_engine-0.9.5 → contextual_engine-0.9.6}/docs/DRs/GRAPH_LAYER_OPEN_QUESTIONS_RESOLVED.md +0 -0
  242. {contextual_engine-0.9.5 → contextual_engine-0.9.6}/docs/DRs/KIMI-DR-tech-stack-optimization.md +0 -0
  243. {contextual_engine-0.9.5 → contextual_engine-0.9.6}/docs/DRs/PERPLEXITY-DR-L2-temporal.md +0 -0
  244. {contextual_engine-0.9.5 → contextual_engine-0.9.6}/docs/DRs/PERPLEXITY-DR-client-integration.md +0 -0
  245. {contextual_engine-0.9.5 → contextual_engine-0.9.6}/docs/DRs/PERPLEXITY-DR-indexing-optimisation.md +0 -0
  246. {contextual_engine-0.9.5 → contextual_engine-0.9.6}/docs/DRs/PERPLEXITY-DR-lancedb-implementation.md +0 -0
  247. {contextual_engine-0.9.5 → contextual_engine-0.9.6}/docs/DRs/PERPLEXITY-DR-local-data-infrastructure.md +0 -0
  248. {contextual_engine-0.9.5 → contextual_engine-0.9.6}/docs/DRs/PERPLEXITY-DR-mcp-config.md +0 -0
  249. {contextual_engine-0.9.5 → contextual_engine-0.9.6}/docs/DRs/PERPLEXITY-DR-mcp-security-hardening.md +0 -0
  250. {contextual_engine-0.9.5 → contextual_engine-0.9.6}/docs/DRs/PERPLEXITY-DR-models-pipelines.md +0 -0
  251. {contextual_engine-0.9.5 → contextual_engine-0.9.6}/docs/DRs/PERPLEXITY-DR-python-async-ai-pipelines.md +0 -0
  252. {contextual_engine-0.9.5 → contextual_engine-0.9.6}/docs/DRs/PERPLEXITY-DR-semantic-indexing.md +0 -0
  253. {contextual_engine-0.9.5 → contextual_engine-0.9.6}/docs/FRONTEND.md +0 -0
  254. {contextual_engine-0.9.5 → contextual_engine-0.9.6}/docs/GITHUB.md +0 -0
  255. {contextual_engine-0.9.5 → contextual_engine-0.9.6}/docs/INTEGRATIONS.md +0 -0
  256. {contextual_engine-0.9.5 → contextual_engine-0.9.6}/docs/MCP_TOOLS.md +0 -0
  257. {contextual_engine-0.9.5 → contextual_engine-0.9.6}/docs/MEMORY.md +0 -0
  258. {contextual_engine-0.9.5 → contextual_engine-0.9.6}/docs/PROJECT_MANAGEMENT.md +0 -0
  259. {contextual_engine-0.9.5 → contextual_engine-0.9.6}/docs/PROJECT_PHASES.md +0 -0
  260. {contextual_engine-0.9.5 → contextual_engine-0.9.6}/docs/RESOURCES.md +0 -0
  261. {contextual_engine-0.9.5 → contextual_engine-0.9.6}/docs/ROADMAP.md +0 -0
  262. {contextual_engine-0.9.5 → contextual_engine-0.9.6}/docs/TEAMS.md +0 -0
  263. {contextual_engine-0.9.5 → contextual_engine-0.9.6}/docs/TECHNICAL_SPEC.md +0 -0
  264. {contextual_engine-0.9.5 → contextual_engine-0.9.6}/docs/TESTING.md +0 -0
  265. {contextual_engine-0.9.5 → contextual_engine-0.9.6}/docs/VERSION.MD +0 -0
  266. {contextual_engine-0.9.5 → contextual_engine-0.9.6}/scripts/mcp_stress_test.py +0 -0
  267. {contextual_engine-0.9.5 → contextual_engine-0.9.6}/tests/README.md +0 -0
  268. {contextual_engine-0.9.5 → contextual_engine-0.9.6}/tests/__init__.py +0 -0
  269. {contextual_engine-0.9.5 → contextual_engine-0.9.6}/tests/fixtures/__init__.py +0 -0
  270. {contextual_engine-0.9.5 → contextual_engine-0.9.6}/tests/fixtures/sample_code.py +0 -0
  271. {contextual_engine-0.9.5 → contextual_engine-0.9.6}/tests/fixtures/sample_docs.md +0 -0
  272. {contextual_engine-0.9.5 → contextual_engine-0.9.6}/tests/test_architecture.py +0 -0
  273. {contextual_engine-0.9.5 → contextual_engine-0.9.6}/tests/test_behaviour.py +0 -0
  274. {contextual_engine-0.9.5 → contextual_engine-0.9.6}/tests/test_cache_stats.py +0 -0
  275. {contextual_engine-0.9.5 → contextual_engine-0.9.6}/tests/test_cli.py +0 -0
  276. {contextual_engine-0.9.5 → contextual_engine-0.9.6}/tests/test_flow.py +0 -0
  277. {contextual_engine-0.9.5 → contextual_engine-0.9.6}/tests/test_git.py +0 -0
  278. {contextual_engine-0.9.5 → contextual_engine-0.9.6}/tests/test_graph.py +0 -0
  279. {contextual_engine-0.9.5 → contextual_engine-0.9.6}/tests/test_graph_resolution_order.py +0 -0
  280. {contextual_engine-0.9.5 → contextual_engine-0.9.6}/tests/test_incremental.py +0 -0
  281. {contextual_engine-0.9.5 → contextual_engine-0.9.6}/tests/test_indexing.py +0 -0
  282. {contextual_engine-0.9.5 → contextual_engine-0.9.6}/tests/test_latency.py +0 -0
  283. {contextual_engine-0.9.5 → contextual_engine-0.9.6}/tests/test_mcp_hardening.py +0 -0
  284. {contextual_engine-0.9.5 → contextual_engine-0.9.6}/tests/test_observability.py +0 -0
  285. {contextual_engine-0.9.5 → contextual_engine-0.9.6}/tests/test_performance.py +0 -0
  286. {contextual_engine-0.9.5 → contextual_engine-0.9.6}/tests/test_query_cache_roundtrip.py +0 -0
  287. {contextual_engine-0.9.5 → contextual_engine-0.9.6}/tests/test_retry.py +0 -0
@@ -21,6 +21,7 @@ share/python-wheels/
21
21
  .installed.cfg
22
22
  *.egg
23
23
  MANIFEST
24
+ pytest.ini
24
25
 
25
26
  # Virtual environments
26
27
  .venv/
@@ -106,3 +107,6 @@ output.md
106
107
  audit_report.mduv.lock
107
108
  audit.md
108
109
  .agent
110
+ .cursor
111
+ .cursor/rules
112
+ .benchmarks
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: contextual-engine
3
- Version: 0.9.5
3
+ Version: 0.9.6
4
4
  Summary: Temporal-first local code memory for AI tools via MCP
5
5
  Project-URL: Homepage, https://contextuallabs.dev
6
6
  Project-URL: Documentation, https://contextuallabs.dev/docs
@@ -125,16 +125,19 @@ Classifier: Environment :: Console
125
125
  Classifier: Intended Audience :: Developers
126
126
  Classifier: License :: Other/Proprietary License
127
127
  Classifier: Operating System :: OS Independent
128
+ Classifier: Programming Language :: Python :: 3.11
128
129
  Classifier: Programming Language :: Python :: 3.12
129
130
  Classifier: Programming Language :: Python :: 3.13
131
+ Classifier: Programming Language :: Python :: 3.14
130
132
  Classifier: Topic :: Software Development :: Libraries
131
133
  Classifier: Topic :: Text Processing :: Indexing
132
134
  Classifier: Typing :: Typed
133
- Requires-Python: <3.14,>=3.12
135
+ Requires-Python: <3.15,>=3.11
134
136
  Requires-Dist: blake3>=0.4.1
137
+ Requires-Dist: datasketch>=1.6.4
135
138
  Requires-Dist: docutils>=0.21
136
139
  Requires-Dist: dulwich>=0.21
137
- Requires-Dist: einops>=0.7
140
+ Requires-Dist: fastembed>=0.4.2
138
141
  Requires-Dist: fastmcp<4,>=3.2
139
142
  Requires-Dist: httpx[http2]>=0.27.0
140
143
  Requires-Dist: huggingface-hub>=0.23
@@ -153,8 +156,7 @@ Requires-Dist: pygit2>=1.15
153
156
  Requires-Dist: python-frontmatter
154
157
  Requires-Dist: rapidfuzz>=3
155
158
  Requires-Dist: rich>=13.0
156
- Requires-Dist: safetensors>=0.4.3
157
- Requires-Dist: sentence-transformers>=3.0
159
+ Requires-Dist: setproctitle>=1.3.0
158
160
  Requires-Dist: simsimd<6,>=3.9
159
161
  Requires-Dist: sqlglot>=20.0
160
162
  Requires-Dist: starlette>=0.37
@@ -162,10 +164,7 @@ Requires-Dist: structlog>=25.4
162
164
  Requires-Dist: tantivy>=0.20.1
163
165
  Requires-Dist: tenacity>=8.0
164
166
  Requires-Dist: tiktoken>=0.5
165
- Requires-Dist: tokenizers<=0.23.0,>=0.19
166
167
  Requires-Dist: tomli-w>=1.0.0
167
- Requires-Dist: torch>=2.2
168
- Requires-Dist: transformers<4.60,>=4.40
169
168
  Requires-Dist: tree-sitter-language-pack>=0.7.2
170
169
  Requires-Dist: typer<1.0,>=0.9
171
170
  Requires-Dist: uvicorn>=0.27
@@ -178,9 +177,6 @@ Requires-Dist: build>=1.0; extra == 'dev'
178
177
  Requires-Dist: mypy>=1.10; extra == 'dev'
179
178
  Requires-Dist: ruff>=0.4; extra == 'dev'
180
179
  Requires-Dist: twine>=5.0; extra == 'dev'
181
- Provides-Extra: mps
182
- Requires-Dist: torch>=2.4.0; extra == 'mps'
183
- Requires-Dist: torchvision>=0.19.0; extra == 'mps'
184
180
  Provides-Extra: test
185
181
  Requires-Dist: anyio[trio]>=4.3.0; extra == 'test'
186
182
  Requires-Dist: freezegun>=1.5.0; extra == 'test'
@@ -14,7 +14,6 @@ from contextual.config.paths import (
14
14
  LOG_DIR,
15
15
  MODELS_DIR,
16
16
  embed_model_present,
17
- rerank_model_present,
18
17
  workspace_config,
19
18
  workspace_db,
20
19
  workspace_logs,
@@ -85,14 +84,10 @@ async def doctor(
85
84
  # 3. Models Check — check the actual weight dirs, not MODELS_DIR (which
86
85
  # always contains cache/ after setup and would false-positive before fetch).
87
86
  embed_ok = embed_model_present()
88
- rerank_ok = rerank_model_present()
89
- models_ok = embed_ok # embed is the hard requirement; reranker is search-only
90
- if embed_ok and rerank_ok:
91
- model_detail = "Embed + reranker weights present."
92
- elif embed_ok and not rerank_ok:
93
- model_detail = "Embed weights present. Reranker missing — run 'contextual fetch --rerank'."
94
- else:
95
- model_detail = "Embed weights missing or empty. Run 'contextual fetch'."
87
+ models_ok = embed_ok
88
+ model_detail = (
89
+ "Embed weights present." if embed_ok else "Embed weights missing. Run 'contextual fetch'."
90
+ )
96
91
  checks.append(HealthCheck(name="Models", status=models_ok, detail=model_detail))
97
92
 
98
93
  # 4. Daemon & Locks Check
@@ -0,0 +1,158 @@
1
+ """Global model fetch command for Contextual.
2
+
3
+ Downloads the fastembed/ONNX embedding model into ~/.contextual/models/
4
+ (the canonical global model directory) using fastembed's cache_dir parameter.
5
+ After download, computes and stores a BLAKE3 hash pin for integrity verification
6
+ on every subsequent model load.
7
+
8
+ The old sentence-transformers download path is fully removed.
9
+ """
10
+
11
+ from __future__ import annotations
12
+
13
+ import asyncio
14
+
15
+ import structlog
16
+ import typer
17
+
18
+ from contextual.cli.core.decorators import register_command, require_config
19
+ from contextual.cli.core.output import (
20
+ model_download_progress,
21
+ print_error,
22
+ print_fetch_complete,
23
+ print_fetch_start,
24
+ )
25
+ from contextual.config.paths import GLOBAL_CONFIG, MODELS_DIR, ONNX_PIN_FILE, VERSION_FILE
26
+ from contextual.models.unified_embedder import _FASTEMBED_MODEL, _find_onnx_model_path
27
+
28
+ _EMBED_FRIENDLY = "Nomic Embed v1.5-Q (ONNX/fastembed)"
29
+
30
+
31
+ class FetchError(Exception):
32
+ """Raised when a global model fetch cannot complete."""
33
+
34
+ def __init__(self, message: str, step: str | None = None, recoverable: bool = False) -> None:
35
+ super().__init__(message)
36
+ self.step = step
37
+ self.recoverable = recoverable
38
+
39
+
40
+ def _is_fastembed_model_cached() -> bool:
41
+ """Return True if the ONNX model already exists in ~/.contextual/models/."""
42
+ onnx_path = _find_onnx_model_path(MODELS_DIR)
43
+ return onnx_path is not None and onnx_path.exists()
44
+
45
+
46
+ def _verify_setup() -> None:
47
+ from contextual import __version__ as current_version
48
+
49
+ if not VERSION_FILE.exists():
50
+ print_error(
51
+ "Global setup not found.",
52
+ hint="Run: contextual setup",
53
+ )
54
+ raise typer.Exit(1)
55
+
56
+ if not GLOBAL_CONFIG.exists():
57
+ print_error(
58
+ "Global config missing.",
59
+ hint="Run: contextual setup",
60
+ )
61
+ raise typer.Exit(1)
62
+
63
+ installed = VERSION_FILE.read_text(encoding="utf-8").strip()
64
+ if installed != current_version:
65
+ print_error(
66
+ f"Version mismatch: installed={installed}, current={current_version}.",
67
+ hint="Run: contextual setup to upgrade.",
68
+ )
69
+ raise typer.Exit(1)
70
+
71
+
72
+ async def download_embed_model() -> None:
73
+ """Download the fastembed ONNX model into ~/.contextual/models/ and pin its hash."""
74
+ logger = structlog.get_logger()
75
+
76
+ with model_download_progress(_FASTEMBED_MODEL, size_hint="~130MB"):
77
+ try:
78
+ def _load() -> None:
79
+ from fastembed import TextEmbedding
80
+ MODELS_DIR.mkdir(parents=True, exist_ok=True)
81
+ # cache_dir routes fastembed to store weights under ~/.contextual/models/
82
+ # using HuggingFace Hub directory layout.
83
+ model = TextEmbedding(
84
+ model_name=_FASTEMBED_MODEL,
85
+ threads=1,
86
+ cache_dir=str(MODELS_DIR),
87
+ )
88
+ # One inference pass — verifies the ONNX session loads correctly.
89
+ list(model.embed(["warmup"], batch_size=1))
90
+
91
+ await asyncio.to_thread(_load)
92
+ except Exception as exc:
93
+ raise FetchError(
94
+ f"Failed to download fastembed model: {exc}", step="embed"
95
+ ) from exc
96
+
97
+ # Pin the BLAKE3 hash of the ONNX file so _load_model() can verify integrity
98
+ # on every subsequent load without re-downloading.
99
+ try:
100
+ import blake3 as _blake3
101
+
102
+ onnx_path = _find_onnx_model_path(MODELS_DIR)
103
+ if onnx_path and onnx_path.exists():
104
+ pin = _blake3.blake3(onnx_path.read_bytes()).hexdigest()
105
+ ONNX_PIN_FILE.write_text(pin, encoding="utf-8")
106
+ logger.info(
107
+ "onnx_pin_written",
108
+ hash_prefix=pin[:16],
109
+ onnx_path=str(onnx_path),
110
+ )
111
+ else:
112
+ logger.warning("onnx_pin_skipped", reason="model_file_not_found_after_download")
113
+ except Exception as exc:
114
+ logger.warning("onnx_pin_write_failed", error=str(exc))
115
+
116
+ logger.info("fastembed_model_ready", model=_FASTEMBED_MODEL, cache_dir=str(MODELS_DIR))
117
+
118
+
119
+ @register_command()
120
+ @require_config
121
+ def fetch(
122
+ embed: bool = typer.Option(False, "--embed", help="Download the Nomic embed model (ONNX)."),
123
+ all_: bool = typer.Option(False, "--all", help="Download all models (default)."),
124
+ ) -> None:
125
+ """Pre-download fastembed ONNX model weights into ~/.contextual/models/.
126
+
127
+ Model is stored in the global Contextual directory alongside the LanceDB
128
+ index and daemon config. Running this before the first `contextual index`
129
+ avoids an inline download during indexing and pins the BLAKE3 integrity hash.
130
+ """
131
+ _verify_setup()
132
+
133
+ print_fetch_start([_EMBED_FRIENDLY])
134
+
135
+ downloaded: list[str] = []
136
+ already_present: list[str] = []
137
+
138
+ if _is_fastembed_model_cached():
139
+ already_present.append(_EMBED_FRIENDLY)
140
+ # Re-pin even if cached — updates stale or missing pin file.
141
+ try:
142
+ import blake3 as _blake3
143
+
144
+ onnx_path = _find_onnx_model_path(MODELS_DIR)
145
+ if onnx_path and onnx_path.exists():
146
+ pin = _blake3.blake3(onnx_path.read_bytes()).hexdigest()
147
+ ONNX_PIN_FILE.write_text(pin, encoding="utf-8")
148
+ except Exception:
149
+ pass
150
+ else:
151
+ try:
152
+ asyncio.run(download_embed_model())
153
+ downloaded.append(_EMBED_FRIENDLY)
154
+ except FetchError as exc:
155
+ print_error(str(exc), hint="contextual fetch --embed")
156
+ raise typer.Exit(1) from exc
157
+
158
+ print_fetch_complete(downloaded, already_present)
@@ -95,16 +95,11 @@ async def index(
95
95
  try:
96
96
  with index_progress() as prog:
97
97
  try:
98
- # Suppress BLAKE3 pin warning during model load — pins are not
99
- # registered until `contextual fetch` is run with a real model.
100
- # The warning fires during SentenceTransformer.__init__, before
101
- # the outer warnings.simplefilter("ignore") wrapper takes effect.
102
98
  warnings.filterwarnings(
103
99
  "ignore",
104
100
  message=".*No BLAKE3 hash pins.*",
105
101
  category=UserWarning,
106
102
  )
107
- # Reranker is search-only — never load at index time (~1.2GB saved).
108
103
  await ensure_models_warm(models=["code", "docs"])
109
104
 
110
105
  chunking_started = False
@@ -103,8 +103,7 @@ def _write_default_config() -> None:
103
103
  'tier = "free"\n\n'
104
104
  "[models]\n"
105
105
  'embed_model = "nomic-ai/nomic-embed-text-v1.5"\n'
106
- 'rerank_model = "jinaai/jina-reranker-v2-base-multilingual"\n'
107
- f'models_dir = "{MODELS_DIR}"\n'
106
+ f'models_dir = "{MODELS_DIR}"\n'
108
107
  f'cache_dir = "{MODELS_CACHE_DIR}"\n\n'
109
108
  "[storage]\n"
110
109
  f'global_db_path = "{GLOBAL_DB_DIR}"\n'
@@ -19,7 +19,6 @@ from contextual.config.workspace.retrieval_config import (
19
19
  BM25Config,
20
20
  DenseConfig,
21
21
  MMRConfig,
22
- RerankerConfig,
23
22
  RetrievalConfig,
24
23
  )
25
24
  from contextual.config.workspace.workspace_config import WorkspaceConfig
@@ -109,7 +108,6 @@ __all__ = [
109
108
  "MMRConfig",
110
109
  "ObservabilityConfig",
111
110
  "PipelineConfig",
112
- "RerankerConfig",
113
111
  "RetrievalConfig",
114
112
  "SecurityConfig",
115
113
  "StorageConfig",
@@ -25,7 +25,7 @@ class ContextualConfig(BaseModel):
25
25
  project_root: Absolute path to the project being indexed.
26
26
  indexing: Indexing configuration for code and workspace files.
27
27
  embedding: Embedding model configuration.
28
- retrieval: Retrieval configuration for search and reranking.
28
+ retrieval: Retrieval configuration for search (RRF fusion + MMR).
29
29
  storage: Storage configuration for database and index paths.
30
30
  security: Security configuration for filesystem and workspace policy.
31
31
  """
@@ -34,10 +34,16 @@ class DaemonConfig(BaseModel):
34
34
  port: int = 9091 # must match _platform.WINDOWS_PORT/TCP_PORT
35
35
 
36
36
  # Lifecycle
37
- idle_sleep_minutes: int = 30 # Minutes idle before daemon sleeps (releases RAM)
38
- die_after_sleep_hours: float = 2.0 # Hours asleep before daemon fully exits (0 = never)
39
- startup_timeout: float = 45.0 # Seconds to wait for the daemon to start serving
40
- # (model load is 20-50s on 8GB unified memory)
37
+ # idle_sleep_minutes: minutes of no incoming MCP requests before the daemon
38
+ # unloads the ONNX model and enters sleep state. Active shim connections
39
+ # (idle SSE sessions) do NOT prevent this only actual HTTP requests reset
40
+ # the clock. die_after_sleep_hours: hours asleep before a clean SIGTERM
41
+ # exit. Total inactivity before full exit = idle_sleep_minutes +
42
+ # die_after_sleep_hours * 60. Set die_after_sleep_hours = 0 to never exit.
43
+ idle_sleep_minutes: int = 30 # Minutes of no requests before sleeping
44
+ die_after_sleep_hours: float = 1.0 # Hours asleep before clean exit (0 = never)
45
+ startup_timeout: float = 15.0 # Seconds to wait for the daemon to start serving
46
+ # (ONNX model loads in ~2-5s from ~/.contextual/models/)
41
47
 
42
48
  # Rate limiting
43
49
  rate_limit_per_minute: int = 120 # Max tool calls per minute per client
@@ -53,11 +59,13 @@ class DaemonConfig(BaseModel):
53
59
  # Heap / memory trimmer
54
60
  # When the daemon's physical footprint exceeds heap_trim_threshold_mb a
55
61
  # hard trim fires (GC + malloc page return). If the footprint is still over
56
- # the threshold on the next tick and no sessions are active, models are
57
- # offloaded to CPU to recover MPS/GPU pages. Set to 0 to disable.
62
+ # the threshold on the next tick and no sessions are active, the ONNX model
63
+ # session is unloaded (freed from memory). Set to 0 to disable.
64
+ # 1500 MB accounts for: ONNX session (~130 MB) + LanceDB PyArrow buffers
65
+ # (~400-800 MB active) + graph/cache overhead — triggers before OOM pressure.
58
66
  heap_monitor_enabled: bool = True
59
67
  heap_monitor_interval_seconds: int = 30
60
- heap_trim_threshold_mb: int = 2500
68
+ heap_trim_threshold_mb: int = 1500
61
69
 
62
70
  # Logging
63
71
  log_level: str = "INFO"
@@ -38,12 +38,11 @@ def resolve_local_model_path(model_ref: str) -> Path:
38
38
 
39
39
 
40
40
  class EmbeddingConfig(BaseModel):
41
- """Embedding model configuration (ADR-005: sentence-transformers unified stack)."""
41
+ """Embedding model configuration (nomic-embed-text-v1.5 via fastembed/ONNX Runtime since v0.10)."""
42
42
 
43
43
  # Production models — all Apache-2.0 licensed, all 768d
44
44
  code_model: str = Field(default=str(MODEL_CACHE_DIR / "nomic-embed-text-v1.5"))
45
45
  docs_model: str = Field(default=str(MODEL_CACHE_DIR / "nomic-embed-text-v1.5"))
46
- reranker_model: str = Field(default=str(MODEL_CACHE_DIR / "jina-reranker-v2-base-multilingual"))
47
46
  dimension: int = Field(default=768)
48
47
  batch_size: int = Field(default=16) # conservative default for 8GB unified memory Macs
49
48
  max_context_length: int = Field(default=8192)
@@ -90,49 +89,17 @@ class IndexingConfig(BaseModel):
90
89
  debounce_ms: int = Field(default=500) # file watcher debounce
91
90
 
92
91
 
93
- class RerankerConfig(BaseModel):
94
- """Reranker service settings (BGE cross-encoder via sentence-transformers)."""
95
-
96
- top_k: int = Field(default=15)
97
- max_candidate_length: int = Field(default=2000)
98
- batch_size: int = Field(default=15)
99
- timeout_seconds: float = Field(default=10.0)
100
- enable_retry: bool = Field(default=True)
101
- fallback_on_error: bool = Field(default=True)
102
-
103
-
104
92
  class SearchConfig(BaseModel):
105
- """Search pipeline settings (RRF + reranker + MMR)."""
93
+ """Search pipeline settings (RRF + MMR)."""
106
94
 
107
95
  rrf_k: int = Field(default=60)
108
96
  bm25_weight: float = Field(default=0.4)
109
97
  dense_weight: float = Field(default=0.6)
110
- rrf_candidate_pool: int = Field(
111
- default=35,
112
- ge=10,
113
- le=200,
114
- description="Number of candidates retrieved before reranking.",
115
- )
116
- enable_reranker: bool = Field(default=False) # 124x latency overhead with no accuracy gain on MPS
117
- rerank_top_k: int = Field(
118
- default=10,
119
- ge=5,
120
- le=100,
121
- description="Number of candidates passed to cross-encoder.",
122
- )
98
+ rrf_candidate_pool: int = Field(default=35, ge=10, le=200)
123
99
  mmr_lambda: float = Field(default=0.7)
124
100
  mmr_max_per_file: int = Field(default=2)
125
101
  mmr_max_per_symbol: int = Field(default=1)
126
102
 
127
- @model_validator(mode="after")
128
- def validate_pool_sizes(self) -> SearchConfig:
129
- if self.rerank_top_k > self.rrf_candidate_pool:
130
- raise ValueError(
131
- f"rerank_top_k ({self.rerank_top_k}) cannot exceed "
132
- f"rrf_candidate_pool ({self.rrf_candidate_pool})"
133
- )
134
- return self
135
-
136
103
 
137
104
  class CacheConfig(BaseModel):
138
105
  """Embedding cache settings."""
@@ -150,11 +117,9 @@ class RetrievalConfig:
150
117
  dense_candidates: int = 100
151
118
  rrf_candidates: int = 50
152
119
  rrf_k: int = 60
153
- rrf_dense_weight: float = 0.6
154
- rrf_bm25_weight: float = 0.4
155
- reranker_enabled: bool = False # 124x latency overhead with no accuracy gain on MPS
156
- reranker_top_n: int = 15
157
- reranker_max_chunk_chars: int = 2000
120
+ rrf_dense_weight: float = 0.50
121
+ rrf_bm25_weight: float = 0.35
122
+ rrf_trigram_weight: float = 0.15
158
123
  mmr_enabled: bool = True
159
124
  mmr_lambda: float = 0.7
160
125
  mmr_max_chunks_per_file: int = 2
@@ -168,6 +133,10 @@ class RetrievalConfig:
168
133
  # distances. 10-20 recovers near-flat recall at a few ms cost.
169
134
  refine_factor: int = 20
170
135
  query_cache_ttl_seconds: int = 300
136
+ # Row count at which the incremental indexer triggers background IVF-PQ
137
+ # index maintenance. Below this threshold flat-scan ANN is fast enough
138
+ # and building IVF-PQ would waste CPU. Set to 0 to disable.
139
+ ann_index_row_threshold: int = 50_000
171
140
 
172
141
  @classmethod
173
142
  def from_toml(cls, config_path: Path) -> RetrievalConfig:
@@ -200,12 +169,8 @@ class RetrievalConfig:
200
169
  rrf_bm25_weight=float(
201
170
  retrieval_data.get("rrf_bm25_weight", defaults.rrf_bm25_weight)
202
171
  ),
203
- reranker_enabled=bool(
204
- retrieval_data.get("reranker_enabled", defaults.reranker_enabled)
205
- ),
206
- reranker_top_n=int(retrieval_data.get("reranker_top_n", defaults.reranker_top_n)),
207
- reranker_max_chunk_chars=int(
208
- retrieval_data.get("reranker_max_chunk_chars", defaults.reranker_max_chunk_chars)
172
+ rrf_trigram_weight=float(
173
+ retrieval_data.get("rrf_trigram_weight", defaults.rrf_trigram_weight)
209
174
  ),
210
175
  mmr_enabled=bool(retrieval_data.get("mmr_enabled", defaults.mmr_enabled)),
211
176
  mmr_lambda=float(retrieval_data.get("mmr_lambda", defaults.mmr_lambda)),
@@ -224,6 +189,9 @@ class RetrievalConfig:
224
189
  query_cache_ttl_seconds=int(
225
190
  retrieval_data.get("query_cache_ttl_seconds", defaults.query_cache_ttl_seconds)
226
191
  ),
192
+ ann_index_row_threshold=int(
193
+ retrieval_data.get("ann_index_row_threshold", defaults.ann_index_row_threshold)
194
+ ),
227
195
  )
228
196
 
229
197
 
@@ -233,7 +201,6 @@ class PipelineConfig(BaseModel):
233
201
  embedding: EmbeddingConfig = Field(default_factory=EmbeddingConfig)
234
202
  chunking: ChunkingConfig = Field(default_factory=ChunkingConfig)
235
203
  indexing: IndexingConfig = Field(default_factory=IndexingConfig)
236
- reranker: RerankerConfig = Field(default_factory=RerankerConfig)
237
204
  search: SearchConfig = Field(default_factory=SearchConfig)
238
205
  cache: CacheConfig = Field(default_factory=CacheConfig)
239
206
 
@@ -247,8 +214,6 @@ class PipelineConfig(BaseModel):
247
214
  cfg.embedding.code_model = v
248
215
  if v := os.getenv("CONTEXTUAL_DOCS_MODEL"):
249
216
  cfg.embedding.docs_model = v
250
- if v := os.getenv("CONTEXTUAL_RERANKER_MODEL"):
251
- cfg.embedding.reranker_model = v
252
217
  if v := os.getenv("CONTEXTUAL_EMBED_DIM"):
253
218
  cfg.embedding.dimension = int(v)
254
219
  if v := os.getenv("CONTEXTUAL_EMBED_BATCH_SIZE"):
@@ -258,7 +223,6 @@ class PipelineConfig(BaseModel):
258
223
 
259
224
  cfg.embedding.code_model = str(resolve_local_model_path(cfg.embedding.code_model))
260
225
  cfg.embedding.docs_model = str(resolve_local_model_path(cfg.embedding.docs_model))
261
- cfg.embedding.reranker_model = str(resolve_local_model_path(cfg.embedding.reranker_model))
262
226
 
263
227
  # Indexing overrides
264
228
  if v := os.getenv("CONTEXTUAL_BATCH_WRITE_SIZE"):
@@ -315,8 +279,6 @@ class RuntimeRetrievalConfig:
315
279
  rrf_k: int = 60
316
280
  rrf_dense_weight: float = 0.6
317
281
  rrf_bm25_weight: float = 0.4
318
- reranker_enabled: bool = False # 124x latency overhead with no accuracy gain on MPS
319
- reranker_top_n: int = 15
320
282
  mmr_lambda: float = 0.7
321
283
  mmr_max_chunks_per_file: int = 2
322
284
  mmr_max_chunks_per_symbol: int = 1
@@ -390,8 +352,6 @@ class ConfigLoader:
390
352
  "rrf_k": 60,
391
353
  "rrf_dense_weight": 0.6,
392
354
  "rrf_bm25_weight": 0.4,
393
- "reranker_enabled": False, # 124x latency overhead with no accuracy gain on MPS
394
- "reranker_top_n": 15,
395
355
  "mmr_lambda": 0.7,
396
356
  "mmr_max_chunks_per_file": 2,
397
357
  "mmr_max_chunks_per_symbol": 1,
@@ -435,8 +395,6 @@ class ConfigLoader:
435
395
  env_overrides["retrieval"]["rrf_dense_weight"] = float(value)
436
396
  if value := os.getenv("CONTEXTUAL_RRF_BM25_WEIGHT"):
437
397
  env_overrides["retrieval"]["rrf_bm25_weight"] = float(value)
438
- if value := os.getenv("CONTEXTUAL_RERANKER_TOP_N"):
439
- env_overrides["retrieval"]["reranker_top_n"] = int(value)
440
398
  if value := os.getenv("CONTEXTUAL_MMR_LAMBDA"):
441
399
  env_overrides["retrieval"]["mmr_lambda"] = float(value)
442
400
  if value := os.getenv("CONTEXTUAL_MMR_MAX_CHUNKS_PER_FILE"):
@@ -46,12 +46,13 @@ MCP_CONFIG_FILE = CONTEXTUAL_HOME / "mcp.json"
46
46
  WORKSPACES_JSON_PATH = CONTEXTUAL_HOME / "workspaces.json"
47
47
  LOG_DIR = Path.home() / ".local" / "state" / "contextual" / "logs"
48
48
 
49
- # Canonical per-model weight directories. `contextual fetch` downloads into
50
- # these exact paths. Readiness checks MUST look here, not at MODELS_DIR — the
51
- # latter always contains `cache/` after `setup`, so a bare MODELS_DIR.iterdir()
52
- # is non-empty even when no weights have been fetched (false positive).
53
- EMBED_MODEL_DIR = MODELS_DIR / "nomic-embed-text-v1.5"
54
- RERANK_MODEL_DIR = MODELS_DIR / "jina-reranker-v2-base-multilingual"
49
+ # fastembed Hub cache directory for the embed model.
50
+ # `contextual fetch` downloads into MODELS_DIR using fastembed's cache_dir
51
+ # parameter; fastembed mirrors HuggingFace Hub layout under that root.
52
+ EMBED_MODEL_DIR = MODELS_DIR / "models--nomic-ai--nomic-embed-text-v1.5"
53
+
54
+ # BLAKE3 hash pin file written by `contextual fetch` and verified on model load.
55
+ ONNX_PIN_FILE = MODELS_DIR / ".onnx_pin"
55
56
 
56
57
 
57
58
  def _dir_has_content(path: Path) -> bool:
@@ -62,17 +63,17 @@ def _dir_has_content(path: Path) -> bool:
62
63
 
63
64
 
64
65
  def embed_model_present() -> bool:
65
- """True when the embed model weights have been fetched.
66
-
67
- Embed weights are the hard requirement for indexing (the reranker is
68
- search-only), so this is the canonical "models ready enough to index" gate.
69
- """
70
- return _dir_has_content(EMBED_MODEL_DIR)
71
-
72
-
73
- def rerank_model_present() -> bool:
74
- """True when the reranker weights have been fetched."""
75
- return _dir_has_content(RERANK_MODEL_DIR)
66
+ """True when the ONNX embed model has been fetched into ~/.contextual/models/."""
67
+ if not _dir_has_content(EMBED_MODEL_DIR):
68
+ return False
69
+ snapshots = EMBED_MODEL_DIR / "snapshots"
70
+ if not snapshots.is_dir():
71
+ return False
72
+ return any(
73
+ (s / "onnx" / "model_quantized.onnx").exists()
74
+ for s in snapshots.iterdir()
75
+ if s.is_dir()
76
+ )
76
77
 
77
78
 
78
79
  # ── Workspace subdirectories ──────────
@@ -5,7 +5,6 @@ from contextual.config.workspace.retrieval_config import (
5
5
  BM25Config,
6
6
  DenseConfig,
7
7
  MMRConfig,
8
- RerankerConfig,
9
8
  RetrievalConfig,
10
9
  RRFConfig,
11
10
  )
@@ -20,7 +19,6 @@ __all__ = [
20
19
  "MMRConfig",
21
20
  "ObservabilityConfig",
22
21
  "RRFConfig",
23
- "RerankerConfig",
24
22
  "RetrievalConfig",
25
23
  "WorkspaceConfig",
26
24
  ]
@@ -24,13 +24,6 @@ class RRFConfig(BaseModel):
24
24
  bm25_weight: float = 0.4
25
25
 
26
26
 
27
- class RerankerConfig(BaseModel):
28
- """Cross-encoder reranking settings."""
29
-
30
- top_n: int = 15
31
- max_chunk_chars: int = 2000
32
-
33
-
34
27
  class MMRConfig(BaseModel):
35
28
  """MMR diversity settings."""
36
29
 
@@ -45,7 +38,6 @@ class RetrievalConfig(BaseModel):
45
38
  bm25: BM25Config = BM25Config()
46
39
  dense: DenseConfig = DenseConfig()
47
40
  rrf: RRFConfig = RRFConfig()
48
- reranker: RerankerConfig = RerankerConfig()
49
41
  mmr: MMRConfig = MMRConfig()
50
42
  final_top_k: int = 10
51
43
  max_context_tokens: int = 8000
@@ -138,7 +138,6 @@ class ErrorCode(StrEnum):
138
138
  RETRIEVAL_BM25_FAILED = "retrieval_bm25_failed"
139
139
  RETRIEVAL_DENSE_SEARCH_FAILED = "retrieval_dense_search_failed"
140
140
  RETRIEVAL_FUSION_FAILED = "retrieval_fusion_failed"
141
- RETRIEVAL_RERANK_FAILED = "retrieval_rerank_failed"
142
141
  RETRIEVAL_HYDRATION_FAILED = "retrieval_hydration_failed"
143
142
  RETRIEVAL_NO_RESULTS = "retrieval_no_results" # Not an error, informational
144
143
 
@@ -315,7 +314,7 @@ class GitError(ContextualExceptionError):
315
314
 
316
315
 
317
316
  class RetrievalError(ContextualExceptionError):
318
- """Errors from the retrieval pipeline (search, fusion, reranking)."""
317
+ """Errors from the retrieval pipeline (search, RRF fusion, MMR)."""
319
318
 
320
319
 
321
320
  class SecurityError(ContextualExceptionError):