contextual-engine 0.9.4__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 (289) hide show
  1. {contextual_engine-0.9.4 → contextual_engine-0.9.6}/.gitignore +4 -0
  2. {contextual_engine-0.9.4 → contextual_engine-0.9.6}/PKG-INFO +7 -11
  3. {contextual_engine-0.9.4 → 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.4 → contextual_engine-0.9.6}/contextual/cli/commands/index.py +10 -5
  6. {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/cli/commands/initialisation.py +22 -0
  7. {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/cli/commands/install.py +1 -2
  8. contextual_engine-0.9.6/contextual/cli/commands/workspace.py +100 -0
  9. {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/config/__init__.py +0 -2
  10. {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/config/base.py +1 -1
  11. {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/config/global_/mcp_config.py +15 -7
  12. {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/config/indexing.py +15 -69
  13. {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/config/paths.py +19 -17
  14. {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/config/workspace/__init__.py +0 -2
  15. {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/config/workspace/retrieval_config.py +0 -10
  16. {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/core/errors.py +1 -2
  17. contextual_engine-0.9.6/contextual/core/memory.py +46 -0
  18. {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/git/incremental_git.py +65 -2
  19. {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/graph/extractor.py +521 -10
  20. {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/graph/integrator.py +4 -2
  21. {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/graph/resolver.py +127 -8
  22. {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/graph/traversal.py +9 -0
  23. {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/incremental/daemon_embed.py +6 -5
  24. {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/incremental/file_watcher.py +2 -30
  25. {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/incremental/incremental_indexer.py +132 -7
  26. {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/indexing/__init__.py +2 -37
  27. {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/indexing/_config.py +0 -9
  28. {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/indexing/index_writer.py +2 -1
  29. {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/indexing/pipeline.py +427 -121
  30. {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/indexing/processor.py +0 -86
  31. {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/mcp/__init__.py +1 -1
  32. {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/mcp/__main__.py +6 -0
  33. {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/mcp/memory_monitor.py +4 -25
  34. {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/mcp/middleware/audit.py +1 -1
  35. {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/mcp/middleware/auth.py +0 -2
  36. contextual_engine-0.9.6/contextual/mcp/middleware/identity.py +185 -0
  37. {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/mcp/middleware/ratelimit.py +9 -0
  38. {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/mcp/middleware/warmup.py +3 -3
  39. {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/mcp/middleware/workspace.py +24 -23
  40. {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/mcp/router.py +12 -6
  41. {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/mcp/server.py +73 -88
  42. {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/mcp/session_manager.py +80 -163
  43. {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/mcp/shim.py +222 -88
  44. {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/mcp/tools/__init__.py +284 -1
  45. contextual_engine-0.9.6/contextual/mcp/tools/_gcf.py +279 -0
  46. {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/mcp/tools/graph.py +251 -24
  47. {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/mcp/tools/nexus.py +69 -10
  48. {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/mcp/tools/semantic.py +194 -31
  49. {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/mcp/tools/system.py +153 -22
  50. {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/mcp/tools/temporal.py +22 -12
  51. contextual_engine-0.9.6/contextual/mcp/workspace_registry.py +410 -0
  52. contextual_engine-0.9.6/contextual/models/__init__.py +353 -0
  53. contextual_engine-0.9.6/contextual/models/_inference.py +15 -0
  54. {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/models/allowlist.py +2 -3
  55. contextual_engine-0.9.6/contextual/models/base_embedder.py +23 -0
  56. contextual_engine-0.9.6/contextual/models/unified_embedder.py +353 -0
  57. {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/retrieval/__init__.py +3 -24
  58. {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/retrieval/mmr.py +1 -46
  59. {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/retrieval/pipeline.py +271 -137
  60. {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/retrieval/ranker.py +2 -34
  61. contextual_engine-0.9.6/contextual/retrieval/structural_similarity.py +150 -0
  62. {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/storage/__init__.py +20 -2
  63. {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/storage/connection.py +11 -0
  64. {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/storage/fts.py +38 -1
  65. {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/storage/lancedb_provider.py +84 -16
  66. contextual_engine-0.9.6/contextual/storage/migrations/m015_symbol_ngram.py +1 -0
  67. {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/storage/migrations/runner.py +18 -1
  68. contextual_engine-0.9.6/contextual/storage/migrations/solo/m015_symbol_ngram.py +154 -0
  69. {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/storage/schema.py +15 -4
  70. {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/temporal/blame_pipeline.py +11 -84
  71. contextual_engine-0.9.6/docs/ADRs/ADR-006-remove-bm25-k1-b-dead-config.md +92 -0
  72. contextual_engine-0.9.6/docs/DRs/GEMINI-DR-analysis-extraction.md +319 -0
  73. contextual_engine-0.9.6/docs/DRs/GEMINI_DR_extraction-optimisation.md +158 -0
  74. contextual_engine-0.9.6/docs/SECURITY.md +116 -0
  75. {contextual_engine-0.9.4 → contextual_engine-0.9.6}/pyproject.toml +12 -14
  76. contextual_engine-0.9.6/scripts/benchmark_golden.json +56 -0
  77. contextual_engine-0.9.6/scripts/run_benchmark.py +161 -0
  78. {contextual_engine-0.9.4 → contextual_engine-0.9.6}/tests/conftest.py +0 -15
  79. contextual_engine-0.9.6/tests/test_accuracy.py +90 -0
  80. contextual_engine-0.9.6/tests/test_async.py +121 -0
  81. contextual_engine-0.9.6/tests/test_mcp.py +155 -0
  82. {contextual_engine-0.9.4 → contextual_engine-0.9.6}/tests/test_retrieval.py +8 -54
  83. contextual_engine-0.9.6/tests/test_security.py +153 -0
  84. {contextual_engine-0.9.4 → contextual_engine-0.9.6}/tests/test_storage.py +171 -0
  85. contextual_engine-0.9.4/.cursor/rules/contextual.mdc +0 -87
  86. contextual_engine-0.9.4/contextual/cli/commands/fetch.py +0 -221
  87. contextual_engine-0.9.4/contextual/cli/commands/workspace.py +0 -53
  88. contextual_engine-0.9.4/contextual/mcp/middleware/identity.py +0 -65
  89. contextual_engine-0.9.4/contextual/models/__init__.py +0 -575
  90. contextual_engine-0.9.4/contextual/models/_inference.py +0 -21
  91. contextual_engine-0.9.4/contextual/models/base_embedder.py +0 -72
  92. contextual_engine-0.9.4/contextual/models/reranker_model.py +0 -386
  93. contextual_engine-0.9.4/contextual/models/unified_embedder.py +0 -429
  94. contextual_engine-0.9.4/docs/SECURITY.md +0 -0
  95. contextual_engine-0.9.4/pytest.ini +0 -80
  96. contextual_engine-0.9.4/tests/test_accuracy.py +0 -23
  97. contextual_engine-0.9.4/tests/test_async.py +0 -23
  98. contextual_engine-0.9.4/tests/test_mcp.py +0 -33
  99. contextual_engine-0.9.4/tests/test_security.py +0 -23
  100. {contextual_engine-0.9.4 → contextual_engine-0.9.6}/.contextualignore +0 -0
  101. {contextual_engine-0.9.4 → contextual_engine-0.9.6}/.github/workflows/ci.yml +0 -0
  102. {contextual_engine-0.9.4 → contextual_engine-0.9.6}/.github/workflows/release.yml +0 -0
  103. {contextual_engine-0.9.4 → contextual_engine-0.9.6}/.mcp.json +0 -0
  104. {contextual_engine-0.9.4 → contextual_engine-0.9.6}/LICENSE +0 -0
  105. {contextual_engine-0.9.4 → contextual_engine-0.9.6}/README.md +0 -0
  106. {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/__init__.py +0 -0
  107. {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/__main__.py +0 -0
  108. {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/cli/__init__.py +0 -0
  109. {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/cli/commands/__init__.py +0 -0
  110. {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/cli/commands/auth.py +0 -0
  111. {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/cli/commands/client.py +0 -0
  112. {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/cli/commands/config.py +0 -0
  113. {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/cli/commands/mcp.py +0 -0
  114. {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/cli/commands/stats.py +0 -0
  115. {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/cli/core/__init__.py +0 -0
  116. {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/cli/core/context.py +0 -0
  117. {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/cli/core/decorators.py +0 -0
  118. {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/cli/core/editor.py +0 -0
  119. {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/cli/core/output.py +0 -0
  120. {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/config/global_/__init__.py +0 -0
  121. {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/config/global_/security_config.py +0 -0
  122. {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/config/global_/storage_config.py +0 -0
  123. {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/config/workspace/cache_config.py +0 -0
  124. {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/config/workspace/indexing_config.py +0 -0
  125. {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/config/workspace/observability_config.py +0 -0
  126. {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/config/workspace/workspace_config.py +0 -0
  127. {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/core/__init__.py +0 -0
  128. {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/core/models.py +0 -0
  129. {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/git/__init__.py +0 -0
  130. {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/git/blame.py +0 -0
  131. {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/git/hooks.py +0 -0
  132. {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/graph/__init__.py +0 -0
  133. {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/graph/dedup.py +0 -0
  134. {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/graph/staleness.py +0 -0
  135. {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/graph/store.py +0 -0
  136. {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/incremental/__init__.py +0 -0
  137. {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/indexing/_ignore.py +0 -0
  138. {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/indexing/chunker.py +0 -0
  139. {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/indexing/docs_pipeline.py +0 -0
  140. {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/indexing/merkle_tree.py +0 -0
  141. {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/indexing/symbol_extractor.py +0 -0
  142. {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/integrations/__init__.py +0 -0
  143. {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/integrations/client_content.py +0 -0
  144. {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/integrations/client_writer.py +0 -0
  145. {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/mcp/_platform.py +0 -0
  146. {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/mcp/access.py +0 -0
  147. {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/mcp/bootstrap.py +0 -0
  148. {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/mcp/config.py +0 -0
  149. {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/mcp/daemon.py +0 -0
  150. {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/mcp/middleware/__init__.py +0 -0
  151. {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/observability/__init__.py +0 -0
  152. {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/observability/config.py +0 -0
  153. {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/observability/exporters.py +0 -0
  154. {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/observability/logging.py +0 -0
  155. {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/observability/retention.py +0 -0
  156. {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/observability/tracer.py +0 -0
  157. {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/retrieval/context_assembler.py +0 -0
  158. {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/retrieval/tokenizer.py +0 -0
  159. {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/security/__init__.py +0 -0
  160. {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/security/paths.py +0 -0
  161. {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/security/sanitize.py +0 -0
  162. {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/security/workspace.py +0 -0
  163. {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/storage/cache.py +0 -0
  164. {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/storage/migrations/__init__.py +0 -0
  165. {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/storage/migrations/enterprise/me001_orgs.py +0 -0
  166. {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/storage/migrations/enterprise/me002_org_members.py +0 -0
  167. {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/storage/migrations/enterprise/me003_teams.py +0 -0
  168. {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/storage/migrations/enterprise/me004_team_members.py +0 -0
  169. {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/storage/migrations/enterprise/me005_org_workspaces.py +0 -0
  170. {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/storage/migrations/enterprise/me006_workspace_permissions.py +0 -0
  171. {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/storage/migrations/enterprise/me007_idp_sync_log.py +0 -0
  172. {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/storage/migrations/enterprise/me008_org_policies.py +0 -0
  173. {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/storage/migrations/enterprise/me009_api_keys.py +0 -0
  174. {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/storage/migrations/enterprise/me010_org_audit_log.py +0 -0
  175. {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/storage/migrations/enterprise/me011_workspace_traceability.py +0 -0
  176. {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/storage/migrations/m001_global.py +0 -0
  177. {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/storage/migrations/m002_embeddings.py +0 -0
  178. {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/storage/migrations/m003_temporal.py +0 -0
  179. {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/storage/migrations/m004_graph.py +0 -0
  180. {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/storage/migrations/m005_cache.py +0 -0
  181. {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/storage/migrations/m006_logs.py +0 -0
  182. {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/storage/migrations/m007_terminal_sessions.py +0 -0
  183. {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/storage/migrations/m008_queue.py +0 -0
  184. {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/storage/migrations/m009_swarm.py +0 -0
  185. {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/storage/migrations/m010_task_force.py +0 -0
  186. {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/storage/migrations/m011_reminders.py +0 -0
  187. {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/storage/migrations/m013_temporal_l2.py +0 -0
  188. {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/storage/migrations/m014_nexus_foundation.py +0 -0
  189. {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/storage/migrations/solo/m001_global.py +0 -0
  190. {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/storage/migrations/solo/m002_embeddings.py +0 -0
  191. {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/storage/migrations/solo/m003_temporal.py +0 -0
  192. {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/storage/migrations/solo/m004_graph.py +0 -0
  193. {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/storage/migrations/solo/m005_cache.py +0 -0
  194. {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/storage/migrations/solo/m006_logs.py +0 -0
  195. {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/storage/migrations/solo/m007_terminal_sessions.py +0 -0
  196. {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/storage/migrations/solo/m008_queue.py +0 -0
  197. {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/storage/migrations/solo/m009_swarm.py +0 -0
  198. {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/storage/migrations/solo/m010_task_force.py +0 -0
  199. {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/storage/migrations/solo/m011_reminders.py +0 -0
  200. {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/storage/migrations/solo/m012_workspace_metadata.py +0 -0
  201. {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/storage/migrations/solo/m013_temporal_l2.py +0 -0
  202. {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/storage/migrations/solo/m014_nexus_foundation.py +0 -0
  203. {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/storage/migrations/teams/mt001_orgs.py +0 -0
  204. {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/storage/migrations/teams/mt002_org_members.py +0 -0
  205. {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/storage/migrations/teams/mt003_teams.py +0 -0
  206. {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/storage/migrations/teams/mt004_team_members.py +0 -0
  207. {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/storage/migrations/teams/mt005_team_workspaces.py +0 -0
  208. {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/storage/migrations/teams/mt006_workspace_permissions.py +0 -0
  209. {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/storage/migrations/teams/mt007_team_audit_log.py +0 -0
  210. {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/storage/migrations/teams/mt008_workspace_traceability.py +0 -0
  211. {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/storage/schema_base.py +0 -0
  212. {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/storage/schema_ent.py +0 -0
  213. {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/storage/schema_team.py +0 -0
  214. {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/temporal/__init__.py +0 -0
  215. {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/temporal/adr.py +0 -0
  216. {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/temporal/context.py +0 -0
  217. {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/temporal/query.py +0 -0
  218. {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/temporal/velocity.py +0 -0
  219. {contextual_engine-0.9.4 → contextual_engine-0.9.6}/docs/ADRs/ADR-001-lancedb-over-vec0.md +0 -0
  220. {contextual_engine-0.9.4 → contextual_engine-0.9.6}/docs/ADRs/ADR-002-retry-exponential-backoff.md +0 -0
  221. {contextual_engine-0.9.4 → contextual_engine-0.9.6}/docs/ADRs/ADR-003-blake3-deduplication.md +0 -0
  222. {contextual_engine-0.9.4 → contextual_engine-0.9.6}/docs/ADRs/ADR-004-async-first-architecture.md +0 -0
  223. {contextual_engine-0.9.4 → contextual_engine-0.9.6}/docs/ADRs/ADR-005-model-lineup.md +0 -0
  224. {contextual_engine-0.9.4 → contextual_engine-0.9.6}/docs/ARCHITECTURE.md +0 -0
  225. {contextual_engine-0.9.4 → contextual_engine-0.9.6}/docs/CHANGELOG.md +0 -0
  226. {contextual_engine-0.9.4 → contextual_engine-0.9.6}/docs/DATABASE.md +0 -0
  227. {contextual_engine-0.9.4 → contextual_engine-0.9.6}/docs/DEPLOYMENT.md +0 -0
  228. {contextual_engine-0.9.4 → contextual_engine-0.9.6}/docs/DISTRIBUTIONS.md +0 -0
  229. {contextual_engine-0.9.4 → contextual_engine-0.9.6}/docs/DRs/CHATGPT-DR-mcp-cli-security-testing-distribution.md +0 -0
  230. {contextual_engine-0.9.4 → contextual_engine-0.9.6}/docs/DRs/CHATGPT-DR-web-ui-experience.md +0 -0
  231. {contextual_engine-0.9.4 → contextual_engine-0.9.6}/docs/DRs/CLAUDE-DR-ai-agents-teams.md +0 -0
  232. {contextual_engine-0.9.4 → contextual_engine-0.9.6}/docs/DRs/CLAUDE-DR-competitive-landscape-market-analysis.md +0 -0
  233. {contextual_engine-0.9.4 → contextual_engine-0.9.6}/docs/DRs/CLAUDE-DR-core-architecture.md +0 -0
  234. {contextual_engine-0.9.4 → contextual_engine-0.9.6}/docs/DRs/CLAUDE-DR-mvp-phase0-technical-plan.md +0 -0
  235. {contextual_engine-0.9.4 → contextual_engine-0.9.6}/docs/DRs/CLAUDE-DR-strategic-briefing.md +0 -0
  236. {contextual_engine-0.9.4 → contextual_engine-0.9.6}/docs/DRs/GEMINI-DR-graph-implementation.md +0 -0
  237. {contextual_engine-0.9.4 → contextual_engine-0.9.6}/docs/DRs/GEMINI-DR-hybrid-retrieval-local-optimization.md +0 -0
  238. {contextual_engine-0.9.4 → contextual_engine-0.9.6}/docs/DRs/GEMINI-DR-infrastructure-security.md +0 -0
  239. {contextual_engine-0.9.4 → contextual_engine-0.9.6}/docs/DRs/GEMINI-DR-lance-specs.md +0 -0
  240. {contextual_engine-0.9.4 → contextual_engine-0.9.6}/docs/DRs/GEMINI-DR-nexus-graph-architecture.md +0 -0
  241. {contextual_engine-0.9.4 → contextual_engine-0.9.6}/docs/DRs/GEMINI-DR-nexus-graph-engineering.md +0 -0
  242. {contextual_engine-0.9.4 → contextual_engine-0.9.6}/docs/DRs/GEMINI-DR-vec0-vs-lancedb.md +0 -0
  243. {contextual_engine-0.9.4 → contextual_engine-0.9.6}/docs/DRs/GRAPH_LAYER_OPEN_QUESTIONS_RESOLVED.md +0 -0
  244. {contextual_engine-0.9.4 → contextual_engine-0.9.6}/docs/DRs/KIMI-DR-tech-stack-optimization.md +0 -0
  245. {contextual_engine-0.9.4 → contextual_engine-0.9.6}/docs/DRs/PERPLEXITY-DR-L2-temporal.md +0 -0
  246. {contextual_engine-0.9.4 → contextual_engine-0.9.6}/docs/DRs/PERPLEXITY-DR-client-integration.md +0 -0
  247. {contextual_engine-0.9.4 → contextual_engine-0.9.6}/docs/DRs/PERPLEXITY-DR-indexing-optimisation.md +0 -0
  248. {contextual_engine-0.9.4 → contextual_engine-0.9.6}/docs/DRs/PERPLEXITY-DR-lancedb-implementation.md +0 -0
  249. {contextual_engine-0.9.4 → contextual_engine-0.9.6}/docs/DRs/PERPLEXITY-DR-local-data-infrastructure.md +0 -0
  250. {contextual_engine-0.9.4 → contextual_engine-0.9.6}/docs/DRs/PERPLEXITY-DR-mcp-config.md +0 -0
  251. {contextual_engine-0.9.4 → contextual_engine-0.9.6}/docs/DRs/PERPLEXITY-DR-mcp-security-hardening.md +0 -0
  252. {contextual_engine-0.9.4 → contextual_engine-0.9.6}/docs/DRs/PERPLEXITY-DR-models-pipelines.md +0 -0
  253. {contextual_engine-0.9.4 → contextual_engine-0.9.6}/docs/DRs/PERPLEXITY-DR-python-async-ai-pipelines.md +0 -0
  254. {contextual_engine-0.9.4 → contextual_engine-0.9.6}/docs/DRs/PERPLEXITY-DR-semantic-indexing.md +0 -0
  255. {contextual_engine-0.9.4 → contextual_engine-0.9.6}/docs/FRONTEND.md +0 -0
  256. {contextual_engine-0.9.4 → contextual_engine-0.9.6}/docs/GITHUB.md +0 -0
  257. {contextual_engine-0.9.4 → contextual_engine-0.9.6}/docs/INTEGRATIONS.md +0 -0
  258. {contextual_engine-0.9.4 → contextual_engine-0.9.6}/docs/MCP_TOOLS.md +0 -0
  259. {contextual_engine-0.9.4 → contextual_engine-0.9.6}/docs/MEMORY.md +0 -0
  260. {contextual_engine-0.9.4 → contextual_engine-0.9.6}/docs/PROJECT_MANAGEMENT.md +0 -0
  261. {contextual_engine-0.9.4 → contextual_engine-0.9.6}/docs/PROJECT_PHASES.md +0 -0
  262. {contextual_engine-0.9.4 → contextual_engine-0.9.6}/docs/RESOURCES.md +0 -0
  263. {contextual_engine-0.9.4 → contextual_engine-0.9.6}/docs/ROADMAP.md +0 -0
  264. {contextual_engine-0.9.4 → contextual_engine-0.9.6}/docs/TEAMS.md +0 -0
  265. {contextual_engine-0.9.4 → contextual_engine-0.9.6}/docs/TECHNICAL_SPEC.md +0 -0
  266. {contextual_engine-0.9.4 → contextual_engine-0.9.6}/docs/TESTING.md +0 -0
  267. {contextual_engine-0.9.4 → contextual_engine-0.9.6}/docs/VERSION.MD +0 -0
  268. {contextual_engine-0.9.4 → contextual_engine-0.9.6}/scripts/mcp_stress_test.py +0 -0
  269. {contextual_engine-0.9.4 → contextual_engine-0.9.6}/tests/README.md +0 -0
  270. {contextual_engine-0.9.4 → contextual_engine-0.9.6}/tests/__init__.py +0 -0
  271. {contextual_engine-0.9.4 → contextual_engine-0.9.6}/tests/fixtures/__init__.py +0 -0
  272. {contextual_engine-0.9.4 → contextual_engine-0.9.6}/tests/fixtures/sample_code.py +0 -0
  273. {contextual_engine-0.9.4 → contextual_engine-0.9.6}/tests/fixtures/sample_docs.md +0 -0
  274. {contextual_engine-0.9.4 → contextual_engine-0.9.6}/tests/test_architecture.py +0 -0
  275. {contextual_engine-0.9.4 → contextual_engine-0.9.6}/tests/test_behaviour.py +0 -0
  276. {contextual_engine-0.9.4 → contextual_engine-0.9.6}/tests/test_cache_stats.py +0 -0
  277. {contextual_engine-0.9.4 → contextual_engine-0.9.6}/tests/test_cli.py +0 -0
  278. {contextual_engine-0.9.4 → contextual_engine-0.9.6}/tests/test_flow.py +0 -0
  279. {contextual_engine-0.9.4 → contextual_engine-0.9.6}/tests/test_git.py +0 -0
  280. {contextual_engine-0.9.4 → contextual_engine-0.9.6}/tests/test_graph.py +0 -0
  281. {contextual_engine-0.9.4 → contextual_engine-0.9.6}/tests/test_graph_resolution_order.py +0 -0
  282. {contextual_engine-0.9.4 → contextual_engine-0.9.6}/tests/test_incremental.py +0 -0
  283. {contextual_engine-0.9.4 → contextual_engine-0.9.6}/tests/test_indexing.py +0 -0
  284. {contextual_engine-0.9.4 → contextual_engine-0.9.6}/tests/test_latency.py +0 -0
  285. {contextual_engine-0.9.4 → contextual_engine-0.9.6}/tests/test_mcp_hardening.py +0 -0
  286. {contextual_engine-0.9.4 → contextual_engine-0.9.6}/tests/test_observability.py +0 -0
  287. {contextual_engine-0.9.4 → contextual_engine-0.9.6}/tests/test_performance.py +0 -0
  288. {contextual_engine-0.9.4 → contextual_engine-0.9.6}/tests/test_query_cache_roundtrip.py +0 -0
  289. {contextual_engine-0.9.4 → 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.4
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)
@@ -47,6 +47,15 @@ async def index(
47
47
  "-f",
48
48
  help="Force full re-index even if already up-to-date",
49
49
  ),
50
+ bootstrap_cochange: bool = typer.Option(
51
+ False,
52
+ "--bootstrap-cochange",
53
+ help=(
54
+ "Walk up to 2000 git commits to pre-populate entity_commits for "
55
+ "co-change analysis. Only effective with --force. Commits touching "
56
+ ">50 files are excluded as noise."
57
+ ),
58
+ ),
50
59
  ctx: str | None = typer.Option(None, hidden=True),
51
60
  ) -> None:
52
61
  """Index codebase for semantic search."""
@@ -86,16 +95,11 @@ async def index(
86
95
  try:
87
96
  with index_progress() as prog:
88
97
  try:
89
- # Suppress BLAKE3 pin warning during model load — pins are not
90
- # registered until `contextual fetch` is run with a real model.
91
- # The warning fires during SentenceTransformer.__init__, before
92
- # the outer warnings.simplefilter("ignore") wrapper takes effect.
93
98
  warnings.filterwarnings(
94
99
  "ignore",
95
100
  message=".*No BLAKE3 hash pins.*",
96
101
  category=UserWarning,
97
102
  )
98
- # Reranker is search-only — never load at index time (~1.2GB saved).
99
103
  await ensure_models_warm(models=["code", "docs"])
100
104
 
101
105
  chunking_started = False
@@ -151,6 +155,7 @@ async def index(
151
155
  context=cli_ctx.request_context,
152
156
  force=force,
153
157
  incremental=incremental,
158
+ bootstrap_cochange=bootstrap_cochange,
154
159
  on_discovery=_on_discovery,
155
160
  on_file_chunked=_on_file_chunked,
156
161
  on_batch_embedded=_on_batch_embedded,
@@ -531,6 +531,28 @@ async def run_workspace_init(workspace_root: Path) -> None:
531
531
 
532
532
  await _register_workspace_globally(global_conn, workspace_id, workspace_root, logger)
533
533
 
534
+ # Also register in workspaces.json for multi-workspace MCP support.
535
+ # Non-fatal: the DB registration above is authoritative for init; the
536
+ # registry entry is a convenience that `contextual workspace add` can
537
+ # replicate if this fails.
538
+ try:
539
+ from contextual.mcp.workspace_registry import WORKSPACE_REGISTRY
540
+
541
+ try:
542
+ WORKSPACE_REGISTRY.add_workspace(workspace_root.name, workspace_root)
543
+ logger.info(
544
+ "workspace_registry_json_added",
545
+ name=workspace_root.name,
546
+ path=str(workspace_root),
547
+ )
548
+ except ValueError:
549
+ logger.debug(
550
+ "workspace_registry_json_already_registered",
551
+ name=workspace_root.name,
552
+ )
553
+ except Exception as exc:
554
+ logger.warning("workspace_registry_json_add_failed", error=str(exc))
555
+
534
556
  try:
535
557
  if not (
536
558
  config_path.exists()
@@ -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'
@@ -0,0 +1,100 @@
1
+ """Workspace management commands."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import json
6
+ from pathlib import Path
7
+
8
+ import typer
9
+
10
+ from contextual.cli.core import register_command
11
+ from contextual.cli.core.output import print_error, print_workspace_list
12
+
13
+
14
+ @register_command(group="workspace", name="list")
15
+ async def workspace_list() -> None:
16
+ """List all registered workspaces."""
17
+ from contextual.mcp.workspace_registry import WORKSPACE_REGISTRY
18
+
19
+ ws_map = WORKSPACE_REGISTRY.load_registered_workspaces()
20
+ if not ws_map:
21
+ print_workspace_list([])
22
+ return
23
+
24
+ workspaces = []
25
+ for name, path_str in ws_map.items():
26
+ path = Path(path_str)
27
+ workspace_id = ""
28
+ last_indexed_at = "never"
29
+
30
+ try:
31
+ state_file = path / ".contextual" / "state.json"
32
+ if state_file.exists():
33
+ state_data = json.loads(state_file.read_text(encoding="utf-8"))
34
+ last_indexed_at = state_data.get("last_indexed_at", "never")
35
+ except Exception:
36
+ pass
37
+
38
+ try:
39
+ from contextual.indexing._config import load_runtime_config
40
+
41
+ cfg = load_runtime_config(path)
42
+ workspace_id = str(cfg.workspace_id)
43
+ except Exception:
44
+ pass
45
+
46
+ workspaces.append({
47
+ "path": f"{name} {path_str}",
48
+ "workspace_id": workspace_id,
49
+ "last_indexed_at": last_indexed_at,
50
+ })
51
+
52
+ print_workspace_list(workspaces)
53
+
54
+
55
+ @register_command(group="workspace", name="add")
56
+ async def workspace_add(
57
+ path: str = typer.Argument(..., help="Absolute path to the workspace root"),
58
+ name: str = typer.Option(
59
+ None,
60
+ "--name",
61
+ "-n",
62
+ help="Human-readable workspace name (defaults to directory basename)",
63
+ ),
64
+ ) -> None:
65
+ """Register a workspace in the multi-workspace registry."""
66
+ from contextual.mcp.workspace_registry import WORKSPACE_REGISTRY
67
+
68
+ resolved = Path(path).expanduser().resolve()
69
+ ws_name = name or resolved.name
70
+ if not ws_name:
71
+ print_error("Could not derive a workspace name.", hint="Use --name <name>")
72
+ raise typer.Exit(1)
73
+
74
+ try:
75
+ WORKSPACE_REGISTRY.add_workspace(ws_name, resolved)
76
+ typer.echo(f"Registered workspace '{ws_name}' at {resolved}")
77
+ except ValueError as exc:
78
+ print_error(str(exc))
79
+ raise typer.Exit(1) from exc
80
+ except Exception as exc:
81
+ print_error(f"Failed to register workspace: {exc}")
82
+ raise typer.Exit(1) from exc
83
+
84
+
85
+ @register_command(group="workspace", name="remove")
86
+ async def workspace_remove(
87
+ name: str = typer.Argument(..., help="Workspace name to deregister"),
88
+ ) -> None:
89
+ """Remove a workspace from the multi-workspace registry."""
90
+ from contextual.mcp.workspace_registry import WORKSPACE_REGISTRY
91
+
92
+ try:
93
+ WORKSPACE_REGISTRY.remove_workspace(name)
94
+ typer.echo(f"Removed workspace '{name}'")
95
+ except KeyError as exc:
96
+ print_error(str(exc))
97
+ raise typer.Exit(1) from exc
98
+ except Exception as exc:
99
+ print_error(f"Failed to remove workspace: {exc}")
100
+ raise typer.Exit(1) from exc
@@ -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"