How CodeGraph's Context Builder Algorithm Selects Relevant Code Snippets

CodeGraph's context builder algorithm selects relevant code snippets by combining hybrid symbolic/semantic search with graph traversal, extracting symbol names from task descriptions to execute exact and fuzzy matching against a code graph database, then expanding around high-scoring entry points via BFS while enforcing strict node budgets and diversity constraints.

The context builder in the colbymchenry/codegraph repository transforms natural language task descriptions into focused code contexts by traversing a pre-built graph of your codebase. Located primarily in src/context/index.ts, this sophisticated pipeline balances precision and recall through fourteen distinct stages that rank symbols by relevance before expanding the subgraph.

Parsing Task Descriptions and Extracting Symbols

The algorithm begins by normalizing the input task description into a query string. Whether receiving a plain string or a structured object with title and description fields, the builder concatenates them into a single searchable query.

In src/context/index.ts (lines 17-18), the parsing logic handles both input types:

const query = typeof input === 'string' ? input : `${input.title}${input.description ? `: ${input.description}` : ''}`;

Once normalized, the builder extracts candidate symbol names using regex patterns designed to identify CamelCase, snake_case, SCREAMING_SNAKE_CASE, dot-notation segments, acronyms, and plain identifiers. This extraction phase (lines 43-102) filters out common English words to focus on code-relevant terms.

Hybrid Search: Exact Matches and Stem Variants

The search phase operates through multiple channels to maximize recall. First, the algorithm performs an exact name lookup using queries.findNodesByExactName with a generous result limit. This phase applies a co-location boost that rewards symbols appearing together in the same file, increasing relevance scores when multiple query terms occur in proximity (lines 10-38).

For each extracted term, the builder executes a stem-variant and class-prefix search. It queries for title-cased prefixes—for example, transforming "Rest" into potential matches like RestController—and applies a brevity bonus that favors shorter symbol names (lines 51-89). This heuristic captures common naming conventions while prioritizing concise, likely-relevant identifiers.

Full-Text Search and Result Merging

Parallel to symbolic matching, the algorithm runs full-text search (FTS) against natural language terms. The extractSearchTerms function splits the query into searchable tokens, then queries.searchNodes executes searches for each term. Results matching multiple terms receive compounding relevance boosts, while import statements are excluded by default to focus on implementation code (lines 96-135).

The merging stage (lines 140-176) handles results from all search channels:

  • Duplicate symbols across channels retain only their highest score
  • Test files receive a 0.3x down-weight multiplier unless the query explicitly mentions tests
  • Multi-term co-occurrence triggers additional scoring boosts calculated as +0.5 × termCount

Advanced Matching: CamelCase and Compound Terms

Beyond exact matches, the algorithm employs boundary-aware heuristics for partial matching. The CamelCase-boundary matching phase (lines 448-525) executes substring searches via findNodesByNameSubstring, but retains only matches that cross CamelCase boundaries (e.g., "User" matching "UserManager" but not "SuperUser"). Scores increase when multiple extracted terms hit within the same symbol.

When two or more symbols are extracted from the query, the compound-term matching pass (lines 530-574) identifies nodes containing two or more distinct search terms regardless of case boundaries. These matches receive a large relevance boost for capturing composite concepts like "User Authentication" matching authenticateUser.

Resolving Imports and Building Entry Points

Before graph traversal, the algorithm resolves references to their canonical definitions. Import and export statement nodes are replaced with their actual target definitions by following outgoing imports and exports edges (lines 992-1016).

For class and interface entry points, the builder retrieves type hierarchy information using traverser.getTypeHierarchy to include superclass and subclass relationships. This expansion respects a strict budget, consuming no more than maxNodes / 4 of the total allocation (lines 1019-1037).

Graph Traversal with Budget Constraints

The core expansion mechanism uses breadth-first search (BFS) via traverser.traverseBFS, starting from each entry point and limited by configurable traversalDepth and per-entry-point node budgets (lines 1071-1079).

To prevent context bloat, the algorithm enforces aggressive pruning:

  • Primary capping: If results exceed maxNodes, priority is given to entry points and direct neighbors (lines 1089-1100)
  • Per-file diversity cap: No single file may consume more than approximately 20% of the total node budget
  • Test file limits: Non-production files are restricted to roughly 15% of the budget unless the query is test-focused

After pruning, edge recovery (lines 1095-1109) queries for missing relationships between retained nodes using findEdgesBetweenNodes, ensuring the subgraph maintains connectivity and semantic relationships.

Assembling the Final Context

The final stage compiles the pruned subgraph into a structured TaskContext object. The builder gathers entry points (root nodes), code blocks (source snippets truncated to maxCodeBlockSize), related files, summaries, and statistics. The src/context/formatter.ts module then renders this structure as markdown or JSON according to the requested format (lines 1020-1080).

Usage Example

To utilize the context builder in your own tooling:

import { createContextBuilder } from 'codegraph';
import { QueryBuilder } from './src/db/queries';
import { GraphTraverser } from './src/graph';

// Initialize helpers (normally handled by CodeGraph.init)
const projectRoot = '/path/to/project';
const queries = new QueryBuilder();
const traverser = new GraphTraverser(queries);

const ctxBuilder = createContextBuilder(projectRoot, queries, traverser);

// Build context from natural language
const contextMd = await ctxBuilder.buildContext(
  'Add a retry mechanism to the HTTP client',
  { maxNodes: 15, traversalDepth: 2, format: 'markdown' }
);

// Or use structured input with JSON output
const contextJson = await ctxBuilder.buildContext(
  { title: 'Refactor user service', description: 'split login and registration' },
  { format: 'json', maxCodeBlocks: 3 }
);

Summary

  • Hybrid search strategy: Combines exact symbol lookup, stem-variant matching, and full-text search to balance precision and recall
  • Multi-stage scoring: Applies co-location boosts, brevity bonuses, multi-term rewards, and test-file penalties to rank candidates
  • Graph traversal: Expands from high-scoring entry points using BFS with configurable depth limits
  • Budget enforcement: Maintains diversity through per-file caps (~20%) and test-file limits (~15%) while resolving imports to canonical definitions
  • Edge recovery: Reconstructs relationships between pruned nodes to preserve semantic context

Frequently Asked Questions

How does the algorithm handle test files?

Test files receive a 0.3x relevance penalty during the scoring phase unless the task description explicitly mentions testing keywords. Additionally, non-production files are capped at approximately 15% of the total node budget to prevent test infrastructure from overwhelming production code context.

What is the difference between exact matching and CamelCase boundary matching?

Exact matching requires the search term to match the complete symbol name or a registered stem variant, while CamelCase boundary matching (lines 448-525) accepts partial matches that cross word boundaries within PascalCase or camelCase identifiers. For example, "User" exactly matches User but boundary-matches UserManager and SuperUser.

How does the node budget system prevent context overload?

The system implements a hierarchical budgeting strategy: a global maxNodes limit restricts total context size, while a per-file cap of roughly 20% prevents any single file from dominating. During BFS traversal, the algorithm allocates budgets per entry point and aggressively prunes distant nodes, prioritizing immediate neighbors and high-scoring entry points.

Can the algorithm resolve imported symbols to their definitions?

Yes. During the entry-point preparation phase (lines 992-1016), the algorithm identifies nodes that represent import or export statements and replaces them with their target definition nodes by traversing imports and exports edges. This ensures that the final context contains actual implementation code rather than import references.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →