Quickstart
poly needs no configuration to be useful. Point it at a repository and it works out what each file is and which backend should handle it.
-
Lint everything
Section titled “Lint everything”Terminal window $ poly lint./app.pywarning ruff T201 5:5 `print` foundwarning ruff ANN201 4:5 Missing return type annotation for public function `main`error ruff F401 1:8 `os` imported but unused3 issues found.2 files linted1 issue fixable with the `--fix` optionOnly the
errorline fails the run. Warning-severity findings — the code-quality tier,typos, and the widened rule selections — never redden CI on their own. -
Check formatting
Section titled “Check formatting”Terminal window $ poly fmt --checkwould reformat ./src/main.rs1 file will change.2 files checkedpoly fmtis a dry run by default, which is what a CI job wants.--checkis just the explicit form of the default. -
Apply changes
Section titled “Apply changes”Terminal window $ poly fmt --fixreformatted ./src/main.rs1 file reformatted.2 files checkedTerminal window $ poly lint --fix -
Wire the git hooks
Section titled “Wire the git hooks”Terminal window $ poly hooks install✓ Installed 2 git hooks in .git/hooks› commit-msg› pre-commitLint, format and Conventional-Commit checks now run on every
git commit, with no external hook framework in between.
A first poly.toml
Section titled “A first poly.toml”Everything above works with no config at all. Add one when you want to change poly’s opinions:
[defaults]line_length = 120line_ending = "lf"final_newline = truetrim_trailing_whitespace = true
[discovery]exclude = ["vendor/**", "fixtures/**"]
[lint.python.ruff]extend_select = ["D"]
[hooks]stages = ["pre-commit", "commit-msg"]
[hooks.builtin]lint = truefmt = truecommit = { stages = ["commit-msg"] }file_safety = truepoly.local.toml layers machine-local overrides on top, and nested poly.toml files cascade in a
monorepo. See Configuration for the full surface.
Exit codes are a contract
Section titled “Exit codes are a contract”| Code | Meaning |
|---|---|
0 |
Clean. |
1 |
Error-severity findings, a failed whole-project tool, or (for poly fmt) files that would change. |
2 |
The run verified less than it claims — a file an engine failed on, a skip budget exceeded, a config error, or a report that failed to serialize. |
A --format json or --format toon consumer must check the exit code, not just the payload:
the whole-project phase’s own pass/fail is written to stderr so that stdout stays a single valid
document.
name: linton: [push, pull_request]
jobs: poly: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: Goldziher/poly@v0 - run: poly fmt --check . - run: poly lint --deny-skips .--deny-skips turns any skipped file into an exit-2 failure, so the job cannot quietly stop
covering part of the tree. Use --max-skips <N> if you have a known, budgeted set of skips.
Add -q on a large repository to trim the per-file discovery detail; every count and reason still
appears in the summary.