Skip to main content
BGTS Context Engine

Deterministic code-graph context for AI coding agents.

Ask "why does the login timeout fire on the meeting webhook?" and get the eight symbols that actually answer it — ranked, budgeted, and reproducible.

PyPI Python CI License: MIT MCP Stars

Quick start · Use it from your agent · How it works · Documentation · Türkçe


Why this exists

An agent working on an unfamiliar repository has to decide what to read before it can decide what to change. The usual answer is embedding search over chunked files. It is cheap to build and wrong in a specific way: it returns text that reads like the question rather than code that participates in the behaviour. Ask about a login timeout and you get the five files that mention timeouts, not the one function that sets it and the three callers that break when you change it.

That information is structural, and it has an exact answer. handleLogin calls refreshSession, which reads SESSION_TTL, which is written in exactly one place. That is a graph walk.

BGTS Context Engine indexes your repositories into that graph — symbols, calls, references, type hierarchies, HTTP routes, cross-language bridges — and answers questions by walking it. Embeddings are used in one place only: finding entry points when the task text names nothing recognisable. They never affect ranking.

The same task text, against the same commit, returns the same context pack. No model in the retrieval path, no clock, no randomness. When an agent makes a bad change you can replay exactly what it was told, find the stage that surfaced the wrong symbol, and fix that stage.

The engine is published so people can run it. Organisations that want the same thing inside their own perimeter — help with indexing, deployment, scoring tuned to their repositories, or the agent stack around it — can engage BGTS for consulting. Write to opensource-ai@bgts.com.

UI walkthrough of the BGTS Context Engine web interface.

Quick start

# 1. PostgreSQL 16 with Apache AGE + pgvector, in one database
docker compose -f deploy/docker-compose.yml up -d

# 2. Install and migrate
pip install bgts-context-engine
cp .env.example .env
bce migrate

# 3. Index something
bce index --repo /path/to/your/repo --name my-service

# 4. Ask
bce context --task "fix the login timeout in the meeting webhook"

Then serve it:

bce serve        # REST at :8000/docs, web UI at :8000/ui/
bce serve-mcp    # MCP over stdio, for agents

Use it from your agent

The MCP surface is behind the mcp extra: pip install "bgts-context-engine[mcp]". It speaks stdio, so every MCP client configures it the same way — bce serve-mcp, plus the database connection in the environment.

Cursor.cursor/mcp.json in the project, or ~/.cursor/mcp.json for every project:

{
  "mcpServers": {
    "bgts-context-engine": {
      "command": "bce",
      "args": ["serve-mcp"],
      "env": { "BCE_DB_HOST": "localhost", "BCE_DB_NAME": "bce" }
    }
  }
}

Claude Code — one command:

claude mcp add bgts-context-engine --env BCE_DB_HOST=localhost -- bce serve-mcp

VS Code.vscode/mcp.json:

{
  "servers": {
    "bgts-context-engine": { "type": "stdio", "command": "bce", "args": ["serve-mcp"] }
  }
}

Claude Desktop — same block as Cursor, in claude_desktop_config.json.

Without a global install, uvx --from "bgts-context-engine[mcp]" bce serve-mcp works as the command anywhere above.

Then ask your agent something that needs the repository rather than the file you have open: "what breaks if I change the session TTL?" The agent calls get_context_for_task, and the fourteen tools in docs/mcp.md let it drill from there — exact callers, type hierarchy, route handlers — without guessing at file names.

What comes back

Not a list of file paths. A ranked pack, with the reasoning attached:

{
  "anchors": {
    "python::api::webhooks::handle_meeting_webhook#a3f1": ["explicit", "lexical"],
    "python::auth::session::refresh_session#88c2":        ["lexical", "semantic"]
  },
  "context": {
    "items": [
      { "symbol_id": "...refresh_session#88c2", "detail_level": "full",
        "graph_distance": 0, "score": 11.42, "tokens": 214, "content": "def refresh_session(...)" },
      { "symbol_id": "...SESSION_TTL#4b0d",     "detail_level": "signature",
        "graph_distance": 2, "score": 6.10,  "tokens": 31,  "content": "SESSION_TTL: int" }
    ],
    "used_tokens": 2913, "budget": 4000, "included": 8, "skipped": 0
  },
  "coverage": {
    "anchor_source_count": 3, "connected_component_ratio": 0.875,
    "top_candidate_margin": 1.84, "orphan_ratio": 0.0,
    "touches_god_node": false, "commit_mismatch": false,
    "confidence": "high"
  }
}

Three things here that a vector store cannot give you:

anchors says why the engine looked where it did, and which independent sources agreed. Three sources agreeing is usually right; one is a guess.

coverage is a trust report. confidence: "low" means the engine found something but could not corroborate it — the moment for an agent to ask a follow-up question instead of editing. commit_mismatch means the index is behind your working tree.

detail_level falls off with graph distance: the symbol you are changing arrives in full, its neighbours as signatures, the outer ring as name @ file:line. That is how eight genuinely relevant symbols fit in 4000 tokens.

How it works

task text
   │
   ├─ anchors       four independent sources nominate entry points:
   │                explicit names, task history, full-text, vector
   ├─ expansion     fixed-shape graph walk: callers 2 hops, callees 1,
   │                references, type hierarchy, same-file siblings
   ├─ scoring       weighted sum over reference kind, task signal, centrality,
   │                distance, leaf penalty, edge provenance
   ├─ scope         drop repositories this caller may not see
   ├─ narrowing     keep the top N
   ├─ assembly      fit the token budget, cheaper detail further out
   └─ coverage      report how much of this is trustworthy

Callers reach two hops and callees only one, on purpose: when you change a function, what breaks is upstream of it. Reference kind carries the heaviest weight, because a place that writes a value is where the bug lives while a place that reads it is usually just downstream. Centrality saturates at degree 20, because a logger touches everything and explains nothing.

The full formula, every weight, and the confidence thresholds are in docs/retrieval.md.

Features

  • Code graph, not chunks. Symbols, CALLS, REFERENCES, INHERITS, IMPLEMENTS, IMPORTS, HTTP ROUTES_TO handlers, and WHY: comments bound to what they explain.
  • Deterministic by construction. Sorted traversal, stable tiebreaks, versioned scoring weights. bce bench verifies it by running each case repeatedly and comparing output.
  • Six languages. Python, JavaScript and TypeScript built in; Java, C# and Go behind the langs extra. Adding one touches two files.
  • Cross-language call edges. React Native and Expo bridges connect NativeModules.Foo.bar() in TypeScript to bar in Objective-C, Swift or Kotlin — a hole no single parser can see.
  • Edge provenance you can audit. scip from a real compiler index, treesitter from syntax, heuristic from a pattern match. Scored differently, reported per response.
  • Incremental re-indexing. git diff decides what to re-parse. Symbol ids survive file moves and reformatting, so history and embeddings stay valid.
  • One database. Apache AGE and pgvector in the same PostgreSQL, so one query joins a graph traversal, a vector search and a SQL filter — and one pg_dump backs up the index.
  • MCP and REST from one implementation. Fourteen tools over stdio, the same functions over HTTP. Nothing to drift.
  • A UI that explains itself. /ui ships in the wheel and replays a real retrieval call stage by stage: anchors lighting up, expansion spreading, candidates scored and cut.
  • Runs offline. The default embedding provider is deterministic arithmetic over token digests. No API key, no network, repeatable benchmarks.

Where it fits

Embedding RAG Language server BGTS Context Engine
Retrieval basis text similarity compiler index code graph + anchors
Cross-file, cross-repo weak per project yes
Cross-language edges no no yes, heuristic
Same query, same answer no yes yes
Ranked for a task by similarity not ranked yes, with coverage
Token budget aware chunk count no yes, detail by distance
Explains its own answer no no anchors + provenance + confidence

A language server is exact but scoped to what you have open. Embedding search is broad but unaccountable. This sits between them: repository-wide and cross-language like the former, exact and reproducible like the latter.

Measuring it

Retrieval quality claims are worthless without the task set they were measured on, so the harness ships instead of a leaderboard. You give it your own tasks and the symbols you believe answer them:

bce bench --cases my-tasks.json --out report.json

Each case is a task text plus its ground-truth symbol_ids. The report gives recall, precision, precision@1 and MRR per case, median and p95 latency, and two pass/fail checks that matter more than the scores: every case is run repeatedly and must return a byte-identical ordering, and any case with a scoped principal must not surface a repository that principal cannot read.

Building the case file is the real work — it means deciding, by hand, what the right answer is. It is also the only honest way to know whether a change to the scoring weights helped. The format and a worked example are in docs/deployment.md.

Roadmap

Ordered by how often it comes up, not by difficulty:

  • Scope enforcement on every layer. Layer 3 applies the per-user repository filter; Layers 1 and 2 do not. Until that closes, the API belongs behind a proxy — see SECURITY.md.
  • Streamable HTTP transport for MCP. Today the MCP surface is stdio only, so the server runs next to the agent. Remote transport makes one index serve a team.
  • More languages. Rust, Kotlin and PHP are the most requested. The provider interface is the contribution path with the least friction — see docs/languages.md.
  • Wider SCIP ingestion. Compiler-grade edges beat syntax-derived ones and are scored as such; more toolchains means more of the graph carries scip provenance.
  • A published benchmark corpus. An open task set over public repositories, so results are comparable between projects rather than only between your own runs.

Requests and disagreements belong in issues — what people actually ask for reorders this list.

Documentation

Architecture the deterministic line, the three layers, indexing
Retrieval anchors, expansion, every scoring weight, confidence
Data model node labels, edge types, tables, symbol identity
MCP and API all 14 tools, every endpoint, the CLI
Languages what each parser extracts, and how to add one
Deployment configuration reference, jobs, backup, benchmarking
Web interface developing the frontend

Contributing

Contributions are welcome — especially new languages, which is the contribution the pipeline is most ready for.

Read CONTRIBUTING.md first. The one rule worth knowing up front: determinism is the product. A change that makes the same task return different results will not be merged without an explicit opt-in flag, and anything touching scoring or ordering needs a test that pins the output.

pip install -e ".[dev,mcp]"
ruff check src tests scripts && pytest
cd web && npm ci && npm test

Security

The engine has no authentication of its own and expects to sit behind something that does. Only the Layer-3 endpoints apply the per-user repository scope. Read SECURITY.md before exposing a port, and report vulnerabilities privately rather than in an issue.

License

MIT © BGTS.

Built by Oğuz Öztürk and Enes İyidil.

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

bgts_context_engine-0.2.0.tar.gz (274.2 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

bgts_context_engine-0.2.0-py3-none-any.whl (304.9 kB view details)

Uploaded Python 3

File details

Details for the file bgts_context_engine-0.2.0.tar.gz.

File metadata

  • Download URL: bgts_context_engine-0.2.0.tar.gz
  • Upload date:
  • Size: 274.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/7.0.0 CPython/3.12.14

File hashes

Hashes for bgts_context_engine-0.2.0.tar.gz
Algorithm Hash digest
SHA256 69947d1aa1a16361131ee406987b5b2a1c4be3175a74738801975d7e534e0230
MD5 eb8730fb2b3d146a5eccc4dcfcf8c165
BLAKE2b-256 ef2e3519b0dfa3004e75ee17eff99d7721010483657280f711cdb653f3cac9d1

See more details on using hashes here.

File details

Details for the file bgts_context_engine-0.2.0-py3-none-any.whl.

File metadata

File hashes

Hashes for bgts_context_engine-0.2.0-py3-none-any.whl
Algorithm Hash digest
SHA256 98748636f82d44ee124f46988e501077a420ea7eefa5752367ca8c6859c77b79
MD5 c3b94467902bed0b9a99f6c86d56dacb
BLAKE2b-256 3ba00011444d00556de205e013e184615fa0a8a02a449aba4825d302c264eb86

See more details on using hashes here.

Release history Release notifications | RSS feed

0.2.1

2 files

This release

0.2.0 This release

2 files

0.1.0

2 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page