rrt hooks
rrt hooks
Section titled “rrt hooks”Overview
Section titled “Overview”repo-release-tools publishes reusable hooks in .pre-commit-hooks.yaml. This page
covers pre-commit, lefthook, and husky wiring for those hooks. It is written for
maintainers setting up local policy in a repository. Start with the changelog workflow.
The hook set follows from that choice.
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.
Examples
Section titled “Examples”Two starting configurations cover most repositories. Pick the one that matches the workflow chosen above.
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.18.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.18.0 hooks: - id: rrt-branch-name - id: rrt-commit-subjectUse this when pull requests are squash-merged. It keeps ten tiny commit-level changelog bullets from becoming 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.
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.18.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.
Use it to confirm hook and CI surfaces are configured before a release:
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.18.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.18.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. Use it 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. It checks that version targets resolve, that pin targets reference known
files, and that the structure is well-formed. docs/rrt-config-reference.toml
is schema-generated. rrt-config-reference-check (manual stage) fails the hook
run when that file is stale relative to the current schema.
Regenerating and staging the reference 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.
It requires sentence case, caps entry length, and rejects 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 |
Caveats
Section titled “Caveats”- Under
changelog_workflow = "squash"the changelog hooks stay configured but do nothing. You can leave them during migration. The cleaner setup is to remove them and keep only the non-changelog policy hooks. rrt-update-unreleasedandrrt-changelogoverlap. Enable one, not both.- Commit-msg hooks only fire when
commit-msgis listed indefault_install_hook_types. A missing entry skips them silently. rrt-dirty-treefails an ordinarypre-commitrun, because the working tree is dirty at that point. Register it atpre-pushor the manual stage.- Lefthook and husky call
rrt-hooksdirectly. Installrepo-release-toolsfirst so the binary is onPATH. - Husky hook files must be executable. Run
chmod +x .husky/<hook>after creating each one.
Related docs
Section titled “Related docs”- Hook & Action reference for ready-to-paste agent prompts
- GitHub Action for the CI counterpart of these hooks
rrt doctorto verify hook and CI wiringrrt branchfor the branch naming the hooks enforce
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.