Skip to content
nulleanPublic

About

A source generator for command line parsing and command invocations.

Topics

Resources

Contributing

Security policy

Stars

1 star

Watchers

0 watching

Forks

Latest commit

 

History

177 Commits

Folders and files

Repository files navigation

Nullean.Argh

Build full-featured .NET CLIs without writing a parser: methods become commands, XML docs become help text.

NuGet CI Docs

Sample CLI help output (XmlDocShowcase)

Methods become commands, XML docs become help text, records become option sets. A Roslyn source generator emits parsing, routing, dispatch and help into your assembly at build time: no reflection, no runtime overhead, trimming- and AOT-safe by default.

Write vanilla C# and get a fully functional CLI in return: rich --help output, shell tab-completions for bash, zsh and fish, and a machine-readable JSON schema ready for agentic use cases, all without writing a line of plumbing code.

Heavily inspired by ConsoleAppFramework (Cysharp): rewritten from scratch with a different feature set, but ConsoleAppFramework laid out the path for source-generated CLIs in .NET.

Install

dotnet add package Nullean.Argh

For an app built on Microsoft.Extensions.Hosting and DI:

dotnet add package Nullean.Argh.Hosting
dotnet add package Microsoft.Extensions.Hosting

Quick start

Console app

using Nullean.Argh;

var app = new ArghApp();
app.Map("hello", Handlers.Hello);

return await app.RunAsync(args);

static class Handlers
{
	/// <summary>Greets someone by name.</summary>
	/// <param name="name">-n,--name, Name to greet.</param>
	public static void Hello(string name) => Console.WriteLine($"Hello, {name}!");
}

dotnet run -- hello --name Argh prints Hello, Argh!, and dotnet run -- hello --help prints the XML docs as help.

Hosted app

using Microsoft.Extensions.Hosting;
using Nullean.Argh.Hosting;

var builder = Host.CreateApplicationBuilder(args);

builder.Services.AddArgh(args, b =>
{
	b.Map("hello", Handlers.Hello);
});

await builder.Build().RunAsync();

Features

  • XML docs are your help text: summaries, param descriptions, remarks and <example> blocks appear in --help automatically.
  • Everything is generated C#: typed dispatch tree, option parsers and help printers emitted directly into your assembly.
  • MapGroup-style namespaces: nested command groups with their own help pages and scoped option types.
  • DTO binding with [AsParameters]: records and classes expand into flags without a custom bind loop.
  • Shell completions built in: bash, zsh, fish; one install command per shell.
  • Agent-ready schema: myapp __schema emits full JSON, conforming to cli-schema v1.
  • Fuzzy matching: typos produce actionable errors with suggestions.
  • DataAnnotations validation: [Range], [StringLength], [AllowedValues], [Existing] and more; constraints show in --help, failures exit 2.
  • CancellationToken injection: add it to a handler and it tracks Ctrl+C (or host shutdown with Hosting).
  • Zero-dep or ME.* native: Nullean.Argh has no Microsoft.Extensions.* dependency; Nullean.Argh.Hosting plugs into IHost and DI.

Registration model

// Method group: direct typed dispatch
app.Map("deploy", DeployHandlers.Run);

// Lambda: one-liners
app.Map("greet", (string name) => Console.WriteLine($"Hello, {name}!"));

// Class: every public method becomes a command
app.Map<StorageHandlers>();

// Namespaces: nested command groups
app.MapNamespace<StorageCommands>("storage", ns =>
{
	ns.MapNamespace<BlobCommands>("blob");
});

Parameters

using System.ComponentModel.DataAnnotations;
using Nullean.Argh;

public record DeployOptions(string Environment, bool DryRun = false);

public static class Commands
{
	// Positional arguments
	public static void Deploy([Argument] string environment) => Console.WriteLine(environment);

	// Named flags, kebab-cased: --output-dir ./bin --release
	public static void Build(string outputDir, bool release = false) => Console.WriteLine($"{outputDir} {release}");

	// DTO binding: --environment prod --dry-run
	public static void Ship([AsParameters] DeployOptions opts) => Console.WriteLine(opts);

	// Validation
	public static void Run(
		[Range(1, 65535)] int port,
		[AllowedValues("dev", "staging", "prod")] string env) => Console.WriteLine($"{env}:{port}");
}

Shell completions

eval "$(myapp __completion bash)"                                # bash
source <(myapp __completion zsh)                                 # zsh
myapp __completion fish > ~/.config/fish/completions/myapp.fish  # fish

Schema

myapp __schema > cli-schema.json

Emits a full JSON description conforming to cli-schema v1: feed it to an LLM, generate docs, or diff it in CI.

Packages

Package What it is
Nullean.Argh metapackage for console apps (Core + Interfaces) NuGet
Nullean.Argh.Hosting Microsoft.Extensions.Hosting and DI integration NuGet
Nullean.Argh.Core shared runtime and embedded source generator (transitive) NuGet
Nullean.Argh.Interfaces contracts and attributes (transitive, or for shared libraries) NuGet

Which package do I need? Nullean.Argh for dependency-free console apps, Nullean.Argh.Hosting for apps using Microsoft.Extensions.Hosting and DI. Everything else is pulled in transitively.

Learn more

MIT licensed. Copyright Nullean and contributors.

About

A source generator for command line parsing and command invocations.

Topics

Resources

Contributing

Security policy

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages