Update the HAL+JSON release information graph when new .NET releases ship. Regenerates index files across the version hierarchy (root → major → patch), timeline hierarchy (timeline → year → month), llms.json, and downloads using graph generator tools. USE FOR: adding a new patch release to the graph, adding a new major version, updating timeline entries after a release, refreshing the graph after source data changes. DO NOT USE FOR: supported-os.json changes (use update-supported-os skill), querying the graph (use dotnet-releases skill on release-index branch), editing generated graph files by hand (update source data and regenerate).
Update the HAL+JSON release information graph when new .NET releases ship. Regenerates index files across the version hierarchy (root → major → patch), timeline hierarchy (timeline → year → month), llms.json, and downloads using graph generator tools. USE FOR: adding a new patch release to the graph, adding a new major version, updating timeline entries after a release, refreshing the graph after source data changes. DO NOT USE FOR: supported-os.json changes (use update-supported-os skill), querying the graph (use dotnet-releases skill on release-index branch), editing generated graph files by hand (update source data and regenerate).
Update Release Graph
Regenerate the HAL+JSON information graph in release-notes/. The graph is a set of interconnected JSON files using HAL_links and _embedded properties. It is generated from source data — never hand-edit the output files.
Architecture
Source data (inputs — edit these)
File
Location
Purpose
releases.json
{ver}/releases.json
Legacy release list with all patches, SDKs, component versions, download URLs, hashes
release.json
{ver}/{patch}/release.json
Individual patch release data (subset of releases.json entry)
_manifest.json
{ver}/_manifest.json
Lifecycle data and reference links (GA date, EOL date, what's-new, compatibility)
_llms.json
_llms.json (root, optional)
Partial overrides merged into generated llms.json
cve.json
timeline/{year}/{month}/cve.json
CVE disclosure records
Generated graph (outputs — do not hand-edit)
release-notes/
├── index.json ← root: all major versions
├── llms.json ← AI entry point: latest patches per supported version
├── {ver}/
│ ├── index.json ← major: all patches for this version
│ ├── manifest.json ← reference hub: compatibility, OS support, what's-new
│ ├── sdk/
│ │ ├── index.json ← SDK version index
│ │ └── sdk-{band}.json ← per-band SDK history
│ ├── downloads/
│ │ ├── index.json ← components + feature bands
│ │ ├── runtime.json ← per-RID runtime downloads
│ │ ├── sdk.json ← per-RID SDK downloads
│ │ ├── sdk-{band}.json ← per-RID band-specific SDK downloads
│ │ ├── aspnetcore.json ← per-RID ASP.NET Core downloads
│ │ └── windowsdesktop.json ← per-RID Windows Desktop downloads
│ └── {patch}/
│ └── index.json ← patch detail (immutable after creation)
└── timeline/
├── index.json ← timeline root: all years
├── {year}/
│ ├── index.json ← year: all months with releases
│ └── {month}/
│ └── index.json ← month: all patches released (immutable)
Graph generators
The release-notes tool includes four graph generation commands:
Command
Generates
From
generate version-index
Root index, major indexes, patch indexes, manifests, SDK indexes, downloads
A new .NET patch release ships (monthly servicing) — source data is updated, graph needs regenerating
A new .NET major version is added — _manifest.json and initial releases.json are created
CVE data changes — cve.json files are updated, graph needs refreshing
A .NET version reaches end-of-life — _manifest.json is updated, graph needs regenerating
Any source data file is modified and the graph should reflect the changes
Prerequisites
release-notes
The release-notes tool handles both graph generation and legacy file operations. The public dotnet-release tool is for navigating release data and CVEs. Packages are published to GitHub Packages.
dotnet tool install -g release-notes \
--add-source https://nuget.pkg.github.com/richlander/index.json
# Verify — should show graph generation commands
release-notes --help
Note: GitHub Packages requires authentication even for public repositories. If you get a 401 error, configure credentials for the source:
What changed — new patch release, new major version, EOL update, CVE refresh, etc.
Which source files were updated — releases.json, release.json, _manifest.json, etc.
Optionally, a custom --url-root for link generation (defaults to the release-index branch URL)
Process — Regenerate after a new patch release
This is the most common operation. Source data (releases.json, release.json) has been updated with a new patch release.
1. Verify source data is ready
Confirm these files exist and are updated:
# The major version's releases.json must include the new patchcat release-notes/{ver}/releases.json | python3 -c "
import sys, json
data = json.load(sys.stdin)
print(f\"Latest: {data['releases'][0]['release-version']} ({data['releases'][0]['release-date']})\")"# The patch directory should exist with release.jsonls release-notes/{ver}/{patch}/
# Expected: release.json, {patch}.md
The _manifest.json should also be present for the major version:
# Verify release links and hashes (can take minutes — do not cancel)
release-notes verify releases release-notes
# Or for a specific version
release-notes verify releases {ver} release-notes
# Skip hash verification for faster iteration
release-notes verify releases release-notes --skip-hash
# Lint generated markdown
npx markdownlint --config .github/linters/.markdown-lint.yml release-notes/releases.md
Exit codes for verify:
0 — no issues
2 — issues found (report written to stdout as markdown)
5. Spot-check the graph
Verify key relationships are correct:
# Root index lists all versions
python3 -c "
import json
data = json.load(open('release-notes/index.json'))
for r in data['_embedded']['releases']:
print(f\"{r['version']}: supported={r.get('supported', 'N/A')}\")"# Major index has the new patch as latest
python3 -c "
import json
data = json.load(open('release-notes/{ver}/index.json'))
print(f\"Latest patch: {data['latest_patch']}\")
print(f\"First embedded: {data['_embedded']['patches'][0]['version']}\")"# Month timeline includes the patch
python3 -c "
import json
data = json.load(open('release-notes/timeline/{year}/{month}/index.json'))
for ver, patch in data['_embedded']['patches'].items():
print(f\"{ver}: {patch['version']}\")"# llms.json is current
python3 -c "
import json
data = json.load(open('release-notes/llms.json'))
for ver, patch in data['_embedded']['patches'].items():
print(f\"{ver}: {patch['version']} ({patch['date']})\")"
The _links section contains reference links that are merged into the generated manifest. These are links that cannot be computed (what's-new pages, compatibility docs, release blog, etc.).
release.json (per-patch)
Contains the full release data for a single patch: component versions, download URLs, file hashes. This is a subset of the corresponding entry in releases.json.
The generators use release.json to:
Build patch detail indexes with embedded runtime/SDK data
Generate per-RID download files
Compute SDK feature band information
Preview releases
Preview/RC releases are stored in a different directory structure:
{ver}/preview/preview1/ for preview.1
{ver}/preview/rc1/ for RC1
The generators automatically detect this from the version string (contains -preview. or -rc.).
After GA, the generators filter previews from _embedded.patches in the major index. RC releases are kept because they have go-live support.