Skill v1.0.0
Trusted Publisher100/100version: "1.0.0" 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
- User types a query in Command Palette
- If no top-level commands match, CmdPal asks extensions for fallback results
- Your extension's
FallbackCommands()provides items that respond to the query - The fallback items can be static (always shown) or dynamic (filtered by query)
Quick Start: Static Fallback
Override FallbackCommands() in your CommandProvider:
public partial class MyCommandsProvider : CommandProvider{private readonly ICommandItem[] _commands;private readonly FallbackCommandItem[] _fallbacks;public MyCommandsProvider(){DisplayName = "Web Search";Icon = new IconInfo("\uE721"); // Search iconvar 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:
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 typingawait 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 periodicallyreturn [];}}
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()returnsIFallbackCommandItem[](notICommandItem[])- Use
FallbackCommandItemwrapper (notCommandItem) - Wrap a
DynamicListPagefor query-reactive results - Cancel previous searches when new input arrives
- Keep fallback responses fast — users expect instant results
- Use
PlaceholderTexton your page to guide users