| 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");
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:
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)
{
_cts?.Cancel();
_cts = new CancellationTokenSource();
var token = _cts.Token;
_ = Task.Run(async () =>
{
await Task.Delay(300, token);
if (token.IsCancellationRequested) return;
_results = await SearchAsync(newSearch, token);
RaiseItemsChanged();
}, token);
}
public override IListItem[] GetItems() => _results;
private async Task<IListItem[]> SearchAsync(string query, CancellationToken token)
{
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