How do I generate release notes?

Table of Contents

This recipe is what the Sprint closure phase calls into. The companion sprint-opening flow is How do I open a new sprint?.

Question

I'm closing a sprint. How do I assemble release notes from the merged PRs and the sprint's stories, then cut a draft GitHub release?

Answer

  1. Prepare a fresh branch. Run on a branch (e.g. feature/release-N) rather than main:

    git fetch origin main
    git checkout -b feature/release-<N> origin/main
    
  2. Collect merged-PR data since the last release tag. The script uses gh to enumerate PRs and pulls out reviewer-bot overviews for each:

    python3 build/scripts/collect_release_pr_data.py
    

    Output: tmp/release_pr_data/pr_<N>.json per PR, plus a summary.json index. The script auto-detects the previous v* tag via git tag --sort-v:refname=; override with --since-tag v0.0.<N> if needed. gh must be authenticated.

  3. Read the closing sprint. The sprint's sprint.org holds the mission, * Stories table, and the per-story states (DONE / STARTED / BLOCKED / ABANDONED). PRs alone are not authoritative — the sprint backlog tells you what should have shipped; PRs tell you what did ship; the release notes reconcile both.
  4. Scaffold the notes via compass. The release_notes document type produces the org skeleton — summary blurb placeholder, the four emoji sections, and the sprint-charts section pre-wired:

    ./compass.sh add release_notes \
      --parent-dir doc/agile/versions/v0/sprint_<N> \
      --slug release_notes \
      --title "ORE Studio Sprint <N> – Release Notes" \
      --description "Sprint <N> release notes (<Month> <Year>)." \
      --tags "release_notes:sprint_<N>:v0"
    

    If the scaffold lands in a release_notes/ subdirectory, move the file up to the sprint root and remove the directory — the chart file: image links only resolve from there.

  5. Populate the notes in the ORE Studio template (one page, four sections plus the pre-wired charts):

    • Highlights — 3–5 major outcomes, outcome-oriented.
    • Key Improvements — thematic sub-sections (architecture, UI, testing, infrastructure, …); group related PRs.
    • Known Issues & Postponed — anything BLOCKED or ABANDONED, with a short reason.
    • Time Summary — total effort and the dominant component mix. If the sprint did not track time, say so explicitly rather than inventing numbers.

    Under each sprint chart, add a short commentary paragraph reading this sprint's data — peaks, outliers, and what they correspond to — not just the generic legend text. Keep under one page; do not invent details not present in the input. Write honestly: if the sprint missed its mission, the summary paragraph says so (sprints 18 and 19 are the model). Link the notes from the sprint's Status table Release Notes row and * Release Notes section by id-link. Stage and commit.

  6. Open the PR via PR Manager. Merge once green.
  7. Tag main and open a draft GitHub release. The release stays in draft so a human can add screenshots/binaries and publish:

    git checkout main && git pull --ff-only origin main
    git tag -s v0.0.<N> -m "Sprint <N>"
    git push origin v0.0.<N>
    
    gh release create v0.0.<N> \
      --draft \
      --title "Sprint <N>" \
      --notes "See doc/agile/versions/v0/sprint_<N>/release_notes.org"
    

    The canonical notes live in the sprint's release_notes.org; export or summarise for the GitHub release body as needed.

Template skeleton

# **ORE Studio Sprint N – Release Notes**
*Month Year*

One-paragraph summary of the sprint's focus and outcomes.
---

## ✅ **Highlights**

- ...

## 🛠️ **Key Improvements**

### **Theme A**
- ...

### **Theme B**
- ...

## ⚠️ **Known Issues & Postponed**

- ...

## 📊 **Time Summary**

**Total effort**: Xh Ym
**Code**: A% | **Infra**: B% | **Agile/Analysis/Doc**: C%

---

*Next sprint: one sentence summarising the upcoming mission.*

Script

build/scripts/collect_release_pr_data.py for PR data; bare git and gh for the tag and draft release.

Tested by

Manual. The script is exercised every sprint closure.

See also

Emacs 29.1 (Org mode 9.6.6)