rrt hooks
rrt hooks
Section titled “rrt hooks”repo-release-tools publishes reusable hooks in .pre-commit-hooks.yaml.
The first decision is not which hook do I add? — it is which changelog workflow does this repo follow?
Choose the workflow first
Section titled “Choose the workflow first”| Workflow | Recommended hooks | Best for |
|---|---|---|
incremental (default) |
rrt-branch-name, rrt-commit-subject, plus rrt-update-unreleased or rrt-changelog |
teams that maintain changelog state while developing |
squash |
rrt-branch-name, rrt-commit-subject, optional rrt-dirty-tree / rrt-doctor / rrt-release-check |
repos that squash many commits and do changelog work at release time |
With changelog_workflow = "squash", the changelog-writing and changelog-check
hooks intentionally skip changelog enforcement. You can leave them configured
during migration, but the cleaner setup is to remove them and keep only the
non-changelog policy hooks.
Incremental workflow: keep [Unreleased] current
Section titled “Incremental workflow: keep [Unreleased] current”default_install_hook_types: [pre-commit, commit-msg]
repos: - repo: https://github.com/Anselmoo/repo-release-tools rev: v1.14.0 hooks: - id: rrt-branch-name - id: rrt-update-unreleased - id: rrt-commit-subjectInstall both hook types:
pre-commit install --hook-type pre-commit --hook-type commit-msgThis setup keeps CHANGELOG.md moving with development. rrt-update-unreleased
auto-writes changelog bullets for changelog-relevant commit types, while
rrt-commit-subject enforces Conventional Commits.
If you prefer manual changelog edits instead of auto-writing them, replace
rrt-update-unreleased with rrt-changelog.
Squash workflow: keep local policy, skip per-commit changelog noise
Section titled “Squash workflow: keep local policy, skip per-commit changelog noise”default_install_hook_types: [pre-commit, commit-msg]
repos: - repo: https://github.com/Anselmoo/repo-release-tools rev: v1.14.0 hooks: - id: rrt-branch-name - id: rrt-commit-subjectUse this when pull requests are squash-merged and you do not want ten tiny commit-level changelog bullets to become one giant release footnote monster. Pair it with:
changelog_workflow = "squash"in repo config- GitHub Action
changelog-strategy: "auto"or"release-only" rrt bumpto generate release-time changelog content
Hook overview
Section titled “Hook overview”| Hook | Stage | Description |
|---|---|---|
rrt-branch-name |
pre-commit | Validate branch naming convention |
rrt-update-unreleased |
commit-msg | Auto-write a bullet under [Unreleased] for changelog-relevant commits |
rrt-changelog |
pre-commit | Require a staged changelog update for changelog-relevant work |
rrt-commit-subject |
commit-msg | Validate Conventional Commit subjects |
rrt-dirty-tree |
pre-push / manual | Fail on uncommitted changes |
rrt-doctor |
manual | Run rrt doctor core automation checks on rrt config |
rrt-release-check |
manual | Run rrt release check for version targets, pin targets, and changelog files |
rrt-docs-lock |
manual | Regenerate the source-owned docs lockfile (.rrt/docs.lock.toml) |
rrt-docs-publish |
manual | Regenerate CLI reference documentation and topic pages |
rrt-docs-inject |
manual | Synchronize shared anchor blocks across documentation |
rrt-docstring-suggest |
manual | Apply scaffolded docstrings to missing or thin module docstrings |
rrt-folder-check |
pre-commit / pre-push | Validate repository folder structure against [tool.rrt.folders] config |
rrt-artifacts-generate |
pre-commit | Run generation commands and snapshot hashes to .rrt/artifacts.lock.toml |
rrt-artifacts-check |
manual | Verify artifact hashes match the committed lock (strict by default) |
rrt-artifacts-snapshot |
manual | Snapshot artifact hashes without running generation commands |
rrt-tree-check |
pre-push | Validate project tree structure against the committed .rrt/tree.lock.toml |
rrt-drift-check |
pre-push | Verify agent-facing surfaces match the committed .rrt/drift.lock.toml |
rrt-changelog-postcorrect |
manual | Consolidate fragmented changelog entries after a squash merge |
rrt-sync |
manual | List upstream releases newer than the current version |
rrt-config-validate |
pre-commit / pre-push | Validate [tool.rrt] config — version targets, pin targets, and structure |
rrt-config-reference-check |
manual | Fail when docs/rrt-config-reference.toml is stale vs the schema |
rrt-changelog-lint |
pre-commit | Enforce changelog entry style (sentence case, length, no duplicates) |
rrt-tag-check |
pre-push | Validate existing git tags follow the configured naming convention |
rrt-update-unreleased and rrt-changelog are alternatives for the
incremental workflow. You usually want one or the other, not both.
Optional guards
Section titled “Optional guards”Dirty tree check
Section titled “Dirty tree check”rrt-dirty-tree is not enabled in the minimal configs because a normal
pre-commit run happens while the working tree is intentionally dirty. It is
better suited for pre-push or manual execution when you want to enforce a
clean repository before publishing work:
repos: - repo: https://github.com/Anselmoo/repo-release-tools rev: v1.14.0 hooks: - id: rrt-dirty-tree stages: [pre-push]Doctor check
Section titled “Doctor check”rrt-doctor runs rrt doctor against the repository’s core automation wiring
so you can confirm hook and CI surfaces are configured before a release or
automation rollout:
pre-commit run rrt-doctor --hook-stage manual# or directly:rrt doctorRelease check
Section titled “Release check”rrt-release-check runs rrt release check against version targets, pin
targets, and changelog files in [tool.rrt]. It is also registered at the
manual stage so you can invoke it on demand before releases:
pre-commit run rrt-release-check --hook-stage manual# or directly:rrt release checkYou can also run the same dirty-tree logic directly:
rrt-hooks check-dirty-treeTree check
Section titled “Tree check”rrt-tree-check validates the project directory structure against the
committed .rrt/tree.lock.toml. Run it at pre-push to catch accidental
layout changes before they reach the remote:
repos: - repo: https://github.com/Anselmoo/repo-release-tools rev: v1.14.0 hooks: - id: rrt-tree-check stages: [pre-push]Generate or refresh the lock with rrt tree --lock.
Drift check
Section titled “Drift check”rrt-drift-check verifies that agent-facing surfaces (MCP tool definitions,
skills, and related metadata) match the committed .rrt/drift.lock.toml.
Pair it with pre-push to prevent publishing stale agent interfaces:
repos: - repo: https://github.com/Anselmoo/repo-release-tools rev: v1.14.0 hooks: - id: rrt-drift-check stages: [pre-push]Update the lock with rrt drift snapshot.
Upstream sync
Section titled “Upstream sync”rrt-sync lists upstream releases that are strictly newer than the current
project version. It is a read-only informational hook registered at the
manual stage — useful in release pipelines to decide whether a bump is
needed:
# List newer versions one per linepre-commit run rrt-sync --hook-stage manual# or directly:rrt syncrrt sync --jsonSee [tool.rrt.upstream] config and the rrt sync command for details.
Config reference & validation
Section titled “Config reference & validation”rrt-config-validate gates commits and pushes by validating the [tool.rrt]
config — checking that version targets resolve, pin targets reference known
files, and the overall structure is well-formed. docs/rrt-config-reference.toml
is schema-generated; rrt-config-reference-check (manual stage) fails the hook
run when the file is stale relative to the current schema. (Regenerating and
staging that file on each commit is repo self-tooling — wire a local
bash -c 'rrt config --reference --check || (rrt config --reference && git add …)'
hook in your own .pre-commit-config.yaml if you vendor the reference.)
Changelog lint
Section titled “Changelog lint”rrt-changelog-lint enforces changelog entry style on every pre-commit run —
requiring sentence case, capping entry length, and rejecting duplicate bullets
before they accumulate.
Tag check
Section titled “Tag check”rrt-tag-check runs at pre-push and validates that existing git tags in the
repository follow the naming convention configured under [tool.rrt].
Post-correction mode (squash-merge workflows)
Section titled “Post-correction mode (squash-merge workflows)”When a pull request is merged via squash merge, GitHub condenses all
per-commit changelog entries into the squash commit. The result can be
fragmented micro-commit noise in CHANGELOG.md — for example several
"CI: add Node 26" / "CI: remove Node 26" pairs that cancel each other out.
rrt-hooks changelog post-correct consolidates those entries by:
- Inspecting the diff that the squash commit introduced to
CHANGELOG.md. - Removing exact duplicate bullet entries (case-insensitive).
- Removing semantically-cancelling pairs — e.g.
"CI: add Node 26"followed by"CI: remove Node 26", or bare"add X"/"remove X". Scope prefixes (e.g.CI:,Deps:) must match for entries to be considered a pair. - Rewriting
CHANGELOG.mdin-place with the cleaned content, restricting removals to the exact diff hunk so older release sections are never touched. - Optionally creating a follow-up commit (
--commit).
Quick usage
Section titled “Quick usage”# auto mode — use HEAD as the squash commit (default when no SHA given)rrt-hooks changelog post-correct
# explicit squash commit SHArrt-hooks changelog post-correct --squash-commit abc1234
# write a follow-up commit automaticallyrrt-hooks changelog post-correct --commitAs a GitHub Actions step (post-merge on default branch)
Section titled “As a GitHub Actions step (post-merge on default branch)”- name: Consolidate changelog after squash merge if: github.event_name == 'push' && github.ref == 'refs/heads/main' run: uvx --from repo-release-tools rrt-hooks changelog post-correct --commitOptions
Section titled “Options”| Flag | Description |
|---|---|
--squash-commit SHA |
Explicit commit SHA to inspect (defaults to HEAD) |
--output PATH |
Changelog file to rewrite (default: CHANGELOG.md) |
--commit |
Create a follow-up commit with the corrected changelog |
Lefthook setup
Section titled “Lefthook setup”Lefthook can run the same local
policy with an installed rrt-hooks binary.
Install repo-release-tools so rrt-hooks is on PATH, then add the commands
that match your workflow.
Incremental workflow example
Section titled “Incremental workflow example”commit-msg: commands: rrt-update-unreleased: run: rrt-hooks update-unreleased --message-file {1} rrt-commit-subject: run: rrt-hooks commit-msg {1}
pre-commit: commands: rrt-branch-name: run: rrt-hooks pre-commit
pre-push: commands: rrt-changelog: run: rrt-hooks check-changelog --subject "$(git log -1 --format=%s)" --strategy unreleasedSquash workflow example
Section titled “Squash workflow example”commit-msg: commands: rrt-commit-subject: run: rrt-hooks commit-msg {1}
pre-commit: commands: rrt-branch-name: run: rrt-hooks pre-commitHusky setup
Section titled “Husky setup”Husky v9 runs shell scripts from .husky/
and works with any installed CLI, including rrt-hooks.
Install repo-release-tools so rrt-hooks is on PATH, then initialise Husky
once and add the script files that match your workflow:
pip install repo-release-tools # or: uv pip install repo-release-toolsnpx husky initHusky v9 hook file format:
npx husky initcreates.husky/pre-commitwith a shell shebang. Keep the header it generates and replace only the command body. Each hook file must be executable — runchmod +x .husky/<hook>after creating it.
Incremental workflow example
Section titled “Incremental workflow example”#!/usr/bin/env shrrt-hooks pre-commit#!/usr/bin/env shrrt-hooks update-unreleased --message-file "$1"rrt-hooks commit-msg "$1"#!/usr/bin/env sh# .husky/pre-push (optional — add when you want an unreleased guard)rrt-hooks check-changelog --subject "$(git log -1 --format=%s)" --strategy unreleasedAfter creating each file, make it executable:
chmod +x .husky/pre-commit .husky/commit-msg # add .husky/pre-push if usedSquash workflow example
Section titled “Squash workflow example”#!/usr/bin/env shrrt-hooks pre-commit#!/usr/bin/env shrrt-hooks commit-msg "$1"Comparison: pre-commit · lefthook · husky
Section titled “Comparison: pre-commit · lefthook · husky”| Policy | pre-commit | lefthook | husky |
|---|---|---|---|
| Auto-write changelog | rrt-update-unreleased (commit-msg) |
rrt-update-unreleased --message-file {1} |
rrt-hooks update-unreleased --message-file "$1" |
| Validate commit subject | rrt-commit-subject (commit-msg) |
rrt-commit-subject {1} |
rrt-hooks commit-msg "$1" |
| Validate branch name | rrt-branch-name (pre-commit) |
rrt-hooks pre-commit |
rrt-hooks pre-commit |
| Pre-push unreleased guard | rrt-changelog or rrt-dirty-tree |
rrt-hooks check-changelog --subject "$(git log -1 --format=%s)" --strategy unreleased |
rrt-hooks check-changelog --subject "$(git log -1 --format=%s)" --strategy unreleased |
Badge families are intentionally complete for the current icon registry across platform, registry, and language labels; see src/repo_release_tools/tools/platform.py if you think one is missing.
Chat is powered by Context7, a third-party service with its own terms and privacy policy.