Skip to content

One binary lints and formats the whole repository

Curated Rust backends for the languages that matter, a tree-sitter tier for everything else, and one poly.toml driving lint, format, git hooks and commit policy. No Node, no Python, no Ruby, no JVM.

poly wraps ruff, oxc, biome, mago, taplo, rumdl, sqruff, malva, markup_fmt, rubyfmt and more as in-process Rust crates — not subprocesses — and falls through to a tree-sitter generic tier for the long tail. Two cross-cutting lint tiers, a code-quality metrics engine and a 26-rule built-in ast-grep pack, run on top of every language.

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.

No toolchain to install

Most backends are Rust crates compiled into the binary. rustfmt, gofmt and shellcheck are used when found on PATH; everything else is opt-in. A missing tool lowers fidelity, never fails a run.

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.

Built for agents

A Claude/Codex plugin and a stdio MCP server ship in the box. An agent calls poly’s eleven tools directly instead of shelling out and parsing terminal text.

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.

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/poly/main/install.sh | sh