Labsco
microsoft logo

add-fallback-commands

✓ Official136,050

by microsoft · part of microsoft/powertoys

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.

🧰 Not standalone. This skill ships with microsoft/powertoys and only works together with that tool — install the tool first, then add this skill.

This is the playbook your agent receives when the skill activates — you don't need to read it to use the skill, but it's here to audit before installing.

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)

Dynamic Fallback with DynamicListPage

For fallbacks that filter results based on the query, use DynamicListPage:

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:

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)

ExtensionFallback Behavior
AppsSearch installed applications by name
CalcEvaluate mathematical expressions directly
ShellExecute command-line commands
WebSearchSearch the web with configured engine
IndexerOpen files by path
TimeDateParse time/date queries
WindowsSettingsJump to Windows Settings pages
WinGetSearch WinGet packages
WindowWalkerFind 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