Content verified against ast-grep 0.45.1. Flags can drift between versions — when a command fails, check ast-grep <cmd> --help.
Overview
ast-grep is a fast, Rust-based CLI tool. It parses code with tree-sitter and matches the syntax tree, not the text. You write patterns that look like the code you search for. Metavariables ($NAME, $$$ARGS) act as wildcards for AST nodes.
Three main modes:
| Mode | Command | Use for |
|---|---|---|
| Search / rewrite | ast-grep run -p '<pattern>' (default command) |
One-time queries and codemods |
| Lint | ast-grep scan |
YAML rule sets, CI checks, complex rules |
| Explore | ast-grep outline |
Symbols, imports, exports of files |
It supports 25+ languages: JavaScript, TypeScript, TSX, Python, Rust, Go, Java, C, C++, C#, Kotlin, Swift, Ruby, PHP, and more. See the language table in references/cli-reference.md.
Installation
Check first: which ast-grep. If it is not installed, run the bundled helper:
bash <SKILL_DIR>/scripts/install.sh
The script tries brew, cargo, npm, pip3, and MacPorts in order, and verifies the result. For manual installation see https://ast-grep.github.io/guide/quick-start.html.
Note: some systems have a different sg binary (shell group). Always use the full name ast-grep.
Tool Selection: grep vs ast-grep vs LSP
| The question is about... | Use |
|---|---|
| Text: strings, error messages, config values, file names | grep / rg / fd |
| Syntax: "all calls that look like X", pattern rewrites, codemods, lint rules | ast-grep |
| Semantics: go-to-definition, find-references across scopes, types, scope-aware rename | LSP / compiler tooling |
| Graphs: transitive callers, circular imports, dead-code detection across a whole codebase | A graph script over ast-grep --json output; ast-grep alone sees only per-file matches |
ast-grep matches syntax, not semantics. It cannot tell two same-named symbols in different scopes apart. A rename with ast-grep is an exact syntactic replace (it skips comments, strings, and oldNameHelper), but it hits every scope. For a true semantic rename, prefer an LSP rename; use ast-grep when no LSP is available and verify the diff.
There is no runtime conflict with LSP tools: the ast-grep CLI is stateless — it reads files, matches, and exits. It starts no server and builds no index.
Also do NOT use ast-grep when:
- The pattern spans comments or string contents — patterns cannot match inside them.
- The codebase is tiny (< 5 files) — just read the files.
Files with syntax errors are usually fine: tree-sitter error recovery still matches the valid regions.
Quick Start
# Find all console.log calls in TypeScript
ast-grep -p 'console.log($$$ARGS)' -l ts src/
# Rewrite: var -> const, interactive review per match
ast-grep -p 'var $N = $V' -r 'const $N = $V' -l js --interactive src/
# Apply all rewrites without confirmation
ast-grep -p '$P && $P()' -r '$P?.()' -l ts -U src/
# Only list files that contain a match
ast-grep -p 'eval($$$A)' -l js --files-with-matches src/
# JSON output for scripts (note: --json requires `=` for its value)
ast-grep -p 'function $NAME($$$P) { $$$B }' -l ts --json=compact src/ > matches.json
# Run one inline YAML rule without a file
ast-grep scan --inline-rules 'id: no-eval
language: typescript
severity: error
rule: {pattern: "eval($$$A)"}' src/
# Show the structure of a file
ast-grep outline src/parser.ts --type class,function
# Test a pattern without files, via stdin
echo 'var x = 1' | ast-grep -p 'var $N = $V' -l js --stdin
Always put patterns in single quotes — double quotes let the shell expand $NAME first. For interactive pattern experiments there is an online playground: https://ast-grep.github.io/playground.html
Metavariables — Minimal Reminder
$VARmatches exactly one AST node.$$$ARGSmatches zero or more.- Default to
$$$for arguments, parameters, and bodies.foo($ARG)matches only one-argument calls — this is the most common cause of missed matches. - Repeated names must match identical content:
$A == $Amatchesx == x, notx == y. - Names use
A-Z,_, digits.$varis invalid.$_NAMEis non-capturing.
Full syntax, pattern objects, strictness, and language pitfalls (TypeScript generics, keywords, statement-vs-expression): references/pattern-syntax.md.
Standard Workflow: Rewrite
- Search:
ast-grep -p '<pattern>' -l <lang> <path>— check the matches. - Inspect: add
--json=compactif you must verify match boundaries. - Preview: add
-r '<rewrite>'— the diff prints to stdout, nothing is written. - Apply: add
--interactivefor per-match review, or-Uto apply all. - Verify: run the search again and expect exit code 1 (no matches). Then run the project tests.
A rename needs multiple passes (definition, call sites, imports are distinct node kinds) — see references/pattern-syntax.md.
Exit Codes
run:0= at least one match,1= no match. In scripts, "no matches" is not an error.scan:0= clean,1= diagnostics witherrorseverity found. Use this as a CI gate.- Other non-zero codes signal usage or config errors (e.g.
2bad flag,8invalid pattern/rule). - Pipelines mask exit codes.
ast-grep ... | other-toolreports the last command's status. Setset -o pipefail(bash/zsh) when the ast-grep status matters.
Reference Files
Read these on demand. Do not load them all at once.
- references/cli-reference.md — All subcommands and flags (verified against 0.45.1), flag syntax rules, language table.
- references/pattern-syntax.md — Full pattern syntax, pattern objects, strictness levels, pitfalls with examples.
- references/rule-yaml.md — YAML rule files, rule object (atomic/relational/composite),
sgconfig.ymlproject setup, rule testing, CI. - references/pattern-cookbook.md — Ready-to-use patterns for JS/TS/Python, rewrite recipes with semantic warnings, task recipes (find callers, dead exports), YAML rule scenarios.
Bundled Scripts
Replace <SKILL_DIR> with the absolute directory of this SKILL.md file.
-
scripts/install.sh— Try available package managers in order and install ast-grep. -
scripts/json-summary.py— Summarizeast-grep --jsonoutput: match counts per file plus a compact match list. Usage:set -o pipefail # keep ast-grep's exit code visible ast-grep -p '<pattern>' --json=compact <path> | python3 <SKILL_DIR>/scripts/json-summary.py