Free SKILL.md scraped from GitHub. Clone the repo or copy the file directly into your Claude Code skills directory.
npx versuz@latest install add-fallback-commandsgit clone https://github.com/microsoft/PowerToys.gitcp PowerToys/src/modules/cmdpal/ExtensionTemplate/TemplateCmdPalExtension/.github/skills/add-fallback-commands/SKILL.md ~/.claude/skills/add-fallback-commands/SKILL.md---
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)