| name | tools-ast-grep |
| description | Gather structural-pattern architecture evidence with ast-grep syntax-tree queries. Use when checking module boundaries, layer violations, forbidden imports, direct DB/framework access, route declarations, exported surface area, or framework leaks across seams. Yields exact file:line evidence for modularity, coupling, and fragility claims. NOT for whole-graph dependency analysis (use tools-codegraph), exact text discovery (use tools-code-search), or semantic/type resolution (use tools-lsp-tree-sitter). |
ast-grep
ast-grep matches code by its syntax tree, so a pattern survives reformatting,
whitespace, and comments that defeat grep. It is the cheapest way to answer
"does this pattern exist where it shouldn't?" with a precise file:line list.
Evidence dimension: structural. Output is a concrete evidence ref per match.
When to use
Use when a finding hypothesis is a structural code pattern: "domain code imports
the ORM directly," "routes are declared outside the router module," "this
framework type leaks past the boundary," or "a module exports too much surface."
ast-grep confirms presence/absence with line-anchored hits. Use it before
claiming a boundary is bypassed — a claim about a pattern needs the matched
lines.
Commands
Run from the repo root. -l sets language; -p is an inline pattern; --json
gives machine-readable hits for counting.
ast-grep -l ts -p 'import $$$ from "typeorm"'
ast-grep -l ts -p 'createConnection($$$)' src/domain
ast-grep -l ts -p 'export $$$'
ast-grep -l ts -p 'app.$METHOD($PATH, $$$)'
ast-grep -l python -p 'Request' src/core
ast-grep -l go -p 'sql.Open($$$)' --json | jq length
For reusable, named rules (relational metavariable constraints, inside,
not), put them in a YAML rule file and run ast-grep scan -r rule.yml. See
references/rules.md for the rule patterns this review relies on.
Evidence output
Record:
dimension: structural.
source: ast-grep command, language, pattern/rule file, searched scope, and
version when parser behavior is in doubt.
facts: matched file:line refs or confirmed zero-match scope.
limits: parse errors, unsupported language, regex fallback, or lack of semantic reachability.
Confidence impact
- A pattern search that runs and returns hits or a clean zero is direct
structural evidence:
tools_used for the structural dimension, raises
confidence for the related finding.
- ast-grep proves syntactic presence, not runtime reachability. A matched
forbidden import is strong; "no matches" means the pattern is absent, not that
the boundary is sound by every measure — pair absence claims with the
dependency graph before scoring boundary integrity high.
Failure and missing-tool handling
- Not installed → record the structural dimension
tools_missing, note the
install hint (brew install ast-grep / cargo install ast-grep), and fall
back to tools-lsp-tree-sitter syntax queries or rg/regex search with an
explicit confidence caveat. Do not silently downgrade to regex without saying
so.
- A pattern that errors (unsupported language, bad metavariable) is a tool
failure on that query, not evidence of absence — fix the pattern or record it
tools_failed; never report "no matches" from a query that never parsed.
When to stop
One precise rule per hypothesis is enough. Once a pattern returns hits (or a
confirmed clean zero on a correct pattern), record the evidence and move on. Do
not enumerate twenty variant patterns hunting for more matches — if the
structural question is answered, stop and record coverage. If a pattern needs
graph-level reachability (who actually calls this), that is a coverage gap for
ast-grep: hand it to tools-codegraph rather than approximating with more
syntax searches.
Hard rules
- Cite the matched file:line as the evidence ref; never describe a pattern you
did not run.
- "No matches" is only evidence if the pattern parsed and the language was
correct.
- Do not reimplement ast-grep matching in package code — call the CLI.