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.
Editor setup (JSON Schema)
Section titled “Editor setup (JSON Schema)”poly publishes a JSON Schema for poly.toml at:
https://goldziher.github.io/poly/poly.schema.jsonPoint your editor at it for validation and autocomplete. The simplest way is the
schema directive as the first line of poly.toml:
#:schema https://goldziher.github.io/poly/poly.schema.json
[defaults]line_length = 120The 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:
poly config schema --output poly.schema.jsonThe 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.
Top-level sections
Section titled “Top-level sections”| 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. |
required_version and root
Section titled “required_version and root”| 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. |
[components]
Section titled “[components]”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. |
[defaults]
Section titled “[defaults]”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. |
[discovery]
Section titled “[discovery]”| 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
Section titled “Engines”[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 languageselect = ["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 overridelevel = "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.
ast-grep rules
Section titled “ast-grep rules”[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. |
Python type checking
Section titled “Python type checking”[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 latestsrc = ["src"] # first-party roots; default: the project root and src/extra_paths = ["stubs"] # searched before first-party codety’s own ty.toml and [tool.ty] are not read.
[workspace]
Section titled “[workspace]”| 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. |
[per_file_ignores]
Section titled “[per_file_ignores]”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"][tools]
Section titled “[tools]”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.
[cache]
Section titled “[cache]”| 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"). |
[commit]
Section titled “[commit]”| 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. |
[hooks]
Section titled “[hooks]”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.
extends
Section titled “extends”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.