| name | target-new-framework |
| description | Perform the .NET major version bump (e.g., net11 to net12) in any dotnet repo. Use when asked to "update TFMs", "create workload manifest for new version", "update from netN to netN+1", or "create frozen manifest". Covers eng/Versions.props, Directory.Build.props, workload manifests, templates, test assets, and documentation. |
.NET Major Version Bump
Orchestrate the multi-phase process of bumping any dotnet repo from .NET N to .NET N+1. The core patterns (version properties, TFMs, workload manifests) are universal across dotnet repos; repo-specific content (templates, test assets, build configs) is discovered dynamically.
When to Use This Skill
- Performing a .NET major TFM version bump (e.g.,
net11 → net12, net12 → net13)
- Creating a frozen workload manifest for the outgoing current version
- Updating
TargetFramework references across a repository after a major version change
- Completing a partially-started TFM version bump PR
Execution Guidelines
- Track all discovered files in SQL. Use the SQL tool to store every file that needs updating. Insert during Phase 0 discovery, update status as each file is changed, and query for missed files in Phase 6. Do not rely on memory to track which files have been updated across phases.
- Maximize parallel tool calls. Run independent discovery searches and file edits in parallel.
SQL Schema
Create this table at the start of every run:
CREATE TABLE IF NOT EXISTS bump_files (
path TEXT PRIMARY KEY,
phase TEXT NOT NULL,
category TEXT,
old_value TEXT,
new_value TEXT,
status TEXT DEFAULT 'pending',
notes TEXT
);
Workflow:
- Phase 0 —
INSERT every discovered file with status='pending'
- Phases 1–5 — After editing a file:
UPDATE bump_files SET status='updated' WHERE path='...'
- Intentional skips —
UPDATE bump_files SET status='skipped', notes='intentional previous-version ref' WHERE path='...'
- Phase 6 —
SELECT * FROM bump_files WHERE status='pending' to find anything missed
- Progress check —
SELECT phase, status, COUNT(*) FROM bump_files GROUP BY phase, status at any time
Required User Inputs
Ask the user for:
- Source version (N): Auto-detect from
eng/Versions.props <MajorVersion> if not provided.
- Target version (N+1): Default: N+1.
Phase 0: Discovery
Before making changes, understand what this repo contains. Run these searches and note what exists:
grep -l "MajorVersion" eng/Versions.props
grep -l "NetCoreAppCurrentVersion" Directory.Build.props
find . -type d -name "*.Manifest" | head -20
find . -name "manifest-packages.*" -exec cat {} \;
find . -type f -name "template.json" -path "*/.template.config/*" | head -10
git grep -l "TargetFramework.*netN\.0" -- "**/*.csproj" | head -20
This determines which phases apply. A small repo may only need Phase 1 + 6. A complex repo like dotnet/runtime needs all phases.
Insert every discovered file into SQL immediately:
INSERT OR IGNORE INTO bump_files (path, phase, category) VALUES
('eng/Versions.props', 'core-props', 'version-props'),
('Directory.Build.props', 'core-props', 'tfm-props');
INSERT OR IGNORE INTO bump_files (path, phase, category) VALUES
('src/mono/nuget/Microsoft.NET.Workload.Mono.Toolchain.Current.Manifest/...', 'workloads', 'current-manifest');
INSERT OR IGNORE INTO bump_files (path, phase, category) VALUES
('src/mono/wasm/testassets/BlazorBasicTestApp/BlazorBasicTestApp.csproj', 'projects', 'test-asset');
Continue inserting files discovered in later phases — not all files are found in Phase 0.
Phase 1: Core Version Properties
Update the primary version numbers that the entire build system depends on.
Key files (if they exist):
eng/Versions.props — <MajorVersion>, <ProductVersion>, SDK band versions (e.g., 110100 → 120100), workload manifest version properties
Directory.Build.props — <NetCoreAppCurrentVersion>, <NetCoreAppPrevious>, <NetCoreAppMinimum>, <ApiCompatNetCoreAppBaseline*>
❌ Never modify eng/Version.Details.xml — it is auto-managed by Arcade/Maestro dependency flow.
❌ Not all version N references should change. Some intentionally refer to the previous version for compatibility or baseline testing.
⚠️ Don't set NetCoreAppPrevious too early. It may be intentionally cleared during early development.
📖 See references/version-bump-instructions.md sections 1-3 for property details.
Phase 2: Workload Infrastructure
Skip if no workload manifests found in Phase 0.
Create a frozen workload manifest for netN (the previous Current version) and update workload references.
❌ The frozen manifest is for netN, NOT netN+1. When bumping to .NET 12, you create the net11 frozen manifest.
Dynamic discovery steps:
- Find all
*.Current.Manifest directories — each manifest family needs a frozen version
- Find the most recent
netN-1.Manifest in each family — use as template
- Determine project file type by examining existing manifests (
.pkgproj, .proj, .csproj)
- Check manifest registration: if
manifest-packages.* uses explicit ProjectReference entries, add the new one; if it uses a wildcard glob, no registration needed
- Look for
localize/ in netN-1.Manifest — if present, copy and update version refs
For each manifest family:
- Create
{Family}.netN.Manifest/ directory
- Create project file — copy from
netN-1.Manifest, update package name and version properties
- Create
WorkloadManifest.json.in — copy from Current.Manifest, apply netN transformations
- Create
WorkloadManifest.targets.in — only the TFM-specific section, not the shared logic
- Copy
localize/ from netN-1.Manifest if present, update version refs
- Update Current.Manifest project file to add
RuntimeVersionNetN / version variable for the newly-frozen version
❌ Do NOT blindly copy the entire shared/general section into the frozen manifest's .targets.in. Start with the TFM-specific conditional logic (after the <!-- start of TFM specific logic --> comment in Current.Manifest), then scan the shared section for items that reference current-version properties — those may need TFM-conditioned equivalents in the frozen manifest.
⚠️ Always diff the new frozen manifest against netN-1.Manifest — structure should be similar, with version numbers changed. New content from Current.Manifest's shared section may legitimately expand the frozen manifest beyond what netN-1 had.
Gate: Frozen manifest has same file set as netN-1.Manifest.
📖 See references/workload-version-bump-instructions.md for transformation rules and examples.
📖 See references/workload-manifest-patterns.md for structural patterns across repos.
Phase 3: Project Files and Templates
Discover dynamically — search for files referencing the old version:
git grep -l "netN\.0" -- "**/*.csproj" "**/*.fsproj" "**/*.vbproj"
git grep -l "netN\.0" -- "**/.template.config/template.json"
git grep -l "ProductVersion.*N\.0" -- "**/package.json"
Update TFM references, template identities/choices/defaults, and PackageId values.
📖 See references/version-bump-instructions.md sections 6-8 for common patterns.
Phase 4: Testing Infrastructure
Discover dynamically — search for test-related version references:
git grep -rn "TargetMajorVersion.*=.*N" -- "**/*Test*.cs" "**/*BuildTestBase*"
git grep -l "RUNTIME_PACK_VER" -- "**/*.csproj" "**/*.targets"
git grep -l "workloads-.*\.targets" -- "eng/testing/"
Update constants, env vars, and workload testing configs found.
📖 See references/workload-version-bump-instructions.md "Testing Infrastructure Updates".
Phase 5: Documentation
git grep -rl "netN\.0\|\.NET N\b" -- "docs/" "**/*.md" | head -30
Update version references in all documentation files found.
Phase 6: Verification
💡 Keep the feedback loop tight. Run the fastest check first, fix, repeat.
6a. Check for missed files (~instant)
SELECT path, phase, category FROM bump_files WHERE status = 'pending';
SELECT phase, status, COUNT(*) as count FROM bump_files GROUP BY phase, status ORDER BY phase, status;
If pending files remain, update them or mark as skipped with a reason.
6b. Search for remaining references (~seconds)
⚠️ Always substitute actual version numbers. Never run netN.0 literally.
git grep -i "netN\.0" -- ':!*.md'
git grep "N0100" -- '*.props' '*.targets'
git grep "TargetsNetN" -- '*.props' '*.targets'
Review each match — some are intentional previous-version refs.
Any new files found here that weren't in SQL should be inserted and resolved:
INSERT OR IGNORE INTO bump_files (path, phase, category, notes) VALUES
('...', 'build-config', 'tfm-ref', 'found in 6b sweep');
6c. Structural diff (~seconds)
Diff each new frozen manifest against netN-1.Manifest. Only version numbers should differ.
6d. Build validation (incremental)
Fix errors at each level before moving to the next:
| Level | Command | What it catches |
|---|
| 1 | ./build.sh -restore (or dotnet restore) | MSBuild parse errors, missing imports |
| 2 | Manifest-specific build target (if exists) | Workload manifest packaging |
| 3 | Full subset build | Version property propagation |
⚠️ Level 1 must pass before attempting Level 2.
6e. Cross-reference with prior PRs
Search for the previous version bump PR in the same repo for any missed files.
6f. Final SQL check
SELECT COUNT(*) as remaining FROM bump_files WHERE status = 'pending';
Definition of Done
References