Derive the SemVer release tag from pyproject.toml automatically
Background
pyproject.toml's version field must stay in canonical PEP 440 form
(0.2.0rc15, no hyphen) because that's the literal string hatchling embeds
in the built sdist's filename — publish_muse_release.sh and
smoke_muse.sh both derive the tarball URL directly from it. A hyphenated
form (0.2.0-rc15) was tried during the rc15 release and broke the publish
script's tarball-filename lookup (hatchling normalizes it away regardless of
what's written in the file), so it was reverted back to 0.2.0rc15.
Separately, muse tag add enforces strict SemVer 2.0, which requires the
hyphen before a pre-release identifier (v0.2.0-rc15 is valid, v0.2.0rc15
is rejected with "Version tag must start with 'v' ... is not valid semver").
These two canonical forms are incompatible at the string level — there is no
single literal that satisfies both PEP 440's canonical form and SemVer 2.0's
required hyphen. pyproject.toml stays the single source of truth in PEP 440
form (see decision above); the SemVer tag needs to be derived from it, not
hand-typed as a second, independently-maintained version string.
Goal
Whenever a release is tagged with muse tag add, the SemVer-hyphenated tag
string is computed from pyproject.toml's PEP 440 version automatically —
no one hand-types v0.2.0-rc15 and risks a typo or drift from the actual
shipped version.
Suggested approach
A small helper (Python, using the already-available packaging library)
that takes a PEP 440 version string and emits the SemVer-compatible tag:
from packaging.version import Version
def pep440_to_semver_tag(version_str: str) -> str:
v = Version(version_str)
pre = f"-{v.pre[0]}{v.pre[1]}" if v.pre else ""
return f"v{v.major}.{v.minor}.{v.micro}{pre}"
# pep440_to_semver_tag("0.2.0rc15") -> "v0.2.0-rc15"
Wire this into the standard release flow (documented in
musehub/.muse/agent.md's "Standard release flow" section) as a step after
publish_muse_release.sh succeeds:
TAG=$(python3 -c "from packaging.version import Version; v=Version('$MUSE_VERSION'); pre=f'-{v.pre[0]}{v.pre[1]}' if v.pre else ''; print(f'v{v.major}.{v.minor}.{v.micro}{pre}')")
muse tag add "$TAG" --message "release $MUSE_VERSION"
Deliverables
- [ ] Helper function (or inline one-liner, whichever fits the existing script style better) added to the release flow, not hand-typed.
- [ ]
musehub/.muse/agent.md's "Standard release flow" section updated with the new tagging step. - [ ] Manually QA'd once against a real release before considering this done
(tag the current
0.2.0rc15release once MWP verb QA — muse#63 — is fully signed off, per gabriel's explicit sequencing: manual QA first, then tag).
Out of scope
- Changing
pyproject.toml's format — settled as PEP 440, no hyphen, per the incident above. - Retroactively tagging any release prior to this ticket.