Repo review · Tested September 4, 2026
ast-grep searches code by structure
ast-grep is a syntax-aware code search and rewrite tool for maintainers and coding agents. It can target exact syntax before a broad refactor; writing the rule is still work.

Many developers now ask a coding agent to make the change instead of writing the patch by hand. The agent still has to find every place it should touch. That search happens inside the agent’s transcript, where it is easier to overlook.
ast-grep parses source into syntax trees, then searches those trees with code-shaped patterns and YAML rules. Its official skill teaches Claude Code how to build the query. That makes the modern adoption question unusually clean: does ast-grep give Claude better judgment about source structure, or just more syntax to negotiate before lunch?
In our Claude comparison, the answer was both. ast-grep removed false positives that built-in search and ripgrep accepted. It also made the agent substantially slower.
Tested: commit
979c143639e3588c31f563091e69398683ed34f0on September 4, 2026. Workflow: 16 fresh Claude Code sessions searched four generated repositories through built-in tools, ripgrep, the official ast-grep skill, or a neutral hybrid; a separate rule previewed and applied a TypeScript rewrite. Result: forced ast-grep and hybrid were exact on all four search tasks, while built-in search was exact on three and ripgrep on two. The rewrite changed only four approved ranges and preserved type and behavior checks. Verdict: adopt with care for structural audits and reviewed repository-wide refactors.
How ast-grep searches code structure
Text search answers whether characters appear in a file. Structural code search can distinguish a specific function call from similar text and tell whether it appears inside another block of code rather than merely sharing the same file.
ast-grep gets that distinction from tree-sitter parsers. A one-line pattern such as console.log($ARG) can match differently formatted calls without matching the same words inside a comment. More involved questions combine node kinds, metavariables, regular expressions, and relationships such as inside or has. Rewrites use the same match to replace the selected syntax.
ast-grep is an established MIT-licensed project with regular releases and active development. Most recorded contributions remain concentrated in its lead maintainer’s account, so ownership is narrower than the project’s reach.
The project now maintains an official Claude Code skill and an experimental outline command for agent navigation. Shopify CLI also declares @ast-grep/napi as a dependency. Together they show active use in agent and production tooling, though they do not establish broad adoption.
One Claude, four sets of eyes
We gave Claude Code 2.1.257 the same Sonnet 5 model, high effort, prompt shape, eight-minute limit, output schema, and generated corpus in every run. Four tasks covered TypeScript functions, React effects, Python subprocess calls, and Rust unsafe blocks. Each task had eight intended matches plus comments, strings, nested-function traps, ignored paths, nearby non-matches, and one malformed file.
Only the search surface changed:
| Search profile | Exact tasks | Precision | Recall | Average time | Average tool-result bytes |
|---|---|---|---|---|---|
| Claude built-in search | 3/4 | 80.0% | 100% | 53.8s | 7,977 |
| Ripgrep only | 2/4 | 78.0% | 100% | 69.8s | 12,785 |
| Forced ast-grep skill | 4/4 | 100% | 100% | 172.3s | 43,325 |
| Hybrid | 4/4 | 100% | 100% | 109.0s | 27,394 |
Every profile found all 32 positives. Precision made the difference.
The Python task asked for calls whose callee was exactly subprocess.run, subprocess.Popen, subprocess.call, or subprocess.check_output with shell=True. Built-in search and ripgrep also returned eight calls through an alias such as sp.run. Those calls may deserve attention in a security audit, but they did not satisfy the requested syntax. ast-grep encoded the callee instead of inferring it from nearby text.
Ripgrep’s other false positive came from deliberately malformed Rust. The file contained the right words and punctuation but did not form the requested parsed structure. Claude’s built-in search excluded it after reading the file; ast-grep excluded it through the parser.
The precision was not free. Forced ast-grep took about 3.2 times as long as built-in search and returned over five times as much tool output. Claude probed node kinds, wrote and revised rules, and verified candidates before answering. The official skill also assumed it could use temporary files and compound shell commands. Our locked-down harness denied 17 operations in the forced profile, although Claude recovered every time.
Hybrid was the useful surprise. The prompt did not name ast-grep, yet Claude invoked the skill in all four tasks. It remained exact and averaged fewer tool calls than built-in search, though it was still roughly twice as slow and returned more output. This selective routing is the strongest case for adding the skill: keep ordinary search for ordinary questions and reach for ast-grep when structure decides the match.
One rule, four exact edits
Search accuracy matters because ast-grep can turn a match into an edit. We selected one TypeScript rewrite before inspecting its output:
pattern: legacyLog($MSG, $CTX)
rewrite: audit.info({ context: $CTX }, $MSG)
The fixture contained four permitted calls plus a comment, a string, and a similarly named member call that had to remain unchanged. An invalid YAML rule failed visibly. Preview found four matches, apply changed only those four declared ranges, TypeScript compiled, and the same behavior test passed before and after. This confirms one reviewed rule; generated rewrites still need preview, rule tests, type checks, and behavior tests.
Keep grep nearby
ast-grep fits broad deprecation audits, framework migrations, custom repository policies, and security searches where syntax or ancestry decides whether a match belongs. It also gives coding agents a deterministic target set they can show before changing dozens of files.
Use built-in search or ripgrep for filenames, literals, logs, and quick candidate lists. Choose Semgrep when the job needs its larger security-analysis ecosystem, or a compiler API and language-specific codemod when types and symbol resolution decide correctness. Comby offers another structural rewrite model for teams that prefer its hole-based templates. And if the problem is repeated source rather than syntactic relationships, our jscpd review covers a different kind of codebase archaeology.
Rule ownership is the dividing line. Someone must maintain the patterns as parsers, frameworks, and local conventions change. AI can draft that rule and recover from a bad attempt; it cannot make the rule’s meaning somebody else’s responsibility.
Use ast-grep when structure decides
Adopt ast-grep with care for structural audits and reviewed repository-wide refactors. It gave Claude exact target sets on all four designed tasks and kept one bounded rewrite inside its declared fence.
But ordinary search was already correct on three tasks, finished much faster, and returned far less tool output. Use ast-grep when syntax, ancestry, or rewrite scope changes the decision; use grep when you need to find the name on the door. Choose a compiler API or language-specific codemod when types and symbols across files decide correctness.