Skip to content

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 to ProviderConfig) - 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 — running ruff format . or prettier --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 to repolish apply and to a fast lane CLI's all subcommand; a named lane run uses that lane's own fast_lanes.config commands instead (see fast_lanes below). 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 containing repolish.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-sensitive fnmatch glob; backslashes are accepted for Windows-typed configs. Paused files are excluded from both --check comparison and apply writes, 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.
paused_files:
  - .github/workflows/ci.yml # provider#42 pending
  • 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 is fast_lane (the lane's contribution wins everywhere) or regular (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 is post_process (a list of commands), which replaces the project's top-level post_process in that lane's named CLI run; a lane with no entry runs no post_process at all. The project's own post_process still applies to repolish apply and the CLI's all subcommand.
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 root pyproject.toml. Omit to let repolish discover members automatically.

workspace:
  members:
    - packages/core
    - packages/utils

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 overrides field is the recommended location for all provider-level overrides. It covers context_merge, context_dotted, anchors, file_mappings, and copies in one place. The older top-level fields (context, context_overrides, and anchors) are still supported for backwards compatibility, but they are deprecated and should be migrated to overrides.*.

  • module - an installed Python module that packages the provider's resources, as an alternative to a link CLI. repolish link locates the module in its own process, links the package's resources directory 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 every repolish link. The plain form takes just the dotted module name::
providers:
  workspace:
    module: devkit.workspace

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 by repolish link. The command must write a .provider-info.json file 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 run repolish 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 contains repolish.py and the repolish/ 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 to provider_root. Specify this when the symlink root lives inside a subdirectory of provider_root.

  • overrides - the preferred consolidated override container for this provider. Use it to set context_merge, context_dotted, anchors, and file_mappings in 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 after create_context() runs. Each top-level key replaces the provider's value wholesale. Deprecated in favor of overrides.context_merge. See Override Context.

  • context_overrides - dot-notation overrides applied after finalize_context(). Allows surgical patching of nested context fields without repeating the entire object. Deprecated in favor of overrides.context_dotted. See Override Context.

  • anchors - optional mapping of anchor name to replacement string. Merged on top of whatever create_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 of overrides.anchors. See Block anchors.

  • file_mappings - per-file options within overrides.file_mappings. Each destination path may be enabled or disabled independently, and can also carry skip_render and priority settings. This is the project-level mechanism for opting files in or out without modifying provider code.

  • insertions_extend_files - list of additional file paths within overrides.insertions_extend_files that 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::

providers:
  base:
    cli: codeguide-link

you may simply write::

providers:
  base: codeguide-link

The model validator normalizes this into a ProviderConfig with the string assigned to cli.

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.