ast-grep

AST-aware structural code search and rewrite via ast-grep.

  • ast
  • codemod
  • refactoring
  • structural-search
  • code-search
  • rewrite
  • tree-sitter

Declared platforms: linux · macos · windows

Install
npx skills add 'https://github.com/NousResearch/hermes-agent/tree/main/optional-skills/software-development/ast-grep'
Download bundle ↓
main · 24fd22bScanned 2026-09-15

Contributors

GitHub-linked commit authors for this SKILL.md at the saved revision. Co-authors and history before file renames are not included.

File history ↗
View on GitHub
← Back to SKILL.md

CLI reference — sg / ast-grep

Compact reference for the underlying sg binary that the helper wraps. Use this when the helper isn't enough or when you want to invoke sg directly.

Binary name on Linux: prefer ast-grep over sg because sg collides with setgroups from util-linux.


sg run — one-shot search/rewrite

The default subcommand. sg -p 'foo' is shorthand for sg run -p 'foo'.

sg run [OPTIONS] --pattern <PATTERN> [PATHS...]
FlagPurpose
-p, --pattern <P>AST pattern to match. Always single-quote in shell to prevent $VAR expansion.
-r, --rewrite <R>Replacement pattern. Used with -U to apply.
-l, --lang <LANG>Language. Inferred from path extension if omitted.
--selector <KIND>When the pattern is ambiguous, extract only this AST kind.
--strictness <S>cst | smart (default) | ast | relaxed | signature
--debug-query[=<F>]Print parsed pattern. F: pattern | ast | cst | sexp
--stdinRead code from stdin instead of files. Lang must be set.
--globs <G>Include/exclude glob (repeatable; prefix ! to exclude).
--followFollow symlinks.
--no-ignore <T>Disable a class of ignore: hidden, dot, exclude, global, parent, vcs.
-i, --interactiveStep through matches and confirm each rewrite.
-U, --update-allApply all rewrites without confirmation. Mutually exclusive with --json (silently).
--json[=<S>]Emit JSON. S: pretty | stream | compact (compact is best for piping).
--color <W>auto | always | ansi | never
--inspect <G>Detail level: nothing | summary | entity
-A, -B, -C <N>Context lines after / before / around each match.
-j, --threads <N>Thread count (default: heuristic; 0 = auto).

--update-all + --json — the trap

sg silently ignores --update-all when --json is set. To preview AND apply, run two passes:

# Pass 1: preview
sg run -p 'foo()' -r 'bar()' --json=compact src/

# Pass 2: apply
sg run -p 'foo()' -r 'bar()' --update-all src/

The ast_grep_helper.py replace --apply subcommand does this automatically.

Examples

# Basic search
sg run -p 'console.log($MSG)' --lang ts src/

# Search with context lines
sg run -p 'eval($CODE)' --lang js -C 3 .

# Rewrite, dry-run preview as JSON
sg run -p 'console.log($MSG)' -r 'logger.info($MSG)' --json=compact --lang ts src/

# Rewrite, apply
sg run -p 'console.log($MSG)' -r 'logger.info($MSG)' --update-all --lang ts src/

# Pattern from stdin
echo 'console.log("x")' | sg run -p 'console.log($MSG)' --lang js --stdin

# Limit to specific files
sg run -p 'foo()' --lang ts --globs 'src/**/*.ts' --globs '!**/*.test.ts' .

# Debug a pattern that returns 0 matches
sg run -p 'def $F($$$):' --lang py --debug-query=ast --stdin <<< 'def foo(): pass'

sg scan — YAML rule scanner

Run a configuration of YAML rules across files. Used for project-wide lints and codemods.

sg scan [OPTIONS] [PATHS...]
FlagPurpose
-c, --config <C>Path to sgconfig.yml (default: walk up from cwd looking for one).
-r, --rule <F>Run a single rule file. Mutually exclusive with --config.
--inline-rules <Y>Pass YAML rule text inline. Use --- to separate multiple rules.
--filter <RE>Only run rules whose id matches this regex.
--include-metadataInclude rule metadata field in JSON output.
-U, --update-allApply fixes from fix: automatically.
--report-style <S>rich | medium | short
--format <F>github | sarif (CI-friendly outputs).
--error[=ID], --warning[=ID], --info[=ID], --hint[=ID], --off[=ID]Promote/demote severity.
-i, --interactiveConfirm each fix interactively.
--json[=<S>]JSON output.

Examples

# Run all rules in sgconfig.yml-discovered ruleDirs
sg scan src/

# Run a single rule file (no sgconfig.yml needed)
sg scan -r rules/no-console.yml src/

# Inline rule (great for one-offs and CI)
sg scan --inline-rules '
id: no-todo
language: TypeScript
severity: warning
rule: { pattern: TODO }' src/

# Apply all auto-fixes
sg scan -U src/

# CI-friendly GitHub annotations
sg scan --format github src/

# SARIF for security scanners
sg scan --format sarif src/ > sarif.json

sg test — run rule snapshot tests

sg test [OPTIONS]
FlagPurpose
-c, --config <C>Path to sgconfig.yml.
-t, --test-dir <D>Test directory.
--snapshot-dir <D>Snapshot directory (default: __snapshots__).
--skip-snapshot-testsValidate test code parses; don't compare snapshots.
-U, --update-allUpdate all changed snapshots.
-f, --filter <G>Filter test cases by glob on rule id.
--include-offInclude rules with severity off.
-i, --interactiveStep through changed snapshots and accept/reject each.

A test directory looks like:

test/
├── no-console.yml          # `valid:` and `invalid:` snippets
└── no-console-test.yml     # alternative test file format
__snapshots__/
└── no-console-snapshot.yml # expected match locations

sg new — scaffold

sg new <COMMAND> [NAME] [OPTIONS]
SubcommandCreates
projectsgconfig.yml, rules/, utils/, __snapshots__/ directory tree
ruleA new YAML rule file in the first ruleDirs entry
testA new test file in testConfigs[0].testDir
utilA new utility rule in the first utilDirs entry
# New project in current dir
sg new project --yes

# New rule
sg new rule no-console --lang typescript

# New test
sg new test no-console --yes

sg lsp — language server

sg lsp -c sgconfig.yml

Speak LSP over stdin/stdout. Configure your editor (VS Code extension, Neovim nvim-lspconfig, Helix languages.toml) to spawn this command for live diagnostics.


sg completions — shell completions

sg completions bash >> ~/.bashrc
sg completions zsh > "${fpath[1]}/_sg"
sg completions fish > ~/.config/fish/completions/sg.fish
sg completions powershell >> $PROFILE

Useful one-liners

# Count matches per file
sg run -p 'console.log($_)' --lang ts --json=compact . \
  | jq -r '.[].file' | sort | uniq -c | sort -rn

# Find all unique kinds in a file (great for figuring out kind names)
sg run -p '$_' --lang ts --debug-query=cst src/foo.ts \
  | grep -oE 'kind: [a-z_]+' | sort -u

# Rewrite only in a subset of files
sg run -p 'foo()' -r 'bar()' --update-all --globs 'src/**/*.ts' --globs '!src/legacy/**' .

# Apply fixes from many rules but only ones matching a pattern in their id
sg scan --filter 'no-' -U src/

# Use ast-grep as a linter in pre-commit
sg scan --format github src/ || exit 1

See also

  • references/yaml-rules.md — rule schema (pattern, kind, regex, inside, has, all, any, not, matches, transform, fix).
  • references/sgconfig.md — project configuration.
  • Official: https://ast-grep.github.io/reference/cli.html
Referenced from SKILL.md