Agents Need an AST Layer

@devagrawal09
Dev Agrawal@devagrawal09
65 views Aug 13, 2026 ~7 min read
Advertisement

In the last two days I built two codemods. One helps migrate a codebase from one major version of a framework to the next. The other reviews architecture: it reports what a codebase actually does, as evidence rather than opinion. Both are read-only. Both are deterministic. Neither edits your code.

Media image

They are the most important tools I have built for working with coding agents. Not because they are clever. Because they give the agent something to stand on: exact facts about the code, at exact locations, with exact limits.

The Agent Sees Text. The Codemod Sees a Graph.

Agents are held back by text-shaped views of code. The biggest unlock is not a bigger context window or better prompting. It is deterministic program views — ASTs, binding graphs, resolved imports, exact locations.

An agent that receives "file:42, why, guidance, stop conditions" behaves completely differently from an agent that receives "here is the repo, figure it out." The difference is not the model. The difference is the representation: one agent receives conclusions, the other receives a repository and an instruction to discover them.

The first agent is doing review. The second is doing archaeology. Review is a skill you can verify. Archaeology is a hope.

Binding Resolution Is the Whole Point

Semantic analysis is the difference between a tool that finds things and a tool that knows what it found. Shallow AST matching is regex with extra steps. It matches text that looks like code, and it cannot tell you whether the call site is real.

The migration analyzer needs to find every call site of a specific API, every place a renamed or moved function is actually invoked. The reliable way is not to search for the name. It is to find the import binding first, then follow its references to real call sites. A local variable that shadows the API name never matches. Neither does a function from an unrelated module that happens to share the name. Binding resolution knows the difference, because it knows which declaration every reference resolves to.

Every finding is a fact: this call site is really bound to that import, at this file:line:column. That is why semantic analysis matters more than any model choice. A bigger model does not make a finding auditable. A resolved binding does.

Classify Before You Transform

The migration codemod never edits the target. It scans the source, prints one detailed finding per detection, and sorts the output deterministically. The output is a sorted manifest of observations, each with a classification, a reason, and a next action. Repeated runs produce the same ordered output. Fixture tests prove the target files are unchanged. Verification is part of the project, not an afterthought. The analyzer's job is to classify, not to rewrite; the rewriting happens later, by an agent or a human, guided by the classification.

Every finding gets one of three classifications.

Provable. The change is mechanically certain. An import moved: the old path no longer exists in the new version, the new one is the only correct answer, and the rewrite is mechanical. The codemod handles these alone. No model involved. The finding is ready to apply, and the fixture tests prove nothing else moves.

Agent-guided. The codemod can detect the site but cannot decide the replacement. A lifecycle API's replacement runs at a different time, and whether that matters depends on what the callback does. The finding carries the exact location, the why, guidance with explicit stop conditions, and one instruction: ask for the smallest focused test or runtime observation that would settle the decision. The agent acts inside that finding, not around it.

Manual review. Neither tool can decide. An options API changed its precedence rules for edge values, and the right migration depends on whether the call site relied on them. One API has several valid replacements, and the correct one depends on the author's intent. The finding says why and names a next action. No code change.

The tool is not guessing. It is telling you exactly what it cannot know and exactly what would resolve it.

Honesty by Construction

Deterministic tools can be honest in a way LLMs cannot.

The codemod says "manual review required." It says "coverage is deliberately limited." It documents that a clean run is not a readiness result. The architecture tool stamps every record as an observation, never a verdict. All of that is printed by construction, not chosen at inference time.

An LLM does not reliably say "I don't know." A deterministic analyzer says it by construction, because its limits are part of its output format. The guarantee is not that the analysis is complete. The guarantee is that every finding is either provable or explicitly unproven, and the reader can tell which by reading the status.

That honesty is exactly what makes it safe to delegate to an agent. The agent can be wrong, and the tool's findings are still facts. The agent cannot quietly upgrade a manual-review finding into a provable transform, because the classification was made before the model saw anything, and it does not change.

Read-Only by Construction

The architecture codemod is the second lesson, applied to evidence.

It resolves imports to their real declarations, follows re-export chains to the original definition, and reports the shape of the dependency graph. Its output is a ledger: what was observed, how it was resolved, and never an upgrade from observation to conclusion.

Read-only is not a promise. It is a property. The analysis layer returns nothing, and only an outer writer can create the report, through staging plus rename. There is no other write path.

The artifacts are deterministic: stable ordering, identical output across runs. The verification contract is executable: fixture tests and proof that the target files are untouched. The tool tells you what it covers, and the report repeats its limits back to you, so a reader never confuses the evidence with the verdict.

LLMs Are for Judgment, Not Guarantees

This is the same philosophy as my harness posts — a deterministic harness, a prompt is not a boundary, shrink the action space — applied at the tool level.

A codemod is a compiler for the agent's perception and action space. It compiles a repository into a small, sorted list of facts, and it compiles a migration into a small set of provable changes plus the decisions that need judgment.

LLMs are good at this the way they are good at everything: plausible output, fast. Codemods are slow to build, cover less, and give you back the verification time.

The three-way split I wrote about earlier — safe transform, agent-guided, manual review — is one instance of this pattern. The frame is that guarantees belong to the deterministic layer and judgment belongs to the model. The model should not produce a guarantee and then vouch for it.

Build the AST Layer

If you are building an agentic coding system and you do not have a deterministic AST layer between the model and the repository, you are missing the most important tool you could add.

The AST layer is what turns agent output into auditable work. Without it, "the agent did it" is a claim. With it, "the agent changed line 42, and the change is in the provable class" is a fact you can check in seconds. The same evidence that tells the agent where to look is the evidence that tells you whether the result is trustworthy.

The learnings here are not about any framework. They are about where guarantees belong: the deterministic layer owns the facts, the model owns the judgment calls, and a human owns the decisions neither can make. Every API name in my two projects is replaceable; that division of labor is the point.

The single most valuable thing these two days gave me is a deterministic layer that tells the agent exactly what is true about the code: which call sites are really bound to the import, at exactly which file:line, which changes are provable, and which are not.

Build that layer before you chase the next model. The model will get smarter. The layer is what makes its work mean something.

Actions
What You Can Do
  • Export as PDF or Markdown
  • Batch Export to Notion
  • Bookmark & Highlight
  • LinkedIn & Instagram Carousel Maker
Create Free Account

Includes 7-day Premium trial

Advertisement