Skip to content

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.

Every file in the repository is checked by one of four mechanisms, and every result lands in one report with one exit code:

  • Components — signed engines downloaded per language on first use: ruff, oxc, biome, mago, sqruff, rubyfmt, alejandra, shfmt, …
  • Host tools — rustfmt, gofmt, shellcheck when installed; zig fmt, ktfmt and others opt-in.
  • Recipes — opt-in ecosystem tools: golangci-lint, hadolint, actionlint, buf, checkstyle, …
  • 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.

Engines on demand

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.

Terminal window
curl -fsSL https://raw.githubusercontent.com/Goldziher/polylint/main/install.sh | sh