Skip to content

Configuration reference

poly reads a single poly.toml. This page is the key-by-key reference; the Configuration guide explains how the pieces fit together.

poly publishes a JSON Schema for poly.toml at:

https://goldziher.github.io/poly/poly.schema.json

Point your editor at it for validation and autocomplete. The simplest way is the schema directive as the first line of poly.toml:

poly.toml
#:schema https://goldziher.github.io/poly/poly.schema.json
[defaults]
line_length = 120

The directive is an ordinary TOML comment that taplo and the editors built on it understand, and poly fmt leaves it in place. You can also generate the schema locally — it is derived from the same types the parser uses:

Terminal window
poly config schema --output poly.schema.json

The per-engine [engines.<id>] tables are autocomplete hints: each backend lists the keys it declares, but the tables stay open because a language id may be any tree-sitter grammar and some backends derive their key set from an upstream type. poly lint remains the authority — it reports unknown-config-key for any key no engine reads. The v2 schema is committed as schemas/poly-v2.schema.json; poly config schema prints the one the running binary uses.

Section Purpose
required_version, root Pin the poly version; stop the config cascade.
[components] Which downloadable engine components a run may use.
[defaults] Line width, line endings, whitespace — the base every formatter layers on.
[discovery] The file walk: excludes, the prune set, generated files.
[engines.<id>] Per-engine rule and formatter configuration, including ast-grep’s rule directories.
[workspace] When the whole-project phase of poly lint runs.
[per_file_ignores] Suppress rules by path glob.
[tools] Opt into catalog tools.
[cache] Result-cache and sccache configuration.
[commit] poly commit message linting and cleanup.
[hooks] Git-hook stages, builtins and inline jobs.
extends Share configuration from local or pinned-remote bases.
Key Type Default Meaning
required_version string — Semver requirement on the running poly (">=2.0, <3"). Components version in lock-step with poly, so it pins them too. The GitHub Action reads it for version: from-config.
root boolean false Stop the upward config cascade here (a .git directory is an implicit boundary). Replaces v1’s [workspace] root.

Selection and policy for downloadable engine components. See Components and offline use.

Key Type Default Meaning
enable "auto" or array "auto" "auto" derives components from the discovered files and configured engines; an array names components or presets.
disable array [] Components never to use. Configuring an engine of a disabled component is a config error.
install "auto" | "never" "auto" Whether a run may download a missing component.
on_missing "fail" | "skip" "fail" Exit 2, or skip the files and charge them to the skip budget, when a needed component is unavailable. --on-missing overrides it.

The opinionated base layer. Each key is applied wherever a tool exposes the setting.

Key Type Default Meaning
line_length integer 120 Target maximum line length.
line_ending string "lf" "lf" or "crlf".
final_newline boolean true Enforce a single trailing newline.
trim_trailing_whitespace boolean true Strip trailing whitespace.
Key Type Default Meaning
exclude string or array [] Gitignore-style globs pruned from the walk. A leading / anchors to the config directory; otherwise it matches at any depth. Accumulates across extends (use exclude_mode = "replace" to opt out).
force_exclude boolean true Apply exclude to explicitly named paths too.
no_prune string or array [] Directory names to keep despite the built-in prune set (build, dist, …).
generated boolean true Whether poly lints and formats machine-generated files.

[engines.<id>]: one table per engine, keyed by the engine id (ruff, oxc, taplo, rumdl, typos, astgrep, quality, uncomment, …). See the Backend coverage page for which engine serves each language. Options that apply everywhere sit directly in the table; narrow with sub-tables:

[engines.ruff] # every phase, every language
select = ["E", "F"]
[engines.ruff.format] # the format phase only (also: .lint)
line_length = 100
[engines.ruff.lang.python] # one language (also: .lang.python.lint / .format)
target_version = "py312"
[engines.ruff.rules.ANN201] # a per-rule override
level = "error"

Precedence, lowest to highest: tool defaults, the tool’s native config files, [engines.<id>], its lint or format sub-table, its lang.<language> sub-table, then lang.<language>.lint or .format. The names enabled, lint, format, lang and rules are reserved.

Every engine table accepts enabled (boolean; an absent key means the engine’s own default — typos is off unless [engines.typos] enabled = true). Linter backends that participate in rule selection accept the uniform triple:

Key Type Meaning
select array Replace the default rule set with these codes / categories.
extend_select array Add to the default rule set.
ignore array Remove from the selected set.
rules.<id> table Per-rule override: [engines.<id>.rules.<code>] level = "error" | "warning" | "info" | "hint", plus rule parameters.

Each engine also reads its own keys ([engines.ruff] line_length, [engines.mago] php_version, …). poly lint reports a key that no engine reads as unknown-config-key with a source span, and poly config validate checks the keys offline from the component index.

[engines.astgrep] also carries the ast-grep rule settings that v1 kept in a top-level [rules] table:

Key Type Default Meaning
rule_dirs array [".poly/rules"] Directories of custom ast-grep *.yml rule files, relative to the config. Set to [] to disable.
builtin_pack boolean true Load poly’s built-in ast-grep rule pack.

[engines.python-types] is opt-in Python type checking with ty, a project-check engine. ty is the only backend; pyrefly is not supported.

[engines.python-types]
backend = "ty"
python_version = "3.12" # default: the interpreter's, else ty's latest
src = ["src"] # first-party roots; default: the project root and src/
extra_paths = ["stubs"] # searched before first-party code

ty’s own ty.toml and [tool.ty] are not read.

Key Type Default Meaning
run "auto" | "always" | "never" "auto" When poly lint runs the whole-project phase: for repository-wide runs only (auto), even for named paths (always), or never. --workspace overrides it.

A table of path glob → rule codes to suppress for files matching the glob. Globs are relative to the config that declares them.

[per_file_ignores]
"tests/**" = ["F401"]

Opt into tools from the vendored catalog, keyed by catalog name ([tools.<name>]). Every entry is inert until enabled = true.

Key Type Default Meaning
enabled boolean false Whether the tool runs.
command string — Which catalog command to invoke.
args array — Replace the catalog command’s argv entirely.
stages array [] Git stages the tool runs in.
files string or array — Include glob(s).
exclude string or array — Exclude glob(s).
env table {} Environment variables injected when running the tool.
root string — Working directory, relative to the config root.
extra_args array [] Flags added to every role’s argv, just before the file list. Keeps the catalog’s own flags, so this is where configuration goes (["-c", "checkstyle.xml"]).
format_extra_args array [] extra_args for the formatting role only.
lint_extra_args array [] extra_args for the linting role only.
bin string — Executable to run instead of the catalog binary on PATH. For a JVM tool, the java.
version string — Pinned release to use. Looked up in the catalog’s checksummed releases.
url, sha256 string — Download and digest for a version the catalog does not know.
install string "never" "auto" downloads the pinned version into poly’s cache when the tool is missing. A version that cannot be provisioned makes the tool unavailable; poly never runs a different version from PATH.
values_files array [] helm: values files (-f) passed to every chart, relative to the config root.
chart_values table {} helm: chart-directory glob to the values files passed for the charts it matches.
skip_charts array [] helm: chart-directory globs the tool does not run on (library charts).
prepare bool true helm: run helm dependency build once per chart before linting, unless charts/ already satisfies Chart.lock or POLY_OFFLINE is set.
prepare_attempts integer 5 helm: attempts at the prepare step before checking with the dependencies on disk. 1 disables the retry.
prepare_backoff_secs integer 4 helm: wait after the first failed attempt; doubles after each further failure.
prepare_jitter_secs integer 4 helm: up to this many random extra seconds added to every wait.
verify_skip_charts bool true helm: still run each skip_charts chart and fail when the tool now passes on it; false skips them without running.
new_from_rev string — golangci-lint: report only findings introduced since this git revision (--new-from-rev).
goos array [] golangci-lint: run once per operating system with GOOS set and merge the findings.

Tools with a recipe (checkstyle, palantir-java-format, buildifier, buf, actionlint, gau, hadolint, golangci-lint, helm, helm-template, tflint, tofu, terraform, pyproject-fmt, npm-groovy-lint) run batched, parse the tool’s report into file/line/rule diagnostics, and are described in Tool catalog.

Key Type Default Meaning
enabled boolean true Master switch for both cache tiers.
dir string — Override the cache root directory.
[cache.results] hooks string "safe" "off", "safe" or "aggressive".
[cache.sccache] enabled boolean false Enable tier-2 sccache for compiler hooks.
[cache.sccache] bin string — sccache binary (bare name or absolute path).
[cache.sccache] dir string — sccache storage directory.
[cache.sccache] max_size string — Maximum cache size (e.g. "10G").
Key Type Meaning
preset string Named preset to seed the rules from (e.g. "conventional").
write boolean Whether the cleaner rewrites the message in place.
[commit.rules] message table { pattern, description } — a required subject pattern.
[commit.rules] excludes array of tables { pattern, message } — subjects that skip linting.
[commit.rules] cleanup array of tables { find, replace, description } — find/replace cleanups.
[commit.rules] single_line boolean Reject multi-line subjects.
[commit.rules] require_body boolean Require a non-empty body.
[commit.rules] exit_nonzero_on_rewrite boolean Exit non-zero when the cleaner rewrote the message.
[commit.rules] no_emojis boolean Reject emojis.
[commit.rules] ascii_only boolean Require ASCII-only content.
[commit.rules] title_prefix string Required subject prefix.
[commit.rules] title_prefix_separator string Separator after the prefix.
[commit.rules] title_suffix string Required subject suffix.
[commit.rules] title_suffix_separator string Separator before the suffix.

The [hooks] table holds reserved keys plus one key per git stage ([hooks.pre-commit], [hooks.commit-msg], …).

Reserved keys:

Key Type Meaning
stages array Default stages for builtin hooks that do not set their own.
env table Environment merged into every job.
sources array of tables [[hooks.sources]] producer catalogs: { id, path | git, revision, hooks }.
snapshot_include string or array Untracked paths pulled into the staged snapshot (ADR 0019).
isolate boolean Force hooks onto the staged snapshot (unset uses the per-invocation default).
snapshot "auto" | "full" auto (default) materializes only the staged files and their directory context unless a workspace or cargo job will run; full always materializes the whole index.
partial_stage "fail" | "restage" What a stage_fixed job does when its fix lands on a file that also has unstaged edits. fail (default) withholds the fix and names the commands to resolve it; restage stages only the fixed content and leaves the edits in the worktree.
builtin table See below.

[hooks.builtin] — poly’s in-process hooks. Each of lint, fmt, commit is a bare boolean or a table; file_safety and cargo are a boolean or a tuned group table.

Key Type Meaning
lint / fmt / commit boolean or table { enabled, stages, files, exclude }; lint and fmt also take fix, priority and jobs (see the hooks guide).
file_safety boolean or table { enabled, stages, files, exclude, max_added_file_kb, merge_conflict, added_large_files, private_key, case_conflict, executables_have_shebangs, shebang_scripts_are_executable, aws_credentials, requirements_txt_fixer, priority, jobs }.
cargo boolean or table { enabled, stages, clippy, sort, machete, deny, clippy_args, cache, lint }.

A stage table ([hooks.pre-commit]) accepts:

Key Type Meaning
parallel / piped / follow boolean Concurrency and output-streaming behaviour.
exclude_tags array Tags whose jobs are excluded.
files / exclude string or array Stage-level include/exclude globs.
skip / only boolean or array Guard: a bare bool or [{ run = "<command>" }].
fail_on_changes boolean Fail if jobs dirty the working tree.
precondition string Guard command; non-zero skips the stage with a warning.
before / after string or array Commands run before/after the jobs.
jobs array of tables Ordered jobs ([[hooks.pre-commit.jobs]]).
commands / scripts tables Named jobs ([hooks.pre-commit.commands.<name>]).

A job accepts name, run xor script, runner, args, glob, files, exclude, file_types, root, skip, only, precondition, before, tags, env, fail_text, timeout, priority, serial, stage_fixed, show_output, workspace, interactive, use_stdin and cache.

root runs the job from a subdirectory and passes file arguments relative to it (as lefthook and pre-commit do): a job with root = "products/em/backend" receives src/x.py, not products/em/backend/src/x.py, in "$@" and in {staged_files} / {all_files}. Files outside root are not passed, and a job none of whose files are under root is skipped.

show_output = true prints the job’s output even when it passes; by default only a failing job’s output is shown, so a warning from a job that exits 0 is otherwise dropped. poly hooks run --verbose (-v) does the same for every job.

A top-level list of base configs to inherit from (ADR 0020). Each entry is a local path string or a { path | git, revision, file } table; a single entry may be given without the array.

extends = [
{ git = "https://github.com/acme/poly-baseline", revision = "<40-hex-oid>", file = "poly.toml" },
"./poly.overrides.toml", # later entry = higher precedence
]

exclude_mode = "replace" in a table next to an exclude list makes that list replace the inherited one rather than accumulate. A symbolic (branch/tag) git ref must be locked with poly lock first.