- name
- dpg-migration
- description
- Migration logic for Azure SDK for .NET data-plane libraries migrating from AutoRest/Swagger to TypeSpec-based generation. Uses MCP tools from the generator-agent server for automated deterministic fixes.
# DPG Migration Workflow
Data-plane migration workflow for Azure SDK for .NET libraries.
The workflow uses **MCP tools** from the `generator-agent` server to automate all deterministic, rule-based fixes (field renames, missing usings, type pattern replacements, nullable annotations, etc.) so the LLM only reasons about non-deterministic errors.
## When Invoked
Trigger phrases: "migrate service X", "data-plane migration", "dpg migration", "migrate to TypeSpec", "swagger to TypeSpec migration", "upgrade generator", "generator migration help", "migrate with MCP tools", "use generator-agent tools", "tool-assisted migration", "MCP migration", "automated build fix".
## Prerequisites
This skill requires the SDK repository and the spec repo:
| Path | Purpose | Required? |
|------|---------|----------|
| Current repository (`azure-sdk-for-net`) | Azure SDK for .NET mono-repo. Data-plane SDK packages typically live under `sdk/<service>/<package>/`. | Always |
| Sibling spec folder (`../azure-rest-api-specs`) | Full or sparse-checkout of the [Azure REST API Specs](https://github.com/Azure/azure-rest-api-specs) repo. Used for spec-side changes (`client.tsp`, `tspconfig.yaml` edits) and as the local spec path for code generation after any spec modification. | Always |
| Sibling TypeSpec folder (`../typespec`) | Clone of the [microsoft/typespec](https://github.com/microsoft/typespec) repo. | Only for diagnosing generator bugs |
The local spec repo path (`localSpecsPath`) is **always required** — ask the user for it at the start if not found at `../azure-rest-api-specs`. Code generation starts in **remote mode** (using the commit pinned in `tsp-location.yaml`) and switches to **local mode** (`/p:LocalSpecRepo=<path>`) only after `client.tsp` or `tspconfig.yaml` has been modified locally. Once in local mode, all subsequent generation calls use the local spec path — see [Generation Mode](#generation-mode) for details.
### MCP Server (Generator Agent)
The MCP server provides deterministic fix tools for the build-fix cycle. Configure in `.vscode/mcp.json`:
```json
{
"servers": {
"generator-agent": {
"command": "dotnet",
"args": ["run", "--project", "sdk/tools/Azure.GeneratorAgent/src/Azure.GeneratorAgent.csproj", "--framework", "net10.0"]
}
}
}
```
**Available MCP Tools:**
| Tool | When to Use | What It Does |
|------|-------------|--------------|
| `discover_project` | First step of any migration — call before all other tools | Returns comprehensive project context: detected plane, package name, service name, emitter config, tsp-location.yaml fields, custom code folder, API surface files, and `specsRepoPath` (auto-detected at `../azure-rest-api-specs` sibling of SDK repo root, `null` if not found — ask the user for the path when `null`). |
| `build_and_classify` | First step of every build-fix iteration | Runs `dotnet build`, parses output, classifies each error as deterministic or requires-reasoning |
| `batch_fix` | After `build_and_classify` returns deterministic errors | Applies multiple deterministic fixes in one call |
| `regex_replacement` | Field renames, type pattern replacements | Regex find/replace in a file |
| `add_using_directive` | CS0246/CS0103 for a known type (47 type→namespace mappings) | Adds a missing `using` directive |
| `remove_using_directive` | CS0246 for `*.Rest.*` or `Autorest.*` namespaces | Removes `using` directives matching a pattern |
| `nullable_annotation_fix` | CS8625 or CS8600 errors | Adds `?` nullable annotation on the error line |
| `rename_codegen_type` | CS0246 for mismatched `*ModelFactory` or `*ClientBuilderExtensions` | Updates `[CodeGenType]` attribute to match generated type |
| `fetch_to_fromlro` | CS0103/CS1061 for `Fetch` method calls in custom LRO code | Replaces `Fetch(response)` with `Model.FromLroResponse(response)` |
| `add_codegen_suppress` | CS0111 (duplicate member definition from custom + generated clash) | Adds `[CodeGenSuppress]` attribute to custom partial class, scanning Generated/ for member signature |
| `classify_errors` | Re-classify errors after partial fixes | Classifies errors against the deterministic fix registry |
| `validate_tsp_config` | Before code generation (if not already validated by `commit_iteration`) | Validates `tspconfig.yaml` emitter section: checks `@azure-typespec/http-client-csharp` key exists, required fields present (`emitter-output-dir`, `namespace`, `model-namespace`), and no invalid properties. Works on file path or string content. |
| `commit_iteration` | At migration start and whenever code generation fails with a spec-level error. | Finds a valid spec commit remotely. Supports strict (`commitOverride`), auto-resolve (iterates forward), and fallback (fixes `tspconfig.yaml` locally when `localSpecsPath` is provided — no git commit needed). Returns `useLocalSpecs=true` when tspconfig was fixed locally. See Phase 2 for details. |
| `pregen_cleanup` | Before first code generation | Removes `IncludeAutorestDependency` from `.csproj` |
| `snapshot_generated` | After code generation, before build-fix cycle | Takes SHA-256 snapshot of all Generated/ files. Enables auto-verification in `build_and_classify`. |
| `verify_generated_unchanged` | After build-fix cycle completes | Compares Generated/ files against snapshot. Reports violations (modified/deleted/added). Set `autoRevert=true` to auto-restore via git checkout. |
| `migrate_test_samples` | After src builds, before test build | Moves `Generated/Samples/` to `Samples/` |
| `finalize_migration` | After ALL builds succeed | Runs `Export-API.ps1` and `Update-Snippets.ps1` |
| `run_tests` | After build succeeds, to verify tests pass | Runs `dotnet test --no-build` with configurable filter (defaults to excluding live tests) |
## Inputs
The `discover_project` tool auto-resolves most variables below — it is called in Phase 0 as the first step of any migration. This skill applies only when `Plane = dpg`.
For the purposes of diagnosing generator bugs, the data-plane emitter is located in this repo under `eng/packages/http-client-csharp/`. The base emitter is in the microsoft/typespec repo under `packages/http-client-csharp/`.
| Variable | Example | `discover_project` field | Description |
|----------|---------|--------------------------|-------------|
| `LIBRARY_PATH` | `sdk/communication/Azure.Communication.Messages` | `LibraryPath` | Relative path to the SDK package directory |
| `PACKAGE_NAME` | `Azure.Communication.Messages` | `PackageName` | Full NuGet package / directory name |
| `SERVICE_NAME` | `communication` | `ServiceName` | The folder name immediately after `sdk/` |
| `EMITTER_PACKAGE_JSON_PATH` | see below | `EmitterPackageJsonPath` | Path to the emitter package.json |
| Plane | `dpg` | `Plane` | Should resolve to `dpg` for this skill |
| `SPECS_REPO_PATH` | `../azure-rest-api-specs` | `SpecsRepoPath` | Absolute path to local spec clone (null if not found — ask user) |
| Plane | `EMITTER_PACKAGE_JSON_PATH` | Target emitter in `tspconfig.yaml` |
|-------|----------------------------|------------------------------------|
| **DPG** | `eng/azure-typespec-http-client-csharp-emitter-package.json` | `azure-typespec/http-client-csharp` |
The following variables come from `tsp-location.yaml` (returned in `discover_project`'s `TspLocationFields` when the file exists):
| Variable | Example | `TspLocationFields` key | Description |
|----------|---------|------------------------|-------------|
| `SPEC_DIR` | `specification/<service>/<data-plane-spec-dir>` | `directory` | TypeSpec directory in azure-rest-api-specs |
| `SPEC_COMMIT` | `37052dfa3f...` | `commit` | Commit SHA from the spec repo |
The following variable is **not** auto-resolved by `discover_project` — determine it from the spec:
| Variable | Example | Description |
|----------|---------|-------------|
| `API_VERSION` | `2025-01-01` | Target API version from the spec |
---
## Migration Status File
Migrations often span multiple sessions and machines. To enable seamless pickup, a **`migration-status.md`** file is stored in the SDK package directory and committed to the migration branch.
### Location
```
{LIBRARY_PATH}/migration-status.md
```
Example: `sdk/communication/Azure.Communication.Messages/migration-status.md`
### Template
````markdown
# Migration Status — {PACKAGE_NAME}
**Tracking Issue:** [#{ISSUE_NUMBER}](https://github.com/Azure/azure-sdk-for-net/issues/{ISSUE_NUMBER})
**Last Updated:** {DATE}
## PRs
| PR | URL | Status |
|----|-----|--------|
| **Spec** | {URL or "Not created"} | {Draft/Open/Merged} |
| **SDK** | {URL or "Not created"} | {Draft/Open/Merged} |
| **Generator** | {URL or "N/A"} | {Draft/Open/Merged/N/A} |
## Branches
| Repo | Branch | Fork Remote |
|------|--------|-------------|
| azure-sdk-for-net | `{branch}` | `{remote}` |
| azure-rest-api-specs | `{branch}` | `{remote}` |
## Phase Tracker
**Status legend:** ✅ Done | 🔄 In Progress | ❌ Blocked | ⏭️ Not Started
| Phase | Status | Notes |
|-------|--------|-------|
| Phase 0 — Sync & Resume | {status} | |
| Phase 1 — Discovery & Planning | {status} | |
| Phase 2 — Create/Update tsp-location.yaml | {status} | |
| Phase 3 — Handle Legacy Configuration | {status} | |
| Phase 4 — Update Custom Code | {status} | |
| Phase 5 — Code Generation | {status} | |
| Phase 6 — Build-Fix Cycle | {status} | |
| Phase 7 — Changelog | {status} | |
| Phase 8 — Test Project Build | {status} | |
| Phase 9 — Test Execution | {status} | |
| Phase 10 — Finalization | {status} | |
| Phase 11 — Create Pull Requests | {status} | |
| Phase 12 — Verify and Summarize | {status} | |
## ApiCompat Baseline Summary
| Error Type | Count | Action |
|-----------|-------|--------|
| MembersMustExist | {N} | Fix with custom code |
| TypesMustExist | {N} | Fix with @@clientName |
| CannotChangeAttribute | {N} | Acceptable to baseline |
| ... | | |
## Known Issues
- {issue description and link}
## Next Steps
1. {next action}
````
### When to Save
Commit and push `migration-status.md` to the migration branch at these points:
1. **After Phase 0** — create the initial `migration-status.md` (or update if resuming)
2. **After any phase completes** — update phase status
3. **Before ending a session** — always save current progress
4. **After creating PRs** — update PR links
### Save Command
```bash
git add {LIBRARY_PATH}/migration-status.md
git commit -m "Update migration status for {PACKAGE_NAME}"
git push
```
### When to Delete
Remove `migration-status.md` from the branch when the migration is complete (Phase 12). It should **not** be included in the final PR merge to `main`.
---
## Phase 0 — Sync & Resume
Before any migration work:
### Discover Project
Call `discover_project` with the absolute path to the SDK package directory. This returns the detected plane, package name, service name, emitter config, tsp-location.yaml fields, custom code folder, API surface files, and `SpecsRepoPath` — all in one call. If `SpecsRepoPath` is null, ask the user for the path to their local `azure-rest-api-specs` clone.
### Resume Check
1. Check if `{LIBRARY_PATH}/migration-status.md` exists on the current branch.
- **If it exists**: Read and parse the status file. Report the current phase to the user and resume from the first incomplete phase.
- **If it does not exist**: This is a fresh migration — proceed with sync and Phase 1.
### Sync Repositories
Merge the latest `main` branch into all repos.
### Save Status
Create `migration-status.md` with all phases marked ⏭️ (or update existing with Phase 0 marked ✅). Commit and push to the migration branch.
---
## Phase 1 — Discovery & Planning
Use **explore** agents in parallel:
عرض على GitHub