NxtSoftLabs
← All writing

Budgeted context: just enough of your repo for an LLM

July 12, 2026·5 min read

Budgeted context is retrieval-augmented generation for code: instead of handing an LLM your whole repository (which does not fit) or a guess at the relevant files (which misses things), you give it a neighborhood of the code graph around the symbol in question, packed to fit a token budget. CGraph does this with its graph_context tool — it gathers the surrounding graph, packs the most relevant nodes into your budget with a knapsack, and returns a result you can inspect to see exactly what got in and what got dropped.

This is the mechanism behind the one-line setup in Feeding your codebase to Claude Code. That post covers wiring a graph into an agent; this one covers how the graph decides what to send back.

Why "just enough" is the hard part

An agent's context window is finite. The context packing docs frame the whole problem in one line: when the agent asks for context around a node, CGraph "has to choose which of the surrounding graph to include — enough to be useful, few enough to fit."

Both failure modes are real. Dump the whole repo and it does not fit. Pull only the one file the symbol lives in and you lose its callers, its callees, and the types it depends on — the exact structural context that makes an edit safe. RAG-for-code is the middle path: retrieve a relevant subgraph, not the whole thing and not a lucky guess. CGraph splits that into two steps it calls gather and pack.

gather
fixed or adaptive — pick candidate nodes
pack
knapsack the candidates into the budget
reach
counters that explain what happened
Budgeted context in two decisions plus a receipt: which nodes to consider, which fit, and why.

Gather: fixed vs adaptive

The gather step decides which candidate nodes to consider around the target. Per the context packing docs, CGraph offers two modes:

  • gather: "fixed" packs the whole k-hop neighborhood. It is simple and query-independent — you get everything within k hops of the node, regardless of what you asked.
  • gather: "adaptive" keeps the full 2-hop core but expands the third hop only along nodes relevant to the query.

Adaptive gather is the interesting one. The reasoning, quoted directly from the docs: "Expanding every third hop is expensive; expanding none loses relevant context. Adaptive gather targets the middle: it spends tokens only where the query points."

There is one important constraint. Adaptive mode needs a query (q) to work — without one, the relevance gate is a no-op and it behaves exactly like a fixed gather. The query is what tells CGraph which direction to spend its third-hop budget on, so budgeted context is genuinely query-driven, not just neighborhood-sized.

Pack: a knapsack, not a truncation

Gathering produces a set of candidate nodes. Packing decides which of them actually fit the budget. Naively you would take nodes until you run out of room and truncate the rest — but that throws away relevant nodes just because they were considered late.

CGraph instead uses a knapsack strategy (packing: "knapsack"). As the context packing docs put it, the goal is to "fit the most relevant nodes into the budget rather than truncating arbitrarily." The knapsack framing is the right one: each candidate node has a token cost and a relevance value, and the packer maximizes total relevance under the token ceiling. A highly relevant node discovered late still beats a marginal one discovered early.

A budgeted request looks like this:

cgraph-client context '{"q":"Parser","budget":5000}'

That says: gather a neighborhood around what matches Parser, and pack it into 5,000 tokens of the most relevant surrounding code. The same request is available to a coding agent through the graph_context MCP tool — MCP calls route through the same daemon operation handler as the client, so an agent and a shell get identical semantics.

Reach: an inspectable result

The part that makes this trustworthy rather than a black box is that CGraph tells you how it selected the neighborhood. The context packing docs document a reach object on the response:

CounterMeaning
candidatesTotal potential nodes considered.
expanded_past_coreNodes expanded beyond the 2-hop core.
gated_at_coreNodes filtered out at the core boundary.

Alongside those counters, the response carries the gather and packing mode it used. That means you can audit a context bundle after the fact: how many nodes were in play, how many the adaptive gate let through past the core, how many it stopped. Retrieval you can inspect is retrieval you can tune — and it is the difference between "the model got some files" and "the model got these specific nodes, chosen this way, under this budget."

How it fits the retrieval path

Budgeted context is one of CGraph's read operations. The retrieval docs list context alongside query, explain, impact, and path — all of them funnel through a single daemon operation handler behind every front door, whether the caller is the thin client or an agent over MCP. So graph_context is not a bolt-on: it is the same warm graph that answers "who calls this" and "what breaks if I change it," asked to return a packed neighborhood instead of a single fact.

The token payoff of using a packed context bundle instead of reading files by hand is measured, not asserted here: our benchmark post includes a context-bundle task and documents where it wins and where a single targeted read is cheaper (with the caveats — self-run, Debug build, CGraph's own repo). The context-packing docs are equally disciplined: the recall-versus-token tradeoff of adaptive gather is left to the Benchmarks page with methodology, rather than claimed inline.

Try it

If you want to see budgeted context on your own repo, build CGraph (the getting-started guide is the short path) and run a context request with a q and a budget, then read the reach object to see what it chose. To put it in front of a coding agent instead, wire CGraph into your agent over MCP — the Claude Code walkthrough is a one-line setup. The whole engine is open source — read the code on GitHub.