Portable instructions for AI agents working in this repository. Tool-specific files (CLAUDE.md, .cursor/rules/) are thin adapters only.
mb-pre-commit is a CMake module and optional Python setup script that installs a project-local Python venv, pins pre-commit, installs a Git hook (custom Bash script or native pre-commit install), and exposes a CMake sweep target (mb-pre-commit-sweep) to run hooks on all files.
Consumers integrate via FetchContent + mb_pre_commit_setup_project(), or run ./python/mb-pre-commit-setup.py without CMake. This repo dogfoods its own module in root CMakeLists.txt.
Stack: CMake (module requires 3.21+; presets target CMake 4.0+), Python 3 (venv + setup script), Bash (hook template), YAML (pre-commit config). No compiled application code—LANGUAGES NONE.
From the repository root (requires CMake ≥ 4.0 and Ninja for default presets):
cmake --preset default # or: ci | release | dev-verbose | unix-makefiles
cmake --build --preset defaultWorkflow presets (configure + build):
cmake --workflow --preset dev # default Debug
cmake --workflow --preset ship # release
cmake --workflow --preset ci # strict CI-like configure + buildCMake configure also creates/updates .venv, installs the Git hook when .git exists, and registers mb-pre-commit-sweep.
Without CMake:
./python/mb-pre-commit-setup.pyThere is no separate unit-test suite. Validation is integration-style:
# Match CI: configure, build, full pre-commit sweep
cmake --preset ci
cmake --build --preset ci
cmake --build --preset ci --target mb-pre-commit-sweep
# Symlink integrity (root config must match shipped example)
cmp -s configs/v4/.pre-commit-config.yaml .pre-commit-config.yaml
# Hook installed after configure
test -f .git/hooks/pre-commitPre-commit only (uses hook environments under ~/.cache/pre-commit when run via the action; locally use venv or pre-commit on PATH):
pre-commit run --all-filesHooks are defined in configs/v4/.pre-commit-config.yaml (root .pre-commit-config.yaml is a symlink to that file). Run via sweep or pre-commit:
| Tool | Scope |
|---|---|
| pre-commit-hooks | YAML/JSON, EOF, whitespace, symlinks, etc. |
| markdownlint-cli | *.md (config: .markdownlint.yaml) |
| codespell | text |
| ruff + ruff-format | python/ |
| pyupgrade | Python ( --py310-plus ) |
| gersemi | *.cmake |
| clang-format | C/C++ (when present) |
Preferred local path after CMake configure:
cmake --build --preset default --target mb-pre-commit-sweepEdit hook versions in configs/v4/ only, not by breaking the root symlink.
| Path | Role |
|---|---|
cmake/mb-pre-commit.cmake |
mb_pre_commit_setup(), subdirectory/project helpers |
cmake/pre-commit.in |
Bash hook template (configured into build dir, copied to .git/hooks) |
python/mb-pre-commit-setup.py |
CMake-free setup; mirrors CMake logic |
python/mb-pre-commit-clang-format.py |
Repo-local clang-format launcher (venv also gets mb-pre-commit-clang-format) |
configs/v4/ |
Canonical shipped .pre-commit-config.yaml and .markdownlint.yaml |
CMakePresets.json |
Presets: default, ci, release, dev-verbose, unix-makefiles, xcode, vs2022 |
CMakeLists.txt |
Top-level dogfood; calls mb_pre_commit_setup_project(PRE_COMMIT_INSTALL_EXAMPLE_CONFIG OFF) |
scripts/git-tag |
Maintainer release tagging (stdlib Python); not wired through CMake |
.github/workflows/ |
ci.yml, pre-commit.yml, actionlint.yml |
build/ |
Generated; gitignored |
Cache variable: MB_PRE_COMMIT_SETUP_LAYOUT (AUTO | TOP_LEVEL | SUBDIRECTORY) forces layout in tests/CI.
- CMake:
include_guard(GLOBAL);cmake_parse_argumentsfor public APIs; status viamessage(STATUS ...). Format with gersemi (via pre-commit). Requires CMake 3.21 APIs (file(COPY_FILE),file(CHMOD)). - Python: stdlib-only in shipped scripts; type hints and
from __future__ import annotationsinmb-pre-commit-setup.py. Ruff + pyupgrade via pre-commit. - Hook script: Bash with
pipefail; staged-files only; retries after re-stage on failure (CUSTOM mode). - Docs: README is the user-facing contract; keep
configs/v4and README in sync when behavior changes. - Releases: Annotated tags via
./scripts/git-tag --bump patch|minor|majoror./scripts/git-tag vX.Y.Z(clean tree required).
Before claiming work is done:
- If CMake or hook behavior changed: run
cmake --preset ciandcmake --build --preset ci --target mb-pre-commit-sweep. - If
configs/v4or markdown rules changed: ensurecmpcheck passes and markdownlint still passes on README. - If
.github/workflowschanged: actionlint must pass (workflow runs on path filter).
Do not add a heavyweight test framework unless the user asks; extend CI smoke steps instead.
.github/workflows/**(CI/release automation)—unless the task is explicitly about CI.github/dependabot.ymlbuild/**,.venv/**,__pycache__/**,.ruff_cache/**.git/hooks/pre-commit(generated by configure)- Root
.pre-commit-config.yamlas a regular file (it is a symlink; editconfigs/v4/) CMakeUserPresets.json(local, gitignored)- Annotated release tags /
git push --tagswithout explicit request
- Do not commit secrets, tokens, or local env files.
- Do not add repo-level MCP servers with broad filesystem, shell, browser, or credential access unless the user explicitly requests and accepts the risk.
- Hook and setup scripts invoke
git,pip, andpre-commitwith network access when installing hook environments—normal for this project; do not broaden that surface without reason. scripts/git-tagpushes tooriginby default; use--no-pushwhen a local-only tag is intended.
- Changes match the actual layout above (especially
configs/v4vs root symlink). - If CMake API or defaults changed, README tables/sections updated.
- Ran or described verification: at minimum sweep or relevant
cmp/actionlint when touching those areas. - No edits under forbidden paths unless the user requested them.
- No large generic boilerplate added to agent config files.