Upstream development¶
This page collects rules that apply only when working inside the kdeldycke/repomatic source repository itself.
Documentation sync¶
The following documentation artifacts must stay in sync with the code in this repository. When changing any of these, update the others:
Version samples in
docs/workflows.md: Two samples must name the latest released tag: theuses: kdeldycke/repomatic/.github/workflows/*.yaml@vX.Y.Zreference in the example-usage section, and theUpgrade repomatic to vX.Y.Zpull request title in thesync-repomaticjob description. Bump both by hand during the docs reconciliation pass. Thedocs/install.mdversion pins are covered under the auto-generated docs below.Workflow job descriptions in
docs/workflows.md: Each.github/workflows/*.yamlworkflow section must document all jobs by their actual job ID, with accurate descriptions of what they do, their requirements, and skip conditions.PAT permissions:
PAT_PERMISSION_PROBESinrepomatic/github/token.pyis the single source of truth, onePatProberow per fine-grained permission, run bycheck_all_pat_permissionsfor bothlint-repoandsetup-guide(so a new probe row reaches every consumer automatically). When changing permissions, update: the probe table and module docstring, the permission table and pre-filled URL inrepomatic/templates/setup-guide-token.md, and thesummaryanddescriptionof thepat-permissionsentry inREPO_CHECKS(repomatic/lint_repo.py), which name the permissions inlint-repo --helpand in thelint-repojob description ofdocs/workflows.md.Repository configuration expectations: The
lint-repojob enforces repo settings described in the setup guide. When adding new setup steps, add a correspondingRepoCheckentry toREPO_CHECKSinrepomatic/lint_repo.py, whichrun_repo_lint()walks. Give the entry asummary, whichlint-repo --helprenders with a severity that comes from the entry’sfatalflag. Give it adescriptiontoo, which thelint-repojob description indocs/workflows.mdrenders as the check’s bullet. Open the description onFailsfor a fatal check and onWarnsfor any other:tests/test_lint_repo.pyholds the two together. If the check cannot be automated, document the limitation in a comment.PAT permission review: When adding or removing workflow jobs that use
REPOMATIC_PAT, reviewPAT_PERMISSION_PROBESto verify the permission set is still minimal and complete. Checksecrets.REPOMATIC_PATreferences across all workflow files to audit actual usage.Module reference pages:
[tool.repomatic] docs.apidoc-extra-argspasses--separate, so every module gets its owndocs/{module}.mdpage.repomatic update-docswrites a missing page but never rewrites an existing one. It also lists each new page in the toctree of its package page (docs/repomatic.mdfor a top-level module,docs/repomatic.{subpackage}.mdotherwise). That wiring only adds: a module that is renamed or removed leaves its old page and toctree entry to delete by hand.tests/test_readme.pyfails on a module that has no page. The file inventories thattests/test_metadata.pychecks come fromgit ls-files, so an untracked file in the checkout fails them.
Auto-generated docs:
CLI parameters in
docs/cli.md: rendered live at build time from Click via the{click:tree}directive.Configuration table in
docs/configuration.md: rendered live at build time from theConfigdataclass via the{click:config}directive.Binary download URLs and
Specific versionCLI pin indocs/install.md: both version-pinned, both ratcheted forward to the new release automatically byprepare-release’sfreeze_install_download_urlsandfreeze_install_cli_version.Plugin marketplace pin in
.claude-plugin/marketplace.json, and the plugin manifest version in.claude/.claude-plugin/plugin.json:prepare-release’sfreeze_marketplace_pinwrites both the entry’srefand itsversionon the release commit.freeze_plugin_manifest_versionstamps the same version into the manifest, which is the string the Claude Code CLI compares to detect an update (see § How the pin moves). Thenunfreeze_marketplace_refreturns therefto the default branch and leaves both versions on the release. It is deliberately not a[[tool.bumpversion.files]]entry: that would rewrite the version on the post-release bump too, advertising avX.Y.Z.devNrelease that never exists.
Todo
Replace the UnresolvedAnchors handler in docs/conf.py with the click_extra_fail_on_warnings = ["myst.xref_missing"] line, once a click-extra release ships that option and clears the one-week minimum-release-age cooldown. Both fail the build on an unresolved fragment link, so the swap changes no behavior.
Tool runner: flags vs config¶
When adding or modifying a tool in TOOL_REGISTRY, choose the right mechanism for each default based on whether downstream repos should be able to override it:
default_flags: operational/cosmetic flags that are always applied and not overridable: output formatting (--color), operational mode (--write-changes, --in-place), enforcement level (--strict), network policy (--offline), tool-specific quirks with no config-file equivalent.
default_config (bundled file in repomatic/data/): behavioral preferences a downstream repo might legitimately want to override via its own config: lint rule selection, formatting preferences (numbering, line length), spell-check dictionaries, tool-specific rule configuration (severity, thresholds).
The test: if a downstream repo might reasonably want the opposite setting, it belongs in a config file. CLI flags take precedence over config files in most tools, so an overridable preference in default_flags silently prevents downstream customization.
Config delivery has two paths depending on whether the tool accepts a --config flag:
Tools with
config_flag: the bundled default is passed via that flag at invocation time.Tools without
config_flag(CWD-discovery only): the bundled default is written to the firstnative_config_filespath in CWD and cleaned up after invocation. A second run of the same tool in that directory waits for the first to finish, so it never reads a config the first run is about to remove.
Release checklist¶
The release process is automated by the release.yaml workflow. See § Release engineering for the complete list (git tag, GitHub release, binaries, PyPI, changelog) and design rationale for the workflow itself, including the workflow_run checkout pitfall, immutable-release semantics, concurrency strategies, and freeze/unfreeze commit structure.
PyPI Trusted Publisher registration¶
The upstream kdeldycke/repomatic package publishes to PyPI via OIDC Trusted Publishing. The publisher is registered against the upstream’s own release.yaml workflow file: the publish-pypi job inside that file runs only on the push trigger (self-release), so its OIDC job_workflow_ref claim resolves to kdeldycke/repomatic/.github/workflows/release.yaml. Downstream repos invoking the workflow via workflow_call skip that job and run their own caller-side publish-pypi job instead, which uses the publish-pypi composite action.