ast-grep
The sg engine matches against the structure of a single source file. Because it reads the syntax tree rather than the text, it catches a pattern regardless of formatting, variable names, or whitespace.
It makes a codebase’s structure checkable. Vale makes its contents checkable.
What belongs here
Section titled “What belongs here”Anything one file can decide: a call, an import, a JSX attribute, a type annotation, a function shape.
Correlating two things inside one file is still sg. A useEffect whose dependency array omits a value used in its body compares two places, but both are in the same file, so a single-file engine can decide it. Reach for runtime only when the evidence genuinely leaves the file.
One rule, one directory
Section titled “One rule, one directory”.taskless/rules/sg/no-eval/ no-eval.yml the rule .tests/no-eval-YYYYMMDD-test.yml its test casesThe id is kebab-case and names both the directory and the file. An sg rule carries its own files and ignores, so unlike a Vale rule there is no second config file. The rule file is the whole rule.
The dot on .tests/ is required. See Engines for what breaks without it.
The rule file
Section titled “The rule file”id: no-console-loglanguage: TypeScriptrule: pattern: console.log($$$ARGS)severity: warningmessage: Avoid console.log in production code. Use a structured logger instead.fix: logger.info($$$ARGS)| Field | Purpose |
|---|---|
id |
kebab-case, matching the directory and file name |
language |
the target language, in ast-grep’s own spelling |
rule |
the ast-grep rule object |
severity |
error, warning, info, or hint |
message |
a concise single-line explanation |
note |
optional multi-line guidance, supports Markdown |
fix |
optional auto-fix pattern |
ignores |
optional file patterns to skip |
For the pattern syntax itself, including meta-variables and the any/all/has/inside/not operators, see ast-grep and the upstream rule reference.
To suppress one finding in the scanned code, put ast-grep-ignore at the start of a comment on the line above it. As of ast-grep v0.45.3 the directive takes effect only as the comment’s first alphabetic text; a comment that merely mentions it as prose no longer suppresses anything, so a finding that was hidden that way reappears.
language is ast-grep’s vocabulary, not yours
Section titled “language is ast-grep’s vocabulary, not yours”Supported Languages lists every spelling the pinned ast-grep binary accepts, generated from the binary’s own run -h output.
Copy a spelling from that list rather than typing one that looks right. Three traps in particular:
- Do not copy the language from
detect --json. It reports your repository’s languages in a different vocabulary. It saysC++where this list saysCpp. TsxandTypeScriptare two parsers, not aliases. A rule over.tsxfiles that declaresTypeScriptdoes not merely miss JSX syntax, it does not read those files at all.Markdownsees blocks only. ast-grep exposes the block grammar, soatx_heading,fenced_code_block,list_item,paragraphandsectionare real kinds, while everything inside a line is one opaqueinlinenode. There is nolinkoremphasiskind. A rule about the words inside a line belongs to Vale, not here.
Tests, and the empty bucket problem
Section titled “Tests, and the empty bucket problem”Test cases live in .tests/ and use ast-grep’s own valid and invalid keys, because that file is handed to sg test verbatim.
Where a rule has an arity boundary, put a case on each side of it. A pattern that starts at two arguments when it was meant to start at one passes a suite whose fixtures all have two.
The authoring loop
Section titled “The authoring loop”npx @taskless/cli agent create-sg-ruleThen validate, both taking the rule’s directory:
npx @taskless/cli verify .taskless/rules/sg/no-console-log/npx @taskless/cli test .taskless/rules/sg/no-console-log/verify asks whether the rule is well formed: the YAML matches the ast-grep schema and every required field is present. It needs no test file, so run it the moment the rule exists. test then runs the cases.
Cost and account
Section titled “Cost and account”The sg engine is available in the Taskless Open Source CLI and does not require a Taskless Cloud account.
sg rules are inert data. Running one executes nothing and makes no network call, so it works offline.