repomatic.tooling.tool_registry module¶
Declarative registry of the external tools repomatic run manages.
Each ToolSpec entry pins a tool’s version and, for binary-distributed tools,
its per-platform download URLs and SHA-256 digests in CHECKSUMS; the paired
VERSIONS map records the version each checksum set was computed for. The
ArchiveFormat, NativeFormat, BinarySpec, and NpmSpec types describe how
each tool is fetched and how its [tool.X] section is translated to the tool’s
native config format. The repomatic run engine in tool_runner.py consumes
this data to install and invoke each tool.
Note
sync-tool-versions and update-checksums rewrite this module’s version=,
VERSIONS, and CHECKSUMS literals in place by string substitution, so their
formatting must stay stable. The lint, autofix, and docs workflows key their
tool caches on a hash of this file, so only a genuine version or checksum bump
invalidates a cached tool download.
Todo
Drop the YAML-block fixup in the mdformat post-process callback once
executablebooks/mdformat-myst#49
merges upstream. See _DIRECTIVE_YAML_OPTIONS_RE for the shape it repairs.
Todo
Drop the colon-fence fixup in the same callback once mdformat-myst ships
colon-fence support, via either
executablebooks/mdformat-myst#36
or
executablebooks/mdformat-myst#48.
See _ESCAPED_COLON_FENCE_RE for the shape it repairs.
- exception repomatic.tooling.tool_registry.UnsupportedPlatformError[source]¶
Bases:
RuntimeErrorRaised when a tool publishes no binary for the running platform.
Distinguished from every other install failure (a failed download, a checksum mismatch) because it is a property of the tool’s release matrix rather than a fault: nothing about the current run can make the binary exist. Asking for such a tool directly is still fatal, but a caller provisioning it as a companion can catch this alone and carry on without it. See
repomatic.tooling.tool_runner._path_tools_env().
- repomatic.tooling.tool_registry.GENERATED_HEADER_TEMPLATE = 'Generated by {command} v{version} - https://github.com/kdeldycke/repomatic'¶
Template for the first line of generated-file headers.
Used by both CLI commands (e.g.
sync-mailmap) and the tool runner (e.g.run shfmt) to stamp files with provenance. Format fields:command(full command path) andversion(package version).
- repomatic.tooling.tool_registry.generated_header(command, comment_prefix='# ')[source]¶
Return a generated-by header block with timestamp.
- class repomatic.tooling.tool_registry.ArchiveFormat(*values)[source]¶
Bases:
EnumArchive format for binary tool downloads.
- RAW = 'raw'¶
- TAR_GZ = 'tar.gz'¶
- TAR_XZ = 'tar.xz'¶
- ZIP = 'zip'¶
- tarfile_mode()[source]¶
Return the
tarfile.openmode string for this format.- Raises:
ValueError – If called on a non-tar format.
- Return type:
Literal['r:gz','r:xz']
- class repomatic.tooling.tool_registry.NativeFormat(*values)[source]¶
Bases:
EnumTarget format for
[tool.X]translation.- YAML = 'yaml'¶
- TOML = 'toml'¶
- JSON = 'json'¶
- EDITORCONFIG = 'editorconfig'¶
- FLAGS = 'flags'¶
- serialize(data, tool_name='')[source]¶
Serialize a config dict to this format’s string representation.
When data is a live
[tool.X]table parsed frompyproject.toml(atomlrt.Table), the TOML branch keeps the user’s comments by reparenting the section to the document root; see_reroot_section. A plain dict carries no trivia, so it is rendered as-is. The other formats (YAML, JSON, editorconfig) cannot carry TOML comments across the format boundary, so they serialize the values only.- Parameters:
- Raises:
ValueError – For
FLAGS, which is not a file format.- Return type:
- repomatic.tooling.tool_registry.PlatformKey¶
A
(platform_or_group, architecture)pair used as binary lookup key.The platform element can be a single
Platform(likeMACOS) or aGroup(likeLINUX, which matches any Linux distribution). The architecture is always a concreteArchitecture.Resolution order in
BinarySpec.resolve_platform():Exact Platform match (
current_platform() == key_platform).Group membership (
current_platform() in key_group), preferring the group with fewest members (most specific).The
LINUXfamily, only whencurrent_platform()isUNKNOWN_PLATFORM, so a distribution extra-platforms cannot name still reaches a family-wide key.
alias of
tuple[Platform|Group,Architecture]
- class repomatic.tooling.tool_registry.ToolBackend(short_label, long_label)[source]¶
Bases:
EnumHow a registry tool is delivered and executed.
Each member carries the display labels the documentation generators render, so backends and their vocabulary live in one place: adding a backend means adding a member here and a branch in
ToolSpec.backend(), and every consumer (docs tables, version-sync candidate sources) follows.Note
Code that dereferences a backend’s payload still tests the field directly (
spec.binary is not Nonenarrows the optional for mypy in a way an enum comparison cannot); this enum serves the sites that only need to know which backend, not its payload.- BINARY = ('Binary', 'Binary (downloaded from GitHub Releases)')¶
- NPM = ('npm', 'npm registry, run via `node_modules/.bin`')¶
- VENV = ('PyPI (venv)', 'PyPI, runs in project virtualenv via `uv run`')¶
- UVX = ('PyPI', 'PyPI, installed via `uvx`')¶
- short_label¶
Cell text for the docs summary table.
- long_label¶
Installation-method line in the per-tool reference sections.
- class repomatic.tooling.tool_registry.BinarySpec(urls, checksums, archive_format, archive_executable=None, strip_components=0)[source]¶
Bases:
objectPlatform-specific binary download specification.
Keys are
PlatformKeytuples pairing an extra-platformsPlatformorGroupwith anArchitecture. This lets callers use broad groups (LINUXmatches any distro) or specific platforms (DEBIAN) with full detection heuristics from extra-platforms.Hint
Structural integrity checks (key types, checksum format, URL placeholders, strip_components consistency) are enforced in
test_tool_spec_integrity.Todo
Move those integrity checks to
__post_init__if the registry ever becomes user-configurable: a test only covers the specs shipped here.- urls: dict[tuple[Platform | Group, Architecture], str]¶
Platform key to URL template mapping. URLs use
{version}placeholders.
- checksums: dict[tuple[Platform | Group, Architecture], str]¶
Platform key to SHA-256 hex digest mapping.
- archive_format: ArchiveFormat | dict[tuple[Platform | Group, Architecture] | Platform | Group, ArchiveFormat]¶
Archive format of the downloaded file.
A single
ArchiveFormatapplies to every platform. A dict maps platform specifiers to formats, allowing mixed archives in one spec:archive_format={ALL_PLATFORMS: ArchiveFormat.TAR_GZ, WINDOWS: ArchiveFormat.ZIP}
Dict keys follow the same resolution as
resolve_platform(): exactPlatformKeytuple first, then barePlatformequality, thenGroupmembership (smallest group wins).
- archive_executable: str | None = None¶
Path of the executable inside the archive.
Nonedefaults to the tool name. ForRAWformat, used as the final filename.
- strip_components: int | dict[tuple[Platform | Group, Architecture] | Platform | Group, int] = 0¶
Number of leading path components to strip when extracting.
A single
intapplies to every platform. A dict maps platform specifiers to counts, using the same resolution asget_archive_format(), for a project whose archives are not laid out identically across platforms:strip_components={ALL_PLATFORMS: 1, WINDOWS: 0}
ghis the motivating case: its Linux and macOS archives nest everything under agh_{version}_{platform}_{arch}/directory, while the Windows zip putsbin/gh.exeat the root. The nesting cannot be absorbed byarchive_executableinstead, since that is one string for all platforms and the directory name carries the version and platform.
- resolve_platform()[source]¶
Match the current environment against registered platform keys.
Uses
current_platform()andcurrent_architecture()from extra-platforms, inheriting its full detection heuristics, then falls back to theLINUXfamily when those heuristics name no distribution at all.- Return type:
tuple[Platform|Group,Architecture]- Returns:
The matching
PlatformKey.- Raises:
UnsupportedPlatformError – If no key matches the current environment.
- get_archive_format(key)[source]¶
Return the archive format for the given platform key.
When
archive_formatis a singleArchiveFormat, returns it directly. When it is a dict, resolves through_resolve_per_platform().- Return type:
- get_strip_components(key)[source]¶
Return the leading path components to strip for a platform key.
When
strip_componentsis a plainint, returns it directly. When it is a dict, resolves through_resolve_per_platform().- Return type:
- repomatic.tooling.tool_registry.MYPY_VERSION_MIN = (3, 8)¶
Earliest Python dialect Mypy’s
--python-version 3.xparameter accepts.Floors the value
Metadata.mypy_paramsderives from the project’srequires-python, which themypyentry inTOOL_REGISTRYpasses throughcomputed_params. A project declaring an older floor would otherwise hand mypy a version it rejects outright.
- repomatic.tooling.tool_registry.TOOL_LIST_HEADER_DEFS: tuple[tuple[str, str], ...] = (('Tool', 'tool'), ('Version', 'version'), ('Config source', 'config-source'))¶
Column definitions for the
repomatic run --listtable.Lives beside the registry it renders; the CLI derives its
--sort-bychoices from it.
- repomatic.tooling.tool_registry.NPM_MIN_VERSION_FOR_COOLDOWN = '11.10.0'¶
First npm release honoring
min-release-age, the cooldown gate for npm tools.Older npm silently ignores the
--min-release-ageflag, so_install_npm()warns when it cannot enforce the cooldown. This is a fixed floor (the release that introduced the option), distinct from the auto-bumpednpm@Xbootstrap pin inlint.yaml, which tracks the latest npm.
- class repomatic.tooling.tool_registry.NpmSpec[source]¶
Bases:
objectnpm-registry backend marker for a
ToolSpec.Presence (
ToolSpec.npm is not None) selects the npm backend, the way aBinarySpecselects the download backend. The package name, executable, and version all derive from theToolSpecfields, so no per-tool npm config is needed today; the class exists as a typed discriminator and a home for future npm-specific options.Note
npm tools need Node.js and npm on
PATHat run time: the one backend that depends on a runtime repomatic neither bundles nor provisions (binary tools are self-contained; the uv backends use uv). Integrity is npm’s own per-tarball verification on install, so unlikeBinarySpecthere is no repomatic-pinned checksum; theminimum-release-agecooldown (npm’smin-release-age, npm 11.10.0+) gates the transitive tree instead. Older npm ignores the gate, so the runner warns rather than silently skipping it.
- class repomatic.tooling.tool_registry.ToolSpec(name, display_name=None, version='', package=None, executable=None, module=None, native_config_files=(), config_flag=None, native_format=NativeFormat.YAML, default_config=None, reads_pyproject=False, default_flags=(), ci_flags=(), default_args=(), default_paths=None, per_file=False, with_packages=(), path_tools=(), needs_venv=False, computed_params=None, config_after_subcommand=False, post_process=None, output_flag=None, check_flags=(), rewrite_exit_code=None, binary=None, npm=None, source_url=None, tag_pattern=None, config_docs_url=None, cli_docs_url=None, docs_notes='')[source]¶
Bases:
objectSpecification for an external tool managed by repomatic.
Hint
Structural integrity checks (name format, version format, flag conventions, field consistency) are enforced in
test_tool_spec_integrity.Todo
Move those integrity checks to
__post_init__if the registry ever becomes user-configurable: a test only covers the specs shipped here.Hint
CLI parser quirks for
config_after_subcommandTools that use subcommands (
tool <subcmd> [flags] [files]) may requireconfig_flagto appear after the subcommand name, depending on the CLI parser framework:clap (Rust): global flags accepted before or after the subcommand. No special handling needed. Used by: ruff, labelmaker.
cobra (Go): root-level flags inherited by all subcommands, accepted in both positions. No special handling needed. Used by: gitleaks.
click (Python): global flags accepted before or after the subcommand. No special handling needed. Used by: bump-my-version.
bpaf (Rust):
#[bpaf(external)]fields are scoped inside the subcommand variant, sotool <subcmd> --flagworks buttool --flag <subcmd>does not. Setconfig_after_subcommand=True. Used by: biome.
- name: str¶
Tool identity: CLI name for
repomatic run <name>, default PyPI package name, and default executable name.
- display_name: str | None = None¶
Human-readable name with proper casing for documentation (like
'Biome','Gitleaks').Nonedefaults toname.
- package: str | None = None¶
Install target passed to
uvx/uv run(and pip).Nonedefaults toname. Only set when it differs from the tool name, and may carry an install extra (Nuitka’snuitka[onefile]); for PyPI lookups query the bare project name throughpypi_name, which strips the extra.
- executable: str | None = None¶
Executable name if different from the tool name.
Nonedefaults to the registry key.
- module: str | None = None¶
Python module name for
-m moduleinvocation, e.g.'nuitka'.When set, the tool is invoked as
python -m <module>instead of the console script. Requiresneeds_venv=True. Use when the tool’s script entry point is not reliably found across platforms (for example, Nuitka installs only a.cmdwrapper on Windows, whichuv run -- nuitkacannot locate).
- native_config_files: tuple[str, ...] = ()¶
Config filenames the tool auto-discovers, checked in order.
Paths relative to repo root (e.g.,
'zizmor.yaml','.github/actionlint.yaml'). Empty for tools with no config file.
- config_flag: str | None = None¶
CLI flag to pass a config file path (e.g.,
'--config','--config-file').Noneif the tool only reads from fixed paths.
- native_format: NativeFormat = 'yaml'¶
Target format for
[tool.X]translation.NativeFormat.FLAGStranslates the table to CLI flags (viaconfig_table_to_flags) instead of a config file, for tools that expose their config keys as long options but read no config file themselves. It is mutually exclusive withreads_pyproject,config_flag, andnative_config_files.
- default_config: str | None = None¶
Filename in
repomatic/data/for bundled defaults, stored innative_format.Noneif no bundled default exists.
- reads_pyproject: bool = False¶
Whether the tool natively reads
[tool.X]frompyproject.toml.When
Trueand[tool.X]exists inpyproject.toml, repomatic skips Level 2 translation (the tool reads it directly). Resolution still falls through to Level 3 (bundled default) and Level 4 (bare) when no config is found.
- default_args: tuple[str, ...] = ()¶
Arguments used when the caller passes none of their own.
Together with
default_paths, this makes a barerepomatic run <tool>the invocation CI performs, so nobody has to reconstruct it from a workflow step. It applies only whenextra_argsis empty: any explicit argument means the caller is driving, and nothing is injected on top of it.That all-or-nothing rule is what keeps a subcommand safe to put here. biome’s defaults open with
format, and splicing them into a caller’scheck .would buildbiome format … check .; because an explicit argument suppresses them entirely, that command cannot be built.
- default_paths: str | None = None¶
Name of the
FileInventoryattribute supplying this tool’s targets, when the caller passes no arguments.Caution
An empty inventory means the tool is skipped, not invoked with no path. The distinction is the whole point: a formatter handed zero paths does not no-op, it walks the entire tree in write mode. Replaying a workflow’s
xargspipe on a repo with no matching file did exactly that once, rewriting 3,000+ files, and it is the reason this resolves the list in-process rather than leaving it to a shell.
- per_file: bool = False¶
Invoke the tool once per target rather than once for all of them.
Mirrors
xargs -n1, for a tool whose per-file behaviour differs from its batch behaviour. Only meaningful alongsidedefault_paths.
- with_packages: tuple[str, ...] = ()¶
Extra packages installed alongside the tool (e.g., mdformat plugins).
Passed as
--with <pkg>to uvx.
- path_tools: tuple[str, ...] = ()¶
Other registry tools whose executable must be on
PATHwhile this runs.For a plugin that shells out to a second binary rather than importing it:
mdformat-shfmtformats fenced shell blocks by invokingshfmtfromPATH, somdformatdeclarespath_tools=("shfmt",).Each name is installed through the same registry path as a direct
repomatic run, so the companion arrives at the pinned version, checksum verified, from the shared cache. The alternative, letting the environment supply it, is what this field exists to prevent: a system package manager hands over whatever its archive holds, unpinned and outside the cooldown, and the same tool then behaves differently depending on which job invoked it.Names must resolve in
TOOL_REGISTRYand carry abinaryspec;test_tool_spec_integrityenforces both.
- needs_venv: bool = False¶
If
True, useuv run(project venv) instead ofuvx(isolated).Required when the tool imports project code (mypy, pytest). The project venv materializes from the frozen
uv.lock; in a repository without one the runner degrades to an isolated, cooldown-gated environment (uv run --no-project), see_build_install_argsintool_runner.py.
- computed_params: Callable[[Metadata], list[str]] | None = None¶
Callable that receives a
Metadatainstance and returns extra CLI args derived from project metadata (e.g., mypy’s--python-versionfromrequires-python).Noneif no computed params.
- config_after_subcommand: bool = False¶
Insert
config_flagafter the first token ofextra_args.Needed for tools whose CLI parser (e.g., bpaf) scopes global options inside the subcommand, so
tool subcommand --config-path Xis valid buttool --config-path X subcommandis not. WhenTrue,config_argsare spliced after the first element ofextra_args(the subcommand name).
- post_process: Callable[[Sequence[str]], None] | None = None¶
Callback invoked on
extra_argsafter the tool exits successfully.Intended for temporary workarounds that fix known upstream formatting bugs in-place. Each callback carries its own todo admonition naming the upstream release that retires it.
Note
The callback runs only after a successful write-mode exit (return code 0) and rewrites files on disk, so it cannot apply in check/dry-run mode, which writes nothing. Pair it with
check_flagssorun_toolwarns when a check invocation would silently bypass it. Seecheck_bypasses_post_process().
- output_flag: str | None = None¶
Flag whose argument names the tool’s report destination, when the tool refuses to create missing parent directories itself.
run_toolpre-creates the parent directory of the path following this flag (both--flag pathand--flag=pathforms), so a workflow can point the tool into a scratch subdirectory without a separatemkdirstep. lychee is the motivating case:docs.yamlcollects its report from a dedicated subdirectory, and lychee errors out rather than creating it.
- check_flags: tuple[str, ...] = ()¶
Flags that put the tool in check/dry-run mode, writing no files.
Warning
Check mode bypasses
post_process: that fixup rewrites files on disk, but check mode writes nothing. So when a tool defines both apost_processandcheck_flags, its check-mode exit status is unreliable.run_tooldetects the pairing viacheck_bypasses_post_process()and warns. Verify formatting by running the write path, not the check flag:repomatic.tooling.tool_runner.verify_via_write_path()does exactly that against throwaway copies, so the answer is authoritative and the working tree is still never written to.
- rewrite_exit_code: int | None = None¶
Exit code the tool returns when it rewrote at least one file.
Formatters that signal “I reformatted something” with a non-zero status force every caller to tolerate that code, which is what lets a crash pass for a success: pyproject-fmt exits
1both when it reformats a file and when it dies on aPanicException, and the autofix job cannot tell the two apart from the status alone.Declaring the code here gives
run_toolthe second signal it needs: the files themselves. A run exiting with this code and leaving every target byte-identical contradicts what the code claims, so it is reported as a failure instead of being waved through. Seerepomatic.tooling.tool_runner.TOOL_CRASH_EXIT_CODE.Nonefor tools with no such convention, which is most of them: a formatter that exits0whether or not it wrote anything needs no disambiguation.
- binary: BinarySpec | None = None¶
Platform-specific binary download spec. When set, the tool is downloaded as a binary instead of installed via
uvxoruv run.
- npm: NpmSpec | None = None¶
npm-registry backend marker. When set, the tool is installed from npm and run via its
node_modules/.binexecutable, instead of a binary download or a uv install. Mutually exclusive withbinaryandneeds_venv.
- tag_pattern: str | None = None¶
Regex extracting the version from a GitHub release tag.
Used by
sync-tool-versionsfor binary tools whose tags do not follow the commonvX.Y.Zscheme. The pattern must define aversionnamed group (e.g.r"^lychee-v(?P<version>.+)$"for lychee, r”^@biomejs/biome@ (?P<version>.+)$”``for biome). When``None, the version is the tag with a leadingvstripped.
- docs_notes: str = ''¶
Hand-written Markdown appended to the tool’s section in
tool-runner.md.Free-form usage notes the registry cannot derive: a
**Try it:**shell session, a minimal[tool.X]example, caveats. Rendered live bytool_reference()after the generated metadata lines, so the prose stays next to the spec it documents.
- property backend: ToolBackend¶
Delivery mechanism, derived from which spec fields are set.
binaryandnpmwin overneeds_venv;test_tool_spec_integritykeeps the three mutually exclusive so the order never actually decides.
- property pypi_name: str¶
Bare PyPI project name for version and metadata lookups.
packagedoubles as the install target, so it may carry an install extra (Nuitka’snuitka[onefile]) that_build_install_argsneeds at install time. The PyPI JSON API is keyed by the bare project name, though, and 404s on a bracketed extra, sosync-tool-versionsand the held-back PR links query this stripped name (nuitka) instead.
- property datasource_url: str¶
Human-facing URL for the tool’s version datasource.
npmjs for npm tools, the GitHub
source_urlwhen set, else the PyPI project page. Used bysync-tool-versionsfor the diff-table and held-back links.
- check_bypasses_post_process(extra_args)[source]¶
Return
Truewhen a check-mode flag will skippost_process.Check/dry-run flags (
check_flags) make the tool exit without writing files, so thepost_processfixup never runs and the exit status cannot be trusted: it may flag drift the write path would reconcile, or miss drift the write path would introduce.run_toolwarns on this. ReturnsFalsefor tools with nopost_process, where check mode is authoritative.- Return type:
- repomatic.tooling.tool_registry.CHECKSUMS: dict[str, dict[tuple[Platform | Group, Architecture], str]] = {'actionlint': {(Group(id='linux', name='Linux distributions'), Architecture(id='aarch64', name='ARM64 (AArch64)')): '325e971b6ba9bfa504672e29be93c24981eeb1c07576d730e9f7c8805afff0c6', (Group(id='linux', name='Linux distributions'), Architecture(id='x86_64', name='x86-64 (AMD64)')): '8aca8db96f1b94770f1b0d72b6dddcb1ebb8123cb3712530b08cc387b349a3d8', (Platform(id='macos', name='macOS'), Architecture(id='aarch64', name='ARM64 (AArch64)')): 'aba9ced2dee8d27fecca3dc7feb1a7f9a52caefa1eb46f3271ea66b6e0e6953f', (Platform(id='macos', name='macOS'), Architecture(id='x86_64', name='x86-64 (AMD64)')): '5b44c3bc2255115c9b69e30efc0fecdf498fdb63c5d58e17084fd5f16324c644', (Platform(id='windows', name='Windows'), Architecture(id='aarch64', name='ARM64 (AArch64)')): 'cadcf7ea4efe3a68728893813643cebe1185e5b1d4be5b96245f65c9a4d5ea41', (Platform(id='windows', name='Windows'), Architecture(id='x86_64', name='x86-64 (AMD64)')): '6e7241b51e6817ea6a047693d8e6fed13b31819c9a0dd6c5a726e1592d22f6e9'}, 'biome': {(Group(id='linux', name='Linux distributions'), Architecture(id='aarch64', name='ARM64 (AArch64)')): 'bf593f7955e3a437fb8056b255142b50872baa3e81371cda2c3fce9239af1890', (Group(id='linux', name='Linux distributions'), Architecture(id='x86_64', name='x86-64 (AMD64)')): '013eb5158b9e53235dbbf31255cb3b776fb9338b32fa6ff4a44ee1ceed65ee63', (Platform(id='macos', name='macOS'), Architecture(id='aarch64', name='ARM64 (AArch64)')): '7d8b51dec857ffa8aa35ce5eaa3a4476cd62bed013adc2896bf43cac0a67a79b', (Platform(id='macos', name='macOS'), Architecture(id='x86_64', name='x86-64 (AMD64)')): 'df2b50ee283634cdd6f7570b7da06bc3c9cd7ec0590ecbbaf986c7590bef3289', (Platform(id='windows', name='Windows'), Architecture(id='aarch64', name='ARM64 (AArch64)')): 'd6845ff075043300551d4ad74985814e4e4c56b49ffa87b3724ddf5055a2efe9', (Platform(id='windows', name='Windows'), Architecture(id='x86_64', name='x86-64 (AMD64)')): 'f8474a0f9f457df176c10be3f0e82be890e8986ff2805d4a7f3c5a4cba5962ca'}, 'gh': {(Group(id='linux', name='Linux distributions'), Architecture(id='aarch64', name='ARM64 (AArch64)')): '73ea440ecad9c9e284429997ee6f93577bc6f7bc6fba357ef62c53ad8fb641a5', (Group(id='linux', name='Linux distributions'), Architecture(id='x86_64', name='x86-64 (AMD64)')): 'a2c9b8497e1f85b1ad0dfcb78b5a622e098801b8e461e459e88e1ee12f018112', (Platform(id='macos', name='macOS'), Architecture(id='aarch64', name='ARM64 (AArch64)')): 'a58b8fd77b417a38f47a0b54d1370c59b0fcdb324ccc9ca002b0998f7c4c999e', (Platform(id='macos', name='macOS'), Architecture(id='x86_64', name='x86-64 (AMD64)')): '63298c998cc2a924c9e254c6af6a1caad6ece281122687a91f079bc0a462700e', (Platform(id='windows', name='Windows'), Architecture(id='aarch64', name='ARM64 (AArch64)')): '3e2d4a166da4ee5020c592737b65eec0e724946d5d5b962f5fe59d99116dc4bf', (Platform(id='windows', name='Windows'), Architecture(id='x86_64', name='x86-64 (AMD64)')): '35d7fe05c4dd1411ffda1e73dfc7c6f44b75c936ca51fa6595c657fdc0350cec'}, 'gitleaks': {(Group(id='linux', name='Linux distributions'), Architecture(id='aarch64', name='ARM64 (AArch64)')): 'e4a487ee7ccd7d3a7f7ec08657610aa3606637dab924210b3aee62570fb4b080', (Group(id='linux', name='Linux distributions'), Architecture(id='x86_64', name='x86-64 (AMD64)')): '551f6fc83ea457d62a0d98237cbad105af8d557003051f41f3e7ca7b3f2470eb', (Platform(id='macos', name='macOS'), Architecture(id='aarch64', name='ARM64 (AArch64)')): 'b40ab0ae55c505963e365f271a8d3846efbc170aa17f2607f13df610a9aeb6a5', (Platform(id='macos', name='macOS'), Architecture(id='x86_64', name='x86-64 (AMD64)')): 'dfe101a4db2255fc85120ac7f3d25e4342c3c20cf749f2c20a18081af1952709', (Platform(id='windows', name='Windows'), Architecture(id='aarch64', name='ARM64 (AArch64)')): 'b95f5e4f5c425cedca7ee203d9afd29597e692c4924a12ed42f970537c72cc0f', (Platform(id='windows', name='Windows'), Architecture(id='x86_64', name='x86-64 (AMD64)')): 'd29144deff3a68aa93ced33dddf84b7fdc26070add4aa0f4513094c8332afc4e'}, 'labelmaker': {(Group(id='linux', name='Linux distributions'), Architecture(id='aarch64', name='ARM64 (AArch64)')): '4685e142da55150904d16624fe1052161de5dba1a859cddef19ab41833c37728', (Group(id='linux', name='Linux distributions'), Architecture(id='x86_64', name='x86-64 (AMD64)')): 'd76f8e64f9671884dac1758fe54a28a6680c5d9bf0ffd593a2c68ba558cc49a2', (Platform(id='macos', name='macOS'), Architecture(id='aarch64', name='ARM64 (AArch64)')): 'a52a4e102f0760ce1632da5fdaee2b0debe0e6ddea577b88a94a60172fe85751', (Platform(id='macos', name='macOS'), Architecture(id='x86_64', name='x86-64 (AMD64)')): 'dc8374d6a9bec4ebf143fb42e3024aeffabe8585bb9bd6f134cfaf0693be7688', (Platform(id='windows', name='Windows'), Architecture(id='x86_64', name='x86-64 (AMD64)')): '939195930f9d5fd2b15a5cf43497019a52083e6c6713807d3379de49395c2e10'}, 'lychee': {(Group(id='linux', name='Linux distributions'), Architecture(id='aarch64', name='ARM64 (AArch64)')): '91a7bd65685da41b90ccb9bc867a3d649a7818042dae04ff405e55a25bddee4c', (Group(id='linux', name='Linux distributions'), Architecture(id='x86_64', name='x86-64 (AMD64)')): '1f4e0ef7f6554a6ed33dd7ac144fb2e1bbed98598e7af973042fc5cd43951c9a', (Platform(id='macos', name='macOS'), Architecture(id='aarch64', name='ARM64 (AArch64)')): 'c9d3740ea2d891854d37116c9fba840f37b6e7c89d330e7db84ac333631c4977', (Platform(id='windows', name='Windows'), Architecture(id='x86_64', name='x86-64 (AMD64)')): '32975d1493ee1a975d6bb41e4fb56fe419cb442ded628bb772ba2e614acfacad'}, 'oxipng': {(Group(id='linux', name='Linux distributions'), Architecture(id='aarch64', name='ARM64 (AArch64)')): '97d168c6c0d1dbcb36e7438eb489804748a2ba40d94fe21aa7dab7372e9efe9b', (Group(id='linux', name='Linux distributions'), Architecture(id='x86_64', name='x86-64 (AMD64)')): 'b33f84c73d42cb592bea5d84c431030b1e97784817693380dfcec7d9575f871e', (Platform(id='macos', name='macOS'), Architecture(id='aarch64', name='ARM64 (AArch64)')): '9aad3927d095b6ade2aacb92b89ebaca442483c1f7cde5d7a2486b283c2ed5f9', (Platform(id='macos', name='macOS'), Architecture(id='x86_64', name='x86-64 (AMD64)')): 'c45acf40a70cc02539c55555ac240bf5ef24544b7ea9959d22da19f606cec205', (Platform(id='windows', name='Windows'), Architecture(id='x86_64', name='x86-64 (AMD64)')): 'a5ad52c9c288dc99c2eae90dcad73dee64e39bf3f5aa5303c0fb55ac9c5f069b'}, 'shfmt': {(Group(id='linux', name='Linux distributions'), Architecture(id='aarch64', name='ARM64 (AArch64)')): '32d92acaa5cd8abb29fc49dac123dc412442d5713967819d8af2c29f1b3857c7', (Group(id='linux', name='Linux distributions'), Architecture(id='x86_64', name='x86-64 (AMD64)')): 'fb096c5d1ac6beabbdbaa2874d025badb03ee07929f0c9ff67563ce8c75398b1', (Platform(id='macos', name='macOS'), Architecture(id='aarch64', name='ARM64 (AArch64)')): '9680526be4a66ea1ffe988ed08af58e1400fe1e4f4aef5bd88b20bb9b3da33f8', (Platform(id='macos', name='macOS'), Architecture(id='x86_64', name='x86-64 (AMD64)')): '6feedafc72915794163114f512348e2437d080d0047ef8b8fa2ec63b575f12af', (Platform(id='windows', name='Windows'), Architecture(id='x86_64', name='x86-64 (AMD64)')): '60cd368533d0ad73fa86d93d5bbf95ef40587245ce684ed138c1b31557b5fe97'}, 'typos': {(Group(id='linux', name='Linux distributions'), Architecture(id='aarch64', name='ARM64 (AArch64)')): '85c8b87b22a0fb1da130cd4d495e0beba7f1225eb580933184509e146ec4c509', (Group(id='linux', name='Linux distributions'), Architecture(id='x86_64', name='x86-64 (AMD64)')): '48bd2d58e02ce713b8c0f1aa239e68ee4f7d8c551013135806e6aed3938d9e10', (Platform(id='macos', name='macOS'), Architecture(id='aarch64', name='ARM64 (AArch64)')): '8c0e7bd40b2b60c0b0cfe9f74dd814b4d4385c956ce86860f7da9e62d91fdc73', (Platform(id='macos', name='macOS'), Architecture(id='x86_64', name='x86-64 (AMD64)')): '4cecbf653a9fc45f023abf57f4e2e2f6b138c2d2387b09289beacdd3f0ea7bfd', (Platform(id='windows', name='Windows'), Architecture(id='x86_64', name='x86-64 (AMD64)')): '06d3a1b71c282e021671070696a72696d5c60ea485b47dc4f8f1fbcf90144d02'}}¶
Tool name to platform-keyed SHA-256 hex digest mapping.
Recomputed in place by
repomatic update-checksumsandsync-tool-versions. Kept as a flat sidecar dict (rather than inline in eachBinarySpec) so the checksum recompute can replace a hash by exact string match without re-parsing the registry, and soVERSIONScan anchor the offline staleness test.
- repomatic.tooling.tool_registry.VERSIONS: dict[str, str] = {'actionlint': '1.7.12', 'biome': '2.5.9', 'gh': '2.97.0', 'gitleaks': '8.30.1', 'labelmaker': '0.6.4', 'lychee': '0.24.2', 'oxipng': '10.2.0', 'shfmt': '3.13.1', 'typos': '1.49.0'}¶
Tool name to the version each checksum set was computed for.
test_tool_spec_integrityasserts this equals the matchingToolSpec.version, so a bump whose checksums were never refreshed (a staleCHECKSUMSentry) fails CI offline, without downloading anything.
- repomatic.tooling.tool_registry.TOOL_REGISTRY: dict[str, ToolSpec] = {'actionlint': ToolSpec(name='actionlint', display_name=None, version='1.7.12', package=None, executable=None, module=None, native_config_files=('.github/actionlint.yaml', '.github/actionlint.yml'), config_flag='--config-file', native_format=<NativeFormat.YAML: 'yaml'>, default_config='actionlint.yaml', reads_pyproject=False, default_flags=('-color',), ci_flags=(), default_args=(), default_paths=None, per_file=False, with_packages=(), path_tools=(), needs_venv=False, computed_params=None, config_after_subcommand=False, post_process=None, output_flag=None, check_flags=(), rewrite_exit_code=None, binary=BinarySpec(urls={(Group(id='linux', name='Linux distributions'), Architecture(id='aarch64', name='ARM64 (AArch64)')): 'https://github.com/rhysd/actionlint/releases/download/v{version}/actionlint_{version}_linux_arm64.tar.gz', (Group(id='linux', name='Linux distributions'), Architecture(id='x86_64', name='x86-64 (AMD64)')): 'https://github.com/rhysd/actionlint/releases/download/v{version}/actionlint_{version}_linux_amd64.tar.gz', (Platform(id='macos', name='macOS'), Architecture(id='aarch64', name='ARM64 (AArch64)')): 'https://github.com/rhysd/actionlint/releases/download/v{version}/actionlint_{version}_darwin_arm64.tar.gz', (Platform(id='macos', name='macOS'), Architecture(id='x86_64', name='x86-64 (AMD64)')): 'https://github.com/rhysd/actionlint/releases/download/v{version}/actionlint_{version}_darwin_amd64.tar.gz', (Platform(id='windows', name='Windows'), Architecture(id='aarch64', name='ARM64 (AArch64)')): 'https://github.com/rhysd/actionlint/releases/download/v{version}/actionlint_{version}_windows_arm64.zip', (Platform(id='windows', name='Windows'), Architecture(id='x86_64', name='x86-64 (AMD64)')): 'https://github.com/rhysd/actionlint/releases/download/v{version}/actionlint_{version}_windows_amd64.zip'}, checksums={(Group(id='linux', name='Linux distributions'), Architecture(id='aarch64', name='ARM64 (AArch64)')): '325e971b6ba9bfa504672e29be93c24981eeb1c07576d730e9f7c8805afff0c6', (Group(id='linux', name='Linux distributions'), Architecture(id='x86_64', name='x86-64 (AMD64)')): '8aca8db96f1b94770f1b0d72b6dddcb1ebb8123cb3712530b08cc387b349a3d8', (Platform(id='macos', name='macOS'), Architecture(id='aarch64', name='ARM64 (AArch64)')): 'aba9ced2dee8d27fecca3dc7feb1a7f9a52caefa1eb46f3271ea66b6e0e6953f', (Platform(id='macos', name='macOS'), Architecture(id='x86_64', name='x86-64 (AMD64)')): '5b44c3bc2255115c9b69e30efc0fecdf498fdb63c5d58e17084fd5f16324c644', (Platform(id='windows', name='Windows'), Architecture(id='aarch64', name='ARM64 (AArch64)')): 'cadcf7ea4efe3a68728893813643cebe1185e5b1d4be5b96245f65c9a4d5ea41', (Platform(id='windows', name='Windows'), Architecture(id='x86_64', name='x86-64 (AMD64)')): '6e7241b51e6817ea6a047693d8e6fed13b31819c9a0dd6c5a726e1592d22f6e9'}, archive_format={Group(id='all_platforms', name='All platforms'): <ArchiveFormat.TAR_GZ: 'tar.gz'>, Platform(id='windows', name='Windows'): <ArchiveFormat.ZIP: 'zip'>}, archive_executable=None, strip_components=0), npm=None, source_url='https://github.com/rhysd/actionlint', tag_pattern=None, config_docs_url='https://github.com/rhysd/actionlint/blob/main/docs/config.md', cli_docs_url='https://github.com/rhysd/actionlint/blob/main/docs/usage.md', docs_notes='**Try it:**\n\n```shell-session\n$ repomatic run actionlint\n```\n\n**Minimal `[tool.actionlint]`:**\n\n```toml\n[tool.actionlint.self-hosted-runner]\nlabels = ["my-linux-runner"]\n```\n\nWith no arguments actionlint lints every workflow under `.github/workflows`. The `[tool.actionlint]` section is bridged to a temporary YAML config: declaring self-hosted runner labels stops custom `runs-on:` values being flagged as unknown.'), 'autopep8': ToolSpec(name='autopep8', display_name=None, version='2.3.2', package=None, executable=None, module=None, native_config_files=(), config_flag=None, native_format=<NativeFormat.YAML: 'yaml'>, default_config=None, reads_pyproject=True, default_flags=('--recursive', '--in-place', '--max-line-length', '88', '--select', 'E501'), ci_flags=(), default_args=(), default_paths='python_files', per_file=False, with_packages=(), path_tools=(), needs_venv=False, computed_params=None, config_after_subcommand=False, post_process=None, output_flag=None, check_flags=(), rewrite_exit_code=None, binary=None, npm=None, source_url='https://github.com/hhatto/autopep8', tag_pattern=None, config_docs_url=None, cli_docs_url='https://pypi.org/project/autopep8/', docs_notes='**Try it:**\n\n```shell-session\n$ repomatic run autopep8 -- .\n```\n\nautopep8 takes its configuration from CLI flags only. repomatic passes `--recursive --in-place --max-line-length 88 --select E501` by default; append more flags after `--`.'), 'awesome-lint': ToolSpec(name='awesome-lint', display_name=None, version='2.3.0', package=None, executable=None, module=None, native_config_files=(), config_flag=None, native_format=<NativeFormat.YAML: 'yaml'>, default_config=None, reads_pyproject=False, default_flags=(), ci_flags=(), default_args=(), default_paths=None, per_file=False, with_packages=(), path_tools=(), needs_venv=False, computed_params=None, config_after_subcommand=False, post_process=None, output_flag=None, check_flags=(), rewrite_exit_code=None, binary=None, npm=NpmSpec(), source_url=None, tag_pattern=None, config_docs_url=None, cli_docs_url='https://github.com/sindresorhus/awesome-lint#usage', docs_notes=''), 'biome': ToolSpec(name='biome', display_name='Biome', version='2.5.9', package=None, executable=None, module=None, native_config_files=('biome.json', 'biome.jsonc', '.biome.json', '.biome.jsonc'), config_flag='--config-path', native_format=<NativeFormat.JSON: 'json'>, default_config=None, reads_pyproject=False, default_flags=(), ci_flags=(), default_args=('format', '--write', '--no-errors-on-unmatched', '--json-parse-allow-comments=true', '--json-parse-allow-trailing-commas=true'), default_paths='json_files', per_file=False, with_packages=(), path_tools=(), needs_venv=False, computed_params=None, config_after_subcommand=True, post_process=None, output_flag=None, check_flags=(), rewrite_exit_code=None, binary=BinarySpec(urls={(Group(id='linux', name='Linux distributions'), Architecture(id='aarch64', name='ARM64 (AArch64)')): 'https://github.com/biomejs/biome/releases/download/%40biomejs%2Fbiome%40{version}/biome-linux-arm64', (Group(id='linux', name='Linux distributions'), Architecture(id='x86_64', name='x86-64 (AMD64)')): 'https://github.com/biomejs/biome/releases/download/%40biomejs%2Fbiome%40{version}/biome-linux-x64', (Platform(id='macos', name='macOS'), Architecture(id='aarch64', name='ARM64 (AArch64)')): 'https://github.com/biomejs/biome/releases/download/%40biomejs%2Fbiome%40{version}/biome-darwin-arm64', (Platform(id='macos', name='macOS'), Architecture(id='x86_64', name='x86-64 (AMD64)')): 'https://github.com/biomejs/biome/releases/download/%40biomejs%2Fbiome%40{version}/biome-darwin-x64', (Platform(id='windows', name='Windows'), Architecture(id='aarch64', name='ARM64 (AArch64)')): 'https://github.com/biomejs/biome/releases/download/%40biomejs%2Fbiome%40{version}/biome-win32-arm64.exe', (Platform(id='windows', name='Windows'), Architecture(id='x86_64', name='x86-64 (AMD64)')): 'https://github.com/biomejs/biome/releases/download/%40biomejs%2Fbiome%40{version}/biome-win32-x64.exe'}, checksums={(Group(id='linux', name='Linux distributions'), Architecture(id='aarch64', name='ARM64 (AArch64)')): 'bf593f7955e3a437fb8056b255142b50872baa3e81371cda2c3fce9239af1890', (Group(id='linux', name='Linux distributions'), Architecture(id='x86_64', name='x86-64 (AMD64)')): '013eb5158b9e53235dbbf31255cb3b776fb9338b32fa6ff4a44ee1ceed65ee63', (Platform(id='macos', name='macOS'), Architecture(id='aarch64', name='ARM64 (AArch64)')): '7d8b51dec857ffa8aa35ce5eaa3a4476cd62bed013adc2896bf43cac0a67a79b', (Platform(id='macos', name='macOS'), Architecture(id='x86_64', name='x86-64 (AMD64)')): 'df2b50ee283634cdd6f7570b7da06bc3c9cd7ec0590ecbbaf986c7590bef3289', (Platform(id='windows', name='Windows'), Architecture(id='aarch64', name='ARM64 (AArch64)')): 'd6845ff075043300551d4ad74985814e4e4c56b49ffa87b3724ddf5055a2efe9', (Platform(id='windows', name='Windows'), Architecture(id='x86_64', name='x86-64 (AMD64)')): 'f8474a0f9f457df176c10be3f0e82be890e8986ff2805d4a7f3c5a4cba5962ca'}, archive_format=<ArchiveFormat.RAW: 'raw'>, archive_executable=None, strip_components=0), npm=None, source_url='https://github.com/biomejs/biome', tag_pattern='^@biomejs/biome@(?P<version>.+)$', config_docs_url='https://biomejs.dev/reference/configuration/', cli_docs_url='https://biomejs.dev/reference/cli/', docs_notes='**Try it:**\n\n```shell-session\n$ repomatic run biome -- check .\n```\n\n**Minimal `[tool.biome]`:**\n\n```toml\n[tool.biome.formatter]\nindentStyle = "space"\n```\n\n`biome check` reports formatting and lint issues; add `--write` after `--` to apply fixes. The `[tool.biome]` section is bridged to a temporary `biome.json`, so keys keep Biome\'s camelCase spelling.'), 'bump-my-version': ToolSpec(name='bump-my-version', display_name=None, version='1.5.1', package=None, executable=None, module=None, native_config_files=('.bumpversion.toml',), config_flag='--config-file', native_format=<NativeFormat.TOML: 'toml'>, default_config=None, reads_pyproject=True, default_flags=(), ci_flags=(), default_args=(), default_paths=None, per_file=False, with_packages=(), path_tools=(), needs_venv=False, computed_params=None, config_after_subcommand=False, post_process=None, output_flag=None, check_flags=(), rewrite_exit_code=None, binary=None, npm=None, source_url='https://github.com/callowayproject/bump-my-version', tag_pattern=None, config_docs_url='https://callowayproject.github.io/bump-my-version/reference/configuration/', cli_docs_url='https://callowayproject.github.io/bump-my-version/reference/cli/', docs_notes='**Try it:**\n\n```shell-session\n$ repomatic run bump-my-version -- show-bump\n```\n\n**Minimal `[tool.bumpversion]`:**\n\n```toml\n[tool.bumpversion]\ncurrent_version = "1.2.3"\n```\n\nThe configuration table is `[tool.bumpversion]`, not `[tool.bump-my-version]`: the section name predates the project\'s rename. `show-bump` previews the next versions without writing; `repomatic run bump-my-version -- bump minor` performs the bump.'), 'gh': ToolSpec(name='gh', display_name='GitHub CLI', version='2.97.0', package=None, executable=None, module=None, native_config_files=(), config_flag=None, native_format=<NativeFormat.YAML: 'yaml'>, default_config=None, reads_pyproject=False, default_flags=(), ci_flags=(), default_args=(), default_paths=None, per_file=False, with_packages=(), path_tools=(), needs_venv=False, computed_params=None, config_after_subcommand=False, post_process=None, output_flag=None, check_flags=(), rewrite_exit_code=None, binary=BinarySpec(urls={(Group(id='linux', name='Linux distributions'), Architecture(id='aarch64', name='ARM64 (AArch64)')): 'https://github.com/cli/cli/releases/download/v{version}/gh_{version}_linux_arm64.tar.gz', (Group(id='linux', name='Linux distributions'), Architecture(id='x86_64', name='x86-64 (AMD64)')): 'https://github.com/cli/cli/releases/download/v{version}/gh_{version}_linux_amd64.tar.gz', (Platform(id='macos', name='macOS'), Architecture(id='aarch64', name='ARM64 (AArch64)')): 'https://github.com/cli/cli/releases/download/v{version}/gh_{version}_macOS_arm64.zip', (Platform(id='macos', name='macOS'), Architecture(id='x86_64', name='x86-64 (AMD64)')): 'https://github.com/cli/cli/releases/download/v{version}/gh_{version}_macOS_amd64.zip', (Platform(id='windows', name='Windows'), Architecture(id='aarch64', name='ARM64 (AArch64)')): 'https://github.com/cli/cli/releases/download/v{version}/gh_{version}_windows_arm64.zip', (Platform(id='windows', name='Windows'), Architecture(id='x86_64', name='x86-64 (AMD64)')): 'https://github.com/cli/cli/releases/download/v{version}/gh_{version}_windows_amd64.zip'}, checksums={(Group(id='linux', name='Linux distributions'), Architecture(id='aarch64', name='ARM64 (AArch64)')): '73ea440ecad9c9e284429997ee6f93577bc6f7bc6fba357ef62c53ad8fb641a5', (Group(id='linux', name='Linux distributions'), Architecture(id='x86_64', name='x86-64 (AMD64)')): 'a2c9b8497e1f85b1ad0dfcb78b5a622e098801b8e461e459e88e1ee12f018112', (Platform(id='macos', name='macOS'), Architecture(id='aarch64', name='ARM64 (AArch64)')): 'a58b8fd77b417a38f47a0b54d1370c59b0fcdb324ccc9ca002b0998f7c4c999e', (Platform(id='macos', name='macOS'), Architecture(id='x86_64', name='x86-64 (AMD64)')): '63298c998cc2a924c9e254c6af6a1caad6ece281122687a91f079bc0a462700e', (Platform(id='windows', name='Windows'), Architecture(id='aarch64', name='ARM64 (AArch64)')): '3e2d4a166da4ee5020c592737b65eec0e724946d5d5b962f5fe59d99116dc4bf', (Platform(id='windows', name='Windows'), Architecture(id='x86_64', name='x86-64 (AMD64)')): '35d7fe05c4dd1411ffda1e73dfc7c6f44b75c936ca51fa6595c657fdc0350cec'}, archive_format={Group(id='all_platforms', name='All platforms'): <ArchiveFormat.TAR_GZ: 'tar.gz'>, Platform(id='macos', name='macOS'): <ArchiveFormat.ZIP: 'zip'>, Platform(id='windows', name='Windows'): <ArchiveFormat.ZIP: 'zip'>}, archive_executable='bin/gh', strip_components={Group(id='all_platforms', name='All platforms'): 1, Platform(id='windows', name='Windows'): 0}), npm=None, source_url='https://github.com/cli/cli', tag_pattern=None, config_docs_url=None, cli_docs_url='https://cli.github.com/manual/', docs_notes='**Try it:**\n\n```shell-session\n$ repomatic run gh -- --version\n```\n\nPinned so the release lane gets the same `gh` everywhere. The manylinux container the Linux binaries compile in ships no `gh`, and the runner images that do ship one leave its version to the image. `gh` reads no project configuration: it authenticates from `GH_TOKEN` in the environment.'), 'gitleaks': ToolSpec(name='gitleaks', display_name='Gitleaks', version='8.30.1', package=None, executable=None, module=None, native_config_files=('.gitleaks.toml',), config_flag='--config', native_format=<NativeFormat.TOML: 'toml'>, default_config=None, reads_pyproject=False, default_flags=(), ci_flags=(), default_args=(), default_paths=None, per_file=False, with_packages=(), path_tools=(), needs_venv=False, computed_params=None, config_after_subcommand=False, post_process=None, output_flag=None, check_flags=(), rewrite_exit_code=None, binary=BinarySpec(urls={(Group(id='linux', name='Linux distributions'), Architecture(id='aarch64', name='ARM64 (AArch64)')): 'https://github.com/gitleaks/gitleaks/releases/download/v{version}/gitleaks_{version}_linux_arm64.tar.gz', (Group(id='linux', name='Linux distributions'), Architecture(id='x86_64', name='x86-64 (AMD64)')): 'https://github.com/gitleaks/gitleaks/releases/download/v{version}/gitleaks_{version}_linux_x64.tar.gz', (Platform(id='macos', name='macOS'), Architecture(id='aarch64', name='ARM64 (AArch64)')): 'https://github.com/gitleaks/gitleaks/releases/download/v{version}/gitleaks_{version}_darwin_arm64.tar.gz', (Platform(id='macos', name='macOS'), Architecture(id='x86_64', name='x86-64 (AMD64)')): 'https://github.com/gitleaks/gitleaks/releases/download/v{version}/gitleaks_{version}_darwin_x64.tar.gz', (Platform(id='windows', name='Windows'), Architecture(id='aarch64', name='ARM64 (AArch64)')): 'https://github.com/gitleaks/gitleaks/releases/download/v{version}/gitleaks_{version}_windows_arm64.zip', (Platform(id='windows', name='Windows'), Architecture(id='x86_64', name='x86-64 (AMD64)')): 'https://github.com/gitleaks/gitleaks/releases/download/v{version}/gitleaks_{version}_windows_x64.zip'}, checksums={(Group(id='linux', name='Linux distributions'), Architecture(id='aarch64', name='ARM64 (AArch64)')): 'e4a487ee7ccd7d3a7f7ec08657610aa3606637dab924210b3aee62570fb4b080', (Group(id='linux', name='Linux distributions'), Architecture(id='x86_64', name='x86-64 (AMD64)')): '551f6fc83ea457d62a0d98237cbad105af8d557003051f41f3e7ca7b3f2470eb', (Platform(id='macos', name='macOS'), Architecture(id='aarch64', name='ARM64 (AArch64)')): 'b40ab0ae55c505963e365f271a8d3846efbc170aa17f2607f13df610a9aeb6a5', (Platform(id='macos', name='macOS'), Architecture(id='x86_64', name='x86-64 (AMD64)')): 'dfe101a4db2255fc85120ac7f3d25e4342c3c20cf749f2c20a18081af1952709', (Platform(id='windows', name='Windows'), Architecture(id='aarch64', name='ARM64 (AArch64)')): 'b95f5e4f5c425cedca7ee203d9afd29597e692c4924a12ed42f970537c72cc0f', (Platform(id='windows', name='Windows'), Architecture(id='x86_64', name='x86-64 (AMD64)')): 'd29144deff3a68aa93ced33dddf84b7fdc26070add4aa0f4513094c8332afc4e'}, archive_format={Group(id='all_platforms', name='All platforms'): <ArchiveFormat.TAR_GZ: 'tar.gz'>, Platform(id='windows', name='Windows'): <ArchiveFormat.ZIP: 'zip'>}, archive_executable=None, strip_components=0), npm=None, source_url='https://github.com/gitleaks/gitleaks', tag_pattern=None, config_docs_url='https://github.com/gitleaks/gitleaks#configuration', cli_docs_url='https://github.com/gitleaks/gitleaks#usage', docs_notes="**Try it:**\n\n```shell-session\n$ repomatic run gitleaks -- dir .\n```\n\n**Minimal `[tool.gitleaks]`:**\n\n```toml\n[tool.gitleaks.extend]\nuseDefault = true\n\n[tool.gitleaks.allowlist]\npaths = ['''\\.env\\.sample$''']\n```\n\n`gitleaks dir .` scans the working tree; `gitleaks git` scans history instead. The `[tool.gitleaks]` section is bridged to a temporary `.gitleaks.toml`: keep `extend.useDefault = true`, or a custom config silently replaces the built-in rule set."), 'labelmaker': ToolSpec(name='labelmaker', display_name=None, version='0.6.4', package=None, executable=None, module=None, native_config_files=(), config_flag=None, native_format=<NativeFormat.YAML: 'yaml'>, default_config=None, reads_pyproject=False, default_flags=(), ci_flags=(), default_args=(), default_paths=None, per_file=False, with_packages=(), path_tools=(), needs_venv=False, computed_params=None, config_after_subcommand=False, post_process=None, output_flag=None, check_flags=(), rewrite_exit_code=None, binary=BinarySpec(urls={(Group(id='linux', name='Linux distributions'), Architecture(id='aarch64', name='ARM64 (AArch64)')): 'https://github.com/jwodder/labelmaker/releases/download/v{version}/labelmaker-aarch64-unknown-linux-gnu.tar.xz', (Group(id='linux', name='Linux distributions'), Architecture(id='x86_64', name='x86-64 (AMD64)')): 'https://github.com/jwodder/labelmaker/releases/download/v{version}/labelmaker-x86_64-unknown-linux-gnu.tar.xz', (Platform(id='macos', name='macOS'), Architecture(id='aarch64', name='ARM64 (AArch64)')): 'https://github.com/jwodder/labelmaker/releases/download/v{version}/labelmaker-aarch64-apple-darwin.tar.xz', (Platform(id='macos', name='macOS'), Architecture(id='x86_64', name='x86-64 (AMD64)')): 'https://github.com/jwodder/labelmaker/releases/download/v{version}/labelmaker-x86_64-apple-darwin.tar.xz', (Platform(id='windows', name='Windows'), Architecture(id='x86_64', name='x86-64 (AMD64)')): 'https://github.com/jwodder/labelmaker/releases/download/v{version}/labelmaker-x86_64-pc-windows-msvc.zip'}, checksums={(Group(id='linux', name='Linux distributions'), Architecture(id='aarch64', name='ARM64 (AArch64)')): '4685e142da55150904d16624fe1052161de5dba1a859cddef19ab41833c37728', (Group(id='linux', name='Linux distributions'), Architecture(id='x86_64', name='x86-64 (AMD64)')): 'd76f8e64f9671884dac1758fe54a28a6680c5d9bf0ffd593a2c68ba558cc49a2', (Platform(id='macos', name='macOS'), Architecture(id='aarch64', name='ARM64 (AArch64)')): 'a52a4e102f0760ce1632da5fdaee2b0debe0e6ddea577b88a94a60172fe85751', (Platform(id='macos', name='macOS'), Architecture(id='x86_64', name='x86-64 (AMD64)')): 'dc8374d6a9bec4ebf143fb42e3024aeffabe8585bb9bd6f134cfaf0693be7688', (Platform(id='windows', name='Windows'), Architecture(id='x86_64', name='x86-64 (AMD64)')): '939195930f9d5fd2b15a5cf43497019a52083e6c6713807d3379de49395c2e10'}, archive_format={Group(id='all_platforms', name='All platforms'): <ArchiveFormat.TAR_XZ: 'tar.xz'>, Platform(id='windows', name='Windows'): <ArchiveFormat.ZIP: 'zip'>}, archive_executable=None, strip_components=1), npm=None, source_url='https://github.com/jwodder/labelmaker', tag_pattern=None, config_docs_url=None, cli_docs_url='https://github.com/jwodder/labelmaker', docs_notes="labelmaker syncs a repository's issue and PR labels from a label-definition file, so unlike the linters it needs a target repository and a `GITHUB_TOKEN`, not a path in the working tree. There is no `[tool.labelmaker]` section: the label file is the configuration. See the [upstream usage docs](https://github.com/jwodder/labelmaker) for its flags and file schema."), 'lychee': ToolSpec(name='lychee', display_name='Lychee', version='0.24.2', package=None, executable=None, module=None, native_config_files=('lychee.toml',), config_flag='--config', native_format=<NativeFormat.TOML: 'toml'>, default_config=None, reads_pyproject=True, default_flags=(), ci_flags=(), default_args=(), default_paths=None, per_file=False, with_packages=(), path_tools=(), needs_venv=False, computed_params=None, config_after_subcommand=False, post_process=None, output_flag='--output', check_flags=(), rewrite_exit_code=None, binary=BinarySpec(urls={(Group(id='linux', name='Linux distributions'), Architecture(id='aarch64', name='ARM64 (AArch64)')): 'https://github.com/lycheeverse/lychee/releases/download/lychee-v{version}/lychee-aarch64-unknown-linux-gnu.tar.gz', (Group(id='linux', name='Linux distributions'), Architecture(id='x86_64', name='x86-64 (AMD64)')): 'https://github.com/lycheeverse/lychee/releases/download/lychee-v{version}/lychee-x86_64-unknown-linux-gnu.tar.gz', (Platform(id='macos', name='macOS'), Architecture(id='aarch64', name='ARM64 (AArch64)')): 'https://github.com/lycheeverse/lychee/releases/download/lychee-v{version}/lychee-aarch64-apple-darwin.tar.gz', (Platform(id='windows', name='Windows'), Architecture(id='x86_64', name='x86-64 (AMD64)')): 'https://github.com/lycheeverse/lychee/releases/download/lychee-v{version}/lychee-x86_64-pc-windows-msvc.zip'}, checksums={(Group(id='linux', name='Linux distributions'), Architecture(id='aarch64', name='ARM64 (AArch64)')): '91a7bd65685da41b90ccb9bc867a3d649a7818042dae04ff405e55a25bddee4c', (Group(id='linux', name='Linux distributions'), Architecture(id='x86_64', name='x86-64 (AMD64)')): '1f4e0ef7f6554a6ed33dd7ac144fb2e1bbed98598e7af973042fc5cd43951c9a', (Platform(id='macos', name='macOS'), Architecture(id='aarch64', name='ARM64 (AArch64)')): 'c9d3740ea2d891854d37116c9fba840f37b6e7c89d330e7db84ac333631c4977', (Platform(id='windows', name='Windows'), Architecture(id='x86_64', name='x86-64 (AMD64)')): '32975d1493ee1a975d6bb41e4fb56fe419cb442ded628bb772ba2e614acfacad'}, archive_format={Group(id='all_platforms', name='All platforms'): <ArchiveFormat.TAR_GZ: 'tar.gz'>, Platform(id='windows', name='Windows'): <ArchiveFormat.ZIP: 'zip'>}, archive_executable=None, strip_components=1), npm=None, source_url='https://github.com/lycheeverse/lychee', tag_pattern='^lychee-v(?P<version>.+)$', config_docs_url='https://lychee.cli.rs/guides/config/', cli_docs_url='https://lychee.cli.rs/guides/cli/', docs_notes='**Try it:**\n\n```shell-session\n$ repomatic run lychee -- .\n```\n\n**Minimal `[tool.lychee]`:**\n\n```toml\n[tool.lychee]\nmax_redirects = 5\n```\n\nlychee checks links found in the given path. Since v0.24 it reads `[tool.lychee]` from `pyproject.toml` natively, so repomatic does not translate it.'), 'mdformat': ToolSpec(name='mdformat', display_name=None, version='1.0.0', package=None, executable=None, module=None, native_config_files=('.mdformat.toml',), config_flag=None, native_format=<NativeFormat.TOML: 'toml'>, default_config='mdformat.toml', reads_pyproject=True, default_flags=('--strict-front-matter',), ci_flags=(), default_args=(), default_paths='markdown_files', per_file=True, with_packages=('mdformat_admon==2.1.1', 'mdformat-config==0.2.1', 'mdformat_deflist==0.1.4', 'mdformat_footnote==0.1.3', 'mdformat-front-matters==2.0.0', 'mdformat-gfm==1.0.0', 'mdformat_gfm_alerts==2.1.0', 'mdformat_myst==0.3.0', 'mdformat-pelican==1.0.0', 'mdformat_pyproject==0.1.1', 'mdformat-recover-urls==0.0.2', 'mdformat-shfmt==0.2.0', 'mdformat_simple_breaks==0.1.0', 'mdformat-toc==0.5.0', 'mdformat-web==0.2.0'), path_tools=('shfmt',), needs_venv=False, computed_params=None, config_after_subcommand=False, post_process=<function _fix_myst_directives>, output_flag=None, check_flags=('--check',), rewrite_exit_code=None, binary=None, npm=None, source_url='https://github.com/hukkin/mdformat', tag_pattern=None, config_docs_url='https://mdformat.readthedocs.io/en/stable/users/configuration_file.html', cli_docs_url='https://mdformat.readthedocs.io/en/stable/users/installation_and_usage.html', docs_notes='**Try it:**\n\n```shell-session\n$ repomatic run mdformat -- .\n```\n\n**Minimal `[tool.mdformat]`:**\n\n```toml\n[tool.mdformat]\nwrap = "no"\n```\n\nmdformat rewrites Markdown in place. repomatic bundles a plugin set (GFM, MyST, front-matter, and others) and a baseline `mdformat.toml`; `[tool.mdformat]` in your `pyproject.toml` overrides it.'), 'mypy': ToolSpec(name='mypy', display_name=None, version='2.3.1', package=None, executable=None, module=None, native_config_files=(), config_flag='--config-file', native_format=<NativeFormat.YAML: 'yaml'>, default_config=None, reads_pyproject=True, default_flags=('--color-output',), ci_flags=(), default_args=(), default_paths='python_files', per_file=False, with_packages=(), path_tools=(), needs_venv=True, computed_params=<function <lambda>>, config_after_subcommand=False, post_process=None, output_flag=None, check_flags=(), rewrite_exit_code=None, binary=None, npm=None, source_url='https://github.com/python/mypy', tag_pattern=None, config_docs_url='https://mypy.readthedocs.io/en/stable/config_file.html', cli_docs_url='https://mypy.readthedocs.io/en/stable/command_line.html', docs_notes='**Try it:**\n\n```shell-session\n$ repomatic run mypy -- .\n```\n\n**Minimal `[tool.mypy]`:**\n\n```toml\n[tool.mypy]\nstrict = true\n```\n\nmypy runs inside the project virtualenv (via `uv run`) so it can import your dependencies. repomatic derives `--python-version` from `requires-python`, so the check matches your lowest supported interpreter. In a repository without a `uv.lock` there is no project virtualenv to freeze, so mypy runs in an isolated environment instead and only resolves the standard library: fine for standalone scripts, but dependency imports then report `import-not-found`.\n\n`uv run` provisions only the default dependency groups, so a module that imports a dep declared solely in a non-default group (`docs`, `typing`, …) sees it as missing and mypy reports `import-not-found`. Either move the stub/dependency somewhere mypy resolves, or silence it with an override:\n\n```toml\n[[tool.mypy.overrides]]\nmodule = "the_docs_only_package.*"\nignore_missing_imports = true\n```'), 'nuitka': ToolSpec(name='nuitka', display_name='Nuitka', version='4.1.3', package='nuitka[onefile]', executable=None, module='nuitka', native_config_files=(), config_flag=None, native_format=<NativeFormat.FLAGS: 'flags'>, default_config=None, reads_pyproject=False, default_flags=('--mode=onefile', '--assume-yes-for-downloads'), ci_flags=(), default_args=(), default_paths=None, per_file=False, with_packages=(), path_tools=(), needs_venv=True, computed_params=<function <lambda>>, config_after_subcommand=False, post_process=None, output_flag=None, check_flags=(), rewrite_exit_code=None, binary=None, npm=None, source_url='https://github.com/Nuitka/Nuitka', tag_pattern=None, config_docs_url='https://nuitka.net/doc/user-manual.html', cli_docs_url='https://nuitka.net/doc/user-manual.html', docs_notes='**Try it:**\n\n```shell-session\n$ repomatic run nuitka -- my_app/__main__.py\n```\n\n**Minimal `[tool.nuitka]`:**\n\n```toml\n[tool.nuitka]\nonefile = true\noutput-dir = "build"\n```\n\nrepomatic reads every key from `[tool.nuitka]` and forwards it as a CLI flag: `true` becomes a bare `--flag`, a string or number becomes `--key=value`, and a list repeats the flag once per item. Nuitka does not read `[tool.nuitka]` natively yet ([Nuitka#3909](https://github.com/Nuitka/Nuitka/issues/3909)); repomatic\'s bridge fills the gap until it does.\n\nBinaries skip `tkinter` by default, via the `nuitka.nofollow-imports` setting of [`[tool.repomatic]`](configuration.md): set it to `[]` to bundle Tcl/Tk in a GUI project.'), 'oxipng': ToolSpec(name='oxipng', display_name='Oxipng', version='10.2.0', package=None, executable=None, module=None, native_config_files=(), config_flag=None, native_format=<NativeFormat.YAML: 'yaml'>, default_config=None, reads_pyproject=False, default_flags=(), ci_flags=(), default_args=(), default_paths=None, per_file=False, with_packages=(), path_tools=(), needs_venv=False, computed_params=None, config_after_subcommand=False, post_process=None, output_flag=None, check_flags=(), rewrite_exit_code=None, binary=BinarySpec(urls={(Group(id='linux', name='Linux distributions'), Architecture(id='aarch64', name='ARM64 (AArch64)')): 'https://github.com/shssoichiro/oxipng/releases/download/v{version}/oxipng-{version}-aarch64-unknown-linux-gnu.tar.gz', (Group(id='linux', name='Linux distributions'), Architecture(id='x86_64', name='x86-64 (AMD64)')): 'https://github.com/shssoichiro/oxipng/releases/download/v{version}/oxipng-{version}-x86_64-unknown-linux-gnu.tar.gz', (Platform(id='macos', name='macOS'), Architecture(id='aarch64', name='ARM64 (AArch64)')): 'https://github.com/shssoichiro/oxipng/releases/download/v{version}/oxipng-{version}-aarch64-apple-darwin.tar.gz', (Platform(id='macos', name='macOS'), Architecture(id='x86_64', name='x86-64 (AMD64)')): 'https://github.com/shssoichiro/oxipng/releases/download/v{version}/oxipng-{version}-x86_64-apple-darwin.tar.gz', (Platform(id='windows', name='Windows'), Architecture(id='x86_64', name='x86-64 (AMD64)')): 'https://github.com/shssoichiro/oxipng/releases/download/v{version}/oxipng-{version}-x86_64-pc-windows-msvc.zip'}, checksums={(Group(id='linux', name='Linux distributions'), Architecture(id='aarch64', name='ARM64 (AArch64)')): '97d168c6c0d1dbcb36e7438eb489804748a2ba40d94fe21aa7dab7372e9efe9b', (Group(id='linux', name='Linux distributions'), Architecture(id='x86_64', name='x86-64 (AMD64)')): 'b33f84c73d42cb592bea5d84c431030b1e97784817693380dfcec7d9575f871e', (Platform(id='macos', name='macOS'), Architecture(id='aarch64', name='ARM64 (AArch64)')): '9aad3927d095b6ade2aacb92b89ebaca442483c1f7cde5d7a2486b283c2ed5f9', (Platform(id='macos', name='macOS'), Architecture(id='x86_64', name='x86-64 (AMD64)')): 'c45acf40a70cc02539c55555ac240bf5ef24544b7ea9959d22da19f606cec205', (Platform(id='windows', name='Windows'), Architecture(id='x86_64', name='x86-64 (AMD64)')): 'a5ad52c9c288dc99c2eae90dcad73dee64e39bf3f5aa5303c0fb55ac9c5f069b'}, archive_format={Group(id='all_platforms', name='All platforms'): <ArchiveFormat.TAR_GZ: 'tar.gz'>, Platform(id='windows', name='Windows'): <ArchiveFormat.ZIP: 'zip'>}, archive_executable=None, strip_components=1), npm=None, source_url='https://github.com/shssoichiro/oxipng', tag_pattern=None, config_docs_url=None, cli_docs_url='https://github.com/shssoichiro/oxipng#usage', docs_notes='**Try it:**\n\n```shell-session\n$ repomatic run oxipng -- --opt 4 --strip safe image.png\n```\n\nLossless PNG optimizer. `repomatic format-images` reaches it through {func}`repomatic.tooling.tool_runner.ensure_binary`, so the pinned, checksum-verified build is used instead of whatever the runner image or the distro archive supplies.'), 'pyproject-fmt': ToolSpec(name='pyproject-fmt', display_name=None, version='2.28.0', package=None, executable=None, module=None, native_config_files=('pyproject-fmt.toml',), config_flag='--config', native_format=<NativeFormat.TOML: 'toml'>, default_config=None, reads_pyproject=True, default_flags=(), ci_flags=(), default_args=(), default_paths='pyproject_files', per_file=False, with_packages=(), path_tools=(), needs_venv=False, computed_params=None, config_after_subcommand=False, post_process=None, output_flag=None, check_flags=(), rewrite_exit_code=1, binary=None, npm=None, source_url='https://github.com/tox-dev/pyproject-fmt', tag_pattern=None, config_docs_url='https://pyproject-fmt.readthedocs.io/en/latest/', cli_docs_url='https://pyproject-fmt.readthedocs.io/en/latest/', docs_notes='**Try it:**\n\n```shell-session\n$ repomatic run pyproject-fmt -- pyproject.toml\n```\n\n**Minimal `[tool.pyproject-fmt]`:**\n\n```toml\n[tool.pyproject-fmt]\nindent = 4\n```\n\npyproject-fmt normalizes and reorders `pyproject.toml` in place. It reads its own `[tool.pyproject-fmt]` section natively.'), 'ruff': ToolSpec(name='ruff', display_name='Ruff', version='0.16.3', package=None, executable=None, module=None, native_config_files=('.ruff.toml', 'ruff.toml'), config_flag='--config', native_format=<NativeFormat.TOML: 'toml'>, default_config='ruff.toml', reads_pyproject=True, default_flags=(), ci_flags=(), default_args=(), default_paths=None, per_file=False, with_packages=(), path_tools=(), needs_venv=False, computed_params=None, config_after_subcommand=False, post_process=None, output_flag=None, check_flags=(), rewrite_exit_code=None, binary=None, npm=None, source_url='https://github.com/astral-sh/ruff', tag_pattern=None, config_docs_url='https://docs.astral.sh/ruff/configuration/', cli_docs_url='https://docs.astral.sh/ruff/configuration/#command-line-interface', docs_notes='**Try it:**\n\n```shell-session\n$ repomatic run ruff -- check .\n```\n\n**Minimal `[tool.ruff]`:**\n\n```toml\n[tool.ruff]\nline-length = 100\n```\n\n`ruff check .` lints; `ruff format .` reformats. Both read `[tool.ruff]` natively. With no project config, repomatic falls back to its bundled `ruff.toml` baseline.'), 'shfmt': ToolSpec(name='shfmt', display_name=None, version='3.13.1', package=None, executable=None, module=None, native_config_files=('.editorconfig',), config_flag=None, native_format=<NativeFormat.EDITORCONFIG: 'editorconfig'>, default_config=None, reads_pyproject=False, default_flags=('--write',), ci_flags=(), default_args=(), default_paths='shfmt_files', per_file=False, with_packages=(), path_tools=(), needs_venv=False, computed_params=None, config_after_subcommand=False, post_process=None, output_flag=None, check_flags=(), rewrite_exit_code=None, binary=BinarySpec(urls={(Group(id='linux', name='Linux distributions'), Architecture(id='aarch64', name='ARM64 (AArch64)')): 'https://github.com/mvdan/sh/releases/download/v{version}/shfmt_v{version}_linux_arm64', (Group(id='linux', name='Linux distributions'), Architecture(id='x86_64', name='x86-64 (AMD64)')): 'https://github.com/mvdan/sh/releases/download/v{version}/shfmt_v{version}_linux_amd64', (Platform(id='macos', name='macOS'), Architecture(id='aarch64', name='ARM64 (AArch64)')): 'https://github.com/mvdan/sh/releases/download/v{version}/shfmt_v{version}_darwin_arm64', (Platform(id='macos', name='macOS'), Architecture(id='x86_64', name='x86-64 (AMD64)')): 'https://github.com/mvdan/sh/releases/download/v{version}/shfmt_v{version}_darwin_amd64', (Platform(id='windows', name='Windows'), Architecture(id='x86_64', name='x86-64 (AMD64)')): 'https://github.com/mvdan/sh/releases/download/v{version}/shfmt_v{version}_windows_amd64.exe'}, checksums={(Group(id='linux', name='Linux distributions'), Architecture(id='aarch64', name='ARM64 (AArch64)')): '32d92acaa5cd8abb29fc49dac123dc412442d5713967819d8af2c29f1b3857c7', (Group(id='linux', name='Linux distributions'), Architecture(id='x86_64', name='x86-64 (AMD64)')): 'fb096c5d1ac6beabbdbaa2874d025badb03ee07929f0c9ff67563ce8c75398b1', (Platform(id='macos', name='macOS'), Architecture(id='aarch64', name='ARM64 (AArch64)')): '9680526be4a66ea1ffe988ed08af58e1400fe1e4f4aef5bd88b20bb9b3da33f8', (Platform(id='macos', name='macOS'), Architecture(id='x86_64', name='x86-64 (AMD64)')): '6feedafc72915794163114f512348e2437d080d0047ef8b8fa2ec63b575f12af', (Platform(id='windows', name='Windows'), Architecture(id='x86_64', name='x86-64 (AMD64)')): '60cd368533d0ad73fa86d93d5bbf95ef40587245ce684ed138c1b31557b5fe97'}, archive_format=<ArchiveFormat.RAW: 'raw'>, archive_executable=None, strip_components=0), npm=None, source_url='https://github.com/mvdan/sh', tag_pattern=None, config_docs_url='https://github.com/mvdan/sh/blob/master/cmd/shfmt/shfmt.1.scd', cli_docs_url='https://github.com/mvdan/sh#shfmt', docs_notes='**Try it:**\n\n```shell-session\n$ repomatic run shfmt -- .\n```\n\nshfmt formats shell scripts in place. It has no `[tool.shfmt]` section: indentation and style come from `.editorconfig` (`indent_size`, `shell_variant`, and the `shfmt`-specific keys).'), 'typos': ToolSpec(name='typos', display_name=None, version='1.49.0', package=None, executable=None, module=None, native_config_files=('typos.toml', '_typos.toml', '.typos.toml'), config_flag='--config', native_format=<NativeFormat.TOML: 'toml'>, default_config=None, reads_pyproject=True, default_flags=('--write-changes',), ci_flags=(), default_args=(), default_paths=None, per_file=False, with_packages=(), path_tools=(), needs_venv=False, computed_params=None, config_after_subcommand=False, post_process=None, output_flag=None, check_flags=(), rewrite_exit_code=None, binary=BinarySpec(urls={(Group(id='linux', name='Linux distributions'), Architecture(id='aarch64', name='ARM64 (AArch64)')): 'https://github.com/crate-ci/typos/releases/download/v{version}/typos-v{version}-aarch64-unknown-linux-musl.tar.gz', (Group(id='linux', name='Linux distributions'), Architecture(id='x86_64', name='x86-64 (AMD64)')): 'https://github.com/crate-ci/typos/releases/download/v{version}/typos-v{version}-x86_64-unknown-linux-musl.tar.gz', (Platform(id='macos', name='macOS'), Architecture(id='aarch64', name='ARM64 (AArch64)')): 'https://github.com/crate-ci/typos/releases/download/v{version}/typos-v{version}-aarch64-apple-darwin.tar.gz', (Platform(id='macos', name='macOS'), Architecture(id='x86_64', name='x86-64 (AMD64)')): 'https://github.com/crate-ci/typos/releases/download/v{version}/typos-v{version}-x86_64-apple-darwin.tar.gz', (Platform(id='windows', name='Windows'), Architecture(id='x86_64', name='x86-64 (AMD64)')): 'https://github.com/crate-ci/typos/releases/download/v{version}/typos-v{version}-x86_64-pc-windows-msvc.zip'}, checksums={(Group(id='linux', name='Linux distributions'), Architecture(id='aarch64', name='ARM64 (AArch64)')): '85c8b87b22a0fb1da130cd4d495e0beba7f1225eb580933184509e146ec4c509', (Group(id='linux', name='Linux distributions'), Architecture(id='x86_64', name='x86-64 (AMD64)')): '48bd2d58e02ce713b8c0f1aa239e68ee4f7d8c551013135806e6aed3938d9e10', (Platform(id='macos', name='macOS'), Architecture(id='aarch64', name='ARM64 (AArch64)')): '8c0e7bd40b2b60c0b0cfe9f74dd814b4d4385c956ce86860f7da9e62d91fdc73', (Platform(id='macos', name='macOS'), Architecture(id='x86_64', name='x86-64 (AMD64)')): '4cecbf653a9fc45f023abf57f4e2e2f6b138c2d2387b09289beacdd3f0ea7bfd', (Platform(id='windows', name='Windows'), Architecture(id='x86_64', name='x86-64 (AMD64)')): '06d3a1b71c282e021671070696a72696d5c60ea485b47dc4f8f1fbcf90144d02'}, archive_format={Group(id='all_platforms', name='All platforms'): <ArchiveFormat.TAR_GZ: 'tar.gz'>, Platform(id='windows', name='Windows'): <ArchiveFormat.ZIP: 'zip'>}, archive_executable=None, strip_components=0), npm=None, source_url='https://github.com/crate-ci/typos', tag_pattern=None, config_docs_url='https://github.com/crate-ci/typos/blob/master/docs/reference.md', cli_docs_url='https://github.com/crate-ci/typos/blob/master/docs/reference.md', docs_notes='**Try it:**\n\n```shell-session\n$ repomatic run typos -- .\n```\n\n**Minimal `[tool.typos]`:**\n\n```toml\n[tool.typos.files]\nextend-exclude = ["*.lock"]\n```\n\ntypos scans the tree and, with repomatic\'s default `--write-changes`, fixes what it finds. It reads `[tool.typos]` natively; use `[tool.typos.default.extend-words]` to map project-specific terms to their intended spelling.\n\nBecause the `fix-typos` workflow job ships whatever typos rewrites as an unattended pull request, guard content where a "correction" is a corruption with `[tool.typos.default.extend-ignore-re]` patterns. The two known traps are encoded hashes, whose random letter runs typos happily respells (a Guix `(base32 "...")` source hash losing its value to an `an`-to-`and` fix), and intentional-typo examples that docs or tests exercise on purpose:\n\n```toml\n[tool.typos.default]\nextend-ignore-re = [\n \'base32 "[0-9a-z]{52}"\',\n "\\\\{query\\\\}",\n]\n```'), 'yamllint': ToolSpec(name='yamllint', display_name=None, version='1.38.0', package=None, executable=None, module=None, native_config_files=('.yamllint', '.yamllint.yaml', '.yamllint.yml'), config_flag='--config-file', native_format=<NativeFormat.YAML: 'yaml'>, default_config='yamllint.yaml', reads_pyproject=False, default_flags=('--strict',), ci_flags=('--format', 'github'), default_args=('.',), default_paths=None, per_file=False, with_packages=(), path_tools=(), needs_venv=False, computed_params=None, config_after_subcommand=False, post_process=None, output_flag=None, check_flags=(), rewrite_exit_code=None, binary=None, npm=None, source_url='https://github.com/adrienverge/yamllint', tag_pattern=None, config_docs_url='https://yamllint.readthedocs.io/en/stable/configuration.html', cli_docs_url='https://yamllint.readthedocs.io/en/stable/quickstart.html', docs_notes="**Try it:**\n\n```shell-session\n$ repomatic run yamllint -- .\n```\n\n**Minimal `[tool.yamllint]`:**\n\n```toml\n[tool.yamllint.rules.line-length]\nmax = 120\n```\n\nyamllint has no native `pyproject.toml` support, so repomatic bridges `[tool.yamllint]` to a temporary YAML config passed via `--config-file`. With no project config it uses repomatic's strict bundled `yamllint.yaml`."), 'zizmor': ToolSpec(name='zizmor', display_name=None, version='1.29.0', package=None, executable=None, module=None, native_config_files=('.github/zizmor.yml', '.github/zizmor.yaml', 'zizmor.yml', 'zizmor.yaml'), config_flag='--config', native_format=<NativeFormat.YAML: 'yaml'>, default_config='zizmor.yaml', reads_pyproject=False, default_flags=('--offline',), ci_flags=('--format', 'github'), default_args=('.',), default_paths=None, per_file=False, with_packages=(), path_tools=(), needs_venv=False, computed_params=None, config_after_subcommand=False, post_process=None, output_flag=None, check_flags=(), rewrite_exit_code=None, binary=None, npm=None, source_url='https://github.com/zizmorcore/zizmor', tag_pattern=None, config_docs_url='https://docs.zizmor.sh/configuration/', cli_docs_url='https://docs.zizmor.sh/usage/', docs_notes='**Try it:**\n\n```shell-session\n$ repomatic run zizmor -- .\n```\n\nzizmor audits GitHub Actions workflows for security issues, offline by default. repomatic bridges `[tool.zizmor]` to a temporary YAML config (passed via `--config`); with none, it uses the bundled `zizmor.yaml`. See the [configuration reference](https://docs.zizmor.sh/configuration/) for available keys.')}¶
Tool name to the specification driving its install, config and invocation.
The single source of truth for
repomatic run: every command, workflow job and documentation renderer reads the roster from here rather than hard-coding a tool name, a version or a flag.Todo
Give the
mdformatentry aconfig_flag="--config"once mdformat accepts an explicit config path, so it stops relying on discovery from the working directory: hukkin/mdformat#432 and hukkin/mdformat#562.
- repomatic.tooling.tool_registry.tool_summary()[source]¶
Render the summary table of all managed tools.
- Return type:
- repomatic.tooling.tool_registry.tool_reference()[source]¶
Render the per-tool detail sections.
The metadata of each section (version, install, config, flags, links) is generated from the registry; the trailing free-form prose comes from the spec’s own
docs_notesfield, so hand-written examples and caveats live next to the spec they document.- Return type: