From odin
Performs AST-based code search, structural linting, and safe refactoring using ast-grep (sg). Validates patterns before searching and dry-runs rewrites before applying.
How this skill is triggered — by the user, by Claude, or both
Slash command
/odin:ast-grepThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
ast-grep is a fast and polyglot tool for code searching, linting, and rewriting based on Abstract Syntax Trees (AST). It excels at structural search and replace where regex fails.
ast-grep is a fast and polyglot tool for code searching, linting, and rewriting based on Abstract Syntax Trees (AST). It excels at structural search and replace where regex fails.
foo with 2 arguments") regardless of whitespace.# Search (pattern must be in single quotes)
ast-grep -p '$A + $B' --lang ts
# Rewrite (dry run)
ast-grep -p '$A != null' --rewrite '$A' --lang ts
# Interactive Rewrite
ast-grep -p 'var $A = $B' --rewrite 'const $A = $B' --interactive
$VAR matches any single node.$$$ARGS matches zero or more nodes (list of items).$_ matches any node (non-capturing).$$ matches any list of nodes (non-capturing).See Pattern Syntax for details.
scripts/ast_grep_helper.py wraps two safety gates:
# Lint a pattern before you search with it (exit 0 valid / exit 2 malformed; flags regex-smell)
python3 scripts/ast_grep_helper.py validate '$A + $B' --lang ts
# Preview a rewrite — diff + "N matches across M files", mutates nothing without --apply
python3 scripts/ast_grep_helper.py replace '$A != null' '$A' --lang ts src/
python3 scripts/ast_grep_helper.py replace '$A != null' '$A' --lang ts src/ --apply
validate compiles the pattern through ast-grep's own parser, so it catches malformed queries in every language (including Go/Python where $ is not an identifier char). replace is two-pass: dry-run prints the blast radius, --apply writes.
Rule: emit a pattern → validate it; emit a rewrite → replace dry-run, inspect the diff + match count, only then re-run with --apply.
structural shape (call/func/class/import shaped like X) → ast-grep
text / regex / filenames / comments / string contents → rg / grep
semantic (types, references, "who calls this symbol") → LSP / compiler
across many repos → search engine, then ast-grep per-repo
ast-grep matches syntax, not bytes. The moment you reach for |, .*, \w, or [...], you want rg, not a pattern.
Rewrite flow (never skip the dry-run):
search the pattern to confirm it matches what you think.replace dry-run — read the diff.N matches across M files count; if the blast radius is wrong, stop.--lang, add context).--apply.0-matches ladder (in order):
python3 scripts/ast_grep_helper.py validate '<pat>' --lang L — is the pattern even well-formed?--lang — tsx ≠ ts; the wrong dialect silently matches nothing.ast-grep run -p '<pat>' -l L --debug-query=pattern — look for ERROR in the dumped query tree.--debug-query=ast on a known-matching snippet) — your node kinds may differ from your guess.references/pitfalls.md is the deep field guide — read it when 0 matches surprises you.
--apply (or --update-all) without reading the diff.--json and --update-all conflict: combine them and --json silently wins, so the write is dropped with no error. Preview with --json, then apply with --update-all separately.$VAR must reach ast-grep unexpanded.--lang is required for stdin — piped input has no filename to infer the dialect from.|, .*, \w, or [...].ast-grep, never sg — sg collides with the setgroups binary on many systems.Understanding Named vs Unnamed nodes and Matching Strictness is crucial for precise patterns.
identifier, function_definition (matched by $VAR).(, ), ; (skipped by default in smart mode).smart, cst, ast, relaxed, signature).See Core Concepts for details.
For complex tasks, use YAML configuration files.
id: no-console-log
language: TypeScript
rule:
pattern: console.log($$$ARGS)
inside:
kind: function_declaration
stopBy: end
fix: '' # Remove the log
See Rule Configuration for details.
ast-grep supports complex transformations (regex replace, case conversion) and rewriters for sub-node transformation.
See Rewriting & Transformations for details.
For larger projects, organize rules and tests using sgconfig.yml.
ast-grep new projectsgconfig.yml defines rule and test directories.valid and invalid cases to ensure rule accuracy.See Project Setup & Testing for details.
Reuse logic with local or global utility rules. Enables recursive matching.
utils:
is-literal:
any: [{kind: string}, {kind: number}]
rule:
matches: is-literal
See Utility Rules for details.
Full reference for YAML fields (id, severity, files, ignores) and supported languages.
See Configuration Reference for details.
Common commands: scan, run, new, test, lsp.
See CLI Reference for details.
sg↔setgroups, and the 0-matches debug ladder). Read this when 0 matches surprises you.Use the per-topic references linked above only when that topic is relevant.
npx claudepluginhub outlinedriven/odin-claude-plugin --plugin odinProvides ast-grep CLI syntax, metavariable patterns, and examples for structural code search and rewriting in JavaScript/TypeScript, Python, Go, Rust.
Finds and replaces code patterns structurally using ast-grep by matching AST structure, for functions with specific signatures, API refactors across files, and regex-resistant anti-patterns.
Guides writing ast-grep rules for AST-based structural code search to find patterns like unhandled async functions or specific constructs beyond text matching.