CLI tool
Tyrrrz/CliFx avatar
Tyrrrz/CliFx

CliFx: a class-first framework for .NET command line applications

Class-first framework for building command-line interfaces

1,619 stars68 forksC#MIT

At a glance

What is it?
CliFx is an opinionated framework for .NET command line applications, and the design decision that defines it is that a command is a class with attributes rather than a function with a parsing convention. Source generators discover the commands and write the entry point, help text is produced from the same metadata, and the console is an abstraction so that a command can be tested without a terminal.
Who is it for?
Adopt CliFx if you are building a .NET command line tool and you want the structure of a framework, with typed commands, nested hierarchies, generated help and a testable console layer, without pulling in a large dependency graph.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 3 days ago.
What is it written in?
Mainly C#, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.

Editorial analysis

A command is a class, and the framework writes the entry point

CliFx is described as an opinionated framework for building command-line applications, and it provides a model for expressing command interactions through classes and properties, skipping the low-level infrastructure concerns such as argument parsing, routing, error handling and help generation. The README calls it a complete application framework and not just an argument parser, and the difference shows in the structure of a command. You declare a `partial` type, annotate it with the `[Command]` attribute and implement the `ICommand` interface, with input arriving as properties that carry a `[CommandParameter]` for a positional argument or a `[CommandOption]` for a named option.

csharp
[Command(Description = "Calculates the logarithm of a value.")]
public partial class LogCommand : ICommand
{
    [CommandParameter(0, Description = "Value whose logarithm is to be found.")]
    public required double Value { get; set; }

    [CommandOption("base", 'b', Description = "Logarithm base.")]
    public double Base { get; set; } = 10;

The README is emphatic about the `partial` requirement, and explains why, that the command type must be declared as partial so that CliFx can extend it with the necessary metadata and behaviour, and that if the type is nested within other types then all of them must be marked partial too. And the payoff for that constraint is that no additional setup is required, because CliFx uses source generators to discover the commands and produce the `Main()` method automatically.

IConsole, and a console you can test

The `ICommand` interface requires the type to define an `ExecuteAsync(...)` method holding the command's execution logic, and its only parameter is an instance of `IConsole`, described as a decoupled abstraction used in place of `System.Console` to write text, read binary data or otherwise interact with the console. The method returns a `ValueTask`, and the README points out that if you have no asynchronous work to do you simply return the default value, which is a completed `ValueTask`. Two things follow from the abstraction. A command that writes to `IConsole` can be exercised in a test without allocating a terminal, which is what the feature list means by a testable console interaction layer, and the same abstraction is what makes the framework's support for reading and writing binary data a matter of the interface rather than of each command. It is a small interface, and it is the difference between a command that can be unit tested and one that can only be run.

Help text and errors come from the same metadata

Because the parameters and options are properties with attributes, the framework knows their names, their descriptions and their defaults without any extra configuration, and the help screen is generated from that. The README's example shows the shape of the output, with a usage line, a description, a parameters section listing the value parameter, and an options section listing the base option with its default of 10, the help option, and the version option. The `-h|--help` option is bound automatically, and the same is true of `--version`, and both appear in the generated help with their defaults, which is the detail that makes the output look finished rather than assembled. The error path is equally consistent, since a missing required parameter produces a specific message, `Missing required parameter(s): <value>`, and the application exits with an error. A command with no name in its attribute is treated as the default, that is the root, command, which runs when the user does not name one.

Deep hierarchies, cancellation and native AOT

The feature list covers the parts of a command line application that usually get skipped. Deeply nested command hierarchies are supported, so a tool with verbs and subverbs has a structure that mirrors the CLI surface rather than a flat list of switches. Graceful cancellation is handled through interrupt signals, which for a long running command is the difference between stopping and being killed. Binary data can be read and written through the console abstraction. The library is compatible with Native AOT and trimming, and it targets .NET Standard 2.0 and later, and it declares no external dependencies, which is worth stating plainly because it is unusual for a framework of this size. The README also suggests Binternal if you would rather internalize the library into your own build than take an external dependency, which is the escape hatch for organisations that forbid third party packages at runtime.

The repository separates the generator from the runtime

The tree explains the architecture, and it is worth reading because source generators are a large part of how the framework behaves. There is a `CliFx/` directory for the core library, a separate `CliFx.Generators/` directory for the source generators that discover commands and emit the entry point, a `CliFx.Demo/` project showing the framework in use, `CliFx.Tests/` and `CliFx.Tests.Dummy/` for the test suites, and `CliFx.Benchmarks/` for performance measurement. The build is centralised, with `Directory.Build.props`, `Directory.Packages.props` and a `global.json` pinning the SDK, and the solution is a `CliFx.slnx`, the newer solution format. There is a `NuGet.config`, a `Contributing.md`, a `License.txt` and a `.devcontainer/` for a reproducible development environment. The separation of the generators is the important structural choice, because the generator is what makes the attribute model work, and keeping it in its own project means the runtime package does not have to carry the generator's own dependencies.

Versioning, funding and an unusual terms of use section

The release history shows a major version landing in April 2026, version 3.0, followed by 3.0.1 in August 2026, with 2.3.6 from May 2025 before it, and the last push to the branch on 2026-10-09. The default branch is `prime`, which is the author's convention for the current line of work, and the project carries a status badge that reads active. The project is MIT licensed and community funded, with a note that development is entirely funded by the community and a link to donate. What stands out is the terms of use section, which is a political statement rather than a legal one, stating that by using the project or its source code for any purpose the user grants an implicit agreement to a set of statements about Russia and Ukraine, with a link to the author's page about it. It is unusual in a package README, and whether it affects your adoption is a question for your organisation's policy rather than for the code.

Editorial conclusion

Adopt CliFx if you are building a .NET command line tool and you want the structure of a framework, with typed commands, nested hierarchies, generated help and a testable console layer, without pulling in a large dependency graph. Do not adopt it for a script with one flag, where the ceremony costs more than it saves, and note that the framework is opinionated, since the command type must be partial and your own `Main` is only used if you opt into the application configuration route. Before you start, check the version line, because the 3.0 release landed in April 2026 and the examples in the README are from that era, and decide whether the source generator behaviour fits your build. The licence is MIT, the current release is 3.0.1 from 2026-08-31, and the last push was on 2026-10-09.

Frequently asked questions

What is CliFx?

It is an opinionated .NET framework for building command line applications, providing a model for expressing command interactions through classes and properties, and covering the low-level work such as argument parsing, routing, error handling and help generation. The README calls it a complete application framework rather than just an argument parser.

How do I define a command in CliFx?

Declare a `partial` class annotated with `[Command]`, implement the `ICommand` interface, and expose input as properties carrying `[CommandParameter]` for positional arguments and `[CommandOption]` for named options. The type must be partial so CliFx can extend it with metadata, and nested types must all be partial too.

Does CliFx generate the Main method and the help text?

Yes. The README says that no additional setup is required because CliFx uses source generators to discover the commands and produce the `Main()` method automatically, and it binds the conventional `-h|--help` and `--version` options, with the help screen listing parameters, options, descriptions and defaults.

How do I test a CliFx command?

The `ExecuteAsync(...)` method receives an `IConsole`, a decoupled abstraction used in place of `System.Console` for writing text, reading binary data or otherwise interacting with the console, which the README lists as a testable console interaction layer. The framework also supports Native AOT and trimming, and has no external dependencies.

Official sources

  1. License: MIT
  2. Project website
  3. README
  4. Releases
  5. Tyrrrz/CliFx on GitHub
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/tyrrrz-clifx.svg)](https://hysenlabs.com/projects/tyrrrz-clifx)

Was this useful?