Context Budget Engine
by sivram04
README.md
<h1 align="center">Context Budget Engine</h1>
<p align="center">The context layer that teaches AI coding agents to read less, and keeps improving itself.</p>
<p align="center">
<a href="https://github.com/sivram04/context-budget-engine/actions/workflows/ci.yml"><img src="https://github.com/sivram04/context-budget-engine/actions/workflows/ci.yml/badge.svg" alt="CI"></a>
<img src="https://img.shields.io/badge/python-3.11%2B-3776ab" alt="Python 3.11+">
<img src="https://img.shields.io/badge/MCP-server-1a7f64" alt="MCP server">
<a href="LICENSE"><img src="https://img.shields.io/badge/license-MIT-blue" alt="MIT license"></a>
</p>
<p align="center">
<strong>Most of an agent's tokens are not spent thinking.</strong><br>
They are spent re-reading whole files, long logs and search dumps, on every step.
</p>
<p align="center">
<strong>40 tasks. 3 runs each. −40% tokens. No drop in success.</strong><br>
Then I plugged it into Claude Code: same 10/10 answers with 22% fewer input tokens.
</p>
<p align="center">
Ask a question about a file. It returns the functions that matter, not the whole file.<br>
A gated loop rewrites its own reading policy, and <strong>only keeps changes that are proven cheaper without losing tasks.</strong>
</p>
<p align="center">
<picture>
<source media="(prefers-color-scheme: dark)" srcset="docs/results-dark.svg">
<img src="docs/results-light.svg" alt="Input tokens per task: benchmark agent 26,394 with whole files vs 15,801 with the engine (−40%); Claude Code 49,838 with built-in Read vs 38,820 with read_smart (−22%); success equal or better in both" width="800">
</picture>
</p>
<p align="center"><a href="#your-turn">Try it in one minute ↓</a> · <a href="#results">See every number, including the ones that went wrong →</a></p>
## Your turn
Connect it to the AI assistant you already use. No API key needed.
```bash
git clone https://github.com/sivram04/context-budget-engine && cd context-budget-engine
python -m venv .venv && source .venv/bin/activate # Windows: .venv\Scripts\activate
pip install -e .
claude mcp add cbe -- cbe-mcp
```
Then ask Claude Code something about your codebase and tell it to use `read_smart`. Run
`savings` at any time to see how many tokens it did not have to read.
<p align="center"><sub>Open source. Local. Works with Claude Code, Claude Desktop, Cursor and any MCP client.</sub></p>
## The principles
> Read the part, not the file. Measure, don't assume. A change ships only if it is cheaper **and** solves as many tasks. The loop edits policies, never the judge. Report the noise, not just the best run.
## What it does for you
| Feature | Description |
|---|---|
| **`read_smart`** | Reads a file the way the question needs: the matching functions (AST-based for Python), a skeleton of signatures, a grep window, or the whole file when it is small. Never returns more than the file itself |
| **`log_smart`** | The errors, warnings and last lines of a log, not 10,000 lines of INFO |
| **`search_smart`** | Regex search that returns short `file:line: text` hits, skips caches, binaries and huge files, and caps the result count |
| **`savings`** | Running total of tokens returned vs. what full reads would have cost, and the % saved |
| **Policy file** | One small YAML file (`policies/v1.yaml`) decides which strategy to use by file kind, size and whether there is a question. Strictly validated |
| **Self-improvement loop** | `cbe improve` runs the agent, finds token hot spots and failures, proposes a new policy (LLM optimizer or model-free local search), and passes it through a train + held-out gate |
| **Noise-aware gate** | Every candidate runs several times; it is accepted only if it beats the mean by a minimum effect size on training tasks and does not lose held-out tasks. Duplicate proposals are skipped for free |
| **Benchmark + judge** | 40 tasks on a real codebase: 20 exact-answer questions and 20 planted bugs judged by the repo's own test suite. Verified by `scripts/verify_tasks.py` |
| **Works without a key** | The optional `summarize` strategy uses a cheap model; with no key or a failed call it falls back to a model-free view |
| **Hard budget** | Paid runs stop at `CBE_MAX_USD`, save progress, and resume where they left off |
## What it will not do
- **It never edits your code.** It only decides what the assistant reads.
- **The loop cannot grade itself.** It may only write policy files: never the tasks, the judge, the gate or the agent.
- **It never claims a win the gate did not measure.** Rejected rounds and noisy runs are published below, next to the good ones.
- **It never sends your code anywhere.** The MCP tools run locally; only the optional `summarize` strategy calls a model, and only if you configure one.
## How it works
```
┌──────── cbe improve (self-improvement loop) ────────┐
│ run → measure → diagnose → propose policy → gate │
└───────────────┬─────────────────────────────────────┘
│ edits only the policy (policies/vN.yaml)
test agent / Claude Code ▼
└──► read_smart(path, query) ──► policy picks a strategy ──► reduced view
full · skeleton · extract · grep_window
log_tail · head · summarize (cheap model)
benchmark + judge (read-only) ──► results/*.jsonl ──► cbe report
```
**The gate** (`src/cbe/improve.py`): a candidate must be cheaper on the 27 training tasks by a
minimum margin with no meaningful loss of success, *and* must not lose success on the 13
held-out tasks. **Proposals** come from an LLM that reads the failures and token hot spots,
and from a model-free local search so the loop still works with weak models.
## Results
All raw per-task results are in `results/`. Agent model: Gemini 3.1 Flash-Lite.
### 1. Baseline vs engine, 3 runs each, all 40 tasks
| Policy | Success, mean ± sd (runs) | Tokens / task, mean ± sd |
|---|---|---|
| v0: read whole files | 95.0% ± 0.0 (95, 95, 95) | 26,394 ± 1,673 |
| **v1: Context Budget Engine** | **96.7% ± 3.8 (100, 92, 98)** | **15,801 ± 1,037 (−40%)** |
Paired by task, v1 is cheaper on 27/40 tasks (median ratio 0.75). The −40% is far outside the
~6% run-to-run spread; the success difference is within noise. On bug fixes alone, the first
run used 49,476 → 24,490 tokens per task (−50%).
### 2. Claude Code, with vs without the MCP tools
Same model (Sonnet), same repo copy, isolated config; only the reading tools differ
(`scripts/claude_code_check.py`).
| | Correct | Input tokens / task | Output tokens / task | Turns / task |
|---|---|---|---|---|
| Built-in Read | 10/10 | 49,838 | 538 | 4.3 |
| **`read_smart`** | **10/10** | **38,820 (−22%)** | **376 (−30%)** | **3.2** |
Fewer input tokens on 8 of 10 questions. Caveats: one run per arm; the files are short; and the
list-price cost came out about equal ($0.031 vs $0.033 per question) because the MCP tool calls
caused extra cache writes, which are priced higher than cache reads.
### 3. The self-improvement loop, honestly
**First attempt (1 run per evaluation): 6 rounds, all rejected.** Three times the optimizer
proposed a policy identical to v1, and those re-runs of the *same* policy scored 88.9%, 96.3% and
92.6%. One run cannot tell a real gain from noise, so the gate was rebuilt.
**Noise-aware loop (3 runs per evaluation, ≥5% cheaper, ≤2 pts success drop):**
| Round | Outcome |
|---|---|
| 1 | **Accepted as v2**: training 19,201 → 18,195 tokens/task (−5.2%) at 97.5%; held-out 100% → 100% |
| 2, 3, 5 | Rejected: training success fell to 90.1%, 91.4%, 91.4% |
| 4 | Rejected: success fell to 95.1% |
| 6 | Rejected: only −2.3% tokens, below the bar |
One small verified improvement, and five candidates refused, four of which would have traded
success for tokens. All of them came from the model-free search: the Flash-Lite optimizer only
re-proposed existing policies. Whole study (noise check + loop): **$3.49**.
## Usage
### MCP tools
| Tool | What it does |
|---|---|
| `read_smart(path, query, full=false)` | Read the relevant part of a file for a question |
| `log_smart(path, lines)` | Errors, warnings and the tail of a log file |
| `search_smart(root, pattern)` | Compact repository search |
| `savings()` | Tokens saved so far |
Claude Desktop / Cursor: add to `claude_desktop_config.json` / `.cursor/mcp.json`:
```json
{ "mcpServers": { "cbe": { "command": "/full/path/to/.venv/bin/cbe-mcp" } } }
```
### Commands
| Command | What it does |
|---|---|
| `cbe benchmark --policy policies/v1.yaml` | Run a policy on the 40 tasks (resumable) |
| `cbe improve --repeats 3 --min-gain 0.05` | Run the gated self-improvement loop |
| `cbe report --held-only` | Summarise result files |
| `python scripts/noise_report.py <dir>` | Mean ± sd across repeated runs, paired by task |
| `python scripts/claude_code_check.py --n 10` | The Claude Code with/without comparison |
Any OpenAI-compatible endpoint works for the benchmark and the loop (Gemini, Groq, local Ollama).
Copy `.env.example` to `.env`:
```bash
CBE_PROVIDER=gemini GEMINI_API_KEY=... CBE_MAX_USD=3.0
```
## Benchmark
40 tasks on a fixed snapshot of a real codebase (`bench_repos/gateway`, an LLM gateway with 87
tests):
- **20 code-understanding questions** with exact answers, e.g. *"What is the default
cosine-similarity threshold for a semantic cache hit?"*
- **20 bug fixes**: one bug is planted per task from a plain-language report; it passes only if
the repo's own tests pass afterwards.
`scripts/verify_tasks.py` proves every planted bug breaks its tests and every expected answer
exists in the source. The 27 train / 13 held-out split is a stable hash of the task id.
## Project layout
```
src/cbe/strategies.py ways to read less (AST-based for Python, generic for other languages)
src/cbe/policy.py policy schema + strict validation (what the loop may change)
src/cbe/engine.py picks a strategy per read, accounts tokens, keyless fallback
src/cbe/agent.py small JSON-protocol coding agent used for measurement
src/cbe/bench/ tasks, workspaces, judge (read-only), runner
src/cbe/improve.py diagnose / propose / noise-aware gate loop
src/cbe/mcp_server.py MCP tools for real assistants
policies/ v0-full (baseline), v1 (hand-written)
results/ raw results, loop logs and accepted policies (v2)
```
## Contributing
```bash
pip install -e ".[dev]"
pytest
ruff check src tests scripts
python scripts/verify_tasks.py
```
Ideas that would help most: strategies for more languages (tree-sitter), a stronger optimizer
model for the loop, and benchmarks on larger codebases.
## License
MIT. See [`LICENSE`](LICENSE).
This server cannot be deployed
Maintenance
ActivityMaintained
ResponsivenessNo recent community issues