The polyglot lint and format pipeline for whole repositories.
Polylint ships the poly CLI: one config, one Rust pipeline, curated in-process backends,
tree-sitter fallback for everything else, and repo-wide cache + parallel execution. No language
runtime is required for the default path; gofmt and rustfmt are used when present, and other
external tools are opt-in.
Lint + format · one poly.toml · pure Rust default · blake3 cache · rayon parallelism · hooks +
commit checks · JSON + TOON + MCP
Install · Quickstart · What You Get · How It Works · Backends · CLI
$ poly fmt --check
would reformat crates/example/src/main.rs
1 file(s) will change of 1 file(s)
$ poly fmt --fix
reformatted crates/example/src/main.rs
1 changed of 1 file(s)
$ poly lint --format toon
path: crates/example/src/main.rs
diagnostics[0]: engine=ruff, code=F401, severity=warning, title="`os` imported but unused"
$ poly hooks install
✓ Installed 10 git hooks in .git/hooks
› commit-msg
› pre-commit
› pre-push
…poly fmt is a dry run by default (CI-friendly); add --fix to write changes, and poly lint --fix to apply lint autofixes. poly hooks install wires the git hooks once — lint, format, and
commit checks then run on every git commit.
| Capability | What it does | Main surfaces |
|---|---|---|
| Repo-wide lint + format | Discovers files, routes each language to the best available backend, and reports normalized diagnostics and formatting drift. | poly lint · poly fmt |
| One config | poly.toml drives linting, formatting, hooks, commit-message policy, cache settings, and optional tool catalog entries. |
[defaults] · [lint.*] · [fmt.*] · [hooks] · [tools] |
| Curated Rust backends | Wraps high-quality Rust libraries in-process: oxc, ruff internals, taplo, rumdl, sqruff, malva, markup_fmt, mago, and more. | Backend registry |
| Generic fallback | Uses tree-sitter-language-pack for identified languages without a dedicated backend, reindenting supported grammars and normalizing whitespace where safe. |
treesitter tier |
| Cache + parallelism | Runs per file with rayon and skips unchanged work with a blake3 content-hash cache keyed by file bytes, engine, version, and resolved config. | poly cache · --no-cache · -j |
| Git hooks | Runs first-class builtins and inline hook jobs from poly.toml, with file-safety checks and Cargo tools available as builtins. |
poly hooks install · poly hooks run |
| Commit checks | Enforces Conventional Commits and strips AI-attribution trailers through the bundled gitfluff engine. |
poly commit |
| Agent-friendly output | Emits structured JSON and compact TOON, and exposes lint/format/cache operations over an MCP stdio server. | --format json · --format toon · poly mcp |
| Optional breadth tier | Enables tools from the embedded mdsf catalog only when you opt in; commands are PATH-probed and skipped when absent. | [tools.<name>] |
| Simple distribution | Installs prebuilt release archives containing the poly binary, verified by release checksums. |
Installer · GitHub Action · Homebrew · npm · PyPI |
Polylint is distributed like ruff or biome: prebuilt release artifacts plus thin installers and
package wrappers. The workspace crates are not published to crates.io.
curl -fsSL https://raw.githubusercontent.com/Goldziher/polylint/main/install.sh | shWindows PowerShell:
irm https://raw.githubusercontent.com/Goldziher/polylint/main/install.ps1 | iexBoth installers detect the platform, download the matching release archive, verify it against
sha256sums.txt, and install poly. Set POLY_VERSION=v0.4.0 to pin a version or
POLY_INSTALL_DIR=/path/to/bin to choose the destination.
- uses: Goldziher/polylint@v0
with:
version: latestThe action resolves the requested release, caches the installed binary bundle by version and
platform, and adds poly to PATH.
brew install Goldziher/tap/polylint
npm install -g @nhirschfeld/polylint
pip install polylint
cargo binstall --git https://github.com/Goldziher/polylint poly-cliThe npm and PyPI packages are thin wrappers that download the verified prebuilt binary bundle for your platform.
Download a release archive from GitHub Releases, or build from source:
git clone https://github.com/Goldziher/polylint
cd polylint
cargo build --releaseSource builds place the binary at target/release/poly.
Pipeline
poly discovers files once, plans engines once per language, prefetches the generic tier's
tree-sitter grammars, and then runs the per-file work in parallel. Each backend returns the same
Diagnostic and FormatOutput shapes, so reporting, cache behavior, and MCP output stay uniform.
flowchart LR
A["paths"]
B["discover<br/>gitignore aware"]
C["plan engines<br/>per language"]
D["rayon file loop"]
E["blake3 cache"]
F["lint / format<br/>reports"]
A --> B --> C --> D
D <-->|hit / miss| E
D --> F
Zero-dependency default
The default path does not require Python, Node, Go, a JVM, or a project-local toolchain. Most
backends are Rust crates compiled into the binary. Two canonical native formatters are default-on
when present: gofmt for Go and rustfmt for Rust. If either is missing, the language falls back to
the generic tier. zig fmt, shfmt, shellcheck, and catalog tools are opt-in and are skipped when
absent.
Cache and debug data
The result cache is keyed by file bytes, engine name, engine version(), and resolved engine
configuration. A tool upgrade or config change invalidates stale entries. --debug reports per-file
engine timing and cache hit/miss data in pretty output and attaches it to JSON/TOON output.
Polylint discovers the nearest poly.toml. polylint.toml is still read as a fallback for older
projects, and poly.local.toml can layer local overrides over the primary config. In a monorepo,
nested poly.toml files cascade — see Nested config in a monorepo.
[defaults]
line_length = 120
line_ending = "lf"
final_newline = true
trim_trailing_whitespace = true
[discovery]
# Gitignore-style globs pruned from the file walk on every direct
# `poly lint` / `poly fmt` run (the CI and GitHub Action path), on top of
# `.gitignore` and the built-in vendored/generated prune set.
exclude = ["test_apps/**", "docs/snippets/**", "artifacts/**"]
[fmt.python.ruff]
docstring_code_format = true
docstring_code_line_length = 120
[lint.python.ruff]
select = ["E", "F", "W"]
# All tools support uniform `select`/`ignore` for rule filtering (rule codes or
# category names). Some backends (mago, R) support per-rule overrides under
# `[lint.<lang>.<tool>.rules.<id>]` for backend-specific configuration.
[lint.php.mago]
select = ["correctness", "security"] # categories or rule codes
ignore = ["no-else-clause"]
php_version = "8.2"
[lint.php.mago.rules.cyclomatic-complexity]
level = "warning" # error | warning | info | hint (mago, R only)
threshold = 20
# Suppress specific rules per path glob (lint-only), across every backend.
[per-file-ignores]
"tests/**" = ["F401"]
"**/*.generated.php" = ["correctness"]
[hooks]
stages = ["pre-commit", "commit-msg"]
[hooks.builtin]
polylint = true
polyfmt = true
commit = { stages = ["commit-msg"] }
file_safety = true
cargo = trueRun poly from a monorepo root and each sub-project's poly.toml cascades over the root, the
way ruff and eslint resolve config (see ADR 0018). A
nested config declares only the diff — it inherits [defaults], the [lint.*]/[fmt.*] rule
tables, and [per-file-ignores] from its ancestors, up to the workspace root:
# repo/poly.toml — the workspace root
[workspace]
root = true # stops the upward cascade here (a repo's `.git` dir is
# an implicit boundary too, so this is optional in a repo)
[defaults]
line_length = 120
[lint.python.ruff]
select = ["E", "F", "W"]# repo/frontend/poly.toml — governs repo/frontend/** only
[defaults]
line_length = 100 # overrides the root; ruff select is inherited
[per-file-ignores]
"*.spec.ts" = ["no-console"] # glob is relative to repo/frontend/Resolution rules:
- Rules and defaults cascade (root → child, deep-merged; the nearest config wins).
[discovery] excludeglobs are additive across the tree — each config's excludes prune its own subtree, so a parent exclude already covers its children.[per-file-ignores]globs are relative to the directory of the config that declares them.--config <path>pins one config for the whole run and bypasses nested resolution.
Opt into tools from the embedded mdsf catalog only when you want them:
[tools.prettier]
enabled = true
languages = ["javascript", "typescript"]
[tools.black]
enabled = true
languages = ["python"]Catalog tools are capability-probed on PATH; a missing binary is skipped instead of making the
whole run fail.
Install poly's git hooks once — they then run on every git commit:
poly hooks installHooks come from poly.toml: builtins plus inline jobs. poly never clones or runs foreign
pre-commit repositories.
Builtin hooks
| Builtin | Runs |
|---|---|
polylint |
poly lint over the staged files |
polyfmt |
poly fmt --check over the staged files |
commit |
Conventional Commit + AI-trailer check on the commit message (gitfluff) |
file_safety |
Pure-Rust checks: merge-conflict markers, added large files, private keys, case conflicts, and shebang/executable parity |
cargo |
Whole-workspace cargo clippy, cargo sort, cargo machete, and cargo deny — each PATH-probed and skipped when absent |
Add an inline job for anything else — it wraps an existing script or task target, no plugin needed:
[hooks.pre-commit.scripts.docs]
script = "scripts/check-docs.sh"
runner = "bash"
files = "**/*.md"Polylint uses a tiered model:
- Curated Rust backends for high-fidelity lint and format support.
- Native-toolchain backends for canonical first-party formatters when configured or present.
- Tree-sitter generic formatting for identified languages without a dedicated backend.
- Optional catalog tools from the embedded mdsf 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 |
| Nix | alejandra | no | yes |
| Ruby | rubyfmt | no | yes |
| PHP | mago | yes | yes |
| R | tree-sitter generic tier | no | best effort |
| Go | gofmt when present, tree-sitter fallback otherwise |
no | yes |
| Rust | rustfmt when present, tree-sitter fallback otherwise |
no | yes |
| Zig | opt-in zig fmt, tree-sitter fallback otherwise |
no | yes |
| Shell | opt-in shellcheck + shfmt, tree-sitter fallback otherwise |
optional | optional |
| All text files | typos spell-check | yes | 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, the generic tree-sitter tier identifies and best-effort
formats hundreds of grammars — including first-class detection for Java, Kotlin, C/C++, Elixir,
Protobuf, and the long tail covered by tree-sitter-language-pack.
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
languages = ["javascript", "typescript"]Embedded tool catalog (348 tools across 175 languages)
Opt in per tool with [tools.<name>] enabled = true. Each command is probed on PATH and skipped when absent, so listing one never makes a run fail.
| Tool | Type | Languages |
|---|---|---|
| action-validator | linter | yaml |
| actionlint | linter | yaml |
| air | formatter | r |
| alejandra | formatter | nix |
| alex | spell-check | markdown |
| ameba | linter | crystal |
| ansible-lint | linter | ansible |
| api-linter | linter | protobuf |
| asmfmt | formatter | go |
| astyle | formatter | c, c#, c++, java, objective-c |
| atlas | formatter | hcl |
| auto-optional | formatter | python |
| autocorrect | spell-check | |
| autoflake | linter | python |
| autopep8 | formatter | python |
| bashate | formatter | bash |
| beancount-black | formatter | beancount |
| beautysh | formatter | bash, shell |
| bibtex-tidy | formatter | bibtex |
| bicep | formatter | bicep |
| biome | formatter, linter | javascript, json, typescript, vue |
| black | formatter | python |
| blade-formatter | formatter | blade, laravel, php |
| blue | formatter | python |
| bpfmt | formatter | blueprint |
| brighterscript-formatter | formatter | brighterscript, brightscript |
| brittany | formatter | haskell |
| brunette | formatter | python |
| bslint | linter | brightscript, brightscripter |
| buf | formatter | protobuf |
| buildifier | formatter | bazel |
| c3fmt | formatter | c3 |
| cabal | formatter | cabal |
| cabal-fmt | formatter | cabal |
| cabal-gild | formatter | cabal, haskell |
| cabal-prettify | formatter | cabal |
| caddy | formatter | caddy |
| caramel | formatter | caramel |
| cedar | formatter | cedar |
| cfn-lint | linter | cloudformation, json, yaml |
| checkmake | linter | makefile |
| clang-format | formatter | c, c#, c++, java, javascript, json, objective-c, protobuf |
| clang-tidy | linter | c++ |
| clj-kondo | linter | clojure, clojurescript |
| cljfmt | formatter | clojure |
| cljstyle | formatter | clojure |
| cmake-format | formatter | cmake |
| cmake-lint | linter | cmake |
| codeql | formatter | codeql |
| codespell | spell-check | |
| coffeelint | linter | coffeescript |
| cppcheck | linter | c, c++ |
| cpplint | linter | c++ |
| crlfmt | formatter | go |
| crystal | formatter | crystal |
| csharpier | formatter | c# |
| css-beautify | formatter | css |
| csscomb | formatter | css |
| csslint | linter | css |
| cue | formatter | cue |
| cueimports | formatter | cue |
| curlylint | linter | django, html, jinja, liquid, nunjucks, twig |
| d2 | formatter | d2 |
| dart | formatter, linter | dart, flutter |
| dcm | formatter, linter | dart, flutter |
| deadnix | linter | nix |
| deno | formatter, linter | javascript, json, typescript |
| dfmt | formatter | d |
| dhall | formatter | dhall |
| djade | formatter | django, python |
| djangofmt | formatter | django, html, python |
| djlint | formatter, linter | handlebars, html, jinja, mustache, nunjucks, twig |
| docformatter | formatter | python |
| dockerfmt | formatter | docker |
| dockfmt | formatter | docker |
| docstrfmt | formatter | python, restructuredtext, sphinx |
| doctoc | formatter | markdown |
| dotenv-linter | linter | env |
| dprint | formatter | |
| dscanner | linter | d |
| dune | formatter | dune, ocaml, reasonml |
| duster | formatter, linter | php |
| dx | formatter | rsx, rust |
| easy-coding-standard | formatter, linter | php |
| efmt | formatter | erlang |
| elm-format | formatter | elm |
| eradicate | linter | python |
| erb-formatter | formatter | erb, ruby |
| erg | linter | erg |
| erlfmt | formatter | erlang |
| eslint | linter | javascript, typescript |
| fantomas | formatter | f# |
| fish_indent | formatter | fish |
| fixjson | formatter, linter | json, json5 |
| floskell | formatter | haskell |
| flynt | formatter | python |
| fnlfmt | formatter | fennel |
| forge | formatter | solidity |
| fortitude | linter | fortran |
| fortran-linter | formatter, linter | fortran |
| fourmolu | formatter | haskell |
| fprettify | formatter | fortran |
| futhark | formatter | futhark |
| fvm | formatter, linter | dart, flutter |
| gci | formatter | go |
| gdformat | formatter | gdscript |
| gdlint | linter | gdscript |
| gersemi | formatter | cmake |
| ghokin | formatter | behat, cucumber, gherkin |
| gleam | formatter | gleam |
| gluon | formatter | gluon |
| gofmt | formatter | go |
| gofumpt | formatter | go |
| goimports | formatter | go |
| goimports-reviser | formatter | go |
| golangci-lint | formatter, linter | go |
| golines | formatter | go |
| google-java-format | formatter | java |
| gospel | spell-check | go |
| grafbase | linter | graphql |
| grain | formatter | grain |
| hadolint | linter | dockerfile |
| haml-lint | linter | haml |
| hclfmt | formatter | hcl |
| hfmt | formatter | haskell |
| hindent | formatter | haskell |
| hledger-fmt | formatter | hledger |
| hlint | linter | haskell |
| hongdown | formatter | markdown |
| html-beautify | formatter | html |
| htmlbeautifier | formatter | erb, html, ruby |
| htmlhint | linter | html |
| hurlfmt | formatter | hurl |
| imba | formatter | imba |
| inko | formatter | inko |
| isort | formatter | python |
| janet-format | formatter | janet |
| joker | formatter, linter | clojure |
| jq | formatter | json |
| jqfmt | formatter | jq |
| js-beautify | formatter | javascript |
| json5format | formatter | json, json5 |
| json_repair | linter | json |
| jsona | formatter, linter | jsona |
| jsonlint | formatter, linter | json |
| jsonnet-lint | linter | jsonnet |
| jsonnetfmt | formatter | jsonnet |
| jsonpp | formatter | json |
| juliaformatter_jl | formatter | julia |
| just | formatter | just |
| kcl | formatter | kcl |
| kdlfmt | formatter | kdl |
| kdoc-formatter | formatter | kotlin |
| keep-sorted | formatter | |
| ktfmt | formatter | kotlin |
| ktlint | linter | kotlin |
| kube-linter | linter | kubernetes, yaml |
| kulala-fmt | formatter | http |
| leptosfmt | formatter | rust |
| liquidsoap-prettier | formatter | liquidsoap |
| luacheck | formatter | lua |
| luaformatter | formatter | lua |
| luau-analyze | linter | luau |
| mado | linter | markdown |
| mago | formatter, linter | php |
| markdownfmt | formatter | markdown |
| markdownlint | linter | markdown |
| markdownlint-cli2 | linter | markdown |
| markuplint | linter | html |
| mbake | formatter, linter | make |
| md-padding | formatter | markdown |
| mdformat | formatter | markdwon |
| mdsf | formatter | markdown |
| mdslw | formatter | markdown |
| meson | formatter | meson |
| mh_lint | linter | matlab |
| mh_style | formatter | matlab |
| mise | tool | |
| misspell | spell-check | |
| mix | formatter | elixir |
| mojo | formatter | mojo |
| muon | formatter, linter | meson |
| mypy | linter | python |
| nasmfmt | formatter | assembly |
| nginxbeautifier | formatter | nginx |
| nginxfmt | formatter | nginx |
| nickel | formatter | nickel |
| nimpretty | formatter | nim |
| nixfmt | formatter | nix |
| nixpkgs-fmt | formatter | nix |
| nomad | formatter | hcl |
| nph | formatter | nim |
| npm-groovy-lint | formatter, linter | groovy |
| nufmt | formatter | nushell |
| ocamlformat | formatter | ocaml |
| ocp-indent | formatter | ocaml |
| odinfmt | formatter | odin |
| oelint-adv | linter | bitbake |
| opa | formatter | rego |
| openapi-format | formatter | json, openapi, yaml |
| ormolu | formatter | haskell |
| oxfmt | formatter | javascript, typescript |
| oxlint | linter | javascript, typescript |
| packer | formatter | hcl |
| panache | formatter | markdown, pandoc, quarto, rmarkdown |
| pasfmt | formatter | delphi, pascal |
| perflint | linter | python |
| perltidy | formatter | perl |
| pg_format | formatter | sql |
| php-cs-fixer | formatter, linter | php |
| phpcbf | formatter | php |
| phpinsights | linter | php |
| pint | formatter, linter | php |
| pkl | formatter | pkl |
| prettier | formatter | angular, css, ember, graphql, handlebars, html, javascript, json, less, markdown, scss, typescript, vue |
| prettierd | formatter | angular, css, ember, graphql, handlebars, html, javascript, json, less, markdown, scss, typescript, vue |
| pretty-php | formatter | php |
| prettypst | formatter | typst |
| prisma | formatter | prisma |
| proselint | spell-check | |
| protolint | linter | protobuf |
| ptop | formatter | pascal |
| pug-lint | linter | pug |
| puppet-lint | linter | puppet |
| purs-tidy | formatter | purescript |
| purty | formatter | purescript |
| pycln | formatter | python |
| pycodestyle | linter | python |
| pydoclint | linter | python |
| pydocstringformatter | formatter | python |
| pydocstyle | formatter | python |
| pyflakes | linter | python |
| pyink | formatter | python |
| pylint | linter | python |
| pymarkdownlnt | formatter, linter | markdown |
| pyment | formatter | python |
| pyrefly | linter | python |
| pyupgrade | linter | python |
| qmlfmt | formatter | qml |
| qmlformat | formatter | qml |
| qmllint | linter | qml |
| quick-lint-js | linter | javascript |
| raco | formatter | racket |
| reek | linter | ruby |
| refmt | formatter | reason |
| reformat-gherkin | formatter | gherkin |
| refurb | linter | python |
| regal | linter | rego |
| reorder-python-imports | formatter | python |
| rescript | formatter | rescript |
| revive | linter | go |
| roc | formatter | roc |
| rstfmt | formatter | restructuredtext |
| rubocop | formatter, linter | ruby |
| rubyfmt | formatter | ruby |
| ruff | formatter, linter | python |
| rufo | formatter | ruby |
| rumdl | formatter, linter | markdown |
| rune | formatter | rune |
| runic | formatter | julia |
| rustfmt | formatter | rust |
| rustywind | formatter | html |
| salt-lint | linter | salt |
| scala | formatter | scala |
| scalafmt | formatter | scala |
| scalariform | formatter | scala |
| selene | linter | lua |
| semistandard | formatter, linter | javascript |
| shellcheck | linter | bash, shell |
| shellharden | linter | bash, shell |
| shfmt | formatter | shell |
| sleek | formatter | sql |
| slim-lint | linter | slim |
| smlfmt | formatter | standard-ml |
| snakefmt | formatter | snakemake |
| solhint | linter | solidity |
| sphinx-lint | linter | python, restructredtext |
| sql-formatter | formatter | sql |
| sqlfluff | formatter, linter | sql |
| sqlfmt | formatter | sql |
| sqlint | linter | sql |
| sqruff | formatter, linter | sql |
| squawk | linter | postgresql, sql |
| standardjs | formatter, linter | javascript |
| standardrb | formatter, linter | ruby |
| statix | linter | nix |
| stylefmt | formatter | css, scss |
| stylelint | linter | css, scss |
| stylish-haskell | formatter | haskell |
| stylua | formatter | lua |
| superhtml | formatter | html |
| svlint | linter | systemverilog |
| swift-format | formatter | swift |
| swiftformat | formatter | swift |
| swiftlint | linter | swift |
| taplo | formatter | toml |
| tclfmt | linter | tcl |
| tclint | linter | tcl |
| templ | formatter | go, templ |
| terraform | formatter | terraform |
| terragrunt | formatter | hcl |
| tex-fmt | formatter | latex |
| textlint | spell-check | |
| tlint | linter | php |
| tofu | formatter | terraform, tofu |
| tombi | formatter, linter | toml |
| toml-sort | formatter | toml |
| topiary | formatter | |
| tryceratops | linter | python |
| ts-standard | formatter, linter | typescript |
| tsp | formatter | typespec |
| tsqllint | linter | sql |
| twig-cs-fixer | formatter, linter | twig |
| twigcs | linter | php, twig |
| txtpbfmt | formatter | protobuf |
| ty | linter | python |
| typos | spell-check | |
| typstfmt | formatter | typst |
| typstyle | formatter | typst |
| ufmt | formatter | python |
| uiua | formatter | uiua |
| unimport | formatter | python |
| usort | formatter | python |
| v | formatter | v |
| vacuum | linter | json, openapi, yaml |
| verusfmt | formatter | rust, verus |
| veryl | formatter | veryl |
| vhdl-style-guide | formatter | vhdl |
| vint | linter | vimscript |
| wa | formatter | wa |
| wfindent | formatter | fortran |
| write-good | linter | |
| xmlformat | formatter | xml |
| xmllint | linter | xml |
| xo | linter | javascript, typescript |
| xq | formatter | html, xml |
| yamlfix | formatter | yaml |
| yamlfmt | formatter | yaml |
| yamllint | linter | yaml |
| yapf | formatter | python |
| yard-lint | linter | ruby |
| yew-fmt | formatter | rust |
| yq | formatter | yaml |
| zig | formatter | zig |
| ziggy | formatter | ziggy |
| zprint | formatter | clojure, clojurescript |
| zsweep | linter | zsh |
| zuban | linter | python |
lint and format
poly lint [PATHS]...
poly fmt [PATHS]...
--fix Apply lint fixes or formatting in place.
--check Explicit fmt dry run. This is the default.
--format <pretty|json|toon> Output format. Default: pretty.
--config <PATH> Use an explicit config file.
--exclude <GLOB> Exclude paths from discovery (repeatable; merged
with `[discovery] exclude`).
--no-cache Bypass the result cache.
-j, --jobs <N> Parallel jobs. Default: logical cores.
--no-color Disable colored output.
--verbose Pretty output includes descriptions, URLs, and metadata.
--debug Include cache hit/miss and timing data.
Exit codes:
| Code | Meaning |
|---|---|
| 0 | No issues, no formatting drift, or all writes succeeded |
| 1 | Lint findings remain, or dry-run formatting would change files |
| 2 | Internal error such as config or I/O failure |
commit, hooks, cache, and MCP
poly commit "feat: add backend"
poly hooks install
poly cache stats
poly cache size
poly cache gc
poly cache clean
poly mcp --config /path/to/poly.toml
poly migrate # dry-run: report what would move into poly.toml
poly migrate --write # absorb tool configs into poly.toml, remove redundant filespoly migrate folds settings from ruff/taplo/markdownlint/typos config files
(and pyproject.toml [tool.ruff]/[tool.typos]/[tool.codespell]) into poly.toml,
then deletes or strips only the sources poly can fully honor — files it delegates to
(rustfmt.toml, .golangci.yml, clippy.toml, …) and anything not fully representable
are kept. It is a dry-run report by default; --write applies, --recurse walks nested
projects, and --verify re-runs lint/format after writing.
The MCP server exposes tools for lint, format, and cache operations. Read-only tools are
lint, format_check, and cache_stats; mutating tools are lint_fix, format_write,
and cache_clean. The lint/format tools accept paths, exclude (gitignore-style glob patterns,
merged with config), and config (explicit config file path) parameters for full feature parity
with the CLI.
Every MCP operation returns the same JSON shape as the corresponding CLI command with --format json.
crates/
├── polylint-core/ # Engine trait, registry, discovery, runner, reports
├── poly-config/ # poly.toml schema and config loading
├── poly-cli/ # poly umbrella CLI
├── gitfluff/ # Conventional Commit linter
├── poly-hooks/ # git-hook runner
├── poly-mcp/ # MCP stdio server
├── poly-cache/ # blake3 result cache
├── poly-catalog/ # embedded mdsf tool catalog
└── conformance/ # differential test harness
Keep changes small and test-backed. New or changed backends should include representative known-bad
and known-unformatted fixtures under crates/polylint-core/tests/, and should preserve the uniform
Engine boundary. Before committing, run:
poly hooks install # wires lint/format/cargo checks into git; they run on every commit
cargo test --workspaceMIT - see LICENSE.