agentleFS
michaelnealemichaelneale/mesh-llm/.agents/skills/release-notes/SKILL.md

release-notes

Skill3.8k starsChanged 20 days agoApache-2.0View on GitHub

Use this skill when rewriting, reformatting, or reviewing the notes on a published MeshLLM GitHub release, including the automatic release-notes regrouping job, its deterministic classifier, and its optional agent review pass.

We split this skill into the rules it gives an agent

3 rules. 0 are common, 2 are distinctive, and 1 is very specific to this project.

  • 0

    Common

    Most of the 149 edited versions we read keep these.

  • 2

    Distinctive

    This author's own choices. Worth a look.

  • 1

    Very specific

    Tied to their project's names, files or tools. Probably skip.

  • Common
  • Distinctive
  • Very specific
  1. Very specific:

    Never drop an entry: Every merged PR credits a contributor, including the CI and build churn.

    line 39
  2. Distinctive:

    Always prove no pull request was dropped, duplicated, or invented.

    line 194
  3. Distinctive:

    Every entry the deterministic pass cannot classify is a commit that did not follow Conventional Commits.

    line 233

“Common” is measured: kept by at least 6 in 10 of the 149 edited versions of this file we could read. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
SKILL.md

Release Notes

Release-note automation uses the Rust commands under cargo xtool release. The older Python scripts remain as compatibility references while their test coverage is migrated. New automation follows the Rust ownership rule in ../manage-ci/SKILL.md.

The release workflow publishes with GitHub-generated release notes, so every MeshLLM release starts life as one flat ## What's Changed list. A normal minor release carries a few hundred entries in merge order, which buries the handful of changes a reader actually needs. The release_notes job in release.yml regroups that list into Keep a Changelog 1.1.0 sections right after publication.

This skill formats notes that already exist. It does not decide release readiness or build the change inventory from source; that is release-validation.

Ground Rules

  • Move entries; the only edit is the type prefix. The renderer strips a known conventional type from the front of a subject and sentence-cases what follows, because the type already chose the section and repeating it reads inconsistently beside entries that never had one. A subject with no recognised prefix is left exactly as written -- an unrecognised word: may be part of the sentence, as in "Durable KV prefix cache: agent prefixes survive eviction". Nothing else about a subject changes.
  • Never touch the credit. The by @<author> in <url> tail is copied through byte for byte, and the set of referenced pull requests is the invariant every gate checks.
  • Never drop an entry. Every merged PR credits a contributor, including the CI and build churn. Noisy entries collapse into ### Internal, never deleted.
  • Recover an entry GitHub could not credit. A batch of pull requests merged into a staging branch and rebased into the release is credited once, to the roll-up. The link pass adds the missing entries back in the roll-up's own format, so the reader sees the fixes rather than the vehicle that carried them. Adding is the only direction: the published set is a floor.
  • Keep the tail. ## New Contributors and the **Full Changelog** link stay exactly as GitHub generated them.
  • Never guess a section. An entry the commit metadata cannot place goes to ### Other changes. A wrong section is worse than an honest unsorted one, and misfiling a security fix as a routine fix is the worst case.
  • Editing a published release is a public change. Outside the release job, show the regrouped body and get explicit approval before gh release edit.

How The Pipeline Works

Three passes, in this order. The first two always run and together always produce a publishable body; the third is best-effort.

flowchart TD
    A["Release published"] --> B["Capture GitHub's flat list"]
    B --> L["Link commits to pull requests<br/>recover what GitHub credited to a roll-up"]
    L --> C["Classify by commit type<br/>feat → Added · fix → Fixed · ci → Internal"]
    C --> D{"Agent reachable?"}
    D -- no --> F["Deterministic notes"]
    D -- yes --> E["Agent reviews the plan"]
    E -- valid --> G["Reviewed notes"]
    E -- "invalid or timed out" --> F
    F --> P["Publish"]
    G --> P
    P --> V["Verify the same pull requests"]

One rule gates every step after the link pass: the set of referenced pull requests must not change. Sections move, subjects lose their type prefix, but no PR is dropped, duplicated, or invented, and author credit is copied through untouched. The link pass is the one step allowed to grow that set, and it is gated the other way: it may add entries and may never drop one. Nothing publishes unless both hold.

1. Link pass (authoritative, best-effort calls)

cargo xtool release notes-link pairs each commit in the range with the pull request that carried it. The (#N) suffix a squash merge leaves on the subject is authoritative and free; a commit without one costs a repos/{repo}/commits/{sha}/pulls lookup, and a commit the API cannot place is left unlinked rather than guessed at.

That pairing repairs two things GitHub's generated list cannot express:

  • a commit that reached the branch without the suffix now reaches its entry, so the classifier can read its type instead of dumping it in Other changes;
  • a pull request whose commit is in the release but whose entry GitHub never published is credited beneath the roll-up that carried it in. v0.76.1 shipped fifteen fixes behind a single Fixed entry before this existed.

Both are bounded: --api-budget caps the lookups, and every failed call falls back to the behaviour the pipeline had before the pass existed.

2. Deterministic pass (authoritative)

cargo xtool release notes-classify reads the canonical squash-merge commits between the comparison base and the tag, and maps each entry by its Conventional Commits type:

TypeSection
featAdded (Changed when ! or BREAKING CHANGE:)
fixFixed
perf, revertChanged
securitySecurity
ci, build, deps, chore, test, refactor, style, docsInternal
anything else, or no conventional subjectOther changes

Two rules override the type. A tooling scope — ci, release, build, deps, xtask, bench, just — is Internal whatever the type, because a fix(ci) repairs CI rather than the product. A Release-Notes: <Section> commit trailer wins outright, and is the escape hatch when the type cannot express the change.

cargo xtool release notes-regroup then renders the plan, refusing unless it covers the body exactly.

3. Agent review pass (optional, best-effort)

scripts/release-notes-generate.sh probes for a reachable agent and, only if one answers, asks it to review the deterministic plan — chiefly the Other changes entries and any security-relevant fix committed as a plain fix. Its output goes through the same validation and entry-set gate as the deterministic plan.

The agent is optional by construction. Missing CLI, absent credentials, failed probe, exhausted quota, blown time budget, unparseable plan, or a plan that fails validation each log a reason and keep the deterministic notes. None of them fail the job. AGENT_MODEL is unset by default, so the pipeline ships deterministic-only until a runner provides the CLI and credentials.

Running It By Hand

The job does this automatically for stable releases. Run it yourself to reformat an older release or to recover from a bad edit. Run every command from the repository root, and let the script own its work directory:

export RELEASE_TAG=v0.76.0            # the release to reformat
export RELEASE_NOTES_BASE=v0.75.1     # its stable comparison base
DRY_RUN=true scripts/release-notes-generate.sh

DRY_RUN=true renders and gates without touching the release. Publishing from a manual run additionally needs RELEASE_NOTES_APPROVED=true, so a hand run cannot edit a published release by accident; the release job sets that variable explicitly in its own definition. The work directory it prints keeps body.github.md, exactly as GitHub published it; restore with gh release edit "$RELEASE_TAG" --notes-file <workdir>/body.github.md.

To hand-classify instead, keep the scratch files outside the repository but keep running the scripts from the repository root:

WORK="$(mktemp -d)"
gh release view "$RELEASE_TAG" --json body -q .body > "$WORK/body.md"
cargo xtool release notes-regroup --body "$WORK/body.md" --list
# write "$WORK/plan.json", then:
cargo xtool release notes-regroup \
  --body "$WORK/body.md" --plan "$WORK/plan.json" --out "$WORK/new.md"

The plan assigns every PR number to a section:

{
  "version": "0.76.0",
  "date": "2026-09-10",
  "sections": [
    {
      "title": "Added",
      "groups": [{ "title": "Serving and inference", "prs": [1228, 1439] }]
    },
    { "title": "Removed", "prs": [1399] }
  ],
  "internal": {
    "summary": "CI, build, test, and repository work with no user-facing behavior change",
    "groups": [{ "title": "CI and release engineering", "prs": [1244] }]
  }
}

A section takes either a flat prs list or groups. Section titles are a closed set, and headings, version and date are validated before anything is rendered. Section order follows Keep a Changelog, then Other changes, then Internal. Omit empty sections.

Always prove no pull request was dropped, duplicated, or invented. Entry lines are not byte-identical after prefix stripping, so compare the PR set:

diff <(grep -o 'pull/[0-9]*' "$WORK/body.md" | sort) \
     <(grep -o 'pull/[0-9]*' "$WORK/new.md" | sort) \
  && echo "identical pull-request sets"

Judgement Calls

Conventional-commit prefixes are a strong hint, not the whole answer. When reviewing a plan by hand or as the agent pass:

  • A perf: PR is Changed. Keep a Changelog has no performance section, and a speedup changes existing behavior.
  • A fix: PR that closes an exposure is Security, not Fixed. Classify by what the change protects. This is the single most valuable correction to make, because the commit type cannot express it.
  • A feat: PR that replaces an existing subsystem is Changed, not Added.
  • A docs PR that documents a removal sits beside the removal; a docs PR that publishes a new reference is Added; everything else docs-shaped is Internal.
  • A revert and its later re-land both stay, in the section the change belongs to. The history is the point.
  • Reviewer follow-up PRs ("address review findings for #1478") sit with the change they fix up.

Layout

  • Sub-headings appear automatically in any section past 20 entries, one per scope with at least 4 entries, smaller scopes merged into Other. Below that a flat list reads better.
  • ### Internal goes last, wrapped in <details> with a <summary> stating the count. Keep a blank line after <summary> or GitHub will not render the Markdown inside it.

Improving Coverage

Every entry the deterministic pass cannot classify is a commit that did not follow Conventional Commits. scripts/hooks/commit-msg rejects those locally (just hooks-install), just check-commits validates a range, and the Check commit convention step in the Quality lane enforces the pull request title in CI, which is the part that binds contributors who never install the hook. Because the repository squash-merges, the PR title becomes the commit subject, so the PR title is what has to be conventional.

Coverage is a measurable property of a release:

cargo xtool release notes-classify --body body.md \
  --range v0.75.1..v0.76.0 --version 0.76.0 --date 2026-09-10 --out plan.json
# classified 182/272 entries deterministically (90 in 'Other changes')

v0.76.0 predates the hook and classifies 182 of 272. Releases made entirely under the hook should approach full coverage, leaving the agent pass with only genuine judgement calls.

Download now (ZIP)

Trending

Quiet since April.about the whole repository

Dec 2025: 0 mentionsJan 2026: 0 mentionsFeb 2026: 0 mentionsMar 2026: 4 mentionsApr 2026: 14 mentionsMay 2026: 0 mentionsJun 2026: 0 mentionsJul 2026: 0 mentionsAug 2026: 0 mentionsSep 2026: 0 mentionsOct 2026: 0 mentionsNov 2026: 0 mentions
Dec 2025Jun 2026Nov 2026
Mentions a month of the michaelneale/mesh-llm repository that our weekly crawl found. There is no adoption data for this file yet.

Who's talking about michaelneale/mesh-llm

The biggest 5 of 18 mentions linking to the repository that our crawl found. Each line is their own headline.

See all 18

Talked about on GitHub, Bluesky and Hacker News (18 times).

On GitHub · 15

10 more on GitHub

On Hacker News · 1

Does it work?

Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.

Reviews can't be read right now.

Your trail

Files you open will collect here, so you can find them again.

Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.

Now do this for your own.

Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.