DevToys ships a companion CLI executable (Documentation Index
Fetch the complete documentation index at: https://mintlify.com/DevToys-app/DevToys/llms.txt
Use this file to discover all available pages before exploring further.
devtoys.cli) that exposes tools as sub-commands. Every ICommandLineTool export in an extension becomes a first-class command available from the terminal, complete with typed options, help text, and proper exit codes. The CLI uses the same extension discovery mechanism as the GUI app, so a single .devtoys package can power both experiences.
If you are adding CLI support to an existing extension, skip this step. Otherwise, create a new .NET
net8.0 class library and add the DevToys.Api reference exactly as described in the GUI Tool guide.dotnet new classlib -n MyDevToysExtension -f net8.0
cd MyDevToysExtension
dotnet add package DevToys.Api
InvokeAsync receives an ILogger for telemetry and a CancellationToken that is cancelled when the user interrupts the process. It must return an integer exit code (0 for success, non-zero for failure).[Export(typeof(ICommandLineTool))]
[Name("MyExtension.Base64CLI")]
[CommandName(
Name = "base64",
Alias = "b64",
DescriptionResourceName = nameof(Strings.Base64Description),
ResourceManagerBaseName = "MyDevToysExtension.Strings")]
internal sealed class Base64CommandLineTool : ICommandLineTool
{
public ValueTask<int> InvokeAsync(ILogger logger, CancellationToken cancellationToken)
{
// implementation
return ValueTask.FromResult(0);
}
}
Namebase64). Invoked as devtoys.cli base64 ....Aliasb64). Invoked as devtoys.cli b64 ....DescriptionResourceNameResourceManagerBaseNameEach option the command accepts is a property decorated with
[CommandLineOption]. The property type determines the value type that the CLI parser will coerce — bool, string, FileInfo, int, and other common types are all supported.[CommandLineOption(
Name = "file",
Alias = "f",
IsRequired = true,
DescriptionResourceName = nameof(Strings.FileOptionDescription))]
internal FileInfo? File { get; set; }
[CommandLineOption(
Name = "utf8",
DescriptionResourceName = nameof(Strings.Utf8OptionDescription))]
internal bool Utf8 { get; set; } = true; // default value
CommandLineOption properties (in addition to Name, Alias, and DescriptionResourceName inherited from CommandNameAttribute):Namestring"file" → --file <value>Aliasstring"f" → -f <value>IsRequiredbooltrue, the CLI shows an error if the option is not provided. Default is false.DescriptionResourceNamestringThe integer returned from
InvokeAsync becomes the process exit code. Use 0 for success and a non-zero value for any error condition. The CLI framework propagates this value to the shell.Full Working Example
The following is a complete base64 encode/decode CLI tool, mirroring the canonical example from theICommandLineTool XML documentation:
ConsoleProgressBar
For long-running CLI operations, theConsoleProgressBar class provides an animated in-place progress indicator. It implements IProgress<double> and IDisposable. Call Report(value) with a percentage between 0 and 100. The bar is automatically suppressed when standard output is redirected to a file.
Dual GUI + CLI Extension
A single extension assembly can export both anIGuiTool and an ICommandLineTool for the same feature. This is the recommended pattern — users get a visual tool in the desktop app and a scriptable command in the terminal, without duplicating business logic.
Logging Guidelines
TheILogger passed to InvokeAsync sends telemetry to DevToys. Follow these rules to protect user privacy: