Skip to content

Backend coverage

poly resolves every file through a tiered model:

  1. Curated Rust backends for high-fidelity lint and format support.
  2. Native-toolchain backends for canonical first-party formatters — plus shellcheck — when configured or present on PATH.
  3. Tree-sitter generic formatting for identified languages without a dedicated backend.
  4. Optional catalog tools from the embedded registry.
Language or files Backend Lint Format
JavaScript / TypeScript / JSX / TSX oxc yes yes
JSON / JSONC oxc parse diagnostics + formatter yes yes
Python ruff internals yes yes
TOML taplo yes yes
Markdown rumdl yes yes
SQL sqruff yes yes
YAML saphyr + pretty_yaml yes yes
CSS / SCSS malva (format) + biome (lint) yes yes
Less malva no yes
HTML / Vue / Svelte / Astro / Angular / templates / XML markup_fmt no yes
GraphQL graphql-parser + pretty_graphql (parse-error lint + format) + biome (rule lint) yes yes
HCL / Terraform hcl-edit + hcl-rs, tree-sitter for comment-preserving format fallback yes yes
Dockerfile dockerfile-parser, hadolint-style rules yes no
.env files (.env, .env.*, *.env) dotenv-analyzer yes no
INI and compatible (.ini, .cfg, .desktop, .npmrc, .editorconfig, .pylintrc, .coveragerc, .flake8, …) rust-ini yes no
Nix alejandra no yes
Ruby rubyfmt no yes
PHP mago yes yes
R opt-in styler (via Rscript), tree-sitter fallback otherwise no yes
Go gofmt when present (default-on), tree-sitter fallback otherwise no yes
Rust rustfmt when present (default-on), tree-sitter fallback otherwise no yes
Zig opt-in zig fmt, tree-sitter fallback otherwise no yes
Java opt-in google-java-format, tree-sitter fallback otherwise no yes
Kotlin opt-in ktfmt, tree-sitter fallback otherwise no yes
Swift opt-in swift-format, tree-sitter fallback otherwise no yes
Dart opt-in dart format, tree-sitter fallback otherwise no yes
Gleam opt-in gleam format, tree-sitter fallback otherwise no yes
Shell shellcheck when present (default-on), opt-in shfmt, tree-sitter fallback otherwise optional optional
All text files typos spell-check yes no
Any recognized language opt-in uncomment comment removal opt-in no
Other identified grammars tree-sitter generic tier no best effort

Unsupported or unknown file types are skipped unless tree-sitter-language-pack can identify them. Some whitespace-sensitive data, template or patch grammars intentionally no-op rather than risk a destructive rewrite.

Beyond the dedicated backends above, two lint tiers run on every language:

  • The native quality metric engine — file and function length, type length, parameter count, nesting depth, cyclomatic complexity, and lazy ignore markers. See code quality metrics.
  • A built-in ast-grep rule pack of 26 rules across C#, Elixir, Go, Java, Kotlin, Python, Ruby, Rust and Swift. 13 are on by default; the other 13 author their own severity: off and are one extend_select away.

Both run in-process alongside the backends in the table, at warning severity — so neither fails an unconfigured CI on its own.

.env files autofix with poly lint --fix, and inline # dotenv-linter:off <Check> / # dotenv-linter:on <Check> comments suppress a check for the lines between them — the same directive syntax the standalone dotenv-linter CLI understands.

Rules: DuplicatedKey, EndingBlankLine, ExtraBlankLine, IncorrectDelimiter, KeyWithoutValue, LeadingCharacter, LowercaseKey, QuoteCharacter, SpaceCharacter, SubstitutionKey, TrailingWhitespace, UnorderedKey, ValueWithoutQuotes, SchemaViolation.

rust-ini’s parser discards comments while parsing, so writing its model back out would silently delete every comment in the file. poly never does that — INI formatting stays with the tree-sitter generic tier instead, which preserves comments structurally.

Rules: parse-error (a real syntax error, with the parser’s own line and column), duplicate-key, duplicate-section, key-without-value, inconsistent-separator, trailing-whitespace.

Detection is deliberately narrow. These are never treated as INI:

  • *.conf — most are not INI; nginx, httpd and friends use their own syntax.
  • *.properties — Java’s key=value syntax, not INI’s.
  • .gitconfig — quoted subsections rust-ini cannot parse.
  • systemd units — duplicate keys are legal there.

The generic tier identifies and best-effort formats hundreds of grammars, including first-class detection for C, C++, Elixir, Protobuf and the long tail covered by tree-sitter-language-pack. Java and Kotlin reach it only as the fallback when their opt-in native formatter is absent; both, along with C, C++, C# and Ruby, are languages the cross-cutting code-quality tier lints in full.

For everything else, opt into tools from the embedded mdsf catalog. Entries are PATH-probed and skipped when absent, so enabling one never breaks a run:

[tools.prettier]
enabled = true
files = "**/*.{js,ts}"