This is the canonical release sequence — how to publish, once publishing has been decided. Whether a release is warranted at all, and which version number it gets, is Release Cadence.
Code completion never authorizes publication. Pushing a v*.*.* tag starts the
trusted-publishing workflow, so the tag is an explicit human gate.
This is a template. Copy it into the release’s own evidence document under
docs/release/ and check items off there — leave the boxes here unchecked so
the next release starts from a clean list.
Automated acceptance:
scripts/check_release_tags.py)Operational acceptance:
cairntir-mcp --host claudeRelease operations:
maincairntir version, cairntir --help, and cairntir recipe-listEvidence and known limits for each shipped release live under docs/release/.
The 1.12.3 record covers the current release preparation;
the 1.12.2 record retains the prior publication evidence.
The 1.12.1 record covers the current production installation. The withheld 1.12.0 record preserves its failed
verification and unchanged tag. Earlier published records include
1.11.0 and 1.10.0.
Run every command from the repository root:
$env:HF_HUB_OFFLINE = "1"
uv sync --all-extras
uv run ruff format --check .
uv run ruff check .
uv run mypy --strict src
uv run python scripts/check_no_silent_except.py
uv run pytest -q
uv run mkdocs build --strict
uv build
Also confirm:
pyproject.toml, uv.lock, src/cairntir/__init__.py, and
.claude-plugin/plugin.json contain the same version;CHANGELOG.md has a dated entry and an empty Unreleased section;.github/workflows/release.yml verifies before it builds and publishes only
from a version tag;.claude-plugin/plugin.json;git diff --check is clean and no rehearsal database, virtual environment,
secret, or local Cairntir home is staged.If any publish job fails after PyPI accepts the version, do not delete or reuse the version. Diagnose the partial release, preserve the evidence, and ship the smallest higher patch version if another artifact is required.