This document describes the conventions for implementing command-line interfaces (CLI) in PowerToys modules.
Use the System.CommandLine library for CLI argument parsing. This is already defined in Directory.Packages.props:
<PackageReference Include="System.CommandLine" Version="2.0.0-beta4.22272.1" />Add the reference to your project:
<PackageReference Include="System.CommandLine" />- Use
--kebab-casefor long form (e.g.,--shrink-only). - Use single
-xfor short form (e.g.,-s,-w). - Define aliases as static readonly arrays:
["--silent", "-s"]. - Create options using
Option<T>with descriptive help text. - Add validators for options that require range or format checking.
- Create a
RootCommandwith a brief description. - Add all options and arguments to the command.
- Use
Parser(rootCommand).Parse(args)to parse CLI arguments. - Extract option values using
parseResult.GetValueForOption(). - Note: Use
Parserdirectly;RootCommand.Parse()may not be available with the pinned System.CommandLine version.
- On parse/validation errors, print error messages and usage, then exit with non-zero code.
Reference implementations:
- Awake:
src/modules/Awake/Awake/Program.cs - ImageResizer:
src/modules/imageresizer/ui/Cli/
- Provide a
PrintUsage()method for custom help formatting if needed.
- Consistency: Follow existing module patterns.
- Documentation: Always provide help text for each option.
- Validation: Validate input and provide clear error messages.
- Atomicity: Make one logical change per PR; avoid drive-by refactors.
- Build/Test Discipline: Build and test synchronously, one terminal per operation.
- Style: Follow repo analyzers (
.editorconfig, StyleCop) and formatting rules.
- Use
ManagedCommon.Loggerfor consistent logging. - Initialize logging early in
Main(). - Use dual output (console + log file) for errors and warnings to ensure visibility.
- Reference:
src/modules/imageresizer/ui/Cli/CliLogger.cs
0: Success1: General error (parsing, validation, runtime)2: Invalid arguments (optional)
- Always wrap
Main()in try-catch for unhandled exceptions. - Log exceptions before exiting with non-zero code.
- Display user-friendly error messages to stderr.
- Preserve detailed stack traces in log files only.
- Include tests for argument parsing, validation, and edge cases.
- Place CLI tests in module-specific test projects (e.g.,
src/modules/[module]/tests/*CliTests.cs).
- CLI executables are signed automatically in CI/CD.
- New CLI tools: Add your executable and dll to
.pipelines/ESRPSigning_core.jsonin the signing list. - CLI executables are deployed alongside their parent module (e.g.,
C:\Program Files\PowerToys\modules\[ModuleName]\). - Use self-contained deployment (import
Common.SelfContained.props).