Learn/Semantic · 6 min · updated 2026-08-03

Structural code search: finding patterns instead of strings

Grep finds text. Structural search finds shapes: every call with a literal timeout, every catch block that swallows the error. How AST queries work and when they beat a regex.

Structural search matches patterns in the syntax tree rather than characters in the file. It answers questions a regex cannot: every function longer than fifty lines, every catch that discards the error, every call to fetch without a timeout, every impl of a trait that does not override a given method.

Why regex runs out

Regular expressions do not nest. Matching a balanced block, an argument list that spans lines, or a call whose receiver is an expression means writing a pattern that is wrong in a way you will not find until it matters. The classic failure is a search for a function call that misses every instance where the arguments were wrapped onto a second line.

What a query looks like

With tree-sitter's query language, finding every catch block with an empty body:

(catch_clause
  body: (statement_block) @body
  (#eq? @body "{}"))

With ast-grep, the same class of query is written in the syntax of the language itself, using metavariables:

ast-grep --pattern 'try { $$$ } catch ($E) { }'

When to reach for it

TaskTool
Find a symbol by namegrep, and it is faster
Find every caller of a functionStructural search or a language server
Find a code shape across a codebaseStructural search
Rewrite a shape everywhereStructural search with a rewrite rule, or a codemod
Resolve which overload is calledA language server; the syntax tree does not know

Where it fits with agents

Agents grep. Given a large codebase and a vague instruction, a session will run a dozen text searches and read a lot of files that turn out to be irrelevant, spending context on each one. A structural query answers the same question in one call with a precise result set, which is cheaper in tokens and more accurate.

Aura exposes its index to agents over MCP for exactly this: definitions, references and the dependency graph, queried by structure rather than by string. See the MCP server for the tool list, and tree-sitter for the query language underneath.

Questions

What is structural code search?

Searching for shapes in the parsed code instead of strings in the text — every call with a hard-coded timeout, every catch block that swallows its error, every function returning a raw pointer. The query describes a pattern in the syntax tree.

How is structural search different from grep?

grep matches characters, so it finds your pattern in comments and strings and misses it whenever the code is spaced or wrapped differently. A structural query matches nodes, so formatting is irrelevant and a match is always real code.

When should you use structural search instead of grep?

When the thing you want has a shape rather than a spelling — an empty error handler, a specific argument position, a call inside a loop. For a symbol name or a literal string, grep is faster and entirely sufficient.