# Ast Grep

> Write, debug, and validate ast-grep structural code search rules. Use for syntax-aware code search, AST pattern matching, structural refactor discovery, or searches plain text tools like rg can miss — functions with particular descendants, calls inside specific contexts, decorators, or other Tree-sitter-backed structures.

- Skill: `bahayonghang/ast-grep` (Agent Skill, multi-file: 3 files)
- Install (CLI): `npx skillmds@latest add bahayonghang/ast-grep`
- Raw SKILL.md: https://api.skillmd.com/api/skills/bahayonghang/ast-grep/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Product & Planning
- Author: bahayonghang (https://skillmd.com/u/bahayonghang)
- Updated: 2026-09-10
- Page: https://skillmd.com/skills/bahayonghang/ast-grep

---


# ast-grep Structural Search

Use ast-grep when the user needs code structure, not just text. The useful
outcome is a validated rule plus a clear statement of what it matches and what
it may miss.

## Triage

Start with the smallest tool that can answer the question.

- Use `rg` for exact names, strings, comments, or simple text.
- Use language tooling for semantic facts such as type resolution, references,
  imports, or rename safety.
- Use ast-grep for syntax shape: descendants, ancestors, call forms, decorators,
  missing constructs, nested contexts, or multi-language structural searches.

If ast-grep is not installed, say so and offer an `rg` fallback only when the
fallback will not pretend to be structural.

## Workflow

1. Identify the language and target files.
   - Infer from paths and extensions when possible.
   - Ask only if the language or include/exclude scope cannot be inferred.

2. Write a tiny fixture before searching the real repository.
   - Include at least one positive example.
   - Add a negative example when false positives would be costly.

3. Start with the simplest pattern.
   - Use `ast-grep run --pattern ... --lang ...` for a single-node search.
   - Move to a YAML rule when the search needs `has`, `inside`, `not`, `any`,
     `all`, `regex`, `nthChild`, or reusable metadata.

4. Debug the parsed structure when the first rule misses.
   - Use `ast-grep run --pattern '<sample code>' --lang <lang> --debug-query=ast`.
   - `--debug-query` prints diagnostic output and may exit non-zero; treat the
     printed tree as useful debug output, not as a failed repository search.

5. Validate on the fixture before running on the repository.
   - Keep the rule as simple as possible until it matches the fixture.
   - Then scan the real path and report expected false-negative boundaries.

6. Report the final rule, command, and caveats.
   - Name node kinds or language constructs intentionally excluded.
   - Prefer JSON output when a downstream script will consume matches.

## Rule File First

Rule files avoid most shell quoting problems and are the preferred form for
complex searches.

On Windows, save rule files as UTF-8 without BOM. If `ast-grep scan --rule`
reports `missing field language` even though the YAML has `language`, check for
a BOM at the start of the file.

```yaml
# async-await.yml
id: async-await
language: javascript
rule:
  any:
    - kind: function_declaration
    - kind: arrow_function
    - kind: method_definition
  has:
    pattern: await $EXPR
    stopBy: end
```

```powershell
$rule = @'
id: async-await
language: javascript
rule:
  any:
    - kind: function_declaration
    - kind: arrow_function
    - kind: method_definition
  has:
    pattern: await $EXPR
    stopBy: end
'@
[System.IO.File]::WriteAllText(
  "async-await.yml",
  $rule,
  [System.Text.UTF8Encoding]::new($false)
)

ast-grep scan --rule async-await.yml .\src
ast-grep scan --rule async-await.yml .\src --json
```

```bash
ast-grep scan --rule async-await.yml ./src
ast-grep scan --rule async-await.yml ./src --json
```

## Inline Smoke Tests

Use inline rules only for quick checks. In PowerShell, single-quoted here-strings
preserve `$META` variables without escaping.

```powershell
$rule = @'
id: console-call
language: javascript
rule:
  pattern: console.log($$$ARGS)
'@

"console.log('debug', value);" | ast-grep scan --inline-rules $rule --stdin
```

In POSIX shells, quote the YAML with single quotes or escape `$`.

```bash
printf '%s\n' "console.log('debug', value);" |
  ast-grep scan --inline-rules 'id: console-call
language: javascript
rule:
  pattern: console.log($$$ARGS)' --stdin
```

Every `scan --inline-rules` example must include `id`, `language`, and `rule`.

## Debugging Checklist

When a rule produces no matches:

1. Confirm the language: `--lang javascript` is different from `--lang tsx`.
2. Print the query tree with `--debug-query=ast` or `--debug-query=cst`.
3. Check that rule files are UTF-8 without BOM.
4. Replace the complex rule with one `pattern` or one `kind`.
5. Add relational rules back one at a time.
6. Add `stopBy: end` to deep `has` / `inside` searches.
7. Check whether metavariables occupy a whole syntax node.
8. Broaden node kinds if the language has several forms of the same concept.

## Avoid Silent False Negatives

Do not assume one node kind covers a user concept.

For JavaScript and TypeScript, "function" may include:

- `function_declaration`
- `function`
- `arrow_function`
- `method_definition`
- class fields or object properties containing functions

For React, decide whether the user means `.js`, `.jsx`, `.ts`, or `.tsx`.

For Python, inspect the parsed shape before relying on indentation-sensitive
multi-line patterns.

## Output Contract

When answering an ast-grep task, include:

1. `Rule`: the YAML rule or inline pattern.
2. `Validation`: the fixture command you used or recommend.
3. `Repository command`: the command for the user's target path.
4. `Caveats`: likely false positives, false negatives, and language forms not
   covered.

## Reference

Load `references/rule_reference.md` when the task needs detailed syntax for
atomic rules, relational rules, composite rules, metavariables, or troubleshooting.

