One linter and formatter for every language in your repository
A small binary, poly, and one poly.toml. It fetches the engine each language needs as a signed component, uses the canonical tools you already have, and runs ecosystem linters as built-in recipes — with git hooks, commit linting and an MCP server included.
Tree-sitter tier — best-effort formatting for 300+ other grammars.
polylint runs ruff, oxc, biome, mago, taplo, rumdl, sqruff, markup_fmt, rubyfmt and more as
engines shipped in signed components, falls through to a tree-sitter tier for the long tail, and
adds two cross-cutting lint tiers on every language: a code-quality metrics engine and a 26-rule
built-in ast-grep pack.
A core binary downloads the components for the languages a repository contains, verifies them
against a lock embedded in the binary, and caches them. The Linux musl build has every engine
linked in. A missing engine is an error or a counted skip, never a silent downgrade.
Works with your toolchain
rustfmt, gofmt and shellcheck are used when found on PATH. Recipes run golangci-lint,
hadolint, actionlint, buf, checkstyle and others batched, with per-line findings. JVM, Node and
Python tools use the runtime you already have — polylint never bundles one.
Fast on real repositories
Django: 3,113 files in 0.82s. home-assistant: 25,443 files in 3.5s. Cold cache, on
Apple Silicon — a blake3 content hash skips unchanged work and rayon splits the rest across
cores.
One config file
poly.toml drives linting, formatting, git hooks and commit-message policy. Nested configs
cascade in a monorepo; extends shares a baseline across repositories.
Git hooks without a framework
poly hooks install wires lint, format, file-safety and Conventional-Commit checks into
git. Hooks validate a snapshot of the index, never the live worktree.
Built for agents
Plugins for Claude, Codex, Cursor, OpenCode, Pi, Hermes, Gemini, Kimi and Copilot, and a
stdio MCP server with fourteen tools, so an agent calls polylint directly instead of shelling
out and parsing terminal text.
Honest coverage accounting
Every skipped file is counted with its reason, so a run that checked nothing can never look
like a clean pass. --deny-skips turns that into a CI gate.