microsoft/converting-to-cpm
> Converts .NET projects and solutions to NuGet Central Package Management (CPM) with Directory.Packages.props. Use when the user wants to centralize, convert, align, or sync NuGet package versions across multiple projects, resolve version conflicts or mismatches, or get versions consistent across a solution or repository. Also triggers when packages are out of sync or drifting across projects.
npx skills add https://github.com/microsoft/upgrade-agent-plugins --skill converting-to-cpm
Migrate .NET projects from per-project package versioning to NuGet Central Package Management (CPM), centralizing all package versions into a single Directory.Packages.props.
Directory.Packages.props, CPM, or centralizing NuGet versionspackages.config (must first migrate to PackageReference)| Input | Required | Description |
|-------|----------|-------------|
| Scope | Yes | A project file, solution file, or directory containing .NET projects to convert |
| Version conflict strategy | No | How to resolve version conflicts. Do not assume a default — ask the user when conflicts are detected. |
.sln/.slnx. List projects with dotnet sln list.If the scope is unclear, ask the user.
Verify the scope builds successfully and capture baseline artifacts. See baseline-comparison.md for the full procedure. If the baseline build fails, stop and inform the user — the scope must build cleanly before conversion. Do not delete artifacts — they are needed for the post-conversion comparison.
Search for Directory.Packages.props in scope or ancestor directories. If CPM is already fully enabled, inform the user and stop. If the file exists without CPM enabled, ask the user how to proceed.
Run dotnet package list --format json across all in-scope projects. Scan <Import> elements for shared .props/.targets files containing package references.
Check for complexities per audit-complexities.md: version conflicts, MSBuild property-based versions, conditional references, security advisories, existing VersionOverride usage.
Present audit results to the user before proceeding — a table of packages, versions, and consuming projects, plus any conflicts or complexities requiring decisions.
For version conflicts, present each individually with resolution options and trade-offs. Do not upgrade any package beyond the highest version already in use — note advisories as follow-up items instead. Ask the user to decide on each conflict before proceeding.
Create with dotnet new packagesprops (.NET 8+) or manually. Add <PackageVersion> entries for each unique package. See directory-packages-props.md for placement, conditional versions, and VersionOverride patterns.
Remove Version from every <PackageReference> that has a corresponding <PackageVersion>. Also update shared .props/.targets files from step 4. Use VersionOverride (with user confirmation) when a project needs a different version than the central one. Do not reformat or reorganize unchanged lines.
For PackageReference items that used MSBuild properties for versions, determine whether to inline or keep the property reference. See msbuild-property-handling.md for the decision workflow, import order requirements, and cleanup procedure. Clean up inlined properties only after validation succeeds in step 8.
Run a clean restore and build, capturing post-conversion artifacts. See baseline-comparison.md for the procedure. If errors occur, see validation-and-errors.md for NuGet error codes and multi-TFM guidance.
Do not delete any artifacts — baseline.binlog, after-cpm.binlog, baseline-packages.json, after-cpm-packages.json are deliverables for the user.
Create a convert-to-cpm.md file alongside the artifacts — do not substitute inline chat output. Include:
VersionOverride alignment opportunities)Directory.Packages.props has ManagePackageVersionsCentrally set to truePackageReference has no Version attribute or uses VersionOverridePackageVersion entrydotnet restore and dotnet build succeed from a clean stateTake microsoft/converting-to-cpm from the repository into ~/.claude/skills for personal
use, or into .claude/skills inside a project.
The agent identifies a skill by the name field in its header. Two skills with the
same name cannot sit side by side — one of them will be ignored.