Skill

SkillsSoftware Development › Dev workflow & Git

add-fallback-commands

Add fallback commands to your Command Palette extension for catch-all search behavior. Use when asked to add search functionality, query matching, direct input handling, calculator-style evaluation, URL opening, command execution, or results that appear when no other extension matches. Used by 14 of 20 built-in extensions.

Freerisk: low
addfallbackcommands

The full skill

— name: add-fallback-commands description: >- Add fallback commands to your Command Palette extension for catch-all search behavior. Use when asked to add search functionality, query matching, direct input handling, calculator-style evaluation, URL opening, command execution, or results that appear when no other extension matches. Used by 14 of 20 built-in extensions. — # Add Fallback Commands Fallback commands are shown in Command Palette when no other results match the user's query. They enable your extension to act as a catch-all handler — perfect for calculators, web search, command execution, file path opening, and more. ## When to Use This Skill – Adding search functionality that responds to any user input – Creating a calculator that evaluates expressions as the user types – Building a web search that triggers on unmatched queries – Opening files or URLs typed directly into the palette – Executing shell commands from the search bar ## How Fallback Commands Work 1. User types a query in Command Palette 2. If no top-level commands match, CmdPal asks extensions for fallback results 3. Your extension's `FallbackCommands()` provides items that respond to the query 4. The fallback items can be static (always shown) or dynamic (filtered by query) ## Quick Start: Static Fallback Override `FallbackCommands()` in your `CommandProvider`: “`csharp public partial class MyCommandsProvider : CommandProvider { private readonly ICommandItem[] _commands; private readonly FallbackCommandItem[] _fallbacks; public MyCommandsProvider() { DisplayName = "Web Search"; Icon = new IconInfo("\uE721"); // Search icon var searchPage = new WebSearchPage(); _commands = [new CommandItem(searchPage) { Title = DisplayName }]; _fallbacks = [new FallbackCommandItem(searchPage) { Title = "Search the web" }]; } public override ICommandItem[] TopLevelCommands() => _commands; public override IFallbackCommandItem[] FallbackCommands() => _fallbacks; } “` ## Dynamic Fallback with DynamicListPage For fallbacks that filter results based on the query, use `DynamicListPage`: “`csharp internal sealed partial class WebSearchPage : DynamicListPage { private string _query = string.Empty; public WebSearchPage() { Icon = new IconInfo("\uE721"); Title = "Web Search"; Name = "Search"; PlaceholderText = "Type to search…"; } public override void UpdateSearchText(string oldSearch, string newSearch) { _query = newSearch; RaiseItemsChanged(); } public override IListItem[] GetItems() { if (string.IsNullOrWhiteSpace(_query)) return []; return [ new ListItem(new OpenUrlCommand($"https://www.google.com/search?q={Uri.EscapeDataString(_query)}")) { Title = $"Search Google for \"{_query}\"", Icon = new IconInfo("\uE721"), }, new ListItem(new OpenUrlCommand($"https://www.bing.com/search?q={Uri.EscapeDataString(_query)}")) { Title = $"Search Bing for \"{_query}\"", Icon = new IconInfo("\uE721"), }, ]; } } “` ## Responsive Fallback with Cancellation For expensive operations (API calls, file searches), use cancellation to stay responsive: “`csharp internal sealed partial class SmartSearchPage : DynamicListPage { private CancellationTokenSource? _cts; private IListItem[] _results = []; public override void UpdateSearchText(string oldSearch, string newSearch) { // Cancel any in-flight search _cts?.Cancel(); _cts = new CancellationTokenSource(); var token = _cts.Token; _ = Task.Run(async () => { // Debounce: wait for user to stop typing await Task.Delay(300, token); if (token.IsCancellationRequested) return; // Perform search _results = await SearchAsync(newSearch, token); RaiseItemsChanged(); }, token); } public override IListItem[] GetItems() => _results; private async Task<IListItem[]> SearchAsync(string query, CancellationToken token) { // Your search logic here // Check token.IsCancellationRequested periodically return []; } } “` ## Real-World Examples (from built-in extensions) | Extension | Fallback Behavior | |———–|——————| | **Apps** | Search installed applications by name | | **Calc** | Evaluate mathematical expressions directly | | **Shell** | Execute command-line commands | | **WebSearch** | Search the web with configured engine | | **Indexer** | Open files by path | | **TimeDate** | Parse time/date queries | | **WindowsSettings** | Jump to Windows Settings pages | | **WinGet** | Search WinGet packages | | **WindowWalker** | Find and switch to open windows | ## Key Points – `FallbackCommands()` returns `IFallbackCommandItem[]` (not `ICommandItem[]`) – Use `FallbackCommandItem` wrapper (not `CommandItem`) – Wrap a `DynamicListPage` for query-reactive results – Cancel previous searches when new input arrives – Keep fallback responses fast — users expect instant results – Use `PlaceholderText` on your page to guide users ## Documentation – [Extension samples](https://learn.microsoft.com/windows/powertoys/command-palette/samples) – [Extensibility overview](https://learn.microsoft.com/windows/powertoys/command-palette/extensibility-overview)