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 minimize immediate sizes by 69–74% and ran in beneath 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 useless weight, and outputs an intermediate illustration with solely the element the subsequent step wants. Nothing additional.
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 additional context competes for consideration with the code that truly 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 subsequent few turns making an attempt 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 if you happen to construct prompts with the self-discipline of a compiler relatively than simply retrieving extra stuff.
So I constructed a Context Compiler: a three-pass pipeline written solely with the Python normal 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 minimize immediate sizes by 69–74% with a compile time beneath 75 ms.
Each quantity right here comes from captured terminal runs of the particular code, not estimates. You’ll be able to try the supply and run the demos your self on https://github.com/Emmimal/context-compiler/.
A fast be aware 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 dimension. 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 utility 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 understand how context administration differs from primary immediate engineering or retrieval, so I gained’t rehash all of that right here. Let’s get proper into how the compiler really works.
Move 1: Image Decision
Move 1 solutions one primary query: ranging from the file you might be enhancing, 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/companies.py'): {'receiver'}}
Identify 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
companies.py and fashions.py had been pulled in by express imports. models_order.py got here in through bare-name decision as a result of consumer.save() and Order.save() share a way identify {that a} easy resolver can not separate with no kind checker.
Discover what was disregarded: the 2 handler recordsdata. They’re solely invoked through getattr() at runtime, which static evaluation can not see. Excluding them is the right conduct. 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:
- An ordinary 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. - A logo 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 search 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. Information are tracked so each is visited as soon as, stopping when the hop restrict is reached or there’s nothing left to scan.
Move 2: Interface Extraction
Move 2 handles recordsdata which might be reachable however aren’t the file you might be enhancing. It strips them down to reveal interfaces, holding operate signatures and docstrings whereas changing each operate physique with a single placeholder.
Here’s a actual before-and-after output from a run:
Authentic: 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 strategy 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 cross cuts out.
Move 3: Context Meeting
Move 3 takes the output from the primary two passes, builds a three-tier context, and studies the precise token value:
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.
Observe: 1 name identify(s) resolved to a couple of file (name-only decision) — tier 2 might embrace false positives.
Mapped onto the precise repository, these three tiers seem like this:

The 34.9% token discount right here comes from the nine-file check repo. It isn’t meant to be a headline stat. The aim of this run is to point out how the compiler handles actual failure modes, flagging potential points explicitly within the terminal output relatively than hiding them in a log file.
The first knob you possibly can regulate throughout all three passes is max_hops, which controls how far Move 1 expands.
| max_hops | What reaches Tier 2 | Commerce-off |
| 1 | Direct imports and calls solely | Smallest payload, however a secondary helper operate is likely to 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: maintain it wider when exploring unfamiliar code, and tighten it down as soon as you understand the native dependency construction.
Measuring the Compiler
Listed here are three separate benchmarks with three distinct functions, all pulled straight from captured terminal output relatively than calculated estimates:
| Repository | Function | Information | 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 surroundings for each actual repo runs: Python 3.12, CPU solely, Home windows 11, normal 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 a typical characters // 4 estimate, so deal with the relative percentages relatively than the precise token numbers.
To be clear: a naive full-repo dump is an higher certain, 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 value 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 solely relatively than skeletonized. A flat repo map can not shut that hole.
I’ve not benchmarked this on large 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 characterize the precise examined scope right here.
Who Ought to Really Attain for This
Now that the numbers are out of the best way, right here is the place this device really is smart to make use of.
That is price including to your setup if:
- You run multi-file agent duties the place many of the repo is irrelevant to the energetic edit.
- It’s essential 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 very least proper now, in case your repository is so massive that constructing the module index on each run causes a noticeable bottleneck. I break down that constraint within the trade-offs part under relatively than ignoring it.
A easy sanity examine: in case your agent failed just 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 won’t assist you. That’s nonetheless a immediate engineering downside.
The place Compilation Fails
Resolving calls by identify as an alternative of by kind creates three particular blind spots, all seen within the Move 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 relatively than guessing. Reporting an unknown is healthier than offering a unsuitable dependency graph. - Occasion-driven registration. Capabilities embellished with patterns like
@receiverhearth at runtime with out direct imports or express calls from the energetic file. The resolver flags widespread event-decorator names as hints relatively than resolved dependencies, since static evaluation can not affirm reachability. - Identify collisions. Resolving by naked technique identify means
consumer.save()andOrder.save()look equivalent when looking for.save(). Each recordsdata get pulled into Tier 2. This doesn’t break the output, however it inflates token rely with an additional interface skeleton. That may be a secure path to fail in in comparison with dropping crucial code.
These trade-offs are intentional: pace and 0 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 normal apply for human builders utilizing primary 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 unsuitable 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 unsuitable.
Engineering Commerce-offs
Each compiler design includes 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 would possibly wantmax_hops=3. - Identify-only name decision prioritizes pace and ease. It runs in microseconds and requires zero exterior dependencies, however it causes the identify collision points famous earlier. Including a full kind checker would repair these collisions, however it will destroy the “clone and run with normal Python” setup.
- Token counts use
characters // 4. This heuristic is ok for tough estimates, however it strays on dense code. When you want precise counts, changing it withtiktokenincompiler.pytakes one line. - The decorator listing is hardcoded, and the module index rebuilds on each run. The occasion hints depend on a static listing of widespread framework decorators, and
ModuleIndexrescans the listing per execution. Each might 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 motive about, even when it sacrifices some nuance at greater hop limits.
Operating It Your self
Each quantity on this article might be verified regionally. You solely want Python 3.9 or greater:
git clone https://github.com/Emmimal/context-compiler.git
cd context-compiler
python demo.py
That command builds the artificial check repo utilized in Move 1 and Move 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
Move the repo root as the primary argument, and the file you might be actively enhancing 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 sort-aware resolver would repair the name-collision situation. 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 prolong it.
Compilers don’t exist to make applications shorter. They make them executable by isolating what the subsequent stage really requires. A context compiler doesn’t make a codebase smaller, however it makes passing that code to an LLM sensible by filtering for what really belongs within the immediate.
Context limits will maintain shifting on vendor schedules, generally rising and sometimes shrinking. Counting on compiler self-discipline as an alternative of context window dimension protects your workflow no matter what limits an API exposes. That design precept will outlast any single benchmark determine on this submit.
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, Methods, 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.
