Components, offline and mirrors
poly’s engines ship as signed, downloadable components: bundles of engines that a core binary fetches the first time a run needs them. The engine remains the unit you configure; a component only decides where an engine’s code lives.
Build flavors
Section titled “Build flavors”| Flavor | How it is built | What it does |
|---|---|---|
| bundled | Default features (all-engines and bundled-mcp) |
Every engine family and the MCP server are linked in. Nothing is downloaded. |
| core | cargo build --no-default-features |
Config, discovery, cache, runner, hooks and the tree-sitter tier only. The engines are components. 7.6 MiB at the size profile (fat LTO, opt-level = "z"). |
The release archives are bundled builds. All but the musl one also embed the release’s component
lock; the musl build is fully bundled and embeds no lock, so it downloads nothing. A core build is
produced from source. poly doctor has a components section with the flavor, the cache root and
what the current directory needs.
On a bundled build poly components install only prints a note: there is nothing to fetch.
The components
Section titled “The components”| Component | Engines |
|---|---|
web |
JavaScript, TypeScript, JSON (oxc), YAML, TOML, Markdown, CSS (malva), HTML and the other markup languages, adrlint |
python |
ruff, and ty for type checking |
sql |
sqruff |
php |
mago |
biome |
biome CSS and GraphQL lint |
ruby |
rubyfmt |
nix |
alejandra |
astgrep |
ast-grep and the built-in rule pack |
misc |
dockerfile, dotenv, hcl, graphql |
typos |
typos (opt-in, see below) |
mcp |
the MCP server, a frontend component |
poly components list prints the authoritative list from the index compiled into the binary.
Presets name groups: all (every engine component except typos and mcp), and language names
such as python, ts, markdown or css.
Selecting components
Section titled “Selecting components”A run needs the components for the languages it discovers and for the [engines.*] tables you
configured. Tune that with [components]:
[components]enable = "auto" # or ["python", "web"]disable = ["ruby"]install = "auto" # "auto" | "never"on_missing = "fail" # "fail" | "skip"| Key | Effect |
|---|---|
enable |
"auto" derives components from the discovered files and configured engines. A list names components or presets explicitly. |
disable |
Components never to use, even when auto would select them. Configuring an engine whose component is disabled is a config error. |
install |
"auto" downloads a missing component when a run needs it. "never" forbids downloads. |
on_missing |
"fail" exits 2 when a needed component is unavailable. "skip" skips the files it would have handled and charges them to the skip budget (--deny-skips, --max-skips). |
--on-missing fail|skip overrides on_missing for one run. poly never falls back to the
tree-sitter tier for a language whose component is missing: output would differ between machines.
typos is opt-in
Section titled “typos is opt-in”typos is its own component and is off unless you turn it on:
[engines.typos]enabled = trueWhen downloads happen
Section titled “When downloads happen”Only these commands may use the network for components:
- a
poly lintorpoly fmtrun that discovers files for a missing component (withinstall = "auto"); poly components installandpoly components sync;poly components import, from a file you supply (no network).
poly components list, status, config validate, config show and doctor never download.
Components are fetched before a run is planned, never while files are being checked. Every download
is verified against the lock’s checksum before it is loaded.
poly components status . # what this directory needs, and whether it is usablepoly components status . --verify # also re-check installed archives against the lockpoly components sync . # install everything this directory needspoly components install python web # or: install allpoly components uninstall rubyOffline and air-gapped use
Section titled “Offline and air-gapped use”--offline (or POLY_OFFLINE=1) stops every network access: components, tree-sitter grammars,
catalog-tool installs, remote extends and hook sources. Anything that would need the network is a
skip or an error according to on_missing, never an attempt.
poly --offline components sync . # a check only: exits 2 if something is missingpoly --offline lint .To seed a host with no network access, download the component archives from the release on a connected machine and import them:
poly components import <archive>The archive is verified against the lock the binary carries before it is installed.
Mirrors and the cache location
Section titled “Mirrors and the cache location”| Variable | Effect |
|---|---|
POLY_COMPONENT_MIRROR |
Base URL that replaces the origin (scheme://host[:port]) of each component download. The original path is kept, so mirror the release’s directory layout. Integrity never depends on the URL, because the lock pins each archive’s SHA-256. |
POLY_COMPONENT_CACHE |
Component cache root. Default: components/ inside poly’s cache home (POLY_CACHE_HOME, else the per-user cache directory). |
POLY_OFFLINE |
Same as --offline. |
POLY_COMPONENT_MIRROR=https://artifacts.example.com/poly poly components sync .Cache maintenance
Section titled “Cache maintenance”poly components prune removes cached archives the lock no longer references:
poly components prune --dry-run # list exactly what a real prune removespoly components prune --keep-days 7 # keep unreferenced archives used in the last 7 dayspoly components prune --all # remove every archiveBy default it keeps archives referenced by the lock for any target, and archives used within the last
30 days. It also clears staging directories that an interrupted install left behind, and reports a
file that a loaded library still holds (Windows) as skipped for a later run.
The GitHub Action installs components before the first run and caches them by version and lock, so a second run downloads nothing:
- uses: Goldziher/poly@v0 with: version: from-config # the version required_version in poly.toml names components: auto # or all, none, or "sql,php"- run: poly lint .Pin required_version in poly.toml to fix the poly version, and with it every component:
components are versioned in lock-step with poly, so there is no separate component lock to commit.
See ACTION_USAGE.md for the inputs.