TL;DR:
in pure Python. Earlier than sending something to the mannequin, it figures out what your goal file really relies on, trims non-essential code right down to pure interfaces, and drops every part unreachable.
Examined it on two actual Python repos: it reduce immediate sizes by 69–74% and ran in underneath 75 ms.
All of the numbers under are pulled straight from captured terminal runs. If the device couldn’t decide one thing with certainty, it explicitly marked it as an alternative of guessing.
Compilers Don’t Simply Compile Code
Compilers are simply filters that know what to maintain. You give one an entry level and a codebase, it traces what really will get known as, throws out the lifeless weight, and outputs an intermediate illustration with solely the element the following step wants. Nothing further.
Most coding brokers don’t deal with immediate development like a compiler. They construct some type of repository map, collect recordsdata they imagine are related, and ship them to the mannequin with comparatively little structural discount. Bigger context home windows assist, however they don’t take away irrelevant context. That further context competes for consideration with the code that really issues. And when window sizes shrink, that bloat triggers compaction. Compaction feels like routine cleanup till it occurs mid-task: the agent summarizes its personal context to make room, then spends the following few turns attempting to reconstruct implementation particulars from a lossy abstract of a abstract. Half the time an agent “forgets” one thing, it’s simply its personal reminiscence administration degrading its recall.
I wished to see what occurs should you construct prompts with the self-discipline of a compiler somewhat than simply retrieving extra stuff.
So I constructed a Context Compiler: a three-pass pipeline written totally with the Python customary library. It resolves what a goal file really reaches, trims these dependencies right down to interfaces, and drops every part else.
Throughout two actual Python repos, it reduce immediate sizes by 69–74% with a compile time underneath 75 ms.
Each quantity right here comes from captured terminal runs of the particular code, not estimates. You’ll be able to take a look at the supply and run the demos your self on https://github.com/Emmimal/context-compiler/.

A fast observe on timing: on July 18, OpenAI quietly dropped the default context window for Codex fashions from 372k right down to 272k tokens. Billing correction or functionality trim, it factors to the identical actuality: you don’t personal the context window measurement. You solely management what you feed into it.
Context Compilation Is Not Context Engineering, Simply As soon as
In 2025, Andrej Karpathy coined “context engineering” to explain the general work of deciding what goes right into a mannequin’s immediate. Context compilation is only one particular software of that idea for supply code. Given a identified codebase and a file you need to edit, it figures out which recordsdata that edit really depends on, then shrinks every part else right down to the smallest usable type. That’s so far as this challenge goes. I’m assuming you already know the way context administration differs from fundamental immediate engineering or retrieval, so I received’t rehash all of that right here. Let’s get proper into how the compiler really works.
Cross 1: Image Decision
Cross 1 solutions one fundamental query: ranging from the file you might be modifying, what else within the repo really issues? It traces express imports first. If a name like .save() can’t be defined by an import, it falls again to checking a repo-wide image desk, increasing outward breadth-first as much as a set hop restrict.
Right here is the precise output captured from a run towards a small check repository designed to hit edge circumstances:
Goal: appviews.py
Reachable recordsdata (3):
hop 1: appservices.py
hop 1: appmodels.py
hop 1: appmodels_order.py
Dynamic dispatch flagged in: [WindowsPath('app/views.py')]
Occasion-decorator hints flagged in: {WindowsPath('app/providers.py'): {'receiver'}}
Title collisions: {'save': [WindowsPath('app/models.py'), WindowsPath('app/models_order.py')]}
apphandlershandler_email.py: MISSED (as anticipated) -- getattr() dispatch is invisible to static evaluation
apphandlershandler_sms.py: MISSED (as anticipated) -- getattr() dispatch is invisible to static evaluation
providers.py and fashions.py had been pulled in by express imports. models_order.py got here in by way of bare-name decision as a result of person.save() and Order.save() share a way identify {that a} easy resolver can’t separate and not using a sort checker.
Discover what was omitted: the 2 handler recordsdata. They’re solely invoked by way of getattr() at runtime, which static evaluation can’t see. Excluding them is the right habits. A device that makes a wild guess right here passes an incorrect dependency graph to the mannequin. Reporting an unknown is all the time higher than making issues up.
Two mechanisms drive this output:
- A typical module index. Each Python file maps to its importable dotted path (like
app/fashions.pyturning intoapp.fashions). Importing resolves by a quick dictionary lookup as an alternative of guessing towards the filesystem. - An emblem map fallback. When an import doesn’t clarify a name, the compiler checks a desk of each operate and sophistication definition throughout the repo to seek out the place it lives.
Traversing that is strictly breadth-first. Every thing found at hop 1 will get parsed for its personal calls to construct the hop 2 frontier. Recordsdata are tracked so each is visited as soon as, stopping when the hop restrict is reached or there’s nothing left to scan.
Cross 2: Interface Extraction
Cross 2 handles recordsdata which can be reachable however should not the file you might be modifying. It strips them down to reveal interfaces, preserving operate signatures and docstrings whereas changing each operate physique with a single placeholder.
Here’s a actual before-and-after output from a run:
Unique: 448 chars | Skeleton: 173 chars | 1 operate physique stripped
class PaymentProcessor:
"""Handles cost seize."""
def cost(self, quantity, forex='USD'):
"""Cost a card for `quantity` in `forex`."""
...
That cuts this class down by 61% whereas leaving the signature, default values, and docstrings intact.
When an agent edits a file that calls cost(), it must know the tactic exists and what arguments it expects. It doesn’t want the interior implementation logic. Spending context window funds on these particulars for each dependency is exactly what this go cuts out.
Cross 3: Context Meeting
Cross 3 takes the output from the primary two passes, builds a three-tier context, and studies the precise token price:
Goal file: C:UsersAdminAppDataLocalTempcontext_compiler_demo_1jspidadappviews.py
Repo recordsdata scanned: 9
Tier 1 (full supply): 1 file
Tier 2 (skeletonized): 3 recordsdata
Tier 3 (excluded): 5 recordsdata
Naive full-dump estimate: 556 tokens
Compiled context: 362 tokens
Discount: 34.9%
Construct time: 12.45 ms
Warning: 1 file(s) use getattr()-based dynamic dispatch — targets could also be lacking from tier 2.
Warning: 1 file(s) use event-style decorators (e.g. @receiver) — handlers could also be lacking from tier 2.
Notice: 1 name identify(s) resolved to multiple file (name-only decision) — tier 2 might embrace false positives.
Mapped onto the precise repository, these three tiers appear to be this:

The 34.9% token discount right here comes from the nine-file check repo. It’s not meant to be a headline stat. The aim of this run is to indicate how the compiler handles actual failure modes, flagging potential points explicitly within the terminal output somewhat than hiding them in a log file.
The first knob you may modify throughout all three passes is max_hops, which controls how far Cross 1 expands.
| max_hops | What reaches Tier 2 | Commerce-off |
| 1 | Direct imports and calls solely | Smallest payload, however a secondary helper operate could be missed. |
| 2 | Direct dependencies plus one layer out | Balanced default used for all benchmark runs under. |
| 3+ | Wider transitive neighborhood | Captures a bigger name graph, however financial savings diminish as depth grows. |
All benchmarks within the subsequent part had been run with max_hops=2. This must be tuned primarily based on the duty: preserve it wider when exploring unfamiliar code, and tighten it down as soon as you already know the native dependency construction.
Measuring the Compiler
Listed below are three separate benchmarks with three distinct functions, all pulled straight from captured terminal output somewhat than calculated estimates:
| Repository | Objective | Recordsdata | Naive tokens | Compiled tokens | Discount | Construct time |
| Artificial check repo | Confirm edge circumstances explicitly | 9 | 556 | 362 | 34.9% | N/A |
| context-compiler (self) | Reproducibility | 7 | 9,379 | 2,867 | 69.4% | 49 ms |
| loop-engine (exterior) | Take a look at generalization | 12 | 13,254 | 3,404 | 74.3% | 66 ms |
The self-benchmark exists purely for reproducibility. You’ll be able to clone the repo, run benchmark.py, and hit that precise 69.4% determine your self with out taking my phrase for it.
The loop-engine run is what really reveals generalization. It’s an exterior challenge I didn’t contact whereas constructing the compiler, but the discount remained in the identical 70% ballpark regardless of a totally completely different import construction.
Take a look at setting for each actual repo runs: Python 3.12, CPU solely, Home windows 11, customary library solely, with max_hops=2. Finish-to-end compile occasions ranged from roughly 43 to 73 milliseconds throughout repeated runs on each repositories, utilizing benchmark.py straight. Token counts use an ordinary characters // 4 estimate, so concentrate on the relative percentages somewhat than the precise token numbers.
To be clear: a naive full-repo dump is an higher sure, not essentially what trendy agent instruments do. Options like Aider’s repo map, Cursor’s context choice, and Claude Code already carry out some type of file filtering.
The extra correct comparability is towards a flat repo map that skeletonizes each file with out checking reachability. That’s the place three-tier meeting makes a distinction. A flat repo map nonetheless pays a token price for each single file within the workspace. This compiler pays zero for something the resolver marks as unreachable.
Within the loop-engine run, 9 out of 12 recordsdata had been excluded totally somewhat than skeletonized. A flat repo map can’t shut that hole.
I’ve not benchmarked this on huge monorepos with lots of of recordsdata, so I’m not making claims about efficiency at that scale. Multi-file Python tasks within the tens-of-files vary symbolize the precise examined scope right here.
Who Ought to Really Attain for This
Now that the numbers are out of the way in which, right here is the place this device really is sensible to make use of.
That is value including to your setup if:
- You run multi-file agent duties the place many of the repo is irrelevant to the lively edit.
- It is advisable to keep strictly inside a good context funds.
- Your agent must know that exterior strategies exist with out burning tokens on their full implementations.
Skip it for single-file scripts. A easy file dump is already low-cost sufficient that compilation doesn’t matter there.
Skip it for codebases that rely closely on dynamic dispatch or occasion buses with out static registries. That’s the place static evaluation falls quick.
And skip it, at the least proper now, in case your repository is so giant that constructing the module index on each run causes a noticeable bottleneck. I break down that constraint within the trade-offs part under somewhat than ignoring it.
A easy sanity verify: in case your agent failed lately as a result of it acquired overwhelmed by unrelated code in its context window, this layer straight solves that downside. If it failed due to imprecise directions, this is not going to enable you. That’s nonetheless a immediate engineering downside.
The place Compilation Fails
Resolving calls by identify as an alternative of by sort creates three particular blind spots, all seen within the Cross 1 output proven earlier:
- Dynamic dispatch. Within the check repository,
dispatch_handler()finds its goal utilizingimportlib.import_module()andgetattr()with runtime f-strings. The compiler excludes each vacation spot recordsdata and flags them explicitly somewhat than guessing. Reporting an unknown is best than offering a improper dependency graph. - Occasion-driven registration. Capabilities adorned with patterns like
@receiverfireplace at runtime with out direct imports or express calls from the lively file. The resolver flags frequent event-decorator names as hints somewhat than resolved dependencies, since static evaluation can’t verify reachability. - Title collisions. Resolving by naked methodology identify means
person.save()andOrder.save()look equivalent when looking for.save(). Each recordsdata get pulled into Tier 2. This doesn’t break the output, but it surely inflates token depend with an additional interface skeleton. That may be a protected course to fail in in comparison with dropping vital code.
These trade-offs are intentional: pace and nil dependencies over a full type-aware name graph. Codebases that favor express imports over string-based plugin loading, and preserve express registries for occasions, make these blind spots traceable once more. That’s customary observe for human builders utilizing fundamental reference searches, and it seems to matter for a similar causes when the reader is an agent.
To place this concretely: if an agent traces a bug by a middleware layer that dispatches handlers by string identify, it receives an express warning, a flagged getattr() name, and two excluded handler recordsdata. It doesn’t get an accurate handler by luck or a improper handler delivered with false confidence. The output tells you or the agent exactly the place static evaluation stopped, so no one spends time chasing dangerous context.
That’s the core design selection right here: an incomplete map with express warnings is much extra helpful than a whole map that’s secretly improper.
Engineering Commerce-offs
Each compiler design entails trade-offs. Right here is the place the present implementation makes compromises:
- Setting
max_hops=2is empirical. It labored effectively throughout the check repositories, however a codebase with deeper name chains may wantmax_hops=3. - Title-only name decision prioritizes pace and ease. It runs in microseconds and requires zero exterior dependencies, but it surely causes the identify collision points famous earlier. Including a full sort checker would repair these collisions, however it might destroy the “clone and run with customary Python” setup.
- Token counts use
characters // 4. This heuristic is okay for tough estimates, but it surely strays on dense code. When you want precise counts, changing it withtiktokenincompiler.pytakes one line. - The decorator checklist is hardcoded, and the module index rebuilds on each run. The occasion hints depend on a static checklist of frequent framework decorators, and
ModuleIndexrescans the listing per execution. Each may very well be cached or made configurable later, however they weren’t blockers for this model. - Tiering is strictly binary. You get full supply for the edit goal, and skeletons for each different reachable file. A hop 1 dependency and a hop 2 dependency obtain equivalent therapy as soon as they clear the resolver. Treating all reachable dependencies the identical retains the logic straightforward to cause about, even when it sacrifices some nuance at increased hop limits.
Operating It Your self
Each quantity on this article will be verified regionally. You solely want Python 3.9 or increased:
git clone https://github.com/Emmimal/context-compiler.git
cd context-compiler
python demo.py
That command builds the artificial check repo utilized in Cross 1 and Cross 2, runs the pipeline, and finishes with a benchmark towards the compiler’s personal codebase.
To run it towards your personal challenge:
python benchmark.py /path/to/repo /path/to/repo/target_file.py --max-hops 2
Cross the repo root as the primary argument, and the file you might be actively modifying because the second. That file will get full-source therapy whereas every part reachable will get skeletonized. That is the precise command used to generate the benchmark outcomes above.
What’s Subsequent
A kind-aware resolver would repair the name-collision concern. A cached module index would pace issues up on bigger repos. Swapping in a real tokenizer would give precise numbers as an alternative of estimates. None of those additions change the underlying premise, they only lengthen it.
Compilers don’t exist to make applications shorter. They make them executable by isolating what the following stage really requires. A context compiler doesn’t make a codebase smaller, but it surely makes passing that code to an LLM sensible by filtering for what really belongs within the immediate.
Context limits will preserve shifting on vendor schedules, typically rising and sometimes shrinking. Counting on compiler self-discipline as an alternative of context window measurement protects your workflow no matter what limits an API exposes. That design precept will outlast any single benchmark determine on this publish.
Supply code, runnable demos, and the CLI can be found on https://github.com/Emmimal/context-compiler/
References
[1] GitHub, openai/codex, PR #33972 “Backport refreshed bundled mannequin metadata to 0.144” (merged July 18, 2026). https://github.com/openai/codex/pull/33972
[2] Karpathy, A. (2025). Context Engineering. https://x.com/karpathy/standing/1937902205765607626
[3] OpenAI. (2023). tiktoken: Quick BPE tokeniser to be used with OpenAI’s fashions. https://github.com/openai/tiktoken
[4] Aho, A., Lam, M., Sethi, R., & Ullman, J. (2006). Compilers: Rules, Strategies, and Instruments (2nd ed.). Addison-Wesley, supply of the pass-based, tiered intermediate-representation framing used all through this text.
Disclosure
All code on this article is unique work, written and examined on Python 3.12, on Home windows 11 and Linux. Each benchmark and terminal output proven is from an actual, captured run of demo.py or benchmark.py, reproducible by cloning the repository linked above; nothing right here is calculated or estimated besides the place explicitly marked as a heuristic. I’ve no monetary relationship with OpenAI, Anthropic, Cursor, Aider, or another device talked about on this article.















