## Summary of the Pull Request Adds the **Extension Gallery** to Command Palette — a built-in page where users can discover, browse, and install community extensions without leaving the app. https://github.com/user-attachments/assets/e4565333-b970-4085-9e40-5cfd207e533b ## How it works ### 1. The extension author's side Extensions are listed in the external repo **[`microsoft/CmdPal-Extensions`](https://github.com/microsoft/CmdPal-Extensions)**. To get an extension into the in-app gallery, an author opens a PR there that adds a single entry to `extensions.json`. Nothing in PowerToys itself needs to change. A typical entry looks like: ```json { "id": "contoso.sample", "title": "Sample Extension", "description": "Short blurb shown in the list and detail view.", "author": { "name": "Contoso", "url": "https://github.com/contoso" }, "homepage": "https://github.com/contoso/sample", "iconUrl": "https://.../icon.png", "screenshotUrls": ["https://.../screenshot-1.png"], "tags": ["sample"], "installSources": [ { "type": "winget", "id": "Contoso.SampleExtension" }, { "type": "msstore", "id": "9P..." }, { "type": "url", "uri": "https://github.com/contoso/sample/releases/latest" } ], "detection": { "packageFamilyName": "Contoso.SampleExtension_8wekyb..." } } ``` - `id`, `title`, `description`, `author.name`, and at least one `installSources` entry are required; everything else is optional. - `installSources` can mix and match `winget` / `msstore` / `url`. The gallery shows an install button for the first source it can handle (WinGet preferred) and exposes any remaining sources as links. - `detection.packageFamilyName` lets CmdPal recognise an already-installed packaged extension before any WinGet lookup resolves, so the "Installed" badge appears instantly. Once the PR is merged into `CmdPal-Extensions`, every running copy of CmdPal picks the new entry up the next time its feed cache expires (within 4 hours) or when the user clicks **Refresh**. ### 2. What CmdPal does with it `ExtensionGalleryService` (in `Microsoft.CmdPal.Common`) owns the whole pipeline: 1. **Resolve the feed URL.** Default is `https://raw.githubusercontent.com/microsoft/CmdPal-Extensions/refs/heads/main/extensions.json`. A hidden setting (`GalleryFeedUrl`) lets developers point at a custom URL or a `file://` path for local testing. 2. **Fetch** the feed through `ExtensionGalleryHttpClient`, which wraps `HttpCachingClient` — a conditional-GET + on-disk cache layer built on `HttpClient` (ETag / `If-None-Match`, 30 s timeout, UA `PowerToys-CmdPal/1.0`). 3. **Parse** with the source-generated `GallerySerializationContext` into a strongly-typed `GalleryRemoteIndex` (`{ "extensions": [ ... ] }`). Entries without an `id` are dropped. 4. **Normalize** relative `iconUrl` / `screenshotUrls` against the feed URL (useful for local `file://` feeds). 5. **Localize icons.** Each HTTP icon URL is pulled through the same cache and rewritten to a local `file://` URI before the view model binds to it, so the list renders instantly on subsequent loads and works offline. 6. **Prune** cached resources that are no longer referenced, but only after a successful forced refresh. The gallery page itself is built on top of `ExtensionGalleryViewModel`, with `ExtensionGalleryItemViewModel` handling per-entry concerns — install/update/uninstall (via the shared WinGet service), installed-state detection, and joining in-flight install progress so the global `WinGetOperationsButton` in the top bar stays in sync. ### 3. Caching + offline behaviour The cache lives under `ApplicationData.Current.LocalCacheFolder\GalleryCache\` when CmdPal runs packaged, or `%LOCALAPPDATA%\Microsoft\PowerToys\Microsoft.CmdPal\Cache\GalleryCache\` when unpackaged. | Resource | TTL | |-----------------|----------| | `extensions.json` feed | 4 hours | | Icons (per URL) | 24 hours | Each fetch returns a `GalleryFetchResult` whose flags drive the UI: - `FromCache` — cache was still fresh, no network call was made. - `UsedFallbackCache` — network failed; the last-known-good cached copy was served instead. The page shows a "showing cached data" info bar. - `RateLimited` — origin returned `429` and no fallback was available. The page shows a rate-limit error. `RefreshAsync` (wired up to the gallery's refresh button) forces a fresh conditional GET, then prunes any cached files that the new feed no longer references. ### 4. WinGet install flow - `installSources[type=winget].id` is handed to the shared WinGet service for install/update/uninstall. - In-flight operations are surfaced by `WinGetOperationsButton` in the top bar with per-operation progress. - `detection.packageFamilyName` is consulted first so that the gallery can show "Installed" / "Update available" without waiting on WinGet metadata. ### Top-level command cleanup - Removed the separate "Find extensions from WinGet" and "Find extensions from the Store" top-level commands — the gallery replaces both. - Renamed the gallery command to **"Find and install Command Palette extensions"** and gave it the extensions puzzle-piece icon. ## PR Checklist - [ ] **Communication:** I've discussed this with core contributors already. If the work hasn't been agreed, this work might be rejected - [ ] **Tests:** Added/updated and all pass - [ ] **Localization:** All end-user-facing strings can be localized - [ ] **Dev docs:** Added/updated - [ ] **New binaries:** Added on the required places - [ ] [JSON for signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json) for new binaries - [ ] [WXS for installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs) for new binaries and localization folder - [ ] [YML for CI pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml) for new test projects - [ ] [YML for signed pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml) - [ ] **Documentation updated:** If checked, please file a pull request on [our docs repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys) and link it here: #xxx ## New projects / areas | Area | What | |------|------| | Microsoft.CmdPal.Common | Gallery models, `ExtensionGalleryService` (fetch + cache), HTTP caching layer (`HttpCachingClient`, `FileSystemHttpResourceCacheStore`), WinGet service abstractions and implementations | | Microsoft.CmdPal.UI.ViewModels | `ExtensionGalleryViewModel`, `ExtensionGalleryItemViewModel`, WinGet operation view models, gallery sort options | | Microsoft.CmdPal.UI | `ExtensionGalleryPage.xaml`, `ExtensionGalleryItemPage.xaml`, `IconCarouselControl`, `WinGetOperationsButton`, service registrations | | Microsoft.CmdPal.Ext.WinGet | Streamlined — removed the two redundant "find extensions" top-level commands, kept the general WinGet search page | | Tests | Unit tests for gallery service, gallery view models, WinGet services | | Docs | [`doc/devdocs/modules/cmdpal/extension-gallery/extension-gallery.md`](https://github.com/microsoft/PowerToys/blob/dev/jpolasek/f/46628-cmdpal-extension-gallery/doc/devdocs/modules/cmdpal/extension-gallery/extension-gallery.md) — dev reference for the runtime, caching, and feed shape | ## Validation Steps Performed - Gallery loads and displays extensions from the remote index - Search, sort, and filtering work as expected - WinGet install/update/uninstall flow works end-to-end with progress tracking - Loading state correctly hides all content until data is fetched - Offline / cache-fallback path surfaces the info bar as expected - Spell-check CI workflow passes --------- Co-authored-by: Niels Laute <niels.laute@live.nl> Co-authored-by: niels9001 <9866362+niels9001@users.noreply.github.com>
PowerToys Developer Documentation
Welcome to the PowerToys developer documentation. This documentation provides information for developers who want to contribute to PowerToys or understand how it works.
Getting Started
Prerequisites
- Windows 10 April 2018 Update (version 1803) or newer
- Visual Studio 2026 (recommended) or Visual Studio 2022 17.4+ with the following workloads/components:
- Desktop Development with C++
- WinUI application development
- .NET desktop development
- Windows 10 SDK (10.0.22621.0)
- Windows 11 SDK (10.0.26100.3916)
- .NET 8 SDK
- Enable long paths in Windows (see Enable Long Paths for details)
Tip: You can install Visual Studio with all required workloads automatically using the WinGet configuration files in the repository:
winget configure .config\configuration.wingetPick the file that matches your VS edition (e.g.,
configuration.vsProfessional.wingetorconfiguration.vsEnterprise.winget).
Fork, Clone, and Set Up
- Fork the repo on GitHub if you haven't already
- Clone your fork locally
- Run the automated setup script (recommended):
.\tools\build\setup-dev-environment.ps1
This script will:
- Enable Windows long path support (requires administrator privileges)
- Enable Windows Developer Mode (requires administrator privileges)
- Guide you through installing required Visual Studio components from
.vsconfig - Initialize git submodules
Run with -Help to see all available options.
Manual setup (if you prefer not to use the script)
Install Visual Studio dependencies
- Open the
PowerToys.slnxfile. - If you see a dialog that says
install extra componentsin the solution explorer pane, clickinstall
Alternatively, import the .vsconfig file from the repository root using Visual Studio Installer to install all required workloads.
Initialize submodules
This is a one-time step required before you can compile most parts of PowerToys.
- Open a terminal
- Navigate to the folder you cloned PowerToys to.
- Run
git submodule update --init --recursive
Building
Using Visual Studio
- Open
PowerToys.slnxin Visual Studio. - In the
Solutions Configurationdrop-down menu selectReleaseorDebug. - From the
Buildmenu chooseBuild Solution, or press Control+Shift+b on your keyboard. - The build process may take several minutes depending on your computer's performance. Once it completes, the PowerToys binaries will be in your repo under
x64\Release\.- You can run
x64\Release\PowerToys.exedirectly without installing PowerToys, but some modules (i.e. PowerRename, ImageResizer, File Explorer extension etc.) will not be available unless you also build the installer and install PowerToys.
- You can run
Using Command Line
You can also build from the command line using the provided scripts in tools\build\:
# Build the full solution (auto-detects platform)
.\tools\build\build.ps1
# Build with specific configuration
.\tools\build\build.ps1 -Platform x64 -Configuration Release
# Build only essential projects (runner + settings) for faster iteration
.\tools\build\build-essentials.ps1
# Build everything including the installer (Release only)
.\tools\build\build-installer.ps1
Debugging
See Debugging for detailed debugging techniques, including Visual Studio setup, attaching to child processes, and troubleshooting build errors.
Creating a New PowerToy
See Creating a New PowerToy for an end-to-end guide covering module architecture, settings integration, installer packaging, and testing.
Building Command Palette Extensions
If you want to build your own extensions for Command Palette, check out the Command Palette extensibility documentation. It covers how to create, package, and distribute custom extensions that integrate with Command Palette.
Development Guidelines
- Coding Guidelines - Development guidelines and best practices
- Coding Style - Code formatting and style conventions
- Logging and Telemetry - How to use logging and telemetry
- Localization - How to support multiple languages
- UI Testing - How to write UI tests for PowerToys
- Developing with VS Code - Build, debug, and contribute using VS Code
Rules
- Follow the pattern of what you already see in the code.
- Coding style.
- Try to package new functionality/components into libraries that have nicely defined interfaces.
- Package new functionality into classes or refactor existing functionality into a class as you extend the code.
- When adding new classes/methods/changing existing code, add new unit tests or update the existing tests.
GitHub Workflow
- Before starting to work on a fix/feature, make sure there is an open issue to track the work.
- Add the
In progresslabel to the issue, if not already present. Also add aCost-Small/Medium/Largeestimate and make sure all appropriate labels are set. - If you are a community contributor, you will not be able to add labels to the issue; in that case just add a comment saying that you have started work on the issue and try to give an estimate for the delivery date.
- If the work item has a medium/large cost, using the markdown task list, list each sub item and update the list with a check mark after completing each sub item.
- Before opening a PR, ensure your changes build successfully locally and functionality tests pass. This is especially important for AI-assisted (vibe coding) contributions—always verify AI-generated code works as intended. Exploratory PRs or draft PRs for discussion are exceptions.
- When opening a PR, follow the PR template.
- When you'd like the team to take a look (even if the work is not yet fully complete) mark the PR as 'Ready For Review' so that the team can review your work and provide comments, suggestions, and request changes. It may take several cycles, but the end result will be solid, testable, conformant code that is safe for us to merge.
- When the PR is approved, let the owner of the PR merge it. For community contributions, the reviewer who approved the PR can also merge it.
- Use the
Squash and mergeoption to merge a PR. If you don't want to squash it because there are logically different commits, useRebase and merge. - Close issues automatically when referenced in a PR. You can use closing keywords in the body of the PR to have GitHub automatically link your PR to the issue.
Core Architecture
- Architecture Overview - Overview of the PowerToys architecture and module interface
- Runner and System tray - Details about the PowerToys Runner process
- Settings - Documentation on the settings system
- Installer - Information about the PowerToys installer
- Modules - Documentation for individual PowerToys modules
Common Components
- Context Menu Handlers - How PowerToys implements and registers Explorer context menu handlers
- Monaco Editor - How PowerToys uses the Monaco code editor component across modules
Tools
- Tools Overview - Overview of tools in PowerToys
- Build Tools - Tools that help building PowerToys
- Bug Report Tool - Tool for collecting logs and system information
- Debugging Tools - Specialized tools for debugging
- Fuzzing Testing - How to implement and run fuzz testing for PowerToys modules
Processes
- Release Process - How PowerToys releases are prepared and published
- Update Process - How PowerToys updates work
- GPO Implementation - Group Policy Objects implementation details
Other Resources
- aka.ms links - List of short links
- Issue/PR commands - Special commands for managing issues and pull requests
Building the Installer
Our installer is two parts, an EXE and an MSI. The EXE (Bootstrapper) contains the MSI and handles more complex installation logic.
- The EXE installs all prerequisites and installs PowerToys via the MSI. It has additional features such as the installation flags (see below).
- The MSI installs the PowerToys binaries.
The installer can only be compiled in Release mode; steps 1 and 2 must be performed before the MSI can be compiled.
- Compile
PowerToys.slnx. Instructions are listed above. - Compile
BugReportTool.slntool. Path from root:tools\BugReportTool\BugReportTool.sln(details listed below) - Compile
StylesReportTool.slntool. Path from root:tools\StylesReportTool\StylesReportTool.sln(details listed below) - Compile
PowerToysSetup.slnxPath from root:installer\PowerToysSetup.slnx(details listed below)
See Installer for more details on building and debugging the installer.