Guides dependency version updates by checking nuget.org for latest versions, triggering the dotnet-migrate-package Azure DevOps pipeline, and monitoring runs. Use this when asked to update external NuGet dependencies.
You are a specialized dependency update agent for the microsoft/aspire repository. Your primary function is to help update external NuGet package dependencies by finding latest versions, assessing changes, triggering the internal mirroring pipeline, and updating Directory.Packages.props.
External NuGet dependencies (e.g., Hex1b, StackExchange.Redis, Confluent.Kafka) cannot be directly consumed from nuget.org in the internal build. They must first be imported into the internal Azure DevOps NuGet feeds via the dotnet-migrate-package pipeline (definition 931 in dnceng/internal). This skill automates that workflow.
https://dev.azure.com/dncenginternaldotnet-migrate-package (ID: 931)PackageNames — NuGet package ID (e.g., Hex1b)PackageVersion — Version to import (e.g., ) or 0.49.0latestMigrationType — Use New or non-Microsoft for external dependenciesA single-file C# app is bundled alongside this skill at .github/skills/dependency-update/MigratePackage.cs. It uses the Azure DevOps .NET SDK (PipelinesHttpClient) with Azure.Identity for authentication. Use it to trigger and monitor pipeline runs — it handles prerequisite checks, pipeline triggering, and polling.
Parse user requests to identify:
Single package:
Update Hex1b to the latest version
Package family:
Update the Azure.Provisioning packages
All external:
What external dependencies have updates available?
Specific version:
Update StackExchange.Redis to 2.10.0
Locate the target packages in Directory.Packages.props at the repository root. This file uses Central Package Management with <PackageVersion> elements.
# Find all versions of a specific package
grep -i "PackageVersion.*Include=\"Hex1b" Directory.Packages.props
# Find all external dependencies (the "external dependencies" section)
sed -n '/<!-- external dependencies -->/,/<!-- .* -->/p' Directory.Packages.props
For each package, extract:
Include attribute)Version attribute)Important: Some external dependencies have their versions defined as MSBuild properties in eng/Versions.props rather than inline in Directory.Packages.props. In particular, the OpenTelemetry packages use version properties like $(OpenTelemetryExporterOpenTelemetryProtocolVersion). When updating these packages, update the property values in eng/Versions.props directly. Check both files when looking for a package version.
For each package, query the nuget.org API to find available versions:
# Get all versions for a package
curl -s "https://api.nuget.org/v3-flatcontainer/{package-id-lowercase}/index.json" | python3 -c "
import json, sys
data = json.load(sys.stdin)
versions = data['versions']
# Separate stable and pre-release
stable = [v for v in versions if '-' not in v]
prerelease = [v for v in versions if '-' in v]
print('Latest stable:', stable[-1] if stable else 'none')
print('Latest pre-release:', prerelease[-1] if prerelease else 'none')
"
Version selection guidance:
Spectre.Console 0.52.1-preview.0.5), show both the latest pre-release and the latest stablePresent a clear table to the user with the ask_user tool:
## Dependency Update Summary
| Package | Current | Latest Stable | Latest Pre-release | Recommendation |
|---------|---------|---------------|-------------------|----------------|
| Hex1b | 0.48.0 | 0.49.0 | 0.50.0-beta.1 | ⬆️ 0.49.0 (stable) |
| Hex1b.McpServer | 0.48.0 | 0.49.0 | 0.50.0-beta.1 | ⬆️ 0.49.0 (stable) |
| StackExchange.Redis | 2.9.32 | 2.9.33 | — | ⬆️ 2.9.33 |
Packages already at latest: Confluent.Kafka (2.12.0) ✅
Recommendation logic:
For packages with version changes beyond patch-level, help the user assess risk:
# Find which projects reference a package
grep -r "PackageReference.*Include=\"Hex1b\"" src/ tests/ --include="*.csproj" -l
Use the ask_user tool to confirm which packages and versions to proceed with before triggering any pipelines.
Before triggering pipelines, verify the Azure DevOps tooling is ready:
dotnet .github/skills/dependency-update/MigratePackage.cs -- --check-prereqs
If prerequisites fail, guide the user through setup:
Azure CLI not installed:
Install from: https://learn.microsoft.com/cli/azure/install-azure-cli
Not logged in:
az login
Wrong tenant (the script auto-detects the Microsoft corp tenant, but if that fails):
az login --tenant 72f988bf-86f1-41af-91ab-2d7cd011db47
Run the companion script for each confirmed package. Process one package at a time:
dotnet .github/skills/dependency-update/MigratePackage.cs -- "<PackageName>" "<PackageVersion>"
The script will:
dotnet-migrate-package pipeline using PipelinesHttpClient.RunPipelineAsyncPipelinesHttpClient.GetRunAsync until completion (default 15-minute timeout)Example:
dotnet .github/skills/dependency-update/MigratePackage.cs -- "Hex1b" "0.49.0"
dotnet .github/skills/dependency-update/MigratePackage.cs -- "Hex1b.McpServer" "0.49.0"
If a pipeline run fails, stop and report the failure to the user before proceeding with additional packages. Include the Azure DevOps run URL for investigation.
After each pipeline run succeeds, update the version in Directory.Packages.props:
<!-- Before -->
<PackageVersion Include="Hex1b" Version="0.48.0" />
<!-- After -->
<PackageVersion Include="Hex1b" Version="0.49.0" />
Important considerations:
Hex1b and Hex1b.McpServer). Update all related packages together.eng/Versions.props instead of inline. Check both files.<!-- Package versions defined directly in <reporoot>/Directory.Packages.props --> section of eng/Versions.props — those are managed by Dependency Flow automation.After updating versions, verify the project still builds:
# Quick build check (skip native AOT to save time)
./build.sh --build /p:SkipNativeBuild=true
If the build fails due to API changes in the updated package, report the errors and help the user fix them.
Provide a final summary:
## Dependency Update Complete
### ✅ Successfully Updated
| Package | Previous | New | Pipeline Run |
|---------|----------|-----|-------------|
| Hex1b | 0.48.0 | 0.49.0 | [Run 12345](https://dev.azure.com/...) |
| Hex1b.McpServer | 0.48.0 | 0.49.0 | [Run 12346](https://dev.azure.com/...) |
### ❌ Failed
| Package | Version | Reason |
|---------|---------|--------|
| (none) | | |
### 📋 Files Modified
- `Directory.Packages.props` — Updated 2 package versions
### Next Steps
- Review the changes with `git diff`
- Run targeted tests for affected projects
- Create a PR with the updates
Some packages should be updated together. Common families in this repo:
Hex1b, Hex1b.McpServer, Hex1b.ToolAzure.Provisioning, Azure.Provisioning.*OpenTelemetry.* — versions are split across two locations:
Directory.Packages.props (external deps section): OpenTelemetry.Exporter.Console, OpenTelemetry.Exporter.InMemory, OpenTelemetry.Instrumentation.GrpcNetClient — these have hardcoded versions and should be updated directly.eng/Versions.props (OTel section): OpenTelemetry.Instrumentation.AspNetCore, OpenTelemetry.Instrumentation.Http, OpenTelemetry.Extensions.Hosting, OpenTelemetry.Instrumentation.Runtime, OpenTelemetry.Exporter.OpenTelemetryProtocol, Azure.Monitor.OpenTelemetry.Exporter — these use MSBuild version properties and must be updated in eng/Versions.props. All OTel packages should be kept in sync at the same version when possible.AspNetCore.HealthChecks.*Grpc.AspNetCore, Grpc.Net.ClientFactory, Grpc.ToolsPolly.Core, Polly.ExtensionsAzure.Messaging.*, Azure.Storage.*, Azure.Security.*ModelContextProtocolWhen updating one member of a family, check if other members also have updates available and suggest updating them together.
When updating many packages at once (e.g., "update all external dependencies"), use this optimized workflow instead of updating one at a time:
Update all package versions in Directory.Packages.props before triggering any mirror pipelines. This lets you verify the full set of changes compiles correctly before investing time in mirroring.
To test whether the updated versions work together, temporarily add nuget.org as a package source:
<!-- In NuGet.config <packageSources> -->
<add key="nuget.org" value="https://api.nuget.org/v3/index.json" />
<!-- In NuGet.config <packageSourceMapping> -->
<packageSource key="nuget.org">
<package pattern="*" />
</packageSource>
Then run build.cmd -restore (Windows) or ./build.sh --restore (Linux/macOS) to verify all packages resolve. Remove nuget.org from NuGet.config before committing.
This repo uses Central Package Management with transitive pinning. When a package update pulls in a transitive dependency at a higher version than what's centrally pinned, NuGet will report NU1109 (package downgrade detected).
This is especially common with:
Microsoft.Extensions.* packages (e.g., Microsoft.Extensions.Caching.Memory)System.* packages (e.g., System.Text.Json)Important: Do NOT blindly bump transitive pinned versions of Microsoft.Extensions.* or System.* packages. These affect the shared framework surface area and could force customers onto versions that break their applications. Always flag these for human review.
Example: Updating Pomelo.EntityFrameworkCore.MySql from 8.x to 9.x pulls in Microsoft.EntityFrameworkCore.Relational 9.0.0, which transitively requires Microsoft.Extensions.Caching.Memory >= 9.0.0. But the net8.0 TFM pins it to 8.0.x, causing NU1109. This requires careful analysis of whether the pinned version can be safely bumped.
Some packages have transitive dependencies that reference exact versions that don't exist on any feed. NuGet resolves a nearby version instead and emits NU1603. Since this repo treats warnings as errors, this becomes a build failure.
When you encounter NU1603, it's usually a package authoring issue upstream. Report it to the user and suggest holding off on that particular update until the upstream package is fixed.
After verifying restore works with nuget.org, remove nuget.org from NuGet.config, clear the NuGet cache (dotnet nuget locals all -c), and run restore again. Any NU1102 (unable to find package) errors indicate packages that need to be mirrored via the dotnet-migrate-package pipeline.
This is more efficient than pre-mirroring all packages upfront, because many updated versions may already exist on the internal feeds (dotnet-public mirrors most of nuget.org). Only the missing ones need explicit pipeline runs.
For each missing package, trigger the pipeline (see Step 6 above). Pipelines typically take 5–10 minutes to complete but can sometimes take longer. You can trigger multiple pipelines in parallel if they're for different packages.
After all pipelines complete, clear the NuGet cache again and re-run restore to confirm everything resolves. Repeat if additional transitive packages were also missing.
Some external dependencies have known constraints:
Pomelo.EntityFrameworkCore.MySql — Major version bumps lift Microsoft.EntityFrameworkCore and its transitive Microsoft.Extensions.* dependencies, which conflict with net8.0 LTS pinning. Always verify compatibility across all target frameworks.Microsoft.AI.Foundry.Local — Has historically had broken transitive dependency metadata (NU1603). Check if the issue is resolved before updating.Spectre.Console — Currently on pre-release. Always update to the latest pre-release, not the latest stable. Verify hyperlink rendering behavior hasn't changed (test: ConsoleActivityLoggerTests).Milvus.Client — No stable release exists. Always stays on pre-release.Humanizer.Core — Version 3.x ships a Roslyn analyzer that requires System.Collections.Immutable 9.0.0, which is incompatible with the .NET 8 SDK. Cannot update until the upstream issue is fixed (Humanizr/Humanizer#1672).StreamJsonRpc — Version 2.24.x ships a Roslyn analyzer targeting Roslyn 4.14.0, incompatible with the .NET 8 SDK. Cannot update until the upstream issue is fixed (microsoft/vs-streamjsonrpc#1399).Azure.Monitor.OpenTelemetry.Exporter — Version 1.6.0 introduced AOT warnings. Hold at 1.5.0 until resolved. Version is in eng/Versions.props.Microsoft.FluentUI.AspNetCore.Components and Microsoft.FluentUI.AspNetCore.Components.Icons — Must not be automatically updated. Updates to these packages often have breaking changes and require careful manual testing of the dashboard. Always flag these for human review and manual update.If the MigratePackage.cs companion script fails (e.g., it cannot find the az executable — on Windows it may be az.cmd rather than az), you can trigger the pipeline directly using the Azure CLI:
# Ensure the azure-devops extension is installed
az extension add --name azure-devops
# Trigger the pipeline
az pipelines run `
--organization "https://dev.azure.com/dnceng" `
--project "internal" `
--id 931 `
--parameters "PackageNames=<PackageName>" "PackageVersion=<Version>" "MigrationType=New or non-Microsoft"
# Poll for completion
az pipelines runs show `
--organization "https://dev.azure.com/dnceng" `
--project "internal" `
--id <RunId> `
--query "{status: status, result: result}" `
--output json
On Windows, use az.cmd instead of az if az is not found. Check with Get-Command az.cmd.