CliFx
Class-first framework for building command-line interfaces
Install / Use
/learn @Tyrrrz/CliFxREADME
CliFx
<table> <tr> <td width="99999" align="center">Development of this project is entirely funded by the community. <b><a href="https://tyrrrz.me/donate">Consider donating to support!</a></b></td> </tr> </table> <p align="center"> <img src="favicon.png" alt="Icon" /> </p>CliFx is a simple to use, yet powerful framework for building command-line applications. Its primary goal is to completely take over the user input layer, allowing you to forget about infrastructural concerns and instead focus on writing your application.
Terms of use<sup>[?]</sup>
By using this project or its source code, for any purpose and in any shape or form, you grant your implicit agreement to all the following statements:
- You condemn Russia and its military aggression against Ukraine
- You recognize that Russia is an occupant that unlawfully invaded a sovereign state
- You support Ukraine's territorial integrity, including its claims over temporarily occupied territories of Crimea and Donbas
- You reject false narratives perpetuated by Russian state propaganda
To learn more about the war and how you can help, click here. Glory to Ukraine! 🇺🇦
Install
- 📦 NuGet:
dotnet add package CliFx
Features
- Complete application framework, not just an argument parser
- Minimum boilerplate and easy to get started
- Class-first configuration via attributes
- Comprehensive auto-generated help text
- Support for deeply nested command hierarchies
- Graceful cancellation via interrupt signals
- Support for reading and writing binary data
- Testable console interaction layer
- Built-in analyzers to catch configuration issues
- Targets .NET Standard 2.0+
- No external dependencies
Screenshots

Usage
Quick overview
To turn your program into a command-line interface, modify the Main() method so that it delegates the execution to an instance of CliApplication.
You can use CliApplicationBuilder to simplify the process of creating and configuring an application:
using CliFx;
public static class Program
{
public static async Task<int> Main() =>
await new CliApplicationBuilder()
.AddCommandsFromThisAssembly()
.Build()
.RunAsync();
}
[!WARNING] Ensure that your
Main()method returns the integer exit code provided byCliApplication.RunAsync(), as shown in the above example. Exit code is used to communicate execution result to the parent process, so it's important that your program propagates it.
[!NOTE] When calling
CliApplication.RunAsync(), CliFx resolves command-line arguments and environment variables fromEnvironment.GetCommandLineArgs()andEnvironment.GetEnvironmentVariables()respectively. You can also provide them manually using one of the alternative overloads.
The code above uses AddCommandsFromThisAssembly() to detect command types defined within the current project and register them on the application.
Commands are independent entry points, through which the user can interact with your program.
To define a command, create a class that implements the ICommand interface and annotate it with the [Command] attribute:
using CliFx;
using CliFx.Attributes;
[Command(Description = "Calculates the logarithm of a value.")]
public class LogCommand : ICommand
{
// Order: 0
[CommandParameter(0, Description = "Value whose logarithm is to be found.")]
public required double Value { get; init; }
// Name: --base
// Short name: -b
[CommandOption("base", 'b', Description = "Logarithm base.")]
public double Base { get; init; } = 10;
public ValueTask ExecuteAsync(IConsole console)
{
var result = Math.Log(Value, Base);
console.Output.WriteLine(result);
// If the execution is not meant to be asynchronous,
// return an empty task at the end of the method.
return default;
}
}
In order to implement ICommand, the class needs to define an ExecuteAsync(...) method.
This is the method that gets called by the framework when the user decides to execute the command.
As the only parameter, this method takes an instance of IConsole, which is an abstraction around the system console.
Use this abstraction in place of System.Console whenever you need to write output, read input, or otherwise interact with the console.
In most cases, you will also want to define input bindings, which are properties annotated by the [CommandParameter] and [CommandOption] attributes.
These bindings provide a way to map command-line arguments into structured input data that can be used by the command.
The command in the above example serves as a simple logarithm calculator and defines two inputs: a positional parameter for the input value and a named option for the logarithm base. In order to execute this command, at minimum, the user needs to provide the input value:
$ dotnet myapp.dll 10000
4
They can also pass the -b|--base option to override the default logarithm base of 10:
$ dotnet myapp.dll 729 -b 3
6
In case the user forgets to specify the required value parameter, the application will instead exit with an error:
$ dotnet myapp.dll -b 10
Missing required parameter(s):
<value>
Out of the box, CliFx also provides a built-in --help option, which generates a help screen that lists all parameters and options available for the command:
$ dotnet myapp.dll --help
MyApp v1.0
USAGE
dotnet myapp.dll <value> [options]
DESCRIPTION
Calculates the logarithm of a value.
PARAMETERS
* value Value whose logarithm is to be found.
OPTIONS
-b|--base Logarithm base. Default: "10".
-h|--help Shows help text.
--version Shows version information.
Argument syntax
This library employs a variation of the POSIX argument syntax, which is used in most modern command-line tools. Here are some examples of how it works:
myapp --foo barsets option"foo"to value"bar"myapp -f barsets option'f'to value"bar"myapp --switchsets option"switch"without valuemyapp -ssets option's'without valuemyapp -abcsets options'a','b'and'c'without valuemyapp -xqf barsets options'x'and'q'without value, and option'f'to value"bar"myapp -i file1.txt file2.txtsets option'i'to a sequence of values"file1.txt"and"file2.txt"myapp -i file1.txt -i file2.txtsets option'i'to a sequence of values"file1.txt"and"file2.txt"myapp cmd abc -oroutes to commandcmd(assuming it's a command) with parameterabcand sets option'o'without value
Additionally, argument parsing in CliFx aims to be as deterministic as possible, ideally yielding the same result regardless of the application configuration. In fact, the only context-sensitive part in the parser is the command name resolution, which needs to know the list of available commands in order to discern them from parameters.
The parser's context-free nature has several implications on how it consumes arguments.
For example, myapp -i file1.txt file2.txt will always be parsed as an option with multiple values, regardless of the arity of the underlying property it's bound to.
Similarly, unseparated arguments in the form of myapp -ofile will be treated as five distinct options 'o', 'f', 'i', 'l', 'e', instead of 'o' being set to value "file".
These rules also make the order of arguments important — command-line string is expected to follow this pattern:
$ myapp [...directives] [command] [...parameters] [...options]
Parameters and options
CliFx supports two types of argument bindings: parameters and options. Parameters are bound from the command-line arguments based on the order they appear in, while options are bound by their name.
Besides that, they also differ in the following ways:
-
Parameters are required by default, while options are not.
-
You can make an option required by adding the
requiredkeyword to the property declaration (introduced in C# 11):// Any option can be required or optional without restrictions [CommandOption("foo")] public required string RequiredOption { get; init; } -
To make a parameter optional, omit the
requiredkeyword, but only the last parameter (by order) can be configured in such way:// Only the last parameter can be optional [CommandParameter(0)] public string? OptionalParameter { get; init; }
-
-
Parameters are primarily used for scalar (non-enumerable) properties, while options can be used for both scalar and non-scalar properties.
- You can bind an option to a property of a non-scala
Related Skills
node-connect
335.9kDiagnose OpenClaw node connection and pairing failures for Android, iOS, and macOS companion apps
frontend-design
82.7kCreate distinctive, production-grade frontend interfaces with high design quality. Use this skill when the user asks to build web components, pages, or applications. Generates creative, polished code that avoids generic AI aesthetics.
openai-whisper-api
335.9kTranscribe audio via OpenAI Audio Transcriptions API (Whisper).
commit-push-pr
82.7kCommit, push, and open a PR
