Configuration file schema¶
This document describes the keys recognized by repolish.yaml at load time. The
YAML file is parsed into a Pydantic model called RepolishConfigFile in
repolish.config.models.project. The schema below corresponds directly to that
class. You don't need to read or write the model yourself; it is shown here to
make the behaviour explicit and to document a couple of subtle features.
Top‑level keys¶
Most keys are optional and will be defaulted, but providers is required -
Repolish cannot run without at least one provider configured.
-
providers(mapping of str toProviderConfig) - the core of the configuration. Each entry describes one provider and its resource linking options (see below). -
providers_order(list of strings) - an explicit ordering for processing providers. If omitted, YAML key order is used instead. -
template_overrides(mapping of str to str) - allows you to pin a given output path to a specific provider, regardless of ordering. Keys are glob-like paths, values must name a provider defined elsewhere in the configuration. A validator ensures that all referenced providers actually exist. -
delete_files(list of strings) - POSIX-style paths that repolish should delete from the project after generation. A leading!negates a path, cancelling a delete that a provider scheduled:
delete_files:
- legacy/old-config.ini # delete this
- '!legacy/keep-this.ini' # cancel a provider-scheduled delete
Negation is evaluated in list order. This is useful when a provider's
FileMode.DELETE mapping removes a file that your project still needs.
-
post_process(list of strings) - shell commands to run after rendering, inside the.repolish/_/render/directory. This is where formatters live — runningruff format .orprettier --write .here ensures the diff and apply steps always operate on correctly formatted output. Commands run in order, once per session, with the render directory as their working directory. These commands apply torepolish applyand to a fast lane CLI'sallsubcommand; a named lane run uses that lane's ownfast_lanes.configcommands instead (seefast_lanesbelow). Three placeholders are substituted before execution: -
{render_dir}— absolute path to the render tree holding the final content before it is copied into the project (normally also the working directory) {render_dir_rel}— the same tree relative to the config directory{config_dir}— absolute path to the directory containingrepolish.yaml
The absolute ones are also exported as REPOLISH_RENDER_DIR /
REPOLISH_CONFIG_DIR in the command's environment, and the applied
substitutions are logged next to the command. Reach for the placeholders when
a wrapper (mise, a task runner) resets the working directory, or when a tool
respects .gitignore and would otherwise skip the render tree:
post_process:
- ruff format --no-respect-gitignore {render_dir}
- python {config_dir}/scripts/tidy.py {render_dir}
When a tool does not find its configuration by walking up from the working
directory, prefer its --config flag (ruff, dprint, and most formatters offer
one) pointing at {config_dir} — in repolish-managed projects the config file
itself is provider output, so referencing it by path works no matter where the
command runs from. The inverse problem — a wrapper (poe, a mise task) that
finds its own config through the working directory and breaks when run from
inside the render tree — has an escape hatch: set
REPOLISH_NO_POST_PROCESS_CD and commands execute from the config directory
instead, with {render_dir} still naming the rendered tree.
Tools that scope rules to file paths (ruff's per-file-ignores, dprint's
includes) match against sandbox paths, not project paths: files sit under
.repolish/_/render/repolish/ and mapped files carry the _repolish. prefix
there. A pattern matching src/models.py matches nothing in the render tree —
widen it with globs ("**/*/src/**/*models.py") or the rule silently applies
to no file. See How Repolish Works for
the full pattern pair.
An unrecognized {placeholder} fails the run listing the supported names. If
any command exits non-zero repolish stops immediately.
paused_files(list of strings) - paths that repolish should temporarily ignore. Each entry may be an exact path, a directory (everything under it is paused), or a case-sensitivefnmatchglob; backslashes are accepted for Windows-typed configs. Paused files are excluded from both--checkcomparison andapplywrites, and paused copy targets are not re-copied. Use this to opt out of provider management for specific files while a provider is being fixed or updated. See Pause a File for details.
-
fast_lanes(optional mapping) - fast lane configuration, with two sub-keys: -
resolutions(mapping of path to string) - resolves a dest declared by both a regular provider hook and a fast lane. Each value isfast_lane(the lane's contribution wins everywhere) orregular(the regular hook's contribution wins; lane runs skip the dest). Without an entry here, such a collision stops the run naming both declaration sites. config(mapping of lane name to mapping) - per-lane settings, keyed by lane name. The one field today ispost_process(a list of commands), which replaces the project's top-levelpost_processin that lane's named CLI run; a lane with no entry runs no post_process at all. The project's ownpost_processstill applies torepolish applyand the CLI'sallsubcommand.
fast_lanes:
resolutions:
action1/action.yaml: fast_lane
config:
actions:
post_process:
- ruff format {render_dir}
See Fast Lanes for the full semantics.
-
workspace(optional mapping) - enables workspace (monorepo) mode. When present, repolish runs a session for the root and one for each discovered member. Accepts one optional sub-key: -
members(list of strings, optional) - repo-relative paths to workspace members. When set, overrides auto-detection from[tool.uv.workspace]in the rootpyproject.toml. Omit to let repolish discover members automatically.
Providers subsection¶
The providers key is a dictionary whose keys are aliases - short names
used by configuration and in logged events. The value for each alias is a
ProviderConfig model that currently looks like::
class ProviderConfig(BaseModel):
module: ModuleProviderConfig | None = None
cli: str | None = None
provider_root: Path | None = None
resources_dir: Path | None = None
symlinks: list[Symlink] | None = None
copies: list[ProviderCopy] | None = None
context: dict[str, Any] | None = None
context_overrides: dict[str, Any] = {}
anchors: dict[str, str] | None = None
overrides: ProviderOverrides | None = None
Each provider entry must specify at least one of module, cli, or
provider_root; they may also be combined, in which case module runs first
and the others act as fallbacks. See the Provider configuration
guide for the full resolution rules and CLI protocol.
The consolidated
overridesfield is the recommended location for all provider-level overrides. It coverscontext_merge,context_dotted,anchors,file_mappings, andcopiesin one place. The older top-level fields (context,context_overrides, andanchors) are still supported for backwards compatibility, but they are deprecated and should be migrated tooverrides.*.
module- an installed Python module that packages the provider's resources, as an alternative to a link CLI.repolish linklocates the module in its own process, links the package'sresourcesdirectory into.repolish/<library-name>/, and records the same provider-info file a CLI registration writes, so the downstream pipeline is unchanged. This avoids one or two subprocess startups per provider on everyrepolish link. The plain form takes just the dotted module name::
and the mapping form adds layout overrides when the package does not use the
default resources / templates directories (the same defaults the
resource_linker decorator uses)::
providers:
workspace:
module:
name: devkit.workspace
resources_dir: src/resources
provider_root: pkg-templates
Both layout fields are package-relative, unlike the project-local
provider_root / resources_dir fields described below. When module and
cli are both set, the module path runs first and the CLI is only used as a
fallback, which keeps the option available while a provider environment is being
consolidated into the one repolish runs in.
-
cli- a shell command (string) that will be executed byrepolish link. The command must write a.provider-info.jsonfile under the.repolish/<alias>directory; this JSON describes the template directory and any default symlinks. Libraries that ship a link CLI (e.g.,codeguide-link) follow this pattern. The CLI is invoked once per provider when you runrepolish link; failure of one provider does not prevent the others from running. -
provider_root- path to the root of the provider package (the directory that containsrepolish.pyand therepolish/template subfolder). The path is resolved relative to the configuration file’s directory. Use this for providers that are checked in locally rather than distributed as a package. -
resources_dir- optional path to the directory from which symlinks are created into the project. When omitted it defaults toprovider_root. Specify this when the symlink root lives inside a subdirectory ofprovider_root. -
overrides- the preferred consolidated override container for this provider. Use it to setcontext_merge,context_dotted,anchors, andfile_mappingsin one place. This is the canonical API for project-side configuration overrides and is the location to use for new work.
For insertion workflows, overrides also supports:
insertions: enable/disable insertion ownership per file/function.-
insertions_extend_files: add extra destination files that may use this provider's insertion registry, without changing provider code. -
context- optional mapping merged into this provider's context aftercreate_context()runs. Each top-level key replaces the provider's value wholesale. Deprecated in favor ofoverrides.context_merge. See Override Context. -
context_overrides- dot-notation overrides applied afterfinalize_context(). Allows surgical patching of nested context fields without repeating the entire object. Deprecated in favor ofoverrides.context_dotted. See Override Context. -
anchors- optional mapping of anchor name to replacement string. Merged on top of whatevercreate_anchors()returns for this provider; config-level values take precedence. Note the merge target is one global map: an override here also fills same-named anchors in other providers' templates, so namespace anchor names per provider (see Naming). Providers should document which anchor keys they support. Deprecated in favor ofoverrides.anchors. See Block anchors. -
file_mappings- per-file options withinoverrides.file_mappings. Each destination path may be enabled or disabled independently, and can also carryskip_renderandprioritysettings. This is the project-level mechanism for opting files in or out without modifying provider code. -
insertions_extend_files- list of additional file paths withinoverrides.insertions_extend_filesthat should be allowed to use this provider's insertion functions. This is additive to provider-defined insertion target files and is intended as a conservative extension mechanism.
Shorthand notation is supported in the YAML. Instead of writing::
you may simply write::
The model validator normalizes this into a ProviderConfig with the string
assigned to cli.
Symlinks¶
Each provider may declare default symlinks in its create_default_symlinks()
method. The symlinks key in repolish.yaml lets you override those defaults
per-project:
- Omit
symlinks- use whatever the provider declares as defaults. symlinks: []- disable all symlinks for this provider.- Explicit list - use exactly this list; the provider's defaults are ignored.
providers:
mylib:
cli: mylib-link
symlinks:
- source: configs/.editorconfig
target: .editorconfig
- source: configs/.gitignore
target: .gitignore
Each entry has a source path (relative to the provider's resources_dir) and
a target path (relative to the project root). This is the mechanism for adding
symlinks the provider doesn't ship by default, or for trimming ones you don't
want.
The copies key follows the same rules for resource copies (files that are
physically copied rather than symlinked). To stop copying a single target
without replacing the whole list — for example when the project wants to own the
file outright — use overrides.copies instead:
providers:
mylib:
cli: mylib-link
overrides:
copies:
dprint.json: false # project owns this file; repolish never re-copies it
Keys are destination paths relative to the project root, and they may point
inside a directory copy: disabling .github/workflows/ci.yml excludes just that
file from the provider's whole-folder copy of .github/workflows/.
See Pause a File for the difference between this
permanent opt-out and a temporary paused_files entry.
Notes on schema evolution¶
The RepolishConfigFile model intentionally mirrors the YAML and exists as an
intermediate representation. When the configuration is resolved (via
repolish.config.resolve_config) it becomes a
:class:~repolish.config.models.project.RepolishConfig instance, which contains
fully‑resolved absolute paths and provider metadata loaded from the
.provider-info.json files created by the link step.