About assemble-changelog
A release-time skill for assembling Rerun's upcoming changelog entries into a versioned changeset and updating release notes. It is intended for maintainers working in the root of a standalone `rerun-io/rerun` checkout and enforces repository checks before release commands.
Key features
- 01Validates the standalone repository and origin
- 02Combines upcoming entries by changelog type
- 03Checks unresolved release placeholders
- 04Generates and polishes `CHANGELOG.md`
- 05Removes entries merged into the release
Use cases
- 01Preparing a Rerun minor or patch release
- 02Checking changelog entries before release
- 03Generating release notes from an assembled changeset
Install
Copy the command and run it in a terminal.
npx skills add https:/ / github.com/ rerun-io/ rerun --skill assemble-changelogAfter installing, type/assemble-changelogin Claude Code to confirm it loaded.
Details
From the project READMEAssemble-changelog
Release-time changelog assembly for the Rerun repo.
Always work in the root of a standalone rerun-io/rerun checkout — normally the prepare-release-0.x.y branch, where the result is committed.
This is step 4 of RELEASES.md; read it for the surrounding context.
Before doing any release work, verify that the current directory is the repository root and that its origin is rerun-io/rerun:
test "$(git rev-parse --show-toplevel)" = "$PWD"
git remote get-url origin
Do not run the workflow in the reality monorepo, including from its rerun/ directory.
The release scripts need the standalone repository's 0.x.y tags and resolve (#N) commit references against rerun-io/rerun.
Running them against reality can silently resolve reality PR numbers to unrelated Rerun PRs.
If either precondition is not met, stop before running any release command.
Tell the user that the skill requires the root of a standalone rerun-io/rerun checkout, and ask them to restart it there.
Do not clone a repository, fetch tags, or switch branches for the user.
Resolve the target version from $ARGUMENTS (e.g. 0.34.0). If absent, read it
from Cargo.toml (version = "0.x.y-…") and confirm with the user.
Workflow
1. Assemble upcoming/ → the release changeset
The curated entries live one-file-per-PR in docs/content/changelog/upcoming/*.md
(skip _template.md). Each declares type: highlight|misc|breaking|feature in its
frontmatter. Merge them into docs/content/changelog/changeset-0-XX.md, creating that file from
docs/content/changelog/_template.md if it does not exist yet (set title to the version — keep it
quoted, e.g. title: "0.36", so YAML keeps it a string — and order one lower than the previous release):
highlight→ one###subsection each under## Highlights.feature→ one###subsection each under## New features.misc→ exactly one-list item each under## Other. Fold its###heading and body into the item, preserving links. Do not use headings or prose outside the list items.breaking→ one###subsection each under## Breaking changes. If none, writeNone..
Keep the sections in that order and omit Highlights and Other if they have no entries.
The changelog is user-facing (it's part of the website), so it leads with what's new;
the verbose, developer-only breaking-change migration guides go last so most readers
don't have to scroll past them.
Tailor the output to the release type:
- Patch release (
0.x.Y, Y > 0) → typically only bug fixes. SkipHighlightsandNew features(there usually won't beupcoming/entries anyway); includeOtheronly if there are miscellaneous entries, and keepBreaking changesonly if there are any. - Minor release (
0.X.0) → the full template: highlights, new features, other items, breaking changes.
Preserve each entry's prose and structure (migration guides, tables, snippet: directives,
screenshots, links), except that each miscellaneous entry becomes its single list item.
De-duplicate overlapping entries and order breaking changes most-impactful first.
Drop the per-entry frontmatter.
Relative doc links in entries were written as if from changelog/ (e.g.
../reference/migration/...), which is correct once merged — keep them as-is.
Images and videos must live on static.rerun.io (upload with scripts/upload_image.py), never as
GitHub attachments: attachments uploaded in the private monorepo cannot be shown on the website.
Feature leads write their ## Highlights entries per PR, so read the section as a whole and
flag to the human anything that does not hang together, rather than rewriting it yourself.
Finally, point the redirect: frontmatter in docs/content/changelog.md at
changelog/changeset-0-XX: CI's scripts/ci/check_changelog_redirect.py requires the
newest changeset to be the redirect target, so the repoint must land together with the
new changeset.
2. Resolve release blockers
Ensure that every non-template file from upcoming/ was merged into the changeset, then search the assembled changeset for unresolved placeholders:
rg -n 'TODO\([^)]+\)' docs/content/changelog/changeset-0-XX.md # NOLINT
Resolve every match before continuing.
An unresolved TODO(name) blocks the release.
3. Generate the summary and detail sections into CHANGELOG.md
pixi run uvpy scripts/generate_changelog.py --version 0.x.y
Edit PR titles/labels to improve the output, then copy the result into CHANGELOG.md
(drop the trailing "Chronological changes" section; replace the placeholder video/blogpost
lines as previous releases did). Spot-check a few entries against the actual PRs:
polluted titles (old, unrelated PRs; thanks @… for core team members) mean a PR-number
lookup misfired — see the warning at the top.
Read the generated section for wrong contributor attribution and typos.
If the release ships without Rust crates (publish-crates=false), say in the CHANGELOG.md
section that this version is not on crates.io.
Do this after step 1: the script reads the assembled changeset and emits a summary of it
(section headings + links to the changeset on the website), rather than inlining its prose.
CHANGELOG.md therefore never duplicates the changeset — if the changeset is missing, the
script emits an unresolved placeholder instead.
4. Polish the CHANGELOG.md section
The generated section is a starting point; edit it by hand so readers can find their way to the details.
-
Order the overview by impact. Put the biggest new capabilities first, then integrations and APIs, then format support, then polish, then niche or developer-facing items.
-
Group and order the details. The script emits each details subsection (🐍 Python API, 🪳 Bug fixes, 🌁 Viewer improvements, …) in commit order. Within each subsection, put entries that touch the same feature next to each other (e.g. all MCP/ViewerControl entries, all state timeline entries, all hangs and deadlocks), order the groups by their most impactful entry, and order entries within a group by impact. Only reorder lines; don't move entries between subsections or drop them.
-
Make entries clickable. Wherever possible, link an entry (in the overview and in the details) to the docs that show how to use the feature: the how-to guide, the archetype/view reference page, the CLI or MCP reference section, the Python/JS ref site, or docs.rs. Reuse the links the changeset already contains, converted to
https://rerun.io/docs/<path without .md>, and check that each target file and#anchorheading exists. Link external names too (e.g. a third-party tool to its docs). In detail entries, link the key term, not the whole line, so the trailing commit/PR link stays distinct. -
Link each breaking change to its subheading in the changeset:
https://rerun.io/docs/changelog/changeset-0-XX#<anchor>. Anchors are the lowercased heading with backticks and punctuation dropped and spaces turned into hyphens (rrd::optimize→rrdoptimize). -
Name the actual break. A breaking-change heading (in the changeset and in
CHANGELOG.md) must say what broke, e.g. "WriteChunksremoved", not the new feature that replaces it ("Catalog staging"). Lead the subsection with the removal and migration-guide link, then the replacement. -
Flag experimental and unstable features. Check every new feature in the changeset and
CHANGELOG.mdagainst these markers (PREVis the previous minor release tag, e.g.0.38.0):# Non-blueprint types marked unstable whose definitions changed this cycle git diff --name-only $PREV HEAD -- crates/build/re_type_definitions | grep -v /blueprint/ | xargs rg -l 'state = "unstable"' # Python APIs in the `rerun.experimental` module git log --oneline $PREV..HEAD -- rerun_py/rerun_sdk/rerun/experimental # Viewer features behind a flag in `ExperimentalAppOptions` git diff $PREV HEAD -- crates/viewer_support/re_viewer_context/src/app_options.rs # Docs and docstrings that call something experimental git diff --name-only $PREV HEAD -- docs/content rerun_py/rerun_sdk | xargs rg -l -i 'is experimental'A file showing up in the first command does not mean the type is new: cross-reference the hits with the actual entries. For each matching feature, say so where readers will see it: prefix the changeset heading with "Experimental" (as
### Experimental 3D gaussian splat supportdid in 0.36), and add a sentence saying it may change in future releases (for unstable types: that the data may not stay backwards compatible). If the feature is behind a flag, say how to enable it. In theCHANGELOG.mdoverview, move all of these entries into a final#### 🧪 Experimental and unstablesubsection at the end of "Overview & highlights", with a one-line note that they may change and that unstable types may not stay backwards compatible. Order that subsection by impact too, and don't repeat "Experimental" in its entries. Blueprint types (rerun.blueprint.*, underre_type_definitions/rerun/blueprint/) are an exception: they are all marked unstable, which only means the blueprint data isn't backwards compatible. That alone does not make a feature experimental, so a new view or blueprint setting is only experimental if one of the other markers applies to it (or to the data archetype it shows). Likewise, a Viewer feature is not experimental just because it is configured through an experimental API. -
Add media to the headline features in the overview: a screenshot (or a still frame plus a link to the video) indented under the bullet, using the
<picture>markup thatpixi run upload-imageprints. Aim for a few images (roughly three to five), covering the most visual headline features: a picture sells a new view or renderer feature far better than a bullet does. Start from the media already in the changeset and the PR descriptions; if a visual feature has none, ask the user for a screenshot rather than skipping it. Don't add images to every entry: API, CLI, and bug-fix items rarely benefit. All media must live onstatic.rerun.io. Reuse a PR's media only if it is already onstatic.rerun.ioor publicly accessible:github.com/user-attachments/…links from the private monorepo return 404 for the public. Download those withcurl -L -H "Authorization: token $(gh auth token)" <url>and upload them withpixi run upload-image <file> --name <name>. GitHub does not render<video>from external hosts, so for a video, extract a representative still (ffmpeg -ss <t> -i video.mp4 -frames:v 1 still.png), upload it, and link the.mp4below it. Look at the frames and pick one without a cursor over the subject.
5. Empty the inbox
Delete the merged upcoming/*.md entries, keeping _template.md and any entries not included in this release.
Never add redirects for these temporary entries.
Checklist before declaring done
- Every non-template
upcoming/entry is represented in the changeset. - No
TODO(name)remains in the changeset. - No summaries or other prose were synthesized for existing entries.
- The
CHANGELOG.mdoverview is ordered by impact, a few of its most visual headline features havestatic.rerun.ioimages, and its breaking changes link to the changeset subheadings. - Every overview and detail entry that has relevant docs links to them.
- Each details subsection groups entries by feature, most impactful first.
- Every experimental or unstable feature (feature flag,
rerun.experimental,#[rerun(state = "unstable")]on a non-blueprint type, or documented as experimental) is labeled as such in the changeset, and listed under the overview's final "Experimental and unstable" subsection. -
pixi run lint-rerun CHANGELOG.md docs/content/changelog/changeset-0-XX.mdpasses. - Images and videos are hosted on
static.rerun.io, not as GitHub attachments. -
## Highlightsreads well as a whole, or the human has been told where it doesn't. - The
CHANGELOG.mdsection has correct contributor attribution and no typos. -
upcoming/contains only_template.mdand entries deferred to a later release. -
python scripts/ci/check_changelog_redirect.pypasses (redirect points at this changeset). -
python scripts/ci/check_doc_redirects.py --base origin/mainpasses (upcoming/entries are exempt and DO NOT need a redirect).
Notes
- This skill lives in
skills/assemble-changelogin the standalone Rerun repository. - Synced commits in
rerun-io/reruncarry aSource-Reftrailer (the reality merge commit);generate_changelog.pyresolves it back to the originating reality PR for correct titles, labels, and contributors. - The next release's changeset is not pre-created: an empty changeset for an
unreleased version would make
check_changelog_redirect.pyfail, since it requires the newestchangeset-0-xx.mdto be the redirect target. During a cycle,upcoming/is the only in-flight artifact.