Update copilot instructions, prompts, and skills#2212
Conversation
There was a problem hiding this comment.
Pull request overview
This PR updates the repo’s Copilot skills/prompts by adding redirect-management automation (new skills + PowerShell scripts) and modernizing several snippet-related prompts, while removing older/temporary prompt/agent assets.
Changes:
- Added
redirect-articleandsort-redirectsskills, including PowerShell scripts to create and sort Open Publishing redirect entries. - Updated multiple prompts (snippet migration/push/upgrade and others) to reflect newer conventions and model selections.
- Removed obsolete prompt/agent files (including the old redirect prompt, a temp prompt, and the docwriter agent).
Reviewed changes
Copilot reviewed 14 out of 15 changed files in this pull request and generated 6 comments.
Show a summary per file
| File | Description |
|---|---|
| .github/skills/sort-redirects/SKILL.md | Documents a new skill for sorting Open Publishing redirect JSON entries. |
| .github/skills/sort-redirects/scripts/sort-redirects.ps1 | Implements redirect sorting for redirection JSON files. |
| .github/skills/redirect-article/SKILL.md | Documents a new skill for deleting an article and adding a redirect entry. |
| .github/skills/redirect-article/scripts/create-redirect-entry.ps1 | Implements insertion of a redirect entry into a redirection JSON file. |
| .github/prompts/ValidateTemplate.prompt.md | Updates the model selection used for template validation. |
| .github/prompts/temp.prompt.md | Removes a temporary/one-off prompt file. |
| .github/prompts/Snippets.Upgrade.prompt.md | Updates snippet upgrade guidance (structure, creation via dotnet CLI, etc.). |
| .github/prompts/Snippets.Push.prompt.md | Updates guidance for extracting inline snippets into project-based snippet folders. |
| .github/prompts/Snippets.Migrate.prompt.md | Updates guidance for migrating legacy ~/samples/snippets references to ./snippets/. |
| .github/prompts/RefreshLinks.prompt.md | Adjusts frontmatter metadata (adds a name field) and keeps prompt behavior. |
| .github/prompts/Redirect.Article.prompt.md | Removes the older redirect prompt (superseded by skill-based workflow). |
| .github/prompts/Merge.Article.prompt.md | Adds a new prompt for merging article content and optionally invoking redirect skill afterward. |
| .github/prompts/Editing.FullPass.prompt.md | Updates model/agent selection and simplifies the editing prompt instructions. |
| .github/agents/docwriter.agent.md | Removes the docwriter agent definition. |
| .github/agents/doceditor.agent.md | Expands doceditor to cover both writing and editing modes and adds repo-specific guidance. |
| ## Important Notes | ||
|
|
||
| - The script preserves all existing redirect entries, only changing their order. | ||
| - Sorting is case-sensitive and alphabetical by the normalized path (without leading `/`). |
There was a problem hiding this comment.
The “Important Notes” claim that sorting is case-sensitive and that the script “preserves all existing redirect entries, only changing their order.” The current implementation uses Sort-Object without -CaseSensitive and rewrites the file via ConvertTo-Json, which typically changes formatting/indentation (and can change encoding/line endings), so this note is misleading. Update the note to match actual behavior, or adjust the script to preserve formatting and use case-sensitive sorting if that’s the requirement.
| # Sort the redirections alphabetically by normalized path | ||
| $sortedRedirections = $jsonContent.redirections | Sort-Object -Property { Get-NormalizedPath -Path (Get-EntrySourcePath -Entry $_) } | ||
|
|
||
| # Update the JSON object with sorted redirections | ||
| $jsonContent.redirections = $sortedRedirections | ||
|
|
||
| # Convert back to JSON with proper formatting | ||
| $jsonOutput = $jsonContent | ConvertTo-Json -Depth 10 | ||
|
|
||
| # Write the updated JSON back to the file | ||
| $jsonOutput | Set-Content -Path $redirectionFilePath -Encoding UTF8 | ||
|
|
There was a problem hiding this comment.
Sort-Object is currently case-insensitive by default; if you intend the documented case-sensitive sort, pass -CaseSensitive (or update the docs). Also, writing with ConvertTo-Json + Set-Content -Encoding UTF8 will reformat the JSON and may introduce a UTF-8 BOM on Windows PowerShell, causing large diffs in redirect files. Consider preserving the original line endings/encoding (and ideally indentation) similarly to create-redirect-entry.ps1’s no-BOM write strategy.
| # Core lines of the new entry (closing brace has no comma yet - added below per context) | ||
| $newEntryCore = @( | ||
| "$entryIndent{", | ||
| "$fieldIndent`"source_path_from_root`": `"$sourcePathWithRoot`",", | ||
| "$fieldIndent`"redirect_url`": `"$RedirectUrl`"", |
There was a problem hiding this comment.
The raw JSON splice builds lines using $SourcePath/$RedirectUrl directly inside quoted JSON strings. If either input contains characters that must be escaped in JSON (for example \ from Windows-style paths, or "), the script will write invalid JSON. Add input validation (reject backslashes/quotes) or JSON-escape these values before injecting them into the file.
| # Core lines of the new entry (closing brace has no comma yet - added below per context) | |
| $newEntryCore = @( | |
| "$entryIndent{", | |
| "$fieldIndent`"source_path_from_root`": `"$sourcePathWithRoot`",", | |
| "$fieldIndent`"redirect_url`": `"$RedirectUrl`"", | |
| function Escape-ForJsonString { | |
| param( | |
| [string] $Value | |
| ) | |
| if ($null -eq $Value) { | |
| return "" | |
| } | |
| # Use ConvertTo-Json to perform proper JSON escaping, then trim the surrounding quotes. | |
| $json = $Value | ConvertTo-Json -Compress | |
| if ($json.Length -ge 2 -and $json.StartsWith('"') -and $json.EndsWith('"')) { | |
| return $json.Substring(1, $json.Length - 2) | |
| } | |
| return $json | |
| } | |
| $escapedSourcePath = Escape-ForJsonString -Value $sourcePathWithRoot | |
| $escapedRedirectUrl = Escape-ForJsonString -Value $RedirectUrl | |
| # Core lines of the new entry (closing brace has no comma yet - added below per context) | |
| $newEntryCore = @( | |
| "$entryIndent{", | |
| "$fieldIndent`"source_path_from_root`": `"$escapedSourcePath`",", | |
| "$fieldIndent`"redirect_url`": `"$escapedRedirectUrl`"", |
| $targetPath = Get-EntrySourcePath -Entry $redirectionsList[$insertIndex] | ||
| $targetLineIdx = -1 | ||
| for ($i = 0; $i -lt $lines.Count; $i++) { | ||
| if ($lines[$i] -match [regex]::Escape($targetPath)) { | ||
| $targetLineIdx = $i | ||
| break | ||
| } | ||
| } | ||
| if ($targetLineIdx -lt 0) { | ||
| Write-Error "Could not locate insertion point in file for: $targetPath" | ||
| exit 1 | ||
| } | ||
| # Walk back to find the opening { of that entry | ||
| $entryStartIdx = $targetLineIdx | ||
| for ($i = $targetLineIdx - 1; $i -ge 0; $i--) { | ||
| if ($lines[$i].Trim() -eq '{') { | ||
| $entryStartIdx = $i | ||
| break | ||
| } |
There was a problem hiding this comment.
The insertion point detection searches for the first line that contains $targetPath anywhere in the file (-match [regex]::Escape($targetPath)). This can match unintended lines if the same substring appears elsewhere, which could splice the new entry into the wrong location. Prefer matching the specific "source_path..." property line for that entry (or otherwise anchoring the search) before walking back to the opening {.
| **Requirements for current code standards:** | ||
| - ✅ MUST be complete and compilable | ||
| - ✅ MUST include a project file | ||
| - ✅ MUST target appropriate .NET version (see targeting rules below) | ||
| - ✅ MUST target the latest .NET version | ||
| - ✅ MUST provide BOTH C# and Visual Basic versions | ||
| - ✅ MUST use appropriate syntax for the target framework | ||
| - ✅ MUST use meaningful, descriptive snippet identifiers in CamelCase format |
There was a problem hiding this comment.
This prompt is internally inconsistent about framework targeting: it says ms.service: dotnet-framework articles should “keep .NET Framework targeting”, but the “Requirements for current code standards” section says snippets “MUST target the latest .NET version.” Clarify the rule so the required target framework is unambiguous (for example: latest .NET by default, but keep .NET Framework for dotnet-framework articles, and use net/ + framework/ subfolders for dual-framework articles).
| ### New location (current standard - migrate TO) | ||
| - Path pattern: `./snippets/{article-filename-using-snippet}/[net-or-framework]/[optional-sub-subject]/{code-language}/` | ||
| - Example C# (standard): `./snippets/anchors-in-regular-expressions/csharp/Form1.cs` | ||
| - Example VB (standard): `./snippets/anchors-in-regular-expressions/vb/Form1.vb` | ||
| - Example C# (.NET, dual-framework article): `./snippets/clipboard-operations/net/csharp/Form1.cs` | ||
| - Example C# (.NET Framework, dual-framework article): `./snippets/clipboard-operations/framework/csharp/Form1.cs` | ||
| - Example C# (clash avoidance): `./snippets/program-structure/AsyncProgram/csharp/Program.cs` | ||
| - Example (language guide, no code-language subfolder): `./snippets/pattern-matching/Program.cs` |
There was a problem hiding this comment.
The “New location” section defines a path pattern that includes an optional [net-or-framework]/ folder, but later “Create new or reuse existing folder structure” omits that component and gives an example without it (./snippets/clipboard-operations/csharp/). Align these sections so the folder pattern is consistent and clearly indicates when net/ or framework/ should be used.
Internal previews