#2927·ast-grep

`scan --inline-rules` never binds global utils from `utilDirs`, with or without `--config`

Author: bsamieeCreated Sep 6, 2026Updated Sep 8, 2026
Labelsenhancement

ast-grep 0.45.3, macOS arm64.

sgconfig.yml declares ruleDirs and utilDirs. A rule file under ruleDirs that references a global util through matches: <util-id> loads and passes ast-grep test. The same rule body passed through scan --inline-rules fails the rule parse with Rule <util-id> is not defined, in every configuration form:

  • run from the project root, where sgconfig.yml is discovered by the upward walk
  • run with -c sgconfig.yml
  • run from an unrelated directory with --config /abs/path/sgconfig.yml

The config is read in these runs: with --config, an inline rule under a customLanguages grammar (language: xml) parses and matches, and without it the same rule fails on the unknown language. So --config reaches customLanguages and languageGlobs for inline rules but not utilDirs.

Reproduction:

bash
# utils/hook.yml
#   id: hook
#   language: tsx
#   rule: {kind: arrow_function}
# sgconfig.yml
#   ruleDirs: [rules]
#   utilDirs: [utils]
printf 'const f = () => 1;\n' | ast-grep scan --config sgconfig.yml --inline-rules $'id: p\nlanguage: tsx\nrule: {matches: hook}' --json --stdin
# Error: Cannot parse rule INLINE_RULES ... Rule `hook` is not defined.

The documentation for utilDirs states that global utility rules are discovered from those directories and referenced with matches, and names no exception for --inline-rules. The --inline-rules documentation describes the option as running a rule "without saving it to a file first", which reads as the same rule with the same resolution. Issue #588 settled that scan --rule skips global rules by design as a no-project form; --inline-rules together with an explicit --config is the case that answer does not cover.

Expected: when a --config (or a discovered sgconfig.yml) is present, scan --inline-rules resolves matches: <global-util> from utilDirs the way a rule under ruleDirs does. If the omission is by design, the --inline-rules and utilDirs reference pages could state it.

Why it matters: MCP servers and editor integrations (ast-grep-mcp prepends --config <sgconfig> to every call and runs scan --inline-rules) cannot reuse a project's util library from an ad-hoc rule, so every ad-hoc rule re-inlines the util body.