bgts-context-engine 0.2.2__tar.gz → 0.2.4__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 (131) hide show
  1. {bgts_context_engine-0.2.2 → bgts_context_engine-0.2.4}/CHANGELOG.md +119 -1
  2. {bgts_context_engine-0.2.2 → bgts_context_engine-0.2.4}/MANIFEST.in +1 -0
  3. {bgts_context_engine-0.2.2/src/bgts_context_engine.egg-info → bgts_context_engine-0.2.4}/PKG-INFO +61 -9
  4. {bgts_context_engine-0.2.2 → bgts_context_engine-0.2.4}/README.md +60 -8
  5. {bgts_context_engine-0.2.2 → bgts_context_engine-0.2.4}/README.tr.md +60 -6
  6. {bgts_context_engine-0.2.2 → bgts_context_engine-0.2.4}/pyproject.toml +1 -0
  7. {bgts_context_engine-0.2.2 → bgts_context_engine-0.2.4}/src/bce/__init__.py +1 -1
  8. {bgts_context_engine-0.2.2 → bgts_context_engine-0.2.4}/src/bce/api/mcp/server.py +5 -2
  9. {bgts_context_engine-0.2.2 → bgts_context_engine-0.2.4}/src/bce/api/mcp/tools.py +33 -8
  10. {bgts_context_engine-0.2.2 → bgts_context_engine-0.2.4}/src/bce/api/rest/schemas.py +7 -3
  11. {bgts_context_engine-0.2.2 → bgts_context_engine-0.2.4}/src/bce/api/rest/ui/trace.py +4 -1
  12. {bgts_context_engine-0.2.2 → bgts_context_engine-0.2.4}/src/bce/bench/pr_ablation.py +27 -5
  13. {bgts_context_engine-0.2.2 → bgts_context_engine-0.2.4}/src/bce/cli.py +158 -7
  14. {bgts_context_engine-0.2.2 → bgts_context_engine-0.2.4}/src/bce/config.py +53 -3
  15. {bgts_context_engine-0.2.2 → bgts_context_engine-0.2.4}/src/bce/core/assembler/assembler.py +16 -11
  16. bgts_context_engine-0.2.4/src/bce/core/defaults.py +19 -0
  17. {bgts_context_engine-0.2.2 → bgts_context_engine-0.2.4}/src/bce/core/orchestrator/anchors.py +15 -5
  18. {bgts_context_engine-0.2.2 → bgts_context_engine-0.2.4}/src/bce/core/orchestrator/orchestrator.py +21 -5
  19. bgts_context_engine-0.2.4/src/bce/core/orchestrator/profile.py +125 -0
  20. {bgts_context_engine-0.2.2 → bgts_context_engine-0.2.4}/src/bce/indexing/embedder/__init__.py +4 -0
  21. {bgts_context_engine-0.2.2 → bgts_context_engine-0.2.4}/src/bce/indexing/embedder/encoder.py +173 -3
  22. bgts_context_engine-0.2.4/src/bce/integrations/__init__.py +10 -0
  23. bgts_context_engine-0.2.4/src/bce/integrations/agents.py +271 -0
  24. bgts_context_engine-0.2.4/src/bce/integrations/precontext.py +168 -0
  25. bgts_context_engine-0.2.4/src/bce/integrations/templates/claude_section.md +16 -0
  26. bgts_context_engine-0.2.4/src/bce/integrations/templates/cursor_rule.mdc +20 -0
  27. {bgts_context_engine-0.2.2 → bgts_context_engine-0.2.4}/src/bce/storage/relational/migrator.py +64 -0
  28. {bgts_context_engine-0.2.2 → bgts_context_engine-0.2.4}/src/bce/tools/layer3/__init__.py +3 -0
  29. {bgts_context_engine-0.2.2 → bgts_context_engine-0.2.4}/src/bce/tools/layer3/orchestration.py +45 -10
  30. {bgts_context_engine-0.2.2 → bgts_context_engine-0.2.4/src/bgts_context_engine.egg-info}/PKG-INFO +61 -9
  31. {bgts_context_engine-0.2.2 → bgts_context_engine-0.2.4}/src/bgts_context_engine.egg-info/SOURCES.txt +7 -0
  32. {bgts_context_engine-0.2.2 → bgts_context_engine-0.2.4}/LICENSE +0 -0
  33. {bgts_context_engine-0.2.2 → bgts_context_engine-0.2.4}/setup.cfg +0 -0
  34. {bgts_context_engine-0.2.2 → bgts_context_engine-0.2.4}/src/bce/api/__init__.py +0 -0
  35. {bgts_context_engine-0.2.2 → bgts_context_engine-0.2.4}/src/bce/api/mcp/__init__.py +0 -0
  36. {bgts_context_engine-0.2.2 → bgts_context_engine-0.2.4}/src/bce/api/rest/__init__.py +0 -0
  37. {bgts_context_engine-0.2.2 → bgts_context_engine-0.2.4}/src/bce/api/rest/app.py +0 -0
  38. {bgts_context_engine-0.2.2 → bgts_context_engine-0.2.4}/src/bce/api/rest/deps.py +0 -0
  39. {bgts_context_engine-0.2.2 → bgts_context_engine-0.2.4}/src/bce/api/rest/routes.py +0 -0
  40. {bgts_context_engine-0.2.2 → bgts_context_engine-0.2.4}/src/bce/api/rest/static/assets/index-Cc4pUpSE.js +0 -0
  41. {bgts_context_engine-0.2.2 → bgts_context_engine-0.2.4}/src/bce/api/rest/static/assets/index-DrLRaTMU.css +0 -0
  42. {bgts_context_engine-0.2.2 → bgts_context_engine-0.2.4}/src/bce/api/rest/static/favicon.svg +0 -0
  43. {bgts_context_engine-0.2.2 → bgts_context_engine-0.2.4}/src/bce/api/rest/static/index.html +0 -0
  44. {bgts_context_engine-0.2.2 → bgts_context_engine-0.2.4}/src/bce/api/rest/ui/__init__.py +0 -0
  45. {bgts_context_engine-0.2.2 → bgts_context_engine-0.2.4}/src/bce/api/rest/ui/queries.py +0 -0
  46. {bgts_context_engine-0.2.2 → bgts_context_engine-0.2.4}/src/bce/api/rest/ui/router.py +0 -0
  47. {bgts_context_engine-0.2.2 → bgts_context_engine-0.2.4}/src/bce/api/rest/ui/schemas.py +0 -0
  48. {bgts_context_engine-0.2.2 → bgts_context_engine-0.2.4}/src/bce/bench/__init__.py +0 -0
  49. {bgts_context_engine-0.2.2 → bgts_context_engine-0.2.4}/src/bce/bench/runner.py +0 -0
  50. {bgts_context_engine-0.2.2 → bgts_context_engine-0.2.4}/src/bce/core/__init__.py +0 -0
  51. {bgts_context_engine-0.2.2 → bgts_context_engine-0.2.4}/src/bce/core/assembler/__init__.py +0 -0
  52. {bgts_context_engine-0.2.2 → bgts_context_engine-0.2.4}/src/bce/core/auth/__init__.py +0 -0
  53. {bgts_context_engine-0.2.2 → bgts_context_engine-0.2.4}/src/bce/core/auth/scope.py +0 -0
  54. {bgts_context_engine-0.2.2 → bgts_context_engine-0.2.4}/src/bce/core/coverage/__init__.py +0 -0
  55. {bgts_context_engine-0.2.2 → bgts_context_engine-0.2.4}/src/bce/core/coverage/confidence.py +0 -0
  56. {bgts_context_engine-0.2.2 → bgts_context_engine-0.2.4}/src/bce/core/i18n/__init__.py +0 -0
  57. {bgts_context_engine-0.2.2 → bgts_context_engine-0.2.4}/src/bce/core/i18n/catalogs/en.json +0 -0
  58. {bgts_context_engine-0.2.2 → bgts_context_engine-0.2.4}/src/bce/core/i18n/catalogs/tr.json +0 -0
  59. {bgts_context_engine-0.2.2 → bgts_context_engine-0.2.4}/src/bce/core/i18n/locale.py +0 -0
  60. {bgts_context_engine-0.2.2 → bgts_context_engine-0.2.4}/src/bce/core/i18n/translator.py +0 -0
  61. {bgts_context_engine-0.2.2 → bgts_context_engine-0.2.4}/src/bce/core/logging.py +0 -0
  62. {bgts_context_engine-0.2.2 → bgts_context_engine-0.2.4}/src/bce/core/orchestrator/__init__.py +0 -0
  63. {bgts_context_engine-0.2.2 → bgts_context_engine-0.2.4}/src/bce/core/orchestrator/bulk.py +0 -0
  64. {bgts_context_engine-0.2.2 → bgts_context_engine-0.2.4}/src/bce/core/orchestrator/expand.py +0 -0
  65. {bgts_context_engine-0.2.2 → bgts_context_engine-0.2.4}/src/bce/core/orchestrator/text.py +0 -0
  66. {bgts_context_engine-0.2.2 → bgts_context_engine-0.2.4}/src/bce/core/scoring/__init__.py +0 -0
  67. {bgts_context_engine-0.2.2 → bgts_context_engine-0.2.4}/src/bce/core/scoring/engine.py +0 -0
  68. {bgts_context_engine-0.2.2 → bgts_context_engine-0.2.4}/src/bce/domain/__init__.py +0 -0
  69. {bgts_context_engine-0.2.2 → bgts_context_engine-0.2.4}/src/bce/domain/enums.py +0 -0
  70. {bgts_context_engine-0.2.2 → bgts_context_engine-0.2.4}/src/bce/domain/models.py +0 -0
  71. {bgts_context_engine-0.2.2 → bgts_context_engine-0.2.4}/src/bce/indexing/__init__.py +0 -0
  72. {bgts_context_engine-0.2.2 → bgts_context_engine-0.2.4}/src/bce/indexing/churn.py +0 -0
  73. {bgts_context_engine-0.2.2 → bgts_context_engine-0.2.4}/src/bce/indexing/embedder/embedder.py +0 -0
  74. {bgts_context_engine-0.2.2 → bgts_context_engine-0.2.4}/src/bce/indexing/extractor/__init__.py +0 -0
  75. {bgts_context_engine-0.2.2 → bgts_context_engine-0.2.4}/src/bce/indexing/extractor/bridges.py +0 -0
  76. {bgts_context_engine-0.2.2 → bgts_context_engine-0.2.4}/src/bce/indexing/extractor/designnote.py +0 -0
  77. {bgts_context_engine-0.2.2 → bgts_context_engine-0.2.4}/src/bce/indexing/extractor/extractor.py +0 -0
  78. {bgts_context_engine-0.2.2 → bgts_context_engine-0.2.4}/src/bce/indexing/extractor/routes.py +0 -0
  79. {bgts_context_engine-0.2.2 → bgts_context_engine-0.2.4}/src/bce/indexing/gitsync/__init__.py +0 -0
  80. {bgts_context_engine-0.2.2 → bgts_context_engine-0.2.4}/src/bce/indexing/gitsync/bitbucket.py +0 -0
  81. {bgts_context_engine-0.2.2 → bgts_context_engine-0.2.4}/src/bce/indexing/gitsync/local.py +0 -0
  82. {bgts_context_engine-0.2.2 → bgts_context_engine-0.2.4}/src/bce/indexing/gitsync/remote.py +0 -0
  83. {bgts_context_engine-0.2.2 → bgts_context_engine-0.2.4}/src/bce/indexing/indexer.py +0 -0
  84. {bgts_context_engine-0.2.2 → bgts_context_engine-0.2.4}/src/bce/indexing/linker/__init__.py +0 -0
  85. {bgts_context_engine-0.2.2 → bgts_context_engine-0.2.4}/src/bce/indexing/linker/linker.py +0 -0
  86. {bgts_context_engine-0.2.2 → bgts_context_engine-0.2.4}/src/bce/indexing/parser/__init__.py +0 -0
  87. {bgts_context_engine-0.2.2 → bgts_context_engine-0.2.4}/src/bce/indexing/parser/_treesitter.py +0 -0
  88. {bgts_context_engine-0.2.2 → bgts_context_engine-0.2.4}/src/bce/indexing/parser/base.py +0 -0
  89. {bgts_context_engine-0.2.2 → bgts_context_engine-0.2.4}/src/bce/indexing/parser/languages/__init__.py +0 -0
  90. {bgts_context_engine-0.2.2 → bgts_context_engine-0.2.4}/src/bce/indexing/parser/languages/csharp_provider.py +0 -0
  91. {bgts_context_engine-0.2.2 → bgts_context_engine-0.2.4}/src/bce/indexing/parser/languages/go_provider.py +0 -0
  92. {bgts_context_engine-0.2.2 → bgts_context_engine-0.2.4}/src/bce/indexing/parser/languages/java_provider.py +0 -0
  93. {bgts_context_engine-0.2.2 → bgts_context_engine-0.2.4}/src/bce/indexing/parser/languages/jsts_provider.py +0 -0
  94. {bgts_context_engine-0.2.2 → bgts_context_engine-0.2.4}/src/bce/indexing/parser/languages/python_provider.py +0 -0
  95. {bgts_context_engine-0.2.2 → bgts_context_engine-0.2.4}/src/bce/indexing/parser/registry.py +0 -0
  96. {bgts_context_engine-0.2.2 → bgts_context_engine-0.2.4}/src/bce/indexing/parser/scip/__init__.py +0 -0
  97. {bgts_context_engine-0.2.2 → bgts_context_engine-0.2.4}/src/bce/indexing/parser/scip/resolver.py +0 -0
  98. {bgts_context_engine-0.2.2 → bgts_context_engine-0.2.4}/src/bce/indexing/parser/symbol_id.py +0 -0
  99. {bgts_context_engine-0.2.2 → bgts_context_engine-0.2.4}/src/bce/indexing/upserter/__init__.py +0 -0
  100. {bgts_context_engine-0.2.2 → bgts_context_engine-0.2.4}/src/bce/indexing/upserter/upserter.py +0 -0
  101. {bgts_context_engine-0.2.2 → bgts_context_engine-0.2.4}/src/bce/jobs/__init__.py +0 -0
  102. {bgts_context_engine-0.2.2 → bgts_context_engine-0.2.4}/src/bce/jobs/store.py +0 -0
  103. {bgts_context_engine-0.2.2 → bgts_context_engine-0.2.4}/src/bce/jobs/worker.py +0 -0
  104. {bgts_context_engine-0.2.2 → bgts_context_engine-0.2.4}/src/bce/storage/__init__.py +0 -0
  105. {bgts_context_engine-0.2.2 → bgts_context_engine-0.2.4}/src/bce/storage/graph/__init__.py +0 -0
  106. {bgts_context_engine-0.2.2 → bgts_context_engine-0.2.4}/src/bce/storage/graph/client.py +0 -0
  107. {bgts_context_engine-0.2.2 → bgts_context_engine-0.2.4}/src/bce/storage/graph/repository.py +0 -0
  108. {bgts_context_engine-0.2.2 → bgts_context_engine-0.2.4}/src/bce/storage/relational/__init__.py +0 -0
  109. {bgts_context_engine-0.2.2 → bgts_context_engine-0.2.4}/src/bce/storage/relational/db.py +0 -0
  110. {bgts_context_engine-0.2.2 → bgts_context_engine-0.2.4}/src/bce/storage/relational/migrations/0001_extensions_graph.sql +0 -0
  111. {bgts_context_engine-0.2.2 → bgts_context_engine-0.2.4}/src/bce/storage/relational/migrations/0002_relational.sql +0 -0
  112. {bgts_context_engine-0.2.2 → bgts_context_engine-0.2.4}/src/bce/storage/relational/migrations/0003_vector.sql +0 -0
  113. {bgts_context_engine-0.2.2 → bgts_context_engine-0.2.4}/src/bce/storage/relational/migrations/0004_rls.sql +0 -0
  114. {bgts_context_engine-0.2.2 → bgts_context_engine-0.2.4}/src/bce/storage/relational/migrations/0005_embeddings_dim.sql +0 -0
  115. {bgts_context_engine-0.2.2 → bgts_context_engine-0.2.4}/src/bce/storage/relational/migrations/0006_fts.sql +0 -0
  116. {bgts_context_engine-0.2.2 → bgts_context_engine-0.2.4}/src/bce/storage/relational/migrations/0007_jobs.sql +0 -0
  117. {bgts_context_engine-0.2.2 → bgts_context_engine-0.2.4}/src/bce/storage/relational/migrations/0008_graph_label_indexes.sql +0 -0
  118. {bgts_context_engine-0.2.2 → bgts_context_engine-0.2.4}/src/bce/storage/relational/migrations/0009_fts_identifier_parts.sql +0 -0
  119. {bgts_context_engine-0.2.2 → bgts_context_engine-0.2.4}/src/bce/storage/relational/migrations/0010_file_churn.sql +0 -0
  120. {bgts_context_engine-0.2.2 → bgts_context_engine-0.2.4}/src/bce/storage/relational/queries.py +0 -0
  121. {bgts_context_engine-0.2.2 → bgts_context_engine-0.2.4}/src/bce/storage/vector/__init__.py +0 -0
  122. {bgts_context_engine-0.2.2 → bgts_context_engine-0.2.4}/src/bce/storage/vector/store.py +0 -0
  123. {bgts_context_engine-0.2.2 → bgts_context_engine-0.2.4}/src/bce/tools/__init__.py +0 -0
  124. {bgts_context_engine-0.2.2 → bgts_context_engine-0.2.4}/src/bce/tools/layer1/__init__.py +0 -0
  125. {bgts_context_engine-0.2.2 → bgts_context_engine-0.2.4}/src/bce/tools/layer1/primitives.py +0 -0
  126. {bgts_context_engine-0.2.2 → bgts_context_engine-0.2.4}/src/bce/tools/layer2/__init__.py +0 -0
  127. {bgts_context_engine-0.2.2 → bgts_context_engine-0.2.4}/src/bce/tools/layer2/search.py +0 -0
  128. {bgts_context_engine-0.2.2 → bgts_context_engine-0.2.4}/src/bgts_context_engine.egg-info/dependency_links.txt +0 -0
  129. {bgts_context_engine-0.2.2 → bgts_context_engine-0.2.4}/src/bgts_context_engine.egg-info/entry_points.txt +0 -0
  130. {bgts_context_engine-0.2.2 → bgts_context_engine-0.2.4}/src/bgts_context_engine.egg-info/requires.txt +0 -0
  131. {bgts_context_engine-0.2.2 → bgts_context_engine-0.2.4}/src/bgts_context_engine.egg-info/top_level.txt +0 -0
@@ -7,6 +7,122 @@ project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [0.2.4] - 2026-09-22
11
+
12
+ This release turns the agent benchmark (a Cursor CLI agent on 14 tasks against a
13
+ React/TypeScript codebase, plain vs. with the engine) into product behaviour. The MCP server alone made a Cursor agent *worse*: it asked the graph late (after
14
+ a round of grep) or eight times per task, and the answer it got back had no file or line.
15
+ With one advertised tool, a rule that says "call it first and treat `file:line` as a
16
+ verified location", the answer handed over before the first turn, and a shorter context
17
+ budget, the same agent on the same 14 tasks, model and machine used 20 % fewer tokens,
18
+ produced 46 % less grep/glob output and 13 % fewer model turns, passed 73/73 checks against
19
+ 72/73, and changed 23 % fewer lines. Everything below is what that took.
20
+
21
+ ### Added
22
+
23
+ - `bce cursor-init [--project DIR] [--repo-id ID]... [--env-file PATH] [--bce-command X]`:
24
+ writes a project's `.cursor/mcp.json` (merged into an existing one; other servers are
25
+ kept) with the absolute path of the running `bce`, `serve-mcp --env-file …` and
26
+ `PYTHONUTF8=1`, plus the `alwaysApply` rule `.cursor/rules/bgts-context-engine.mdc`. The
27
+ rule ships in the wheel as a template, so every install gets the same instruction: call
28
+ `get_context_for_task` first with the full task text, open the returned `file:line`
29
+ entries directly instead of grepping for them, treat the list as places to inspect rather
30
+ than files to edit, never repeat a call with the same text. Idempotent.
31
+ - `bce claude-init …[--no-hook]`: the Claude Code counterpart — `.mcp.json` (merged), a
32
+ section in `CLAUDE.md` between `<!-- bgts-context-engine:begin/end -->` markers (the rest
33
+ of the file is kept), and by default a `UserPromptSubmit` hook in `.claude/settings.json`
34
+ (other hooks kept) that runs `bce precontext` before every prompt. Cursor gets no hook: its
35
+ `beforeSubmitPrompt` event can only allow or block a prompt, so there the rule carries the
36
+ instruction and the agent makes the one call itself.
37
+ - `bce precontext [--task TEXT] [--repo-id ID]...`: the compact "Code context for this
38
+ task" block an agent prompt carries — a file list in rank order, then one line per symbol
39
+ (`path:line kind name distance`) with a snippet of at most 12 lines where the snippet says
40
+ more than the name; about 5 k characters at the default budget. Without `--task` it is the
41
+ Claude Code hook: reads the hook JSON on stdin, skips prompts under 20 characters and slash
42
+ commands, prints `hookSpecificOutput.additionalContext` capped at Claude Code's
43
+ 10 000-character limit, and fails open (an unreachable database is a prompt without
44
+ context, never a blocked prompt). `bce.integrations.precontext.render_context_markdown`
45
+ is the renderer, for other hosts.
46
+ - `BCE_MCP_TOOLS`: comma-separated names the MCP server advertises (default: all read
47
+ tools). Agents fetch a tool's schema before first use and chain small calls when many
48
+ tools are on offer; the benchmark ran with `get_context_for_task` alone. Unknown names
49
+ fail at startup, and a tool not advertised cannot be dispatched either.
50
+ - `BCE_EMBEDDING_QUERY_TIMEOUT` (10 s, two attempts): the wait for embedding a single
51
+ *query* at search time, separate from the indexing timeout (600 s). When it expires,
52
+ `get_context_for_task` and `suggest_change_sites` answer from lexical and structural
53
+ anchors alone — visible as lower `coverage.confidence` — instead of failing after having
54
+ waited past an agent's MCP timeout (Cursor: 60 s). Motivated by a RunPod TCP proxy that
55
+ stalled connects for 19–67 s during the benchmark.
56
+ - Context items carry `name`, `kind`, `file_id` and `line` next to `symbol_id`. Without
57
+ them an agent had to search the tree for the file behind every symbol id (the module path
58
+ does not say `.ts` vs `.tsx`, nor the line) — one tool call, one model turn, per item.
59
+
60
+ ### Changed
61
+
62
+ - **Defaults: `max_candidates` 8 → 20, `max_tokens` 4000 → 1500**, on every surface (CLI
63
+ `bce context`, REST, MCP schema defaults, and the `bce.core.defaults` module they all
64
+ read). K=20 is where recall@K flattened in the PR replay for both fitted profiles and
65
+ what the agent benchmark ran with. The budget is shorter because an agent re-sends the
66
+ context on every turn: at 1500 it travelled as ~1.3 k tokens per turn and still halved
67
+ the agent's search output; 4000 travelled as ~4 k per turn for no further gain. Callers
68
+ wanting longer snippets pass `max_tokens` per request; the assembler still degrades items
69
+ to reference level rather than dropping them.
70
+ - `.env.example` shows `voyage-code-4` (the model the voyage profile was fitted on) as the
71
+ Voyage example and documents `BCE_EMBEDDING_QUERY_TIMEOUT` and `BCE_MCP_TOOLS`. The code
72
+ default stays `voyage-code-3` so indexes built with it keep matching.
73
+ - `server.json` describes the catalog as eight read-only tools plus two write tools rather
74
+ than "14 tools".
75
+
76
+ ## [0.2.3] - 2026-09-21
77
+
78
+ ### Added
79
+
80
+ - `BCE_EMBEDDING_PROVIDER=openai`: an encoder that talks to any server speaking the OpenAI
81
+ `/v1/embeddings` protocol (vLLM, Text Embeddings Inference, Ollama, or OpenAI itself), using
82
+ only the standard library. This is how an open model such as `jinaai/jina-code-embeddings-1.5b`
83
+ runs on-prem. Query/document asymmetry is a text prefix — the jina-code family's `nl2code`
84
+ prompts are the default when the model name contains `jina-code`; anything else is unset
85
+ unless `BCE_EMBEDDING_QUERY_PREFIX` / `BCE_EMBEDDING_DOCUMENT_PREFIX` say otherwise.
86
+ `BCE_EMBEDDING_BASE_URL`, `BCE_EMBEDDING_API_KEY`, `BCE_EMBEDDING_EXTRA_BODY` (default
87
+ `{"truncate_prompt_tokens": -1}` so vLLM truncates instead of rejecting a long batch; set
88
+ `{}` for OpenAI's own API, which rejects unknown fields) and `BCE_EMBEDDING_TIMEOUT` (600 s)
89
+ configure the client. Vectors wider than `BCE_EMBEDDING_DIM` are truncated and re-normalised
90
+ (Matryoshka); a narrower reply is a configuration error. Transient 5xx / connection failures
91
+ retry three times; 4xx does not.
92
+ - Retrieval profiles (`bce.core.orchestrator.profile`): the three engine constants that encode
93
+ *where in the model's ranked list the right answers sit* — semantic-anchor rank scale, the
94
+ share of the answer reserved for the model's ranks, and a guard on its top ranks in
95
+ narrowing — grouped per embedding family. `BCE_RETRIEVAL_PROFILE=auto` (the default) picks
96
+ `voyage` for `voyage-*` and unknown models (the historical constants, unchanged) and `jina`
97
+ for `jina-*`. Name one to force it; `BCE_RETRIEVAL_SEMANTIC_GUARD_RANKS` /
98
+ `_RESERVE_SHARE` / `_RANK_SCALE` override a single knob for fitting runs. A profile change
99
+ never needs a re-index. The active profile is written into every `bce bench-prs` report.
100
+ - `bce migrate --reset-embeddings`: after the SQL migrations, `align_embedding_dim` re-types
101
+ `embeddings.embedding` to `BCE_EMBEDDING_DIM`. Stored vectors of another width are refused
102
+ unless the flag is set (they belong to another model and would be discarded); then the HNSW
103
+ index is rebuilt the same way migration `0005` did.
104
+
105
+ ### Changed
106
+
107
+ - Narrowing reads the active retrieval profile. The voyage path is unchanged (no guard,
108
+ share 0.5). The jina profile adds a guard of 10: the model's first ten ranks fill slots
109
+ 1–10 (only the container cap can skip one). jina-code finds more correct symbols than
110
+ voyage-code-4 but spreads them over ranks 1–15, and under the voyage constants the engine's
111
+ agreement with the model's *deeper* ranks satisfied the reserve share and pushed those mid
112
+ hits to positions 11–19 or out of the answer (PR replay, 30 PRs: recall@20 35.7 % → 38.2 %,
113
+ holdout 27.8 % → 34.9 %, retention of the model's own hits 83 % → 92 %). The list stays
114
+ K-monotonic.
115
+ - `bce bench-prs` titles the markdown with the encoder that actually produced the snapshots
116
+ (`jina-code-embeddings-1.5b vs … + BCE`), because the JSON key `voyage` is historical, not
117
+ the model.
118
+
119
+ ### Fixed
120
+
121
+ - `bce bench-prs --from-report` / `--rerun-bce` no longer treats a stored semantic pool
122
+ shorter than K as incomplete. A task whose neighbours are mostly tests legitimately has a
123
+ pool shorter than K — the live run had nothing more either — so the check is now "non-empty
124
+ and at least as long as the list scored from it".
125
+
10
126
  ## [0.2.2] - 2026-09-18
11
127
 
12
128
  ### Added
@@ -254,7 +370,9 @@ First public release.
254
370
  - Docker Compose deployment with PostgreSQL, Apache AGE and pgvector preconfigured.
255
371
  - `server.json` manifest describing the stdio server for the official MCP registry.
256
372
 
257
- [Unreleased]: https://github.com/bgts-ai-org/bgts-context-engine/compare/v0.2.2...HEAD
373
+ [Unreleased]: https://github.com/bgts-ai-org/bgts-context-engine/compare/v0.2.4...HEAD
374
+ [0.2.4]: https://github.com/bgts-ai-org/bgts-context-engine/compare/v0.2.3...v0.2.4
375
+ [0.2.3]: https://github.com/bgts-ai-org/bgts-context-engine/compare/v0.2.2...v0.2.3
258
376
  [0.2.2]: https://github.com/bgts-ai-org/bgts-context-engine/compare/v0.2.1...v0.2.2
259
377
  [0.2.1]: https://github.com/bgts-ai-org/bgts-context-engine/compare/v0.2.0...v0.2.1
260
378
  [0.2.0]: https://github.com/bgts-ai-org/bgts-context-engine/compare/v0.1.0...v0.2.0
@@ -4,6 +4,7 @@ include README.tr.md
4
4
  include CHANGELOG.md
5
5
  recursive-include src/bce/core/i18n/catalogs *.json
6
6
  recursive-include src/bce/storage/relational/migrations *.sql
7
+ recursive-include src/bce/integrations/templates *.mdc *.md
7
8
 
8
9
  # Compiled frontend, vendored by scripts/build_ui.py before a release build.
9
10
  recursive-include src/bce/api/rest/static *
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: bgts-context-engine
3
- Version: 0.2.2
3
+ Version: 0.2.4
4
4
  Summary: Deterministic code-graph context engine for AI coding agents - PostgreSQL, Apache AGE and pgvector, over MCP and REST
5
5
  Author: Oğuz Öztürk, Enes İyidil
6
6
  Maintainer: BGTS
@@ -69,7 +69,7 @@ that actually answer it — ranked, budgeted, and reproducible.
69
69
  [![MCP](https://img.shields.io/badge/MCP-compatible-000000.svg)](docs/mcp.md)
70
70
  [![Stars](https://img.shields.io/github/stars/bgts-ai-org/bgts-context-engine?style=flat&logo=github)](https://github.com/bgts-ai-org/bgts-context-engine/stargazers)
71
71
 
72
- [Quick start](#quick-start) · [Use it from your agent](#use-it-from-your-agent) · [How it works](#how-it-works) · [Documentation](#documentation) · [Türkçe](README.tr.md)
72
+ [Quick start](#quick-start) · [Use it from your agent](#use-it-from-your-agent) · [How it works](#how-it-works) · [Supported models](#supported-models) · [Documentation](#documentation) · [Türkçe](README.tr.md)
73
73
 
74
74
  </div>
75
75
 
@@ -150,9 +150,28 @@ Every MCP client uses the same stdio command plus the database in the environmen
150
150
  leave `bce serve-mcp` running in a terminal for the editor: stdout is the protocol, so the
151
151
  process stays silent, and the IDE starts its own copy.
152
152
 
153
+ **One command per editor.** Run it in the project the agent works on (the repository you
154
+ indexed), pointing at the engine's `.env`:
155
+
156
+ ```bash
157
+ bce --env-file /path/to/engine/.env cursor-init --repo-id my-service # Cursor
158
+ bce --env-file /path/to/engine/.env claude-init --repo-id my-service # Claude Code
159
+ ```
160
+
161
+ `cursor-init` writes `.cursor/mcp.json` (merged into an existing one) and the rule
162
+ `.cursor/rules/bgts-context-engine.mdc`, which tells the agent to call
163
+ `get_context_for_task` *first*, treat its `file:line` entries as verified locations instead
164
+ of grepping for them, and not to edit a file just because it was listed. `claude-init`
165
+ writes `.mcp.json`, a marked section in `CLAUDE.md`, and a `UserPromptSubmit` hook
166
+ (`bce precontext`) that runs the graph once per prompt and hands the agent the answer
167
+ before its first turn — the flow the agent benchmark measured (−20 % tokens, half the search
168
+ output, same or better checks; 14 tasks on a React/TypeScript codebase, same model and machine).
169
+ Cursor's prompt hook cannot add context, so there the rule does that job. `--no-hook`,
170
+ `--repo-id` (repeatable) and `--bce-command` adjust the files; both commands are safe to rerun.
171
+
153
172
  After you add or change the MCP config, **restart Cursor or VS Code** (or Command Palette
154
173
  → “Developer: Reload Window”). The server should then show as enabled with eight tools (ten with indexing enabled).
155
- Setup detail: [docs/mcp.md](docs/mcp.md).
174
+ Setup detail: [docs/mcp.md](docs/mcp.md). The manual equivalents:
156
175
 
157
176
  **Cursor** — user config `~/.cursor/mcp.json` (applies to every project), or a project
158
177
  `.cursor/mcp.json` that stays local (the directory is gitignored):
@@ -217,12 +236,14 @@ Not a list of file paths. A ranked pack, with the reasoning attached:
217
236
  },
218
237
  "context": {
219
238
  "items": [
220
- { "symbol_id": "...refresh_session#88c2", "detail_level": "full",
239
+ { "symbol_id": "...refresh_session#88c2", "name": "refresh_session", "kind": "function",
240
+ "file_id": "my-service:src/auth/session.py", "line": 41, "detail_level": "full",
221
241
  "graph_distance": 0, "score": 11.42, "tokens": 214, "content": "def refresh_session(...)" },
222
- { "symbol_id": "...SESSION_TTL#4b0d", "detail_level": "signature",
242
+ { "symbol_id": "...SESSION_TTL#4b0d", "name": "SESSION_TTL", "kind": "constant",
243
+ "file_id": "my-service:src/auth/config.py", "line": 12, "detail_level": "signature",
223
244
  "graph_distance": 2, "score": 6.10, "tokens": 31, "content": "SESSION_TTL: int" }
224
245
  ],
225
- "used_tokens": 2913, "budget": 4000, "included": 8, "skipped": 0
246
+ "used_tokens": 1388, "budget": 1500, "included": 20, "skipped": 0
226
247
  },
227
248
  "coverage": {
228
249
  "anchor_source_count": 3, "connected_component_ratio": 0.875,
@@ -243,8 +264,10 @@ could not corroborate it — the moment for an agent to ask a follow-up question
243
264
  editing. `commit_mismatch` means the index is behind your working tree.
244
265
 
245
266
  **`detail_level`** falls off with graph distance: the symbol you are changing arrives in
246
- full, its neighbours as signatures, the outer ring as `name @ file:line`. That is how eight
247
- genuinely relevant symbols fit in 4000 tokens.
267
+ full, its neighbours as signatures, the outer ring as `name @ file:line`. That is how twenty
268
+ genuinely relevant symbols fit in 1500 tokens — short enough for an agent to carry on every
269
+ turn. Every item also names its `file_id` and `line`, so the agent opens the file instead of
270
+ searching for the symbol.
248
271
 
249
272
  ## How it works
250
273
 
@@ -294,7 +317,36 @@ The full formula, every weight, and the confidence thresholds are in
294
317
  - **A UI that explains itself.** `/ui` ships in the wheel and replays a real retrieval call
295
318
  stage by stage: anchors lighting up, expansion spreading, candidates scored and cut.
296
319
  - **Runs offline.** The default embedding provider is deterministic arithmetic over token
297
- digests. No API key, no network, repeatable benchmarks.
320
+ digests. No API key, no network, repeatable benchmarks. `openai` talks to any
321
+ OpenAI-compatible `/v1/embeddings` server (vLLM, TEI, Ollama), so a model such as
322
+ [jina-code-embeddings-1.5b](https://huggingface.co/jinaai/jina-code-embeddings-1.5b)
323
+ can run inside the perimeter.
324
+
325
+ ## Supported models
326
+
327
+ Embeddings only find entry points when the task text names nothing the graph already
328
+ knows. They never rank the answer. Out of the box that seed is `hashing`: deterministic
329
+ arithmetic, no API key, no network. For a real code model, set `BCE_EMBEDDING_PROVIDER`
330
+ and `BCE_EMBEDDING_MODEL` to one of these:
331
+
332
+ | Model | Provider | Dimension |
333
+ | --- | --- | --- |
334
+ | [`voyage-code-3`](https://blog.voyageai.com/2024/12/04/voyage-code-3/) | Voyage AI (`voyage`) | 1024 |
335
+ | [`voyage-code-4`](https://blog.voyageai.com/2026/08/13/voyage-code-4/) | Voyage AI (`voyage`) | 1024 |
336
+ | [`jina-code-embeddings-1.5b`](https://huggingface.co/jinaai/jina-code-embeddings-1.5b) | OpenAI-compatible (`openai`) | 1536 |
337
+
338
+ Voyage is a hosted API — `pip install "bgts-context-engine[embed]"` and
339
+ `BCE_VOYAGE_API_KEY`. Jina is the on-prem path: any server that speaks `/v1/embeddings`
340
+ (vLLM, TEI, Ollama). Switching the model or the dimension is a re-index
341
+ (`bce migrate --reset-embeddings`). The knobs are in
342
+ [docs/deployment.md](docs/deployment.md).
343
+
344
+ **Coming next** — same `openai` socket, not yet a fitted retrieval profile:
345
+
346
+ - [`jina-code-embeddings-0.5b`](https://huggingface.co/jinaai/jina-code-embeddings-0.5b)
347
+ — the smaller sibling of 1.5b, for hosts that cannot hold 1.5B parameters.
348
+ - [`Nomic Embed Code`](https://huggingface.co/nomic-ai/nomic-embed-code) — an open 7B
349
+ code retriever.
298
350
 
299
351
  ## Where it fits
300
352
 
@@ -16,7 +16,7 @@ that actually answer it — ranked, budgeted, and reproducible.
16
16
  [![MCP](https://img.shields.io/badge/MCP-compatible-000000.svg)](docs/mcp.md)
17
17
  [![Stars](https://img.shields.io/github/stars/bgts-ai-org/bgts-context-engine?style=flat&logo=github)](https://github.com/bgts-ai-org/bgts-context-engine/stargazers)
18
18
 
19
- [Quick start](#quick-start) · [Use it from your agent](#use-it-from-your-agent) · [How it works](#how-it-works) · [Documentation](#documentation) · [Türkçe](README.tr.md)
19
+ [Quick start](#quick-start) · [Use it from your agent](#use-it-from-your-agent) · [How it works](#how-it-works) · [Supported models](#supported-models) · [Documentation](#documentation) · [Türkçe](README.tr.md)
20
20
 
21
21
  </div>
22
22
 
@@ -97,9 +97,28 @@ Every MCP client uses the same stdio command plus the database in the environmen
97
97
  leave `bce serve-mcp` running in a terminal for the editor: stdout is the protocol, so the
98
98
  process stays silent, and the IDE starts its own copy.
99
99
 
100
+ **One command per editor.** Run it in the project the agent works on (the repository you
101
+ indexed), pointing at the engine's `.env`:
102
+
103
+ ```bash
104
+ bce --env-file /path/to/engine/.env cursor-init --repo-id my-service # Cursor
105
+ bce --env-file /path/to/engine/.env claude-init --repo-id my-service # Claude Code
106
+ ```
107
+
108
+ `cursor-init` writes `.cursor/mcp.json` (merged into an existing one) and the rule
109
+ `.cursor/rules/bgts-context-engine.mdc`, which tells the agent to call
110
+ `get_context_for_task` *first*, treat its `file:line` entries as verified locations instead
111
+ of grepping for them, and not to edit a file just because it was listed. `claude-init`
112
+ writes `.mcp.json`, a marked section in `CLAUDE.md`, and a `UserPromptSubmit` hook
113
+ (`bce precontext`) that runs the graph once per prompt and hands the agent the answer
114
+ before its first turn — the flow the agent benchmark measured (−20 % tokens, half the search
115
+ output, same or better checks; 14 tasks on a React/TypeScript codebase, same model and machine).
116
+ Cursor's prompt hook cannot add context, so there the rule does that job. `--no-hook`,
117
+ `--repo-id` (repeatable) and `--bce-command` adjust the files; both commands are safe to rerun.
118
+
100
119
  After you add or change the MCP config, **restart Cursor or VS Code** (or Command Palette
101
120
  → “Developer: Reload Window”). The server should then show as enabled with eight tools (ten with indexing enabled).
102
- Setup detail: [docs/mcp.md](docs/mcp.md).
121
+ Setup detail: [docs/mcp.md](docs/mcp.md). The manual equivalents:
103
122
 
104
123
  **Cursor** — user config `~/.cursor/mcp.json` (applies to every project), or a project
105
124
  `.cursor/mcp.json` that stays local (the directory is gitignored):
@@ -164,12 +183,14 @@ Not a list of file paths. A ranked pack, with the reasoning attached:
164
183
  },
165
184
  "context": {
166
185
  "items": [
167
- { "symbol_id": "...refresh_session#88c2", "detail_level": "full",
186
+ { "symbol_id": "...refresh_session#88c2", "name": "refresh_session", "kind": "function",
187
+ "file_id": "my-service:src/auth/session.py", "line": 41, "detail_level": "full",
168
188
  "graph_distance": 0, "score": 11.42, "tokens": 214, "content": "def refresh_session(...)" },
169
- { "symbol_id": "...SESSION_TTL#4b0d", "detail_level": "signature",
189
+ { "symbol_id": "...SESSION_TTL#4b0d", "name": "SESSION_TTL", "kind": "constant",
190
+ "file_id": "my-service:src/auth/config.py", "line": 12, "detail_level": "signature",
170
191
  "graph_distance": 2, "score": 6.10, "tokens": 31, "content": "SESSION_TTL: int" }
171
192
  ],
172
- "used_tokens": 2913, "budget": 4000, "included": 8, "skipped": 0
193
+ "used_tokens": 1388, "budget": 1500, "included": 20, "skipped": 0
173
194
  },
174
195
  "coverage": {
175
196
  "anchor_source_count": 3, "connected_component_ratio": 0.875,
@@ -190,8 +211,10 @@ could not corroborate it — the moment for an agent to ask a follow-up question
190
211
  editing. `commit_mismatch` means the index is behind your working tree.
191
212
 
192
213
  **`detail_level`** falls off with graph distance: the symbol you are changing arrives in
193
- full, its neighbours as signatures, the outer ring as `name @ file:line`. That is how eight
194
- genuinely relevant symbols fit in 4000 tokens.
214
+ full, its neighbours as signatures, the outer ring as `name @ file:line`. That is how twenty
215
+ genuinely relevant symbols fit in 1500 tokens — short enough for an agent to carry on every
216
+ turn. Every item also names its `file_id` and `line`, so the agent opens the file instead of
217
+ searching for the symbol.
195
218
 
196
219
  ## How it works
197
220
 
@@ -241,7 +264,36 @@ The full formula, every weight, and the confidence thresholds are in
241
264
  - **A UI that explains itself.** `/ui` ships in the wheel and replays a real retrieval call
242
265
  stage by stage: anchors lighting up, expansion spreading, candidates scored and cut.
243
266
  - **Runs offline.** The default embedding provider is deterministic arithmetic over token
244
- digests. No API key, no network, repeatable benchmarks.
267
+ digests. No API key, no network, repeatable benchmarks. `openai` talks to any
268
+ OpenAI-compatible `/v1/embeddings` server (vLLM, TEI, Ollama), so a model such as
269
+ [jina-code-embeddings-1.5b](https://huggingface.co/jinaai/jina-code-embeddings-1.5b)
270
+ can run inside the perimeter.
271
+
272
+ ## Supported models
273
+
274
+ Embeddings only find entry points when the task text names nothing the graph already
275
+ knows. They never rank the answer. Out of the box that seed is `hashing`: deterministic
276
+ arithmetic, no API key, no network. For a real code model, set `BCE_EMBEDDING_PROVIDER`
277
+ and `BCE_EMBEDDING_MODEL` to one of these:
278
+
279
+ | Model | Provider | Dimension |
280
+ | --- | --- | --- |
281
+ | [`voyage-code-3`](https://blog.voyageai.com/2024/12/04/voyage-code-3/) | Voyage AI (`voyage`) | 1024 |
282
+ | [`voyage-code-4`](https://blog.voyageai.com/2026/08/13/voyage-code-4/) | Voyage AI (`voyage`) | 1024 |
283
+ | [`jina-code-embeddings-1.5b`](https://huggingface.co/jinaai/jina-code-embeddings-1.5b) | OpenAI-compatible (`openai`) | 1536 |
284
+
285
+ Voyage is a hosted API — `pip install "bgts-context-engine[embed]"` and
286
+ `BCE_VOYAGE_API_KEY`. Jina is the on-prem path: any server that speaks `/v1/embeddings`
287
+ (vLLM, TEI, Ollama). Switching the model or the dimension is a re-index
288
+ (`bce migrate --reset-embeddings`). The knobs are in
289
+ [docs/deployment.md](docs/deployment.md).
290
+
291
+ **Coming next** — same `openai` socket, not yet a fitted retrieval profile:
292
+
293
+ - [`jina-code-embeddings-0.5b`](https://huggingface.co/jinaai/jina-code-embeddings-0.5b)
294
+ — the smaller sibling of 1.5b, for hosts that cannot hold 1.5B parameters.
295
+ - [`Nomic Embed Code`](https://huggingface.co/nomic-ai/nomic-embed-code) — an open 7B
296
+ code retriever.
245
297
 
246
298
  ## Where it fits
247
299
 
@@ -14,7 +14,7 @@ veren sekiz sembolü sıralanmış, bütçelenmiş ve yeniden üretilebilir şek
14
14
  [![MCP](https://img.shields.io/badge/MCP-uyumlu-000000.svg)](docs/mcp.md)
15
15
  [![Yıldızlar](https://img.shields.io/github/stars/bgts-ai-org/bgts-context-engine?style=flat&logo=github)](https://github.com/bgts-ai-org/bgts-context-engine/stargazers)
16
16
 
17
- [Hızlı başlangıç](#hızlı-başlangıç) · [Ajanınızdan kullanma](#ajanınızdan-kullanma) · [Nasıl çalışır](#nasıl-çalışır) · [Dokümantasyon](#dokümantasyon) · [English](README.md)
17
+ [Hızlı başlangıç](#hızlı-başlangıç) · [Ajanınızdan kullanma](#ajanınızdan-kullanma) · [Nasıl çalışır](#nasıl-çalışır) · [Desteklenen modeller](#desteklenen-modeller) · [Dokümantasyon](#dokümantasyon) · [English](README.md)
18
18
 
19
19
  </div>
20
20
 
@@ -97,9 +97,31 @@ Her MCP istemcisi aynı stdio komutunu ve ortamındaki veritabanı bağlantısı
97
97
  Editör için terminalde `bce serve-mcp` açık bırakmayın: stdout protokoldür, bu yüzden
98
98
  süreç sessiz kalır; IDE kendi kopyasını başlatır.
99
99
 
100
+ **Editör başına tek komut.** Ajanın çalıştığı projede (indekslediğiniz depoda), motorun
101
+ `.env` dosyasını göstererek çalıştırın:
102
+
103
+ ```bash
104
+ bce --env-file /path/to/engine/.env cursor-init --repo-id my-service # Cursor
105
+ bce --env-file /path/to/engine/.env claude-init --repo-id my-service # Claude Code
106
+ ```
107
+
108
+ `cursor-init`, `.cursor/mcp.json` dosyasını (varsa üzerine birleştirerek) ve
109
+ `.cursor/rules/bgts-context-engine.mdc` kuralını yazar. Kural ajana şunları söyler:
110
+ `get_context_for_task` aracını *ilk iş olarak* çağır, döndürdüğü `dosya:satır`
111
+ girdilerini doğrulanmış konum say ve onları grep ile arama, listelendi diye bir dosyayı
112
+ düzenleme. `claude-init` ise `.mcp.json`, `CLAUDE.md` içinde işaretli bir bölüm ve
113
+ `bce precontext` komutunu çalıştıran bir `UserPromptSubmit` kancası yazar: kanca her
114
+ istemde grafı bir kez sorgular ve yanıtı ajana ilk turundan önce verir. Ajan
115
+ benchmark'ında ölçülen akış budur (−%20 token, yarıya inen arama çıktısı, eşit veya daha
116
+ iyi kontroller; React/TypeScript bir kod tabanında 14 görev, aynı model ve makine).
117
+ Cursor'ın istem kancası bağlam ekleyemediği için orada bu işi kural yapar. `--no-hook`,
118
+ `--repo-id` (tekrarlanabilir) ve `--bce-command` dosyaları ayarlar; iki komut da tekrar
119
+ çalıştırılmaya uygundur.
120
+
100
121
  MCP yapılandırmasını ekledikten veya değiştirdikten sonra **Cursor veya VS Code'u
101
122
  yeniden başlatın** (veya Komut Paleti → “Developer: Reload Window”). Sunucu sekiz araçla
102
123
  (indeksleme açıkken on araçla) etkin görünmelidir. Ayrıntı: [docs/mcp.md](docs/mcp.md).
124
+ Elle yapmanın karşılıkları:
103
125
 
104
126
  **Cursor** — her proje için kullanıcı yapılandırması `~/.cursor/mcp.json`, ya da yerelde
105
127
  kalan bir proje `.cursor/mcp.json` (dizin gitignore'dadır):
@@ -165,12 +187,14 @@ Dosya yolu listesi değil. Gerekçesi ekli, sıralanmış bir paket:
165
187
  },
166
188
  "context": {
167
189
  "items": [
168
- { "symbol_id": "...refresh_session#88c2", "detail_level": "full",
190
+ { "symbol_id": "...refresh_session#88c2", "name": "refresh_session", "kind": "function",
191
+ "file_id": "my-service:src/auth/session.py", "line": 41, "detail_level": "full",
169
192
  "graph_distance": 0, "score": 11.42, "tokens": 214, "content": "def refresh_session(...)" },
170
- { "symbol_id": "...SESSION_TTL#4b0d", "detail_level": "signature",
193
+ { "symbol_id": "...SESSION_TTL#4b0d", "name": "SESSION_TTL", "kind": "constant",
194
+ "file_id": "my-service:src/auth/config.py", "line": 12, "detail_level": "signature",
171
195
  "graph_distance": 2, "score": 6.10, "tokens": 31, "content": "SESSION_TTL: int" }
172
196
  ],
173
- "used_tokens": 2913, "budget": 4000, "included": 8, "skipped": 0
197
+ "used_tokens": 1388, "budget": 1500, "included": 20, "skipped": 0
174
198
  },
175
199
  "coverage": {
176
200
  "anchor_source_count": 3, "connected_component_ratio": 0.875,
@@ -192,7 +216,8 @@ gereken an. `commit_mismatch` ise indeksin çalışma ağacınızın gerisinde k
192
216
 
193
217
  **`detail_level`** graf mesafesiyle azalır: değiştirdiğiniz sembol tam gövdesiyle,
194
218
  komşuları imza olarak, dış halka `name @ dosya:satır` biçiminde gelir. Gerçekten ilgili
195
- sekiz sembolün 4000 token'a sığması bu sayede olur.
219
+ yirmi sembolün 1500 token'a sığması bu sayede olur — bir ajanın her turda taşıyabileceği
220
+ kadar kısa. Her öge `file_id` ve `line` da taşır; ajan sembolü aramak yerine dosyayı açar.
196
221
 
197
222
  ## Nasıl çalışır
198
223
 
@@ -245,7 +270,36 @@ Formülün tamamı, her ağırlık ve güven eşikleri
245
270
  aşama aşama oynatır: çapaların yanması, genişlemenin yayılması, adayların skorlanıp
246
271
  kesilmesi.
247
272
  - **Çevrimdışı çalışır.** Varsayılan embedding sağlayıcısı, token özetleri üzerinde
248
- deterministik aritmetiktir. API anahtarı yok, ağ yok, tekrarlanabilir ölçümler.
273
+ deterministik aritmetiktir. API anahtarı yok, ağ yok, tekrarlanabilir ölçümler. `openai`
274
+ sağlayıcısı OpenAI uyumlu herhangi bir `/v1/embeddings` sunucusuna konuşur (vLLM, TEI,
275
+ Ollama); [jina-code-embeddings-1.5b](https://huggingface.co/jinaai/jina-code-embeddings-1.5b)
276
+ gibi bir model çevre içinde çalışır.
277
+
278
+ ## Desteklenen modeller
279
+
280
+ Embedding yalnızca grafın tanımadığı bir görev metninde giriş noktası bulur. Cevabı asla
281
+ sıralamaz. Varsayılan `hashing`'dir: deterministik aritmetik, API anahtarı yok, ağ yok.
282
+ Gerçek bir kod modeli için `BCE_EMBEDDING_PROVIDER` ve `BCE_EMBEDDING_MODEL`'i şunlardan
283
+ birine ayarlayın:
284
+
285
+ | Model | Sağlayıcı | Boyut |
286
+ | --- | --- | --- |
287
+ | [`voyage-code-3`](https://blog.voyageai.com/2024/12/04/voyage-code-3/) | Voyage AI (`voyage`) | 1024 |
288
+ | [`voyage-code-4`](https://blog.voyageai.com/2026/08/13/voyage-code-4/) | Voyage AI (`voyage`) | 1024 |
289
+ | [`jina-code-embeddings-1.5b`](https://huggingface.co/jinaai/jina-code-embeddings-1.5b) | OpenAI uyumlu (`openai`) | 1536 |
290
+
291
+ Voyage barındırılan bir API'dir — `pip install "bgts-context-engine[embed]"` ve
292
+ `BCE_VOYAGE_API_KEY`. Jina çevre-içi yoldur: `/v1/embeddings` konuşan herhangi bir
293
+ sunucu (vLLM, TEI, Ollama). Model veya boyutu değiştirmek yeniden indekslemedir
294
+ (`bce migrate --reset-embeddings`). Ayarlar
295
+ [docs/deployment.md](docs/deployment.md) içindedir.
296
+
297
+ **Sırada** — aynı `openai` soketi, henüz ayrı bir getirme profili yok:
298
+
299
+ - [`jina-code-embeddings-0.5b`](https://huggingface.co/jinaai/jina-code-embeddings-0.5b)
300
+ — 1.5b'nin küçük kardeşi; 1.5B parametreyi taşıyamayan makineler için.
301
+ - [`Nomic Embed Code`](https://huggingface.co/nomic-ai/nomic-embed-code) — açık kaynaklı
302
+ 7B kod getiricisi.
249
303
 
250
304
  ## Nereye oturur
251
305
 
@@ -106,6 +106,7 @@ include = ["bce*"]
106
106
  bce = [
107
107
  "core/i18n/catalogs/*.json",
108
108
  "storage/relational/migrations/*.sql",
109
+ "integrations/templates/*",
109
110
  # Compiled frontend served at /ui; vendored by scripts/build_ui.py before a release build.
110
111
  "api/rest/static/**/*",
111
112
  ]
@@ -5,4 +5,4 @@ specification for details. This package is the provider side of the deterministi
5
5
  contains no LLM and produces reproducible context packages.
6
6
  """
7
7
 
8
- __version__ = "0.2.2"
8
+ __version__ = "0.2.4"
@@ -44,8 +44,9 @@ def build_server(name: str = "bgts-context-engine") -> Any:
44
44
  from bce.config import get_settings
45
45
  from bce.storage.relational.db import connection
46
46
 
47
- allow_write = get_settings().mcp_allow_write
48
- specs = available_tool_specs(allow_write=allow_write)
47
+ settings = get_settings()
48
+ allow_write = settings.mcp_allow_write
49
+ specs = available_tool_specs(allow_write=allow_write, allowlist=settings.mcp_tool_allowlist)
49
50
  server = Server(name)
50
51
 
51
52
  @server.list_tools()
@@ -56,6 +57,8 @@ def build_server(name: str = "bgts-context-engine") -> Any:
56
57
  ]
57
58
 
58
59
  def _dispatch_blocking(name: str, arguments: dict[str, Any]) -> dict[str, Any]:
60
+ if name not in specs:
61
+ raise KeyError(f"tool '{name}' is not advertised by this server (BCE_MCP_TOOLS)")
59
62
  with connection() as conn:
60
63
  try:
61
64
  result = dispatch_tool(conn, name, arguments, allow_write=allow_write)
@@ -26,6 +26,7 @@ from typing import Any
26
26
  import psycopg
27
27
 
28
28
  from bce.core.auth.scope import Principal, ScopeFilter
29
+ from bce.core.defaults import DEFAULT_MAX_CANDIDATES, DEFAULT_MAX_TOKENS
29
30
  from bce.core.i18n import get_translator
30
31
  from bce.jobs.store import enqueue_job, get_job, list_jobs
31
32
  from bce.storage.graph.client import GraphClient
@@ -57,10 +58,21 @@ TOOL_SPECS: dict[str, dict[str, Any]] = {
57
58
  ),
58
59
  "schema": _schema(
59
60
  {
60
- "task_text": _STR,
61
+ "task_text": {
62
+ **_STR,
63
+ "description": "The task in prose; pass the full request text, once.",
64
+ },
61
65
  "task_id": _STR,
62
- "max_tokens": _INT,
63
- "max_candidates": _INT,
66
+ "max_tokens": {
67
+ **_INT,
68
+ "default": DEFAULT_MAX_TOKENS,
69
+ "description": "Token budget of the assembled context.",
70
+ },
71
+ "max_candidates": {
72
+ **_INT,
73
+ "default": DEFAULT_MAX_CANDIDATES,
74
+ "description": "How many symbols to return (K).",
75
+ },
64
76
  "commit": _STR,
65
77
  "repo_ids": _STR_LIST,
66
78
  "explicit_symbols": _STR_LIST,
@@ -137,11 +149,24 @@ TOOL_SPECS: dict[str, dict[str, Any]] = {
137
149
  }
138
150
 
139
151
 
140
- def available_tool_specs(*, allow_write: bool) -> dict[str, dict[str, Any]]:
141
- """The catalog to advertise: write tools are hidden unless ``allow_write`` is set."""
142
- if allow_write:
143
- return dict(TOOL_SPECS)
144
- return {name: spec for name, spec in TOOL_SPECS.items() if name not in WRITE_TOOLS}
152
+ def available_tool_specs(
153
+ *, allow_write: bool, allowlist: frozenset[str] | None = None
154
+ ) -> dict[str, dict[str, Any]]:
155
+ """The catalog to advertise: write tools are hidden unless ``allow_write`` is set, and an
156
+ ``allowlist`` (``BCE_MCP_TOOLS``) narrows it further. Unknown names in the allowlist raise, so a
157
+ typo does not silently publish nothing."""
158
+ if allowlist is not None:
159
+ unknown = sorted(allowlist - set(TOOL_SPECS))
160
+ if unknown:
161
+ raise ValueError(
162
+ f"BCE_MCP_TOOLS names unknown tools {unknown}; known: {sorted(TOOL_SPECS)}"
163
+ )
164
+ specs = {
165
+ name: spec
166
+ for name, spec in TOOL_SPECS.items()
167
+ if (allow_write or name not in WRITE_TOOLS) and (allowlist is None or name in allowlist)
168
+ }
169
+ return specs
145
170
 
146
171
 
147
172
  def dispatch_tool(
@@ -11,6 +11,8 @@ from typing import Any
11
11
 
12
12
  from pydantic import BaseModel, Field
13
13
 
14
+ from bce.core.defaults import DEFAULT_MAX_CANDIDATES, DEFAULT_MAX_TOKENS
15
+
14
16
 
15
17
  class IndexRequest(BaseModel):
16
18
  repo_path: str = Field(..., description="Path to a local repository to index.")
@@ -64,9 +66,11 @@ class ContextForTaskRequest(BaseModel):
64
66
  task_id: str | None = Field(
65
67
  default=None, description="Optional Jira task id (audit + history)."
66
68
  )
67
- max_tokens: int = Field(default=4000, ge=1, le=200000, description="Token budget for assembly.")
69
+ max_tokens: int = Field(
70
+ default=DEFAULT_MAX_TOKENS, ge=1, le=200000, description="Token budget for assembly."
71
+ )
68
72
  max_candidates: int = Field(
69
- default=8, ge=1, le=100, description="Narrow to at most N candidates."
73
+ default=DEFAULT_MAX_CANDIDATES, ge=1, le=100, description="Narrow to at most N candidates."
70
74
  )
71
75
  commit: str | None = Field(default=None, description="Pinned commit sha (stage 0).")
72
76
  repo_ids: list[str] | None = Field(
@@ -108,7 +112,7 @@ class AssembleContextRequest(BaseModel):
108
112
  symbol_ids: list[str] = Field(
109
113
  ..., description="Symbols to deduplicate and fit into the budget."
110
114
  )
111
- max_tokens: int = Field(default=4000, ge=1, le=200000)
115
+ max_tokens: int = Field(default=DEFAULT_MAX_TOKENS, ge=1, le=200000)
112
116
 
113
117
 
114
118
  class ToolResponse(BaseModel):
@@ -21,6 +21,7 @@ from bce.core.coverage import compute_coverage
21
21
  from bce.core.orchestrator.anchors import find_anchors
22
22
  from bce.core.orchestrator.expand import expand_from_anchors, to_candidates
23
23
  from bce.core.orchestrator.orchestrator import RetrievalResult, narrow
24
+ from bce.core.orchestrator.profile import active_profile
24
25
  from bce.core.orchestrator.text import content_tokens
25
26
  from bce.core.scoring.engine import ScoreWeights, score_candidates
26
27
  from bce.storage.graph.repository import GraphRepository
@@ -69,6 +70,7 @@ def trace_context_for_task(
69
70
 
70
71
  # Stage 1: multi-source anchors (spec section 6.2), with evidence strength per anchor.
71
72
  t = time.perf_counter()
73
+ profile = active_profile()
72
74
  anchors = find_anchors(
73
75
  repository,
74
76
  task_text=task_text,
@@ -78,6 +80,7 @@ def trace_context_for_task(
78
80
  component_repo_ids=None,
79
81
  repo_ids=repo_ids,
80
82
  semantic_candidates=semantic_candidates,
83
+ profile=profile,
81
84
  )
82
85
  stages.append(
83
86
  {
@@ -139,7 +142,7 @@ def trace_context_for_task(
139
142
 
140
143
  # Stage 4: diversity-aware narrowing to top-N (the "1000 -> 8" step).
141
144
  t = time.perf_counter()
142
- narrowed = narrow(ranked, max_candidates)
145
+ narrowed = narrow(ranked, max_candidates, profile=profile)
143
146
  stages.append(
144
147
  {
145
148
  "stage": "narrow",