Imported from Goldziher/poly (
.cursor-plugin/skills/poly-lint-and-format/SKILL.md). Install upstream withnpx skills add Goldziher/poly --skill poly-lint-and-format. Copyright stays with the author.
poly Lint and Format
Commands
poly lint [PATHS]…— run the linters. poly applies no fixes without--fix;--fixapplies autofixes (and the whole-project fix phase).--no-workspacerestricts to the per-file tier — and is also what makes a run read-only: without it, plainpoly lintstill executes the configured whole-project tools against the live worktree, and their own side effects (a refreshed lock file, a populated build or type-checker cache) are not poly's to control. Naming paths that narrow the run skips that phase by default (poly lint .names the repo root, so it does not narrow and the phase still runs);--workspaceopts back in, and the tools then cover the whole repository regardless of the named paths and of[discovery] exclude.poly fmt [PATHS]…— dry run by default: reports what would change and writes nothing.--fixwrites changes;--checkis the explicit form of the default dry run and conflicts with--fix.poly fmtis a pure formatter — it never runs the whole-project lint phase.
Flags
--format pretty|json|toon—pretty(the default) is the colored, human-oriented output;jsonand the compacttoonvariant are machine-readable. Under--format json/toon,poly lint's whole-project section and every note (discovery, skips, errors) go to stderr so stdout stays a single valid document — a machine consumer must check the exit code, not just the payload.--exclude <glob>— skip paths on top of.gitignore(repeatable; merged with[discovery] exclude). Gitignore-style: a glob without a leading/matches a directory of that name at any depth (e2e/**also prunessrc/test/java/io/xberg/e2e/), while a leading/anchors it to the config directory (/e2e/**).poly doctorwarns when a rule matches at more than one depth.--include-excluded— check explicitly named files or directory roots even when they match the exclude set. Exclusions below an included directory stay active. Applying the exclude set to explicitly named paths is already the default, so--force-excludeis accepted only as a compatibility no-op — the flag is parsed and never read.--config <path>— point at a specificpoly.toml.--no-cache— bypass the blake3 content-hash result cache.-j <N>— parallelism;--no-color— plain output;--verbose— extra per-finding detail inprettyoutput;--debug— per-engine cache hit/miss and timing, plus debug-level logs on stderr.--fix-generated— let--fixrewrite files markedDO NOT EDIT/@generated, which it otherwise reports on but leaves alone.--deny-skips/--max-skips <N>— strict coverage. A skipped file is one nothing inspected: a path named on the command line that no engine covers (App.csproj), or a file every routed backend declined (Go-templated YAML, a hash-stamped generated file). A skip the caller instructed —--only/--skipnarrowing an engine out, orenabled = falsein config — is not charged against the budget, since it names itself in the report rather than losing coverage silently; only a poly limitation counts. Skips are always reported and named; these flags make a chargeable skip fail the run (exit2), naming every file it fired on.--verboselists every skip inprettyoutput;--format json/tooncarries the full set both as a top-levelskippedarray and as syntheticresultsentries —summary.skippedis the authoritative count, so read it first and use the set only to name the files.
Exit codes
0— clean (no findings, no drift).1— error-severity findings, formatting drift, or a failing whole-project tool.2— an error (bad config, tool failure), or work the run could not verify: a missing path argument, a file an engine failed on — including apoly fmtfile that could not reach a fixed point within its five-pass cap, now reported as an error rather than silently claimed as formatted — or a--deny-skips/--max-skipsbreach.
poly lint exits non-zero only on error-severity findings; warnings do not fail CI —
which is why the on-by-default quality and built-in ast-grep rules (all warnings) never
turn a green pipeline red on their own.
Inline suppression
Silence one finding in place with a directive written in the host language's own comment syntax:
let value = map.get(key).unwrap(); // poly: allow[unwrap-used] key is validated above
poly: allow[RULE] reason— a comment-only line suppresses the next non-blank line; a trailing comment suppresses its own line.poly: allow-file[RULE] reason— suppresses the whole file wherever it appears, and is the only form that can suppress a diagnostic with no span.[RULE]accepts a comma-separated list, or*for every rule.- A reason is mandatory. A directive whose text after
]has no alphanumeric character does not suppress, and reportslazy-ignoreinstead — an empty comment cannot buy a bypass. - Applied centrally in the runner, so it works for every engine (ruff, oxlint, quality,
ast-grep, …). For a whole file or a class of files, use
[per-file-ignores]inpoly.tomlinstead.
The loop
poly fmt --check . --format jsonandpoly lint . --format json— capture drift and findings, checking the exit code.- Read the JSON to see exactly which files and rules are involved.
poly fmt --fix .thenpoly lint --fix .to apply what is auto-fixable.- Re-run the checks; hand-fix whatever remains (exit code back to 0).