diff --git a/.config/dotnet-tools.json b/.config/dotnet-tools.json
index 451b12b8800..5724a00943b 100644
--- a/.config/dotnet-tools.json
+++ b/.config/dotnet-tools.json
@@ -13,6 +13,12 @@
"commands": [
"pwsh"
]
+ },
+ "hex1b.tool": {
+ "version": "0.78.0",
+ "commands": [
+ "hex1b"
+ ]
}
}
}
diff --git a/.github/skills/dependency-update/.editorconfig b/.github/skills/dependency-update/.editorconfig
new file mode 100644
index 00000000000..54135adebee
--- /dev/null
+++ b/.github/skills/dependency-update/.editorconfig
@@ -0,0 +1,12 @@
+# Override repo-level analyzers for standalone tool scripts
+root = true
+
+[*.cs]
+# Disable file header requirement
+dotnet_diagnostic.IDE0073.severity = none
+# Disable unused using warning (script may need conditional usings)
+dotnet_diagnostic.IDE0005.severity = suggestion
+# Disable ConfigureAwait requirement (not needed in console apps)
+dotnet_diagnostic.CA2007.severity = none
+# Disable locale-sensitive parsing warning
+dotnet_diagnostic.CA1305.severity = none
diff --git a/.github/skills/dependency-update/Directory.Packages.props b/.github/skills/dependency-update/Directory.Packages.props
new file mode 100644
index 00000000000..886fb9b1236
--- /dev/null
+++ b/.github/skills/dependency-update/Directory.Packages.props
@@ -0,0 +1,8 @@
+
+
+
+ false
+
+
diff --git a/.github/skills/dependency-update/MigratePackage.cs b/.github/skills/dependency-update/MigratePackage.cs
new file mode 100644
index 00000000000..ff50ebaaf68
--- /dev/null
+++ b/.github/skills/dependency-update/MigratePackage.cs
@@ -0,0 +1,423 @@
+// Triggers and monitors the dotnet-migrate-package Azure DevOps pipeline.
+// Usage: dotnet MigratePackage.cs [options]
+//
+// Options:
+// --poll-interval Polling interval (default: 30)
+// --timeout Max wait time (default: 900)
+// --migration-type Pipeline migration type (default: "New or non-Microsoft")
+// --no-wait Trigger only, don't wait for completion
+// --check-prereqs Check prerequisites and exit
+//
+// Requires: Azure CLI logged in (`az login`) to a tenant with access to the dnceng Azure DevOps org.
+
+#:package Microsoft.TeamFoundationServer.Client@19.*
+#:package Microsoft.VisualStudio.Services.Client@19.*
+#:package Azure.Identity@1.*
+
+using System.Diagnostics;
+using System.Text.Json;
+using Azure.Core;
+using Azure.Identity;
+using Microsoft.Azure.Pipelines.WebApi;
+using Microsoft.VisualStudio.Services.OAuth;
+using Microsoft.VisualStudio.Services.WebApi;
+
+const string AzDoOrg = "https://dev.azure.com/dnceng";
+const string AzDoProject = "internal";
+const int PipelineId = 931;
+const string AzDoScope = "499b84ac-1321-427f-aa17-267ca6975798/.default";
+
+// Parse arguments
+string? packageName = null;
+string? packageVersion = null;
+string migrationType = "New or non-Microsoft";
+int pollInterval = 30;
+int timeout = 900;
+bool noWait = false;
+bool checkPrereqs = false;
+
+for (int i = 0; i < args.Length; i++)
+{
+ switch (args[i])
+ {
+ case "--help" or "-h":
+ PrintUsage();
+ return;
+ case "--check-prereqs":
+ checkPrereqs = true;
+ break;
+ case "--poll-interval":
+ pollInterval = int.Parse(args[++i]);
+ break;
+ case "--timeout":
+ timeout = int.Parse(args[++i]);
+ break;
+ case "--migration-type":
+ migrationType = args[++i];
+ break;
+ case "--no-wait":
+ noWait = true;
+ break;
+ default:
+ if (args[i].StartsWith('-'))
+ {
+ LogError($"Unknown option: {args[i]}");
+ PrintUsage();
+ return;
+ }
+ if (packageName is null)
+ {
+ packageName = args[i];
+ }
+ else if (packageVersion is null)
+ {
+ packageVersion = args[i];
+ }
+ else
+ {
+ LogError($"Unexpected argument: {args[i]}");
+ PrintUsage();
+ return;
+ }
+ break;
+ }
+}
+
+if (checkPrereqs)
+{
+ await CheckPrerequisitesAsync(verbose: true);
+ return;
+}
+
+if (packageName is null || packageVersion is null)
+{
+ LogError("PackageName and PackageVersion are required.");
+ Console.WriteLine();
+ PrintUsage();
+ return;
+}
+
+// Check prerequisites
+if (!await CheckPrerequisitesAsync(verbose: true))
+{
+ return;
+}
+
+Console.WriteLine();
+
+// Connect and trigger
+var client = await ConnectAsync();
+if (client is null)
+{
+ return;
+}
+
+var run = await TriggerPipelineAsync(client, packageName, packageVersion, migrationType);
+if (run is null)
+{
+ return;
+}
+
+if (noWait)
+{
+ LogInfo($"Skipping wait (--no-wait). Monitor at:");
+ LogInfo($" {AzDoOrg}/{AzDoProject}/_build/results?buildId={run.Id}");
+ return;
+}
+
+Console.WriteLine();
+
+// Poll until completion
+await PollPipelineAsync(client, run.Id, pollInterval, timeout);
+
+// --- Functions ---
+
+async Task ConnectAsync()
+{
+ try
+ {
+ var tenantId = await GetAzCliTenantIdAsync();
+ var credential = tenantId is not null
+ ? new AzureCliCredential(new AzureCliCredentialOptions { TenantId = tenantId })
+ : new AzureCliCredential();
+
+ var token = await credential.GetTokenAsync(new TokenRequestContext([AzDoScope]));
+ var vssCred = new VssOAuthAccessTokenCredential(token.Token);
+ var connection = new VssConnection(new Uri(AzDoOrg), vssCred);
+ return connection.GetClient();
+ }
+ catch (Exception ex)
+ {
+ LogError($"Failed to connect to Azure DevOps: {ex.Message}");
+ LogError("Ensure you are logged in with `az login` to a tenant that has access to the dnceng org.");
+ return null;
+ }
+}
+
+async Task TriggerPipelineAsync(PipelinesHttpClient client, string name, string version, string type)
+{
+ LogInfo("Triggering dotnet-migrate-package pipeline...");
+ LogInfo($" Package: {name}");
+ LogInfo($" Version: {version}");
+ LogInfo($" MigrationType: {type}");
+
+ try
+ {
+ var parameters = new RunPipelineParameters
+ {
+ TemplateParameters = new Dictionary
+ {
+ ["PackageNames"] = name,
+ ["PackageVersion"] = version,
+ ["MigrationType"] = type
+ }
+ };
+
+ var run = await client.RunPipelineAsync(parameters, AzDoProject, PipelineId);
+
+ LogSuccess("Pipeline triggered successfully");
+ LogInfo($" Run ID: {run.Id}");
+ LogInfo($" URL: {AzDoOrg}/{AzDoProject}/_build/results?buildId={run.Id}");
+
+ return run;
+ }
+ catch (Exception ex)
+ {
+ LogError($"Failed to trigger pipeline: {ex.Message}");
+ return null;
+ }
+}
+
+async Task PollPipelineAsync(PipelinesHttpClient client, int runId, int interval, int maxWait)
+{
+ LogInfo($"Polling pipeline run {runId} (interval: {interval}s, timeout: {maxWait}s)...");
+
+ var sw = Stopwatch.StartNew();
+
+ while (true)
+ {
+ if (sw.Elapsed.TotalSeconds >= maxWait)
+ {
+ LogError($"Timeout after {maxWait}s waiting for pipeline run {runId}");
+ return;
+ }
+
+ try
+ {
+ var run = await client.GetRunAsync(AzDoProject, PipelineId, runId);
+ var elapsed = sw.Elapsed;
+ var elapsedStr = $"{(int)elapsed.TotalMinutes}m{elapsed.Seconds}s";
+
+ if (run.State == RunState.Completed)
+ {
+ if (run.Result == RunResult.Succeeded)
+ {
+ LogSuccess($"Pipeline completed successfully ({elapsedStr})");
+ }
+ else
+ {
+ LogError($"Pipeline completed with result: {run.Result} ({elapsedStr})");
+ LogError($"See: {AzDoOrg}/{AzDoProject}/_build/results?buildId={runId}");
+ }
+ return;
+ }
+
+ LogInfo($" Status: {run.State} (elapsed: {elapsedStr})...");
+ }
+ catch (Exception ex)
+ {
+ LogWarn($" Poll error (will retry): {ex.Message}");
+ }
+
+ await Task.Delay(TimeSpan.FromSeconds(interval));
+ }
+}
+
+async Task CheckPrerequisitesAsync(bool verbose)
+{
+ var ok = true;
+
+ // Check az CLI
+ if (!await IsCommandAvailableAsync("az"))
+ {
+ if (verbose)
+ {
+ LogError("Azure CLI (az) is not installed.");
+ Console.WriteLine(" Install: https://learn.microsoft.com/cli/azure/install-azure-cli");
+ }
+ ok = false;
+ }
+ else if (verbose)
+ {
+ var (_, version) = await RunProcessAsync("az", "version --query \"azure-cli\" -o tsv");
+ LogSuccess($"Azure CLI found: {version.Trim()}");
+ }
+
+ // Check az login status
+ var (loginSuccess, loginOutput) = await RunProcessAsync("az", "account show --query user.name -o tsv");
+ if (!loginSuccess)
+ {
+ if (verbose)
+ {
+ LogError("Not logged in to Azure CLI.");
+ Console.WriteLine(" Login: az login");
+ }
+ ok = false;
+ }
+ else if (verbose)
+ {
+ LogSuccess($"Logged in as: {loginOutput.Trim()}");
+ }
+
+ // Check tenant
+ if (loginSuccess)
+ {
+ var tenantId = await GetAzCliTenantIdAsync();
+ if (verbose && tenantId is not null)
+ {
+ LogSuccess($"Tenant: {tenantId}");
+ }
+ }
+
+ // Try to get a token for Azure DevOps
+ if (loginSuccess)
+ {
+ try
+ {
+ var tenantId = await GetAzCliTenantIdAsync();
+ var credential = tenantId is not null
+ ? new AzureCliCredential(new AzureCliCredentialOptions { TenantId = tenantId })
+ : new AzureCliCredential();
+ await credential.GetTokenAsync(new TokenRequestContext([AzDoScope]));
+ if (verbose)
+ {
+ LogSuccess("Azure DevOps token acquired successfully");
+ }
+ }
+ catch (Exception ex)
+ {
+ if (verbose)
+ {
+ LogError($"Failed to acquire Azure DevOps token: {ex.Message}");
+ Console.WriteLine(" You may need to log in to the correct tenant: az login --tenant ");
+ }
+ ok = false;
+ }
+ }
+
+ if (verbose)
+ {
+ if (ok)
+ {
+ LogSuccess("All prerequisites met");
+ }
+ else
+ {
+ LogError("Some prerequisites are missing. See above for details.");
+ }
+ }
+
+ return ok;
+}
+
+async Task GetAzCliTenantIdAsync()
+{
+ // Discover the tenant from the current az CLI session.
+ // The dnceng org is in the Microsoft tenant; if the user is logged into
+ // a different tenant we attempt to find the Microsoft corp one.
+ var (success, output) = await RunProcessAsync("az", "account show --query tenantId -o tsv");
+ if (!success)
+ {
+ return null;
+ }
+
+ var currentTenant = output.Trim();
+
+ // If already on the Microsoft corp tenant, use it directly
+ if (string.Equals(currentTenant, "72f988bf-86f1-41af-91ab-2d7cd011db47", global::System.StringComparison.OrdinalIgnoreCase))
+ {
+ return currentTenant;
+ }
+
+ // Check if the Microsoft corp tenant is available in the account list
+ var (listOk, listOutput) = await RunProcessAsync("az", "account list --query \"[?tenantId=='72f988bf-86f1-41af-91ab-2d7cd011db47'].tenantId | [0]\" -o tsv");
+ if (listOk && !string.IsNullOrWhiteSpace(listOutput))
+ {
+ return listOutput.Trim();
+ }
+
+ return currentTenant;
+}
+
+async Task IsCommandAvailableAsync(string command)
+{
+ try
+ {
+ var (success, _) = await RunProcessAsync(command, "--version");
+ return success;
+ }
+ catch
+ {
+ return false;
+ }
+}
+
+async Task<(bool Success, string Output)> RunProcessAsync(string fileName, string arguments)
+{
+ using var process = Process.Start(new ProcessStartInfo
+ {
+ FileName = fileName,
+ Arguments = arguments,
+ RedirectStandardOutput = true,
+ RedirectStandardError = true,
+ UseShellExecute = false
+ });
+
+ if (process is null)
+ {
+ return (false, string.Empty);
+ }
+
+ var output = await process.StandardOutput.ReadToEndAsync();
+ await process.WaitForExitAsync();
+ return (process.ExitCode == 0, output);
+}
+
+void PrintUsage()
+{
+ Console.WriteLine("""
+ MigratePackage.cs — Trigger and monitor the dotnet-migrate-package Azure DevOps pipeline
+
+ USAGE:
+ dotnet MigratePackage.cs [OPTIONS]
+ dotnet MigratePackage.cs --check-prereqs
+ dotnet MigratePackage.cs --help
+
+ ARGUMENTS:
+ PackageName NuGet package ID (e.g., Hex1b)
+ PackageVersion Version to import (e.g., 0.49.0) or "latest"
+
+ OPTIONS:
+ --poll-interval Polling interval (default: 30)
+ --timeout Max wait time (default: 900)
+ --migration-type Pipeline migration type (default: "New or non-Microsoft")
+ --no-wait Trigger only, don't wait for completion
+ --check-prereqs Check prerequisites and exit
+ --help Show this help
+
+ AUTHENTICATION:
+ Uses Azure.Identity (AzureCliCredential) to acquire a token for Azure DevOps.
+ Ensure you are logged in with: az login
+ The script will automatically select the Microsoft corp tenant if available.
+
+ EXAMPLES:
+ dotnet MigratePackage.cs Hex1b 0.49.0
+ dotnet MigratePackage.cs StackExchange.Redis 2.9.33 --no-wait
+ dotnet MigratePackage.cs --check-prereqs
+ """);
+}
+
+void LogInfo(string message) => Console.WriteLine($"\u001b[36m[INFO]\u001b[0m {message}");
+void LogSuccess(string message) => Console.WriteLine($"\u001b[32m[OK]\u001b[0m {message}");
+void LogWarn(string message) => Console.WriteLine($"\u001b[33m[WARN]\u001b[0m {message}");
+void LogError(string message) => Console.Error.WriteLine($"\u001b[31m[ERROR]\u001b[0m {message}");
diff --git a/.github/skills/dependency-update/SKILL.md b/.github/skills/dependency-update/SKILL.md
new file mode 100644
index 00000000000..0f99b55f5a0
--- /dev/null
+++ b/.github/skills/dependency-update/SKILL.md
@@ -0,0 +1,254 @@
+---
+name: dependency-update
+description: 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 dotnet/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`.
+
+## Background
+
+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.
+
+### Pipeline Details
+
+- **Organization**: `https://dev.azure.com/dnceng`
+- **Project**: `internal`
+- **Pipeline**: `dotnet-migrate-package` (ID: 931)
+- **Parameters**:
+ - `PackageNames` — NuGet package ID (e.g., `Hex1b`)
+ - `PackageVersion` — Version to import (e.g., `0.49.0`) or `latest`
+ - `MigrationType` — Use `New or non-Microsoft` for external dependencies
+
+### Companion Script
+
+A 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.
+
+## Understanding User Requests
+
+Parse user requests to identify:
+
+1. **Package name(s)** — Specific packages (e.g., "update Hex1b") or categories (e.g., "update all HealthChecks packages")
+2. **Target version** — Specific version or "latest" (default behavior)
+3. **Scope** — Single package, a family of packages, or all external dependencies
+
+### Example Requests
+
+**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
+
+## Task Execution Steps
+
+### 1. Identify Packages to Update
+
+Locate the target packages in `Directory.Packages.props` at the repository root. This file uses Central Package Management with `` elements.
+
+```bash
+# 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 '//,//p' Directory.Packages.props
+```
+
+For each package, extract:
+- Package ID (the `Include` attribute)
+- Current version (the `Version` attribute)
+
+### 2. Look Up Latest Versions on nuget.org
+
+For each package, query the nuget.org API to find available versions:
+
+```bash
+# 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:**
+
+- **Default to latest stable** for packages currently on stable versions
+- **Note pre-release versions** if they exist and are newer than the latest stable
+- **For packages already on pre-release** (e.g., `Spectre.Console 0.52.1-preview.0.5`), show both the latest pre-release and the latest stable
+- **Always show the current version** for comparison
+
+### 3. Present Version Summary
+
+Present a clear table to the user with the `ask_user` tool:
+
+```markdown
+## 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:**
+- If currently on stable → recommend latest stable
+- If currently on pre-release → recommend latest pre-release (note stable alternative)
+- If current == latest → mark as up-to-date
+- If a major version bump → flag for careful review
+
+### 4. Review Changes (For Major/Minor Bumps)
+
+For packages with version changes beyond patch-level, help the user assess risk:
+
+1. **Find the project/release page** — Search for the package's GitHub repository or changelog
+2. **Summarize notable changes** — Breaking changes, new features, deprecations
+3. **Check for known issues** — Look for open issues related to the new version
+4. **Assess impact** — Which Aspire projects reference this package?
+
+```bash
+# 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.
+
+### 5. Check Prerequisites
+
+Before triggering pipelines, verify the Azure DevOps tooling is ready:
+
+```bash
+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:**
+```bash
+az login
+```
+
+**Wrong tenant (the script auto-detects the Microsoft corp tenant, but if that fails):**
+```bash
+az login --tenant 72f988bf-86f1-41af-91ab-2d7cd011db47
+```
+
+### 6. Trigger Pipeline for Each Package
+
+Run the companion script for each confirmed package. Process **one package at a time**:
+
+```bash
+dotnet .github/skills/dependency-update/MigratePackage.cs -- "" ""
+```
+
+The script will:
+1. Authenticate via Azure.Identity (AzureCliCredential)
+2. Trigger the `dotnet-migrate-package` pipeline using `PipelinesHttpClient.RunPipelineAsync`
+3. Poll every 30 seconds via `PipelinesHttpClient.GetRunAsync` until completion (default 15-minute timeout)
+4. Report success or failure
+
+**Example:**
+```bash
+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.
+
+### 7. Update Directory.Packages.props
+
+After each pipeline run succeeds, update the version in `Directory.Packages.props`:
+
+```xml
+
+
+
+
+
+```
+
+**Important considerations:**
+- Some packages share versions (e.g., `Hex1b` and `Hex1b.McpServer`). Update all related packages together.
+- Some packages have version properties defined in `eng/Versions.props` instead of inline. Check both files.
+- Don't modify packages in the `` section of `eng/Versions.props` — those are managed by Dependency Flow automation.
+
+### 8. Verify the Build
+
+After updating versions, verify the project still builds:
+
+```bash
+# 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.
+
+### 9. Summarize Results
+
+Provide a final summary:
+
+```markdown
+## 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
+```
+
+## Handling Related Package Families
+
+Some packages should be updated together. Common families in this repo:
+
+- **Hex1b**: `Hex1b`, `Hex1b.McpServer`
+- **Azure.Provisioning**: `Azure.Provisioning`, `Azure.Provisioning.*`
+- **OpenTelemetry**: `OpenTelemetry.*` (versions often defined as MSBuild properties in `eng/Versions.props`)
+- **AspNetCore.HealthChecks**: `AspNetCore.HealthChecks.*`
+- **Grpc**: `Grpc.AspNetCore`, `Grpc.Net.ClientFactory`, `Grpc.Tools`
+- **Polly**: `Polly.Core`, `Polly.Extensions`
+- **Azure SDK**: `Azure.Messaging.*`, `Azure.Storage.*`, `Azure.Security.*`
+- **ModelContextProtocol**: `ModelContextProtocol`, `ModelContextProtocol.AspNetCore`
+
+When updating one member of a family, check if other members also have updates available and suggest updating them together.
+
+## Important Constraints
+
+- **One package per pipeline run** — The script processes one dependency at a time
+- **Wait for completion** — Don't start the next pipeline run until the current one finishes (the pipeline queue is aggressive)
+- **Always check nuget.org** — The mirroring pipeline pulls from nuget.org
+- **Verify versions exist** — Before triggering the pipeline, confirm the version exists on nuget.org
+- **Don't modify NuGet.config** — Package sources are managed separately; this skill only handles version updates
+- **Don't modify eng/Version.Details.xml** — That file is managed by Dependency Flow automation (Maestro/Darc)
+- **Ask before proceeding** — Always present the version summary and get user confirmation before triggering pipelines
diff --git a/AGENTS.md b/AGENTS.md
index 156c8f83df6..cb4d5711eb1 100644
--- a/AGENTS.md
+++ b/AGENTS.md
@@ -354,6 +354,7 @@ The following specialized skills are available in `.github/skills/`:
- **cli-e2e-testing**: Guide for writing Aspire CLI end-to-end tests using Hex1b terminal automation
- **test-management**: Quarantines or disables flaky/problematic tests using the QuarantineTools utility
- **connection-properties**: Expert for creating and improving Connection Properties in Aspire resources
+- **dependency-update**: Guides dependency version updates by checking nuget.org, triggering the dotnet-migrate-package Azure DevOps pipeline, and monitoring runs
## Pattern-Based Instructions
diff --git a/Directory.Packages.props b/Directory.Packages.props
index 77397aa81f6..8e4674e5743 100644
--- a/Directory.Packages.props
+++ b/Directory.Packages.props
@@ -98,8 +98,9 @@
-
-
+
+
+