{"kind":"AgentDefinition","metadata":{"namespace":"community","name":"vsixtoolkit","version":"0.1.0"},"spec":{"agents_md":"---\ndescription: 'Guidelines for Visual Studio extension (VSIX) development using Community.VisualStudio.Toolkit'\napplyTo: '**/*.cs, **/*.vsct, **/*.xaml, **/source.extension.vsixmanifest'\n---\n\n# Visual Studio Extension Development with Community.VisualStudio.Toolkit\n\n## Scope\n\n**These instructions apply ONLY to Visual Studio extensions using `Community.VisualStudio.Toolkit`.**\n\nVerify the project uses the toolkit by checking for:\n- `Community.VisualStudio.Toolkit.*` NuGet package reference\n- `ToolkitPackage` base class (not raw `AsyncPackage`)\n- `BaseCommand\u003cT\u003e` pattern for commands\n\n**If the project uses raw VSSDK (`AsyncPackage` directly) or the new `VisualStudio.Extensibility` model, do not apply these instructions.**\n\n## Goals\n\n- Generate async-first, thread-safe extension code\n- Use toolkit abstractions (`VS.*` helpers, `BaseCommand\u003cT\u003e`, `BaseOptionModel\u003cT\u003e`)\n- Ensure all UI respects Visual Studio themes\n- Follow VSSDK and VSTHRD analyzer rules\n- Produce testable, maintainable extension code\n- **Adhere to `.editorconfig` settings** when present in the repository\n\n## Code Style (.editorconfig)\n\n**If an `.editorconfig` file exists in the repository, all generated and modified code MUST follow its rules.**\n\nThis includes but is not limited to:\n- Indentation style (tabs vs spaces) and size\n- Line endings and final newline requirements\n- Naming conventions (fields, properties, methods, etc.)\n- Code style preferences (`var` usage, expression bodies, braces, etc.)\n- Analyzer severity levels and suppressions\n\nBefore generating code, check for `.editorconfig` in the repository root and apply its settings. When in doubt, match the style of surrounding code in the file being edited.\n\n## .NET Framework and C# Language Constraints\n\n**Visual Studio extensions target .NET Framework 4.8** but can use modern C# syntax (up to C# 14) with constraints imposed by the .NET Framework runtime.\n\n### ✅ Supported Modern C# Features\n- Primary constructors\n- File-scoped namespaces\n- Global usings\n- Pattern matching (all forms)\n- Records (with limitations)\n- `init` accessors\n- Target-typed `new`\n- Nullable reference types (annotations only)\n- Raw string literals\n- Collection expressions\n\n### ❌ Not Supported (.NET Framework Limitations)\n- `Span\u003cT\u003e`, `ReadOnlySpan\u003cT\u003e`, `Memory\u003cT\u003e` (no runtime support)\n- `IAsyncEnumerable\u003cT\u003e` (without polyfill packages)\n- Default interface implementations\n- `Index` and `Range` types (no runtime support for `^` and `..` operators)\n- `init`-only setters on structs (runtime limitation)\n- Some `System.Text.Json` features\n\n### Best Practice\nWhen writing code, prefer APIs available in .NET Framework 4.8. If a modern API is needed, check if a polyfill NuGet package exists (e.g., `Microsoft.Bcl.AsyncInterfaces` for `IAsyncEnumerable\u003cT\u003e`).\n\n## Example Prompt Behaviors\n\n### ✅ Good Suggestions\n- \"Create a command that opens the current file's containing folder using `BaseCommand\u003cT\u003e`\"\n- \"Add an options page with a boolean setting using `BaseOptionModel\u003cT\u003e`\"\n- \"Write a tagger provider for C# files that highlights TODO comments\"\n- \"Show a status bar progress indicator while processing files\"\n\n### ❌ Avoid\n- Suggesting raw `AsyncPackage` instead of `ToolkitPackage`\n- Using `OleMenuCommandService` directly instead of `BaseCommand\u003cT\u003e`\n- Creating WPF elements without switching to UI thread first\n- Using `.Result`, `.Wait()`, or `Task.Run` for UI work\n- Hardcoding colors instead of using VS theme colors\n\n## Project Structure\n\n```\nsrc/\n├── Commands/           # Command handlers (menu items, toolbar buttons)\n├── Options/            # Settings/options pages\n├── Services/           # Business logic and services\n├── Tagging/            # ITagger implementations (syntax highlighting, outlining)\n├── Adornments/         # Editor adornments (IntraTextAdornment, margins)\n├── QuickInfo/          # QuickInfo/tooltip providers\n├── SuggestedActions/   # Light bulb actions\n├── Handlers/           # Event handlers (format document, paste, etc.)\n├── Resources/          # Images, icons, license files\n├── source.extension.vsixmanifest  # Extension manifest\n├── VSCommandTable.vsct            # Command definitions (menus, buttons)\n├── VSCommandTable.cs              # Auto-generated command IDs\n└── *Package.cs                    # Main package class\n```\n\n## Community.VisualStudio.Toolkit Patterns\n\n### Global Usings\n\nExtensions using the toolkit should have these global usings in the Package file:\n\n```csharp\nglobal using System;\nglobal using Community.VisualStudio.Toolkit;\nglobal using Microsoft.VisualStudio.Shell;\nglobal using Task = System.Threading.Tasks.Task;\n```\n\n### Package Class\n\n```csharp\n[PackageRegistration(UseManagedResourcesOnly = true, AllowsBackgroundLoading = true)]\n[InstalledProductRegistration(Vsix.Name, Vsix.Description, Vsix.Version)]\n[ProvideMenuResource(\"Menus.ctmenu\", 1)]\n[Guid(PackageGuids.YourExtensionString)]\n[ProvideOptionPage(typeof(OptionsProvider.GeneralOptions), Vsix.Name, \"General\", 0, 0, true, SupportsProfiles = true)]\npublic sealed class YourPackage : ToolkitPackage\n{\n    protected override async Task InitializeAsync(CancellationToken cancellationToken, IProgress\u003cServiceProgressData\u003e progress)\n    {\n        await this.RegisterCommandsAsync();\n    }\n}\n```\n\n### Commands\n\nCommands use the `[Command]` attribute and inherit from `BaseCommand\u003cT\u003e`:\n\n```csharp\n[Command(PackageIds.YourCommandId)]\ninternal sealed class YourCommand : BaseCommand\u003cYourCommand\u003e\n{\n    protected override async Task ExecuteAsync(OleMenuCmdEventArgs e)\n    {\n        // Command implementation\n    }\n\n    // Optional: Control command state (enabled, checked, visible)\n    protected override void BeforeQueryStatus(EventArgs e)\n    {\n        Command.Checked = someCondition;\n        Command.Enabled = anotherCondition;\n    }\n}\n```\n\n### Options Pages\n\n```csharp\ninternal partial class OptionsProvider\n{\n    [ComVisible(true)]\n    public class GeneralOptions : BaseOptionPage\u003cGeneral\u003e { }\n}\n\npublic class General : BaseOptionModel\u003cGeneral\u003e\n{\n    [Category(\"Category Name\")]\n    [DisplayName(\"Setting Name\")]\n    [Description(\"Description of the setting.\")]\n    [DefaultValue(true)]\n    public bool MySetting { get; set; } = true;\n}\n```\n\n## MEF Components\n\n### Tagger Providers\n\nUse `[Export]` and appropriate `[ContentType]` attributes:\n\n```csharp\n[Export(typeof(IViewTaggerProvider))]\n[ContentType(\"CSharp\")]\n[ContentType(\"Basic\")]\n[TagType(typeof(IntraTextAdornmentTag))]\n[TextViewRole(PredefinedTextViewRoles.Document)]\ninternal sealed class YourTaggerProvider : IViewTaggerProvider\n{\n    [Import]\n    internal IOutliningManagerService OutliningManagerService { get; set; }\n\n    public ITagger\u003cT\u003e CreateTagger\u003cT\u003e(ITextView textView, ITextBuffer buffer) where T : ITag\n    {\n        if (textView == null || !(textView is IWpfTextView wpfTextView))\n            return null;\n\n        if (textView.TextBuffer != buffer)\n            return null;\n\n        return wpfTextView.Properties.GetOrCreateSingletonProperty(\n            () =\u003e new YourTagger(wpfTextView)) as ITagger\u003cT\u003e;\n    }\n}\n```\n\n### QuickInfo Sources\n\n```csharp\n[Export(typeof(IAsyncQuickInfoSourceProvider))]\n[Name(\"YourQuickInfo\")]\n[ContentType(\"code\")]\n[Order(Before = \"Default Quick Info Presenter\")]\ninternal sealed class YourQuickInfoSourceProvider : IAsyncQuickInfoSourceProvider\n{\n    public IAsyncQuickInfoSource TryCreateQuickInfoSource(ITextBuffer textBuffer)\n    {\n        return textBuffer.Properties.GetOrCreateSingletonProperty(\n            () =\u003e new YourQuickInfoSource(textBuffer));\n    }\n}\n```\n\n### Suggested Actions (Light Bulb)\n\n```csharp\n[Export(typeof(ISuggestedActionsSourceProvider))]\n[Name(\"Your Suggested Actions\")]\n[ContentType(\"text\")]\ninternal sealed class YourSuggestedActionsSourceProvider : ISuggestedActionsSourceProvider\n{\n    public ISuggestedActionsSource CreateSuggestedActionsSource(ITextView textView, ITextBuffer textBuffer)\n    {\n        return new YourSuggestedActionsSource(textView, textBuffer);\n    }\n}\n```\n\n## Threading Guidelines\n\n### Always switch to UI thread for WPF operations\n\n```csharp\nawait ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync(cancellationToken);\n// Now safe to create/modify WPF elements\n```\n\n### Background work\n\n```csharp\nThreadHelper.JoinableTaskFactory.RunAsync(async () =\u003e\n{\n    await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync();\n    await VS.Commands.ExecuteAsync(\"View.TaskList\");\n});\n```\n\n## VSSDK \u0026 Threading Analyzer Rules\n\nExtensions should enforce these analyzer rules. Add to `.editorconfig`:\n\n```ini\ndotnet_diagnostic.VSSDK*.severity = error\ndotnet_diagnostic.VSTHRD*.severity = error\n```\n\n### Performance Rules\n| ID | Rule | Fix |\n|----|------|-----|\n| **VSSDK001** | Derive from `AsyncPackage` | Use `ToolkitPackage` (derives from AsyncPackage) |\n| **VSSDK002** | `AllowsBackgroundLoading = true` | Add to `[PackageRegistration]` |\n\n### Threading Rules (VSTHRD)\n| ID | Rule | Fix |\n|----|------|-----|\n| **VSTHRD001** | Avoid `.Wait()` | Use `await` |\n| **VSTHRD002** | Avoid `JoinableTaskFactory.Run` | Use `RunAsync` or `await` |\n| **VSTHRD010** | COM calls require UI thread | `await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync()` |\n| **VSTHRD100** | No `async void` | Use `async Task` |\n| **VSTHRD110** | Observe async results | `await task;` or suppress with pragma |\n\n## Visual Studio Theming\n\n**All UI must respect VS themes (Light, Dark, Blue, High Contrast)**\n\n### WPF Theming with Environment Colors\n\n```xml\n\u003c!-- MyControl.xaml --\u003e\n\u003cUserControl x:Class=\"MyExt.MyControl\"\n             xmlns:vsui=\"clr-namespace:Microsoft.VisualStudio.PlatformUI;assembly=Microsoft.VisualStudio.Shell.15.0\"\u003e\n    \u003cGrid Background=\"{DynamicResource {x:Static vsui:EnvironmentColors.ToolWindowBackgroundBrushKey}}\"\u003e\n        \u003cTextBlock Foreground=\"{DynamicResource {x:Static vsui:EnvironmentColors.ToolWindowTextBrushKey}}\"\n                   Text=\"Hello, themed world!\" /\u003e\n    \u003c/Grid\u003e\n\u003c/UserControl\u003e\n```\n\n### Toolkit Auto-Theming (Recommended)\n\nThe toolkit provides automatic theming for WPF UserControls:\n\n```xml\n\u003cUserControl x:Class=\"MyExt.MyUserControl\"\n             xmlns=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\"\n             xmlns:x=\"http://schemas.microsoft.com/winfx/2006/xaml\"\n             xmlns:toolkit=\"clr-namespace:Community.VisualStudio.Toolkit;assembly=Community.VisualStudio.Toolkit\"\n             toolkit:Themes.UseVsTheme=\"True\"\u003e\n    \u003c!-- Controls automatically get VS styling --\u003e\n\u003c/UserControl\u003e\n```\n\nFor dialog windows, use `DialogWindow`:\n\n```xml\n\u003cplatform:DialogWindow\n    x:Class=\"MyExt.MyDialog\"\n    xmlns:platform=\"clr-namespace:Microsoft.VisualStudio.PlatformUI;assembly=Microsoft.VisualStudio.Shell.15.0\"\n    xmlns:toolkit=\"clr-namespace:Community.VisualStudio.Toolkit;assembly=Community.VisualStudio.Toolkit\"\n    toolkit:Themes.UseVsTheme=\"True\"\u003e\n\u003c/platform:DialogWindow\u003e\n```\n\n### Common Theme Color Tokens\n\n| Category | Token | Usage |\n|----------|-------|-------|\n| **Background** | `EnvironmentColors.ToolWindowBackgroundBrushKey` | Window/panel background |\n| **Foreground** | `EnvironmentColors.ToolWindowTextBrushKey` | Text |\n| **Command Bar** | `EnvironmentColors.CommandBarTextActiveBrushKey` | Menu items |\n| **Links** | `EnvironmentColors.ControlLinkTextBrushKey` | Hyperlinks |\n\n### Theme-Aware Icons\n\nUse `KnownMonikers` from the VS Image Catalog for theme-aware icons:\n\n```csharp\npublic ImageMoniker IconMoniker =\u003e KnownMonikers.Settings;\n```\n\nIn VSCT:\n```xml\n\u003cIcon guid=\"ImageCatalogGuid\" id=\"Settings\"/\u003e\n\u003cCommandFlag\u003eIconIsMoniker\u003c/CommandFlag\u003e\n```\n\n## Common VS SDK APIs\n\n### VS Helper Methods (Community.VisualStudio.Toolkit)\n\n```csharp\n// Status bar\nawait VS.StatusBar.ShowMessageAsync(\"Message\");\nawait VS.StatusBar.ShowProgressAsync(\"Working...\", currentStep, totalSteps);\n\n// Solution/Projects\nSolution solution = await VS.Solutions.GetCurrentSolutionAsync();\nIEnumerable\u003cSolutionItem\u003e items = await VS.Solutions.GetActiveItemsAsync();\nbool isOpen = await VS.Solutions.IsOpenAsync();\n\n// Documents\nDocumentView docView = await VS.Documents.GetActiveDocumentViewAsync();\nstring text = docView?.TextBuffer?.CurrentSnapshot.GetText();\nawait VS.Documents.OpenAsync(fileName);\nawait VS.Documents.OpenInPreviewTabAsync(fileName);\n\n// Commands\nawait VS.Commands.ExecuteAsync(\"View.TaskList\");\n\n// Settings\nawait VS.Settings.OpenAsync\u003cOptionsProvider.GeneralOptions\u003e();\n\n// Messages\nawait VS.MessageBox.ShowAsync(\"Title\", \"Message\");\nawait VS.MessageBox.ShowErrorAsync(\"Extension Name\", ex.ToString());\n\n// Events\nVS.Events.SolutionEvents.OnAfterOpenProject += OnAfterOpenProject;\nVS.Events.DocumentEvents.Saved += OnDocumentSaved;\n```\n\n### Working with Settings\n\n```csharp\n// Read settings synchronously\nvar value = General.Instance.MyOption;\n\n// Read settings asynchronously\nvar general = await General.GetLiveInstanceAsync();\nvar value = general.MyOption;\n\n// Write settings\nGeneral.Instance.MyOption = newValue;\nGeneral.Instance.Save();\n\n// Or async\ngeneral.MyOption = newValue;\nawait general.SaveAsync();\n\n// Listen for settings changes\nGeneral.Saved += OnSettingsSaved;\n```\n\n### Text Buffer Operations\n\n```csharp\n// Get snapshot\nITextSnapshot snapshot = textBuffer.CurrentSnapshot;\n\n// Get line\nITextSnapshotLine line = snapshot.GetLineFromLineNumber(lineNumber);\nstring lineText = line.GetText();\n\n// Create tracking span\nITrackingSpan trackingSpan = snapshot.CreateTrackingSpan(span, SpanTrackingMode.EdgeInclusive);\n\n// Edit buffer\nusing (ITextEdit edit = textBuffer.CreateEdit())\n{\n    edit.Replace(span, newText);\n    edit.Apply();\n}\n\n// Insert at caret position\nDocumentView docView = await VS.Documents.GetActiveDocumentViewAsync();\nif (docView?.TextView != null)\n{\n    SnapshotPoint position = docView.TextView.Caret.Position.BufferPosition;\n    docView.TextBuffer?.Insert(position, \"text to insert\");\n}\n```\n\n## VSCT Command Table\n\n### Menu/Command Structure\n\n```xml\n\u003cCommands package=\"YourPackage\"\u003e\n  \u003cMenus\u003e\n    \u003cMenu guid=\"YourPackage\" id=\"SubMenu\" type=\"Menu\"\u003e\n      \u003cParent guid=\"YourPackage\" id=\"MenuGroup\"/\u003e\n      \u003cStrings\u003e\n        \u003cButtonText\u003eMenu Name\u003c/ButtonText\u003e\n        \u003cCommandName\u003eMenu Name\u003c/CommandName\u003e\n        \u003cCanonicalName\u003e.YourExtension.MenuName\u003c/CanonicalName\u003e\n      \u003c/Strings\u003e\n    \u003c/Menu\u003e\n  \u003c/Menus\u003e\n\n  \u003cGroups\u003e\n    \u003cGroup guid=\"YourPackage\" id=\"MenuGroup\" priority=\"0x0600\"\u003e\n      \u003cParent guid=\"guidSHLMainMenu\" id=\"IDM_VS_CTXT_CODEWIN\"/\u003e\n    \u003c/Group\u003e\n  \u003c/Groups\u003e\n\n  \u003cButtons\u003e\n    \u003cButton guid=\"YourPackage\" id=\"CommandId\" type=\"Button\"\u003e\n      \u003cParent guid=\"YourPackage\" id=\"MenuGroup\"/\u003e\n      \u003cIcon guid=\"ImageCatalogGuid\" id=\"Settings\"/\u003e\n      \u003cCommandFlag\u003eIconIsMoniker\u003c/CommandFlag\u003e\n      \u003cCommandFlag\u003eDynamicVisibility\u003c/CommandFlag\u003e\n      \u003cStrings\u003e\n        \u003cButtonText\u003eCommand Name\u003c/ButtonText\u003e\n        \u003cCanonicalName\u003e.YourExtension.CommandName\u003c/CanonicalName\u003e\n      \u003c/Strings\u003e\n    \u003c/Button\u003e\n  \u003c/Buttons\u003e\n\u003c/Commands\u003e\n\n\u003cSymbols\u003e\n  \u003cGuidSymbol name=\"YourPackage\" value=\"{guid-here}\"\u003e\n    \u003cIDSymbol name=\"MenuGroup\" value=\"0x0001\"/\u003e\n    \u003cIDSymbol name=\"CommandId\" value=\"0x0100\"/\u003e\n  \u003c/GuidSymbol\u003e\n\u003c/Symbols\u003e\n```\n\n## Best Practices\n\n### 1. Performance\n\n- Check file/buffer size before processing large documents\n- Use `NormalizedSnapshotSpanCollection` for efficient span operations\n- Cache parsed results when possible\n- Use `ConfigureAwait(false)` in library code\n\n```csharp\n// Skip large files\nif (buffer.CurrentSnapshot.Length \u003e 150000)\n    return null;\n```\n\n### 2. Error Handling\n\n- Wrap external operations in try-catch\n- Log errors appropriately\n- Never let exceptions crash VS\n\n```csharp\ntry\n{\n    // Operation\n}\ncatch (Exception ex)\n{\n    await ex.LogAsync();\n}\n```\n\n### 3. Disposable Resources\n\n- Implement `IDisposable` on taggers and other long-lived objects\n- Unsubscribe from events in Dispose\n\n```csharp\npublic void Dispose()\n{\n    if (!_isDisposed)\n    {\n        _buffer.Changed -= OnBufferChanged;\n        _isDisposed = true;\n    }\n}\n```\n\n### 4. Content Types\n\nCommon content types for `[ContentType]` attribute:\n- `\"text\"` - All text files\n- `\"code\"` - All code files\n- `\"CSharp\"` - C# files\n- `\"Basic\"` - VB.NET files\n- `\"CSS\"`, `\"LESS\"`, `\"SCSS\"` - Style files\n- `\"TypeScript\"`, `\"JavaScript\"` - Script files\n- `\"HTML\"`, `\"HTMLX\"` - HTML files\n- `\"XML\"` - XML files\n- `\"JSON\"` - JSON files\n\n### 5. Images and Icons\n\nUse `KnownMonikers` from the VS Image Catalog:\n\n```csharp\npublic ImageMoniker IconMoniker =\u003e KnownMonikers.Settings;\n```\n\nIn VSCT:\n```xml\n\u003cIcon guid=\"ImageCatalogGuid\" id=\"Settings\"/\u003e\n\u003cCommandFlag\u003eIconIsMoniker\u003c/CommandFlag\u003e\n```\n\n## Testing\n\n- Use `[VsTestMethod]` for tests requiring VS context\n- Mock VS services when possible\n- Test business logic separately from VS integration\n\n## Common Pitfalls\n\n| Pitfall | Solution |\n|---------|----------|\n| Blocking UI thread | Always use `async`/`await` |\n| Creating WPF on background thread | Call `SwitchToMainThreadAsync()` first |\n| Ignoring cancellation tokens | Pass them through async chains |\n| VSCommandTable.cs mismatch | Regenerate after VSCT changes |\n| Hardcoded GUIDs | Use `PackageGuids` and `PackageIds` constants |\n| Swallowing exceptions | Log with `await ex.LogAsync()` |\n| Missing DynamicVisibility | Required for `BeforeQueryStatus` to work |\n| Using `.Result`, `.Wait()` | Causes deadlocks; always `await` |\n| Hardcoded colors | Use VS theme colors (`EnvironmentColors`) |\n| `async void` methods | Use `async Task` instead |\n\n## Validation\n\nBuild and verify the extension:\n\n```bash\nmsbuild /t:rebuild\n```\n\nEnsure analyzers are enabled in `.editorconfig`:\n\n```ini\ndotnet_diagnostic.VSSDK*.severity = error\ndotnet_diagnostic.VSTHRD*.severity = error\n```\n\nTest in VS Experimental Instance before release.\n\n## NuGet Packages\n\n| Package | Purpose |\n|---------|---------|\n| `Community.VisualStudio.Toolkit.17` | Simplifies VS extension development |\n| `Microsoft.VisualStudio.SDK` | Core VS SDK |\n| `Microsoft.VSSDK.BuildTools` | Build tools for VSIX |\n| `Microsoft.VisualStudio.Threading.Analyzers` | Threading analyzers |\n| `Microsoft.VisualStudio.SDK.Analyzers` | VSSDK analyzers |\n\n## Resources\n\n- [Community.VisualStudio.Toolkit](https://github.com/VsixCommunity/Community.VisualStudio.Toolkit)\n- [VS Extensibility Docs](https://learn.microsoft.com/en-us/visualstudio/extensibility/)\n- [VSIX Community Samples](https://github.com/VsixCommunity/Samples)\n\n## README and Marketplace Presentation\n\nA good README works on both GitHub and the VS Marketplace. The Marketplace uses the README.md as the extension's description page.\n\n### README Structure\n\n```markdown\n[marketplace]: https://marketplace.visualstudio.com/items?itemName=Publisher.ExtensionName\n[repo]: https://github.com/user/repo\n\n# Extension Name\n\n[![Build](https://github.com/user/repo/actions/workflows/build.yaml/badge.svg)](...)\n[![Visual Studio Marketplace Version](https://img.shields.io/visual-studio-marketplace/v/Publisher.ExtensionName)][marketplace]\n[![Visual Studio Marketplace Downloads](https://img.shields.io/visual-studio-marketplace/d/Publisher.ExtensionName)][marketplace]\n\nDownload this extension from the [Visual Studio Marketplace][marketplace]\nor get the [CI build](http://vsixgallery.com/extension/ExtensionId/).\n\n--------------------------------------\n\n**Hook line that sells the extension in one sentence.**\n\n![Screenshot](art/screenshot.png)\n\n## Features\n\n### Feature 1\nDescription with screenshot...\n\n## How to Use\n...\n\n## License\n[Apache 2.0](LICENSE)\n```\n\n### README Best Practices\n\n| Element | Guideline |\n|---------|-----------|\n| **Title** | Use the same name as `DisplayName` in vsixmanifest |\n| **Hook line** | Bold, one-sentence value proposition immediately after badges |\n| **Screenshots** | Place in `/art` folder, use relative paths (`art/image.png`) |\n| **Image sizes** | Keep under 1MB, 800-1200px wide for clarity |\n| **Badges** | Version, downloads, rating, build status |\n| **Feature sections** | Use H3 (`###`) with screenshots for each major feature |\n| **Keyboard shortcuts** | Format as **Ctrl+M, Ctrl+C** (bold) |\n| **Tables** | Great for comparing options or listing features |\n| **Links** | Use reference-style links at top for cleaner markdown |\n\n### VSIX Manifest (source.extension.vsixmanifest)\n\n```xml\n\u003cMetadata\u003e\n  \u003cIdentity Id=\"ExtensionName.guid-here\" Version=\"1.0.0\" Language=\"en-US\" Publisher=\"Your Name\" /\u003e\n  \u003cDisplayName\u003eExtension Name\u003c/DisplayName\u003e\n  \u003cDescription xml:space=\"preserve\"\u003eShort, compelling description under 200 chars. This appears in search results and the extension tile.\u003c/Description\u003e\n  \u003cMoreInfo\u003ehttps://github.com/user/repo\u003c/MoreInfo\u003e\n  \u003cLicense\u003eResources\\LICENSE.txt\u003c/License\u003e\n  \u003cIcon\u003eResources\\Icon.png\u003c/Icon\u003e\n  \u003cPreviewImage\u003eResources\\Preview.png\u003c/PreviewImage\u003e\n  \u003cTags\u003ekeyword1, keyword2, keyword3\u003c/Tags\u003e\n\u003c/Metadata\u003e\n```\n\n### Manifest Best Practices\n\n| Element | Guideline |\n|---------|-----------|\n| **DisplayName** | 3-5 words, no \"for Visual Studio\" (implied) |\n| **Description** | Under 200 chars, focus on value not features. Appears in search tiles |\n| **Tags** | 5-10 relevant keywords, comma-separated, helps discoverability |\n| **Icon** | 128x128 or 256x256 PNG, simple design visible at small sizes |\n| **PreviewImage** | 200x200 PNG, can be same as Icon or a feature screenshot |\n| **MoreInfo** | Link to GitHub repo for documentation and issues |\n\n### Writing Tips\n\n1. **Lead with benefits, not features** - \"Stop wrestling with XML comments\" beats \"XML comment formatter\"\n2. **Show, don't tell** - Screenshots are more convincing than descriptions\n3. **Use consistent terminology** - Match terms between README, manifest, and UI\n4. **Keep the description scannable** - Short paragraphs, bullet points, tables\n5. **Include keyboard shortcuts** - Users love productivity tips\n6. **Add a \"Why\" section** - Explain the problem before the solution\n","description":"Guidelines for Visual Studio extension (VSIX) development using Community.VisualStudio.Toolkit","import":{"commit_sha":"541b7819d8c3545c6df122491af4fa1eae415779","imported_at":"2026-05-18T20:05:35Z","license_text":"MIT License\n\nCopyright GitHub, Inc.\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.","owner":"github","repo":"github/awesome-copilot","source_url":"https://github.com/github/awesome-copilot/blob/541b7819d8c3545c6df122491af4fa1eae415779/instructions/vsixtoolkit.instructions.md"},"manifest":{}},"content_hash":[124,194,135,142,71,211,40,62,140,171,79,67,157,196,183,152,207,129,46,187,253,153,43,67,19,162,91,141,127,197,122,203],"trust_level":"unsigned","yanked":false}
