diff --git a/.claude/skills/release/SKILL.md b/.claude/skills/release/SKILL.md index 9022604..8d1f2c2 100644 --- a/.claude/skills/release/SKILL.md +++ b/.claude/skills/release/SKILL.md @@ -27,16 +27,16 @@ click **Publish**. 1. Bump the version → pyproject.toml [project] version = "X.Y.Z" (single source; everos.__version__ reads installed package metadata) 2. Update CHANGELOG.md → move the Unreleased entries under a new - ## [X.Y.Z] - heading + ## [X.Y.Z] - heading, and write the release page's prose here + (lead paragraph + `### Upgrade` group — see "The release page") 3. Commit → git commit -m "chore(release): vX.Y.Z" 4. Open a PR, merge to main after green CI 5. Tag main + push → git tag -a vX.Y.Z -m "vX.Y.Z" && git push origin vX.Y.Z 6. Approve → the release.yml run pauses on the `release` environment; a reviewer approves in the Actions run 7. Verify → https://pypi.org/project/everos/X.Y.Z/ -8. Publish the page → the run leaves a DRAFT GitHub Release titled - "EverOS X.Y.Z", body prefilled from the CHANGELOG section. Write the lead - summary at the top, then click Publish. +8. Publish the page → the run leaves a DRAFT GitHub Release, already + complete if step 2 was done properly. Read it once, click Publish. ``` The tag must equal the `pyproject.toml` version — the workflow refuses to @@ -45,25 +45,37 @@ section fails the release job for the same reason. ## The release page -Every page has the same shape: +**The whole page is written in CHANGELOG.md, during the release PR.** Nothing +is meant to be composed at publish time — by then the changes are weeks old and +the text gets no review. Write the version section like this: -``` - prose — CI cannot write this -## Added / ## Changed / ## Fixed / ... from the CHANGELOG section, verbatim -## Upgrade pip line + compare link prefilled; migration notes by hand +```markdown +## [X.Y.Z] - 2026-09-01 + +**What this release is for.** One paragraph, prose, no bullets — it becomes the +lead of the release page. Say what changed for a user, not what was refactored. + +### Added +### Changed +### Fixed + +### Upgrade + +What a reader must know before upgrading: what happens on first startup, which +command recovers a bad state, which pins moved. Omit the group entirely when a +plain `pip install --upgrade` is all there is — 1.1.4 and 1.2.0 have nothing +here. Do not write filler. ``` -Two parts are yours to write in the draft: +CI turns that into the page: everything above `### Upgrade` is lifted verbatim +with the group headings demoted to `##`, and the Upgrade prose is wrapped in the +boilerplate — pip line above it, compare link below — which is the shape every +release since 1.1.3 has. See +[1.2.1](https://github.com/EverMind-AI/EverOS/releases/tag/v1.2.1). -- **The lead summary** — the two or three sentences above the first heading - saying what this release is for. -- **Migration notes in `## Upgrade`**, when the release has any: what happens on - the first startup after upgrading, which command recovers a bad state, which - pins moved. Skip when a plain `pip install --upgrade` is genuinely all there - is; do not invent filler. - -See [1.2.1](https://github.com/EverMind-AI/EverOS/releases/tag/v1.2.1) for the -shape of both. +So publishing is a read-through and a click. If the draft looks wrong, the fix +belongs in CHANGELOG.md on `main`, not only in the draft — otherwise the two +drift apart and the next release inherits the habit. > While it is a draft, GitHub serves the release at > `releases/tag/untagged-`, and that URL keeps serving a stale page after diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index f912f36..01fa5a8 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -109,8 +109,17 @@ jobs: body = re.sub(r"^### ", "## ", match.group(1).strip(), flags=re.M) + "\n" # Every EverOS release page since 1.1.3 closes with an Upgrade - # section. Only its boilerplate is prefilled here — a release that - # needs migration notes gets them written into the draft by hand. + # section: the pip line, then whatever this release needs a reader to + # know before upgrading, then the compare link. The prose comes from + # an `### Upgrade` group in the CHANGELOG section — written in the + # release PR, where it gets reviewed — and is lifted out here so the + # boilerplate can be wrapped around it instead of colliding with it. + upgrade = "" + found = re.search(r"^## Upgrade\n(.*?)(?=^## |\Z)", body, re.S | re.M) + if found is not None: + upgrade = found.group(1).strip() + body = (body[: found.start()] + body[found.end() :]).rstrip() + "\n" + tags = subprocess.run( ["git", "tag", "--list", "v*", "--sort=-v:refname"], capture_output=True, text=True, check=True, @@ -123,6 +132,8 @@ jobs: ) body += "\n## Upgrade\n\n```bash\npip install --upgrade everos # or: uv sync\n```\n" + if upgrade: + body += f"\n{upgrade}\n" if previous is not None: compare = f"https://github.com/{os.environ['REPO']}/compare/{previous}...{tag}" body += f"\n**Full changelog:** [{previous}...{tag}]({compare})\n"