Git NuGet Release Notes
This skill creates or updates cumulative .nuget/{ProjectName}/PackageReleaseNotes.txt files for packable .NET projects by reading git history and the actual project/package metadata. It is intentionally closer to the package-note style used in codebelt repositories than to a repo-wide CHANGELOG.md.
Read references/package-release-notes-format.md before writing any release-note block.
Critical
- Create or update
.nuget/{ProjectName}/PackageReleaseNotes.txt directly, then stop for user review.
- Discover packable projects under
src/; ignore test/, tuning/, tooling/, and projects that are explicitly non-packable.
- Prefer an existing
.nuget/{ProjectName}/ folder when one already exists for the packable project. If none exists, create .nuget/<MSBuildProjectName>/PackageReleaseNotes.txt.
- For repo-wide requests, every packable
src/ project should end up represented by a corresponding PackageReleaseNotes.txt file.
- Treat the package's base-to-
HEAD state as truth; chronological history is supporting provenance.
- Inspect cumulative package, API, manifest, version, and metadata deltas before classifying the package history.
- Classify each user-facing package capability from whether it existed at the resolved base before considering intermediate commits or individual files.
- Describe only surviving package outcomes. Do not preserve intermediate upgrades, removals, renames, or bug fixes that do not survive into
HEAD.
- Read full commit subjects and bodies before writing the package notes.
- Inspect the net diff too; do not classify a package from commit subjects alone.
- Use cumulative newest-first history.
- If the target version already exists at the top of the file, rewrite that block in place instead of duplicating it.
- If the target version is not present, prepend the new block above the older history.
- Normalize the block you write to
Version: and Availability:.
- Always include
# ALM in the block you write.
- Use only this section order when sections are populated:
ALM, Breaking Changes, New Features, Improvements, Bug Fixes, References.
- Omit empty sections instead of emitting placeholders.
- Start every bullet with an all-caps action verb such as
ADDED, CHANGED, REMOVED, FIXED, EXTENDED, OPTIMIZED, MOVED, RENAMED, DEPRECATED, or REFACTORED.
- Keep package/type/member identifiers exact where possible.
- Do not dump commit subjects verbatim into the release notes.
- Do not invent unsupported changes, package references, or availability.
- Ignore odd historical spacing such as non-breaking spaces in older entries; normalize only the block you are writing unless the user asks for a larger cleanup.
Deterministic Package Delta Model
When a scope is resolved, use this model for each target package:
Result = semantic_delta(PackageBase, PackageHEAD)
History = provenance used to explain Result
History is evidence; the resulting state is truth.
Reduce first. Interpret second. Summarize last.
Establish the classification baseline at the user-facing package-capability boundary, not independently for every changed file or commit. If a capability is absent at the base and present at HEAD, it belongs under # New Features with an ADDED bullet; intermediate commits that refine, fix, document, or validate that capability cannot move it to # Improvements or # Bug Fixes. Dependency, TFM, packaging, or separately pre-existing capability changes remain distinct outcomes classified from their own base states.
- Inspect cumulative manifest, property, version, and metadata deltas that affect the package.
- Inspect the cumulative base-to-
HEAD diff for the package and its shared packaging files.
- Determine which package changes actually survive at
HEAD.
- Read chronological commit subjects and bodies as supporting context.
- Use history to explain the surviving outcomes, then map them into the package-note sections.
Do not accumulate bullets from individual commits and deduplicate them afterward.
Reconciliation rules:
- Base state and
HEAD state are identical -> no entry.
- Dependency, API, metadata, or TFM value that returns to the base state -> no entry.
- Package capability absent at base and present at
HEAD -> one surviving ADDED outcome under # New Features. Do not emit CHANGED, EXTENDED, or FIXED outcomes for refinements within that same introduction cycle.
- Base present and
HEAD absent -> one surviving removal.
- Base present and changed
HEAD state -> one surviving modification, fix, rename, or move derived from the final delta.
- Equivalent entity/path/name moved or renamed -> one rename/move outcome when the cumulative diff supports it, not add plus remove.
Examples:
Newtonsoft.Json 13.0.3 -> 14.0.0 -> 13.0.3 -> no # ALM bullet.
Newtonsoft.Json 13.0.3 -> 14.0.0 -> 14.0.2 -> one surviving upgrade from 13.0.3 to 14.0.2.
- Public API removed and later restored unchanged -> no
# Breaking Changes bullet.
- Feature added, fixed several times, then removed -> no package-note entry for that feature.
- One capability added, reworked, fixed, documented, and still present -> one final
ADDED bullet under # New Features describing what shipped.
Workflow
Step 1: Resolve the source range
Use the most explicit range the user gave you.
- If the user named a range, branch comparison, base branch, or PR range, use that.
- Otherwise, compare the current branch to its upstream merge-base.
- If no upstream is configured, try
main, then master.
- If no safe comparison point can be established, stop and ask for a base branch or range instead of guessing.
Helpful commands:
git status --short --branch
git rev-parse --abbrev-ref HEAD
git rev-parse --abbrev-ref --symbolic-full-name @{upstream}
git merge-base HEAD @{upstream}
git merge-base HEAD main
git merge-base HEAD master
Step 2: Discover the target packages
Discover the packable src/ projects that belong in .nuget/.
- Enumerate
src/**/*.csproj.
- Exclude projects that live outside
src/ or are clearly test, benchmark, sample, or tooling projects.
- Exclude projects with
IsPackable explicitly set to false.
- Keep project identity anchored to the packable project name or the existing
.nuget/{ProjectName}/ folder already used by the repo.
- When the user asked for repo-wide release notes coverage, ensure every packable project is represented. Otherwise, focus on the projects affected by the requested range.
Helpful commands:
rg --files src -g *.csproj
git diff --name-only <base>..HEAD -- src .nuget Directory.Build.props Directory.Build.targets Directory.Packages.props
Step 3: Resolve the concrete release version
Each release-note block needs a real package version, not an [Unreleased] placeholder.
Use this order:
- Explicit version provided by the user.
- Branch prefix such as
v0.3.1/feature-name -> 0.3.1.
- Evaluated package version from the project if it is concrete and safe to use.
If you cannot determine a safe concrete version, stop and ask instead of guessing.
Do not infer a version by bumping the previous entry manually unless the user explicitly asked you to choose the next version.
Step 4: Resolve the availability line
Derive Availability: from the package's target frameworks.
- Read
TargetFramework or TargetFrameworks from the project and any inherited repo-level props when needed.
- Preserve the project order when rendering frameworks.
- Convert TFMs to the human-readable style used by the existing files.
- Join the final list with commas and
and.
Examples:
net10.0;net9.0 -> .NET 10 and .NET 9
net10.0;net9.0;netstandard2.0 -> .NET 10, .NET 9 and .NET Standard 2.0
net10.0;net9.0;netstandard2.1;netstandard2.0 -> .NET 10, .NET 9, .NET Standard 2.1 and .NET Standard 2.0
Do not guess availability from memory if the project file or evaluated MSBuild properties can answer it.
Step 5: Inspect the cumulative package delta first
For each target package, use this order to understand the real release story.
- Build the package-specific path set: the package project, its source folder, any package-specific
.nuget/{ProjectName}/ files, and shared packaging/build files that materially affect it.
- Inspect cumulative manifest, property, version, and metadata deltas first. This includes
Directory.Packages.props, package references in project files, TargetFramework / TargetFrameworks, package metadata, and other shared packaging files that affect the package.
- Inspect the cumulative base-to-
HEAD diff for the package paths.
- Determine which package changes survive at
HEAD: public APIs, dependency versions, TFMs, package metadata, types/members, renames/moves, removals, and bug fixes that still exist.
- Identify each user-facing package capability and test its existence at the resolved base before classifying its child files or commit verbs.
- Eliminate exact reversions, temporary features, reverted dependency churn, and restored APIs or metadata that match the base state.
- Read the full commit bodies only after the cumulative delta is clear. Use history to explain the surviving outcomes, confirm rename intent, understand migration context, and choose accurate user-facing terminology. Never let an intermediate commit override contradictory final-state evidence.
Helpful commands:
git diff --name-status -M -C <base>..HEAD -- <paths>
git diff --stat <base>..HEAD -- <paths>
git diff <base>..HEAD -- <paths>
git log --reverse --format=medium <range> -- <paths>
git log --reverse --stat --format=medium <range> -- <paths>
Step 6: Classify the content into the package-note format
Use the normalized section order from references/package-release-notes-format.md.
Classification guidance:
# ALM: only surviving dependency upgrades/downgrades, TFM support changes, packaging metadata changes, or other release-engineering/package-management changes. Use the final before -> after versions that remain at HEAD.
# Breaking Changes: only incompatible renames, removals, moved APIs, changed contracts, or behavior that still requires consumer action at HEAD.
# New Features: only additive APIs, capabilities, packages, or options that are absent at the base state and present at HEAD.
# Improvements: surviving non-breaking enhancements such as CHANGED, EXTENDED, OPTIMIZED, DEPRECATED, or other refinements to existing behavior.
# Bug Fixes: surviving defect corrections for behavior that remains changed versus the base state.
# References: package IDs only, and only when the package is an umbrella/meta package or the existing file already carries a references section the current release should preserve.
Prefer a minimal truthful block over an inflated one. ALM-only releases are valid when the real change was only dependency or TFM maintenance.
A restored API or reverted dependency upgrade does not earn a section entry. Use history to help group or explain the surviving outcomes, not to manufacture extra bullets.
Refinement or bug-fix commits made after a capability was first added but before its first release remain part of the ADDED new-feature outcome. # Improvements and # Bug Fixes require the affected capability or behavior to exist at the resolved base.
Step 7: Write or update PackageReleaseNotes.txt
Write the block in this normalized shape:
Version: 0.3.1
Availability: .NET 10 and .NET 9
# ALM
- CHANGED Dependencies have been upgraded to the latest compatible versions for all supported target frameworks (TFMs)
# New Features
- ADDED ...
Editing rules:
- If the file is missing, create it with the new block only.
- If the top block already targets the resolved version, replace that top block in place and leave older history below it intact.
- If the top block targets an older version, prepend the new block and a blank line before the existing history.
- Preserve older release blocks below the edited one unless the user explicitly asked for a historical cleanup.
- Keep bullets concise, concrete, and single-line unless a longer line is genuinely needed for clarity.
- Do not add decorative Markdown, tables, or changelog callouts.
Step 8: Stop after the edit
After updating the relevant PackageReleaseNotes.txt files, stop and let the user review them. Do not commit, tag, push, pack, or publish unless the user asks.
Good Output Characteristics
- Reads like curated package release notes, not a repo-wide changelog.
- Keeps one truthful release block per package/version.
- Classifies each package from its surviving base-to-
HEAD delta; reverted churn disappears.
- Uses concrete package/type/member names and namespaces.
- Writes the newest release first while preserving older history.
- Keeps ALM details explicit when dependencies or TFMs changed.
- Creates missing files when the package should be represented.
- Keeps availability aligned with actual target frameworks.
Bad Output Characteristics
- Writing one repo-level summary and copying it into every package file.
- Using
Unreleased or omitting the concrete version line.
- Guessing availability instead of reading project metadata.
- Dumping commit subjects line by line into the file.
- Reporting temporary dependency, API, metadata, or TFM changes that do not survive into
HEAD.
- Emitting
# Breaking Changes, # New Features, or # Bug Fixes bullets for work that was later restored or removed before release.
- Moving a base-absent capability into
# Improvements or # Bug Fixes because intermediate commits refined or fixed it before its first release.
- Creating empty headings or filler bullets like "misc updates".
- Claiming breaking changes, fixes, or references not supported by git and the project/package metadata.
1---2name: git-nuget-release-notes3description: Use when the user wants per-package NuGet release notes in cumulative `.nuget/{ProjectName}/PackageReleaseNotes.txt` files, including creating missing files for packable `src/` projects. Do not use for repository `CHANGELOG.md`, GitHub releases, or package README work.4---56# Git NuGet Release Notes78910This skill creates or updates cumulative `.nuget/{ProjectName}/PackageReleaseNotes.txt` files for packable .NET projects by reading git history and the actual project/package metadata. It is intentionally closer to the package-note style used in codebelt repositories than to a repo-wide `CHANGELOG.md`.1112Read `references/package-release-notes-format.md` before writing any release-note block.1314## Critical1516- Create or update `.nuget/{ProjectName}/PackageReleaseNotes.txt` directly, then stop for user review.17- Discover packable projects under `src/`; ignore `test/`, `tuning/`, `tooling/`, and projects that are explicitly non-packable.18- Prefer an existing `.nuget/{ProjectName}/` folder when one already exists for the packable project. If none exists, create `.nuget/<MSBuildProjectName>/PackageReleaseNotes.txt`.19- For repo-wide requests, every packable `src/` project should end up represented by a corresponding `PackageReleaseNotes.txt` file.20- Treat the package's base-to-`HEAD` state as truth; chronological history is supporting provenance.21- Inspect cumulative package, API, manifest, version, and metadata deltas before classifying the package history.22- Classify each user-facing package capability from whether it existed at the resolved base before considering intermediate commits or individual files.23- Describe only surviving package outcomes. Do not preserve intermediate upgrades, removals, renames, or bug fixes that do not survive into `HEAD`.24- Read full commit subjects and bodies before writing the package notes.25- Inspect the net diff too; do not classify a package from commit subjects alone.26- Use cumulative newest-first history.27- If the target version already exists at the top of the file, rewrite that block in place instead of duplicating it.28- If the target version is not present, prepend the new block above the older history.29- Normalize the block you write to `Version:` and `Availability:`.30- Always include `# ALM` in the block you write.31- Use only this section order when sections are populated: `ALM`, `Breaking Changes`, `New Features`, `Improvements`, `Bug Fixes`, `References`.32- Omit empty sections instead of emitting placeholders.33- Start every bullet with an all-caps action verb such as `ADDED`, `CHANGED`, `REMOVED`, `FIXED`, `EXTENDED`, `OPTIMIZED`, `MOVED`, `RENAMED`, `DEPRECATED`, or `REFACTORED`.34- Keep package/type/member identifiers exact where possible.35- Do not dump commit subjects verbatim into the release notes.36- Do not invent unsupported changes, package references, or availability.37- Ignore odd historical spacing such as non-breaking spaces in older entries; normalize only the block you are writing unless the user asks for a larger cleanup.3839## Deterministic Package Delta Model4041When a scope is resolved, use this model for each target package:4243```text44Result = semantic_delta(PackageBase, PackageHEAD)45History = provenance used to explain Result46```4748History is evidence; the resulting state is truth.4950Reduce first. Interpret second. Summarize last.5152Establish the classification baseline at the user-facing package-capability boundary, not independently for every changed file or commit. If a capability is absent at the base and present at `HEAD`, it belongs under `# New Features` with an `ADDED` bullet; intermediate commits that refine, fix, document, or validate that capability cannot move it to `# Improvements` or `# Bug Fixes`. Dependency, TFM, packaging, or separately pre-existing capability changes remain distinct outcomes classified from their own base states.53541. Inspect cumulative manifest, property, version, and metadata deltas that affect the package.552. Inspect the cumulative base-to-`HEAD` diff for the package and its shared packaging files.563. Determine which package changes actually survive at `HEAD`.574. Read chronological commit subjects and bodies as supporting context.585. Use history to explain the surviving outcomes, then map them into the package-note sections.5960Do not accumulate bullets from individual commits and deduplicate them afterward.6162Reconciliation rules:6364- Base state and `HEAD` state are identical -> no entry.65- Dependency, API, metadata, or TFM value that returns to the base state -> no entry.66- Package capability absent at base and present at `HEAD` -> one surviving `ADDED` outcome under `# New Features`. Do not emit `CHANGED`, `EXTENDED`, or `FIXED` outcomes for refinements within that same introduction cycle.67- Base present and `HEAD` absent -> one surviving removal.68- Base present and changed `HEAD` state -> one surviving modification, fix, rename, or move derived from the final delta.69- Equivalent entity/path/name moved or renamed -> one rename/move outcome when the cumulative diff supports it, not add plus remove.7071Examples:7273- `Newtonsoft.Json 13.0.3 -> 14.0.0 -> 13.0.3` -> no `# ALM` bullet.74- `Newtonsoft.Json 13.0.3 -> 14.0.0 -> 14.0.2` -> one surviving upgrade from `13.0.3` to `14.0.2`.75- Public API removed and later restored unchanged -> no `# Breaking Changes` bullet.76- Feature added, fixed several times, then removed -> no package-note entry for that feature.77- One capability added, reworked, fixed, documented, and still present -> one final `ADDED` bullet under `# New Features` describing what shipped.7879## Workflow8081### Step 1: Resolve the source range8283Use the most explicit range the user gave you.8485- If the user named a range, branch comparison, base branch, or PR range, use that.86- Otherwise, compare the current branch to its upstream merge-base.87- If no upstream is configured, try `main`, then `master`.88- If no safe comparison point can be established, stop and ask for a base branch or range instead of guessing.8990Helpful commands:9192```bash93git status --short --branch94git rev-parse --abbrev-ref HEAD95git rev-parse --abbrev-ref --symbolic-full-name @{upstream}96git merge-base HEAD @{upstream}97git merge-base HEAD main98git merge-base HEAD master99```100101### Step 2: Discover the target packages102103Discover the packable `src/` projects that belong in `.nuget/`.104105- Enumerate `src/**/*.csproj`.106- Exclude projects that live outside `src/` or are clearly test, benchmark, sample, or tooling projects.107- Exclude projects with `IsPackable` explicitly set to `false`.108- Keep project identity anchored to the packable project name or the existing `.nuget/{ProjectName}/` folder already used by the repo.109- When the user asked for repo-wide release notes coverage, ensure every packable project is represented. Otherwise, focus on the projects affected by the requested range.110111Helpful commands:112113```bash114rg --files src -g *.csproj115git diff --name-only <base>..HEAD -- src .nuget Directory.Build.props Directory.Build.targets Directory.Packages.props116```117118### Step 3: Resolve the concrete release version119120Each release-note block needs a real package version, not an `[Unreleased]` placeholder.121122Use this order:1231241. Explicit version provided by the user.1252. Branch prefix such as `v0.3.1/feature-name` -> `0.3.1`.1263. Evaluated package version from the project if it is concrete and safe to use.127128If you cannot determine a safe concrete version, stop and ask instead of guessing.129130Do not infer a version by bumping the previous entry manually unless the user explicitly asked you to choose the next version.131132### Step 4: Resolve the availability line133134Derive `Availability:` from the package's target frameworks.135136- Read `TargetFramework` or `TargetFrameworks` from the project and any inherited repo-level props when needed.137- Preserve the project order when rendering frameworks.138- Convert TFMs to the human-readable style used by the existing files.139- Join the final list with commas and `and`.140141Examples:142143- `net10.0;net9.0` -> `.NET 10 and .NET 9`144- `net10.0;net9.0;netstandard2.0` -> `.NET 10, .NET 9 and .NET Standard 2.0`145- `net10.0;net9.0;netstandard2.1;netstandard2.0` -> `.NET 10, .NET 9, .NET Standard 2.1 and .NET Standard 2.0`146147Do not guess availability from memory if the project file or evaluated MSBuild properties can answer it.148149### Step 5: Inspect the cumulative package delta first150151For each target package, use this order to understand the real release story.152153- Build the package-specific path set: the package project, its source folder, any package-specific `.nuget/{ProjectName}/` files, and shared packaging/build files that materially affect it.154- Inspect cumulative manifest, property, version, and metadata deltas first. This includes `Directory.Packages.props`, package references in project files, `TargetFramework` / `TargetFrameworks`, package metadata, and other shared packaging files that affect the package.155- Inspect the cumulative base-to-`HEAD` diff for the package paths.156- Determine which package changes survive at `HEAD`: public APIs, dependency versions, TFMs, package metadata, types/members, renames/moves, removals, and bug fixes that still exist.157- Identify each user-facing package capability and test its existence at the resolved base before classifying its child files or commit verbs.158- Eliminate exact reversions, temporary features, reverted dependency churn, and restored APIs or metadata that match the base state.159- Read the full commit bodies only after the cumulative delta is clear. Use history to explain the surviving outcomes, confirm rename intent, understand migration context, and choose accurate user-facing terminology. Never let an intermediate commit override contradictory final-state evidence.160161Helpful commands:162163```bash164git diff --name-status -M -C <base>..HEAD -- <paths>165git diff --stat <base>..HEAD -- <paths>166git diff <base>..HEAD -- <paths>167git log --reverse --format=medium <range> -- <paths>168git log --reverse --stat --format=medium <range> -- <paths>169```170171### Step 6: Classify the content into the package-note format172173Use the normalized section order from `references/package-release-notes-format.md`.174175Classification guidance:176177- `# ALM`: only surviving dependency upgrades/downgrades, TFM support changes, packaging metadata changes, or other release-engineering/package-management changes. Use the final before -> after versions that remain at `HEAD`.178- `# Breaking Changes`: only incompatible renames, removals, moved APIs, changed contracts, or behavior that still requires consumer action at `HEAD`.179- `# New Features`: only additive APIs, capabilities, packages, or options that are absent at the base state and present at `HEAD`.180- `# Improvements`: surviving non-breaking enhancements such as `CHANGED`, `EXTENDED`, `OPTIMIZED`, `DEPRECATED`, or other refinements to existing behavior.181- `# Bug Fixes`: surviving defect corrections for behavior that remains changed versus the base state.182- `# References`: package IDs only, and only when the package is an umbrella/meta package or the existing file already carries a references section the current release should preserve.183184Prefer a minimal truthful block over an inflated one. ALM-only releases are valid when the real change was only dependency or TFM maintenance.185A restored API or reverted dependency upgrade does not earn a section entry. Use history to help group or explain the surviving outcomes, not to manufacture extra bullets.186Refinement or bug-fix commits made after a capability was first added but before its first release remain part of the `ADDED` new-feature outcome. `# Improvements` and `# Bug Fixes` require the affected capability or behavior to exist at the resolved base.187188### Step 7: Write or update PackageReleaseNotes.txt189190Write the block in this normalized shape:191192```text193Version: 0.3.1194Availability: .NET 10 and .NET 9195196# ALM197- CHANGED Dependencies have been upgraded to the latest compatible versions for all supported target frameworks (TFMs)198199# New Features200- ADDED ...201```202203Editing rules:204205- If the file is missing, create it with the new block only.206- If the top block already targets the resolved version, replace that top block in place and leave older history below it intact.207- If the top block targets an older version, prepend the new block and a blank line before the existing history.208- Preserve older release blocks below the edited one unless the user explicitly asked for a historical cleanup.209- Keep bullets concise, concrete, and single-line unless a longer line is genuinely needed for clarity.210- Do not add decorative Markdown, tables, or changelog callouts.211212### Step 8: Stop after the edit213214After updating the relevant `PackageReleaseNotes.txt` files, stop and let the user review them. Do not commit, tag, push, pack, or publish unless the user asks.215216## Good Output Characteristics217218- Reads like curated package release notes, not a repo-wide changelog.219- Keeps one truthful release block per package/version.220- Classifies each package from its surviving base-to-`HEAD` delta; reverted churn disappears.221- Uses concrete package/type/member names and namespaces.222- Writes the newest release first while preserving older history.223- Keeps ALM details explicit when dependencies or TFMs changed.224- Creates missing files when the package should be represented.225- Keeps availability aligned with actual target frameworks.226227## Bad Output Characteristics228229- Writing one repo-level summary and copying it into every package file.230- Using `Unreleased` or omitting the concrete version line.231- Guessing availability instead of reading project metadata.232- Dumping commit subjects line by line into the file.233- Reporting temporary dependency, API, metadata, or TFM changes that do not survive into `HEAD`.234- Emitting `# Breaking Changes`, `# New Features`, or `# Bug Fixes` bullets for work that was later restored or removed before release.235- Moving a base-absent capability into `# Improvements` or `# Bug Fixes` because intermediate commits refined or fixed it before its first release.236- Creating empty headings or filler bullets like "misc updates".237- Claiming breaking changes, fixes, or references not supported by git and the project/package metadata.