TimeWarp.Nuru 2.0.0

Prefix Reserved
There is a newer prerelease version of this package available.
See the version list below for details.
dotnet add package TimeWarp.Nuru --version 2.0.0
                    
NuGet\Install-Package TimeWarp.Nuru -Version 2.0.0
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="TimeWarp.Nuru" Version="2.0.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="TimeWarp.Nuru" Version="2.0.0" />
                    
Directory.Packages.props
<PackageReference Include="TimeWarp.Nuru" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add TimeWarp.Nuru --version 2.0.0
                    
#r "nuget: TimeWarp.Nuru, 2.0.0"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package TimeWarp.Nuru@2.0.0
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=TimeWarp.Nuru&version=2.0.0
                    
Install as a Cake Addin
#tool nuget:?package=TimeWarp.Nuru&version=2.0.0
                    
Install as a Cake Tool

TimeWarp.Nuru

<div align="center">

NuGet Version NuGet Downloads Build Status License

Route-based CLI framework for .NET - bringing web-style routing to command-line applications

</div>

Nuru means "light" in Swahili - illuminating the path to your commands with clarity and simplicity.

No Commercial License Required - TimeWarp.Nuru and TimeWarp.Mediator are both released under the Unlicense. Unlike MediatR (which now requires commercial licensing), our libraries are free for any use, commercial or otherwise.

📦 Installation

dotnet add package TimeWarp.Nuru

🚀 Quick Start

Build a powerful calculator CLI that mixes performance and flexibility:

using TimeWarp.Nuru;
using TimeWarp.Mediator;

var builder = new NuruAppBuilder();

// Simple operations: Direct approach (maximum speed)
builder.AddRoute("add {x:double} {y:double}", 
    (double x, double y) => Console.WriteLine($"{x} + {y} = {x + y}"));

builder.AddRoute("multiply {x:double} {y:double}", 
    (double x, double y) => Console.WriteLine($"{x} × {y} = {x * y}"));

// Enable DI for complex operations
builder.AddDependencyInjection();

// Complex operations: Mediator approach (testable, DI)
builder.Services.AddSingleton<ICalculator, Calculator>();
builder.AddRoute<FactorialCommand>("factorial {n:int}");
builder.AddRoute<FibonacciCommand>("fibonacci {n:int}");

var app = builder.Build();
return await app.RunAsync(args);

Run it:

# Fast operations
dotnet run -- add 15 25
# Output: 15 + 25 = 40

# Complex operations with full DI
dotnet run -- factorial 5  
# Output: 5! = 120

🎯 Create .NET 10 single-file executables (requires .NET 10 Preview 6+):

#!/usr/bin/dotnet --
#:project path/to/TimeWarp.Nuru.csproj
// Add your code above and run directly: ./mycalc add 10 20

💡 Explore complete working examples: Calculator Samples

🎯 Why TimeWarp.Nuru?

Mix Direct and Mediator Approaches in One App

Choose the right tool for each command:

var builder = new NuruAppBuilder();

// Direct delegates for simple operations (fast, no overhead)
builder.AddRoute("ping", () => Console.WriteLine("pong"));

// Add DI when you need it
builder.AddDependencyInjection();

// Mediator pattern for complex operations (testable, DI, structured)
builder.Services.AddSingleton<IDatabase, Database>();
builder.AddRoute<QueryCommand>("query {sql}");

Web-Style Route Patterns for CLI

// Familiar syntax from web development
builder.AddRoute("deploy {env} --version {tag}", (string env, string tag) => Deploy(env, tag));
builder.AddRoute("serve --port {port:int} --host {host?}", (int port, string? host) => StartServer(port, host));
builder.AddRoute("backup {*files}", (string[] files) => BackupFiles(files));

Flexibility: Mix Approaches in the Same App

Choose the right approach for each command:

  • Simple commands → Direct delegates (fast, zero overhead)
  • Complex commands → Mediator pattern (testable, DI, structured)
  • Both in the same app → Maximum flexibility

Choose Your Approach Per Command

🚀 Direct - Maximum performance, zero overhead

var app = new NuruAppBuilder()
    .AddRoute("deploy {env}", (string env) => Deploy(env))
    .Build(); // ~4KB memory, blazing fast

🏗️ Mediator - Enterprise patterns, full DI

var builder = new NuruAppBuilder()
    .AddDependencyInjection(); // Enable DI and Mediator support
builder.AddRoute<DeployCommand>("deploy {env} --strategy {strategy}");
// Testable handlers, dependency injection, complex logic

⚡ Mixed - Best of both worlds (recommended)

var builder = new NuruAppBuilder();
// Simple commands: Direct (speed)
builder.AddRoute("status", () => ShowStatus());

// Enable DI for complex commands
builder.AddDependencyInjection();
// Complex commands: Mediator (structure)
builder.AddRoute<AnalyzeCommand>("analyze {*files}");

Use Direct for simple operations, Mediator for complex business logic

📖 Core Concepts

Route Patterns

TimeWarp.Nuru supports intuitive route patterns:

Pattern Example Matches
Literal status ./cli status
Parameter greet {name} ./cli greet Alice
Typed Parameter delay {ms:int} ./cli delay 1000
Optional deploy {env} {tag?} ./cli deploy prod or ./cli deploy prod v1.2
Options build --config {mode} ./cli build --config Release
Catch-all docker {*args} ./cli docker run -it ubuntu

Type Safety

Parameters are automatically converted to the correct types:

// Supports common types out of the box
.AddRoute("wait {seconds:int}", (int s) => Thread.Sleep(s * 1000))
.AddRoute("download {url:uri}", (Uri url) => Download(url))
.AddRoute("verbose {enabled:bool}", (bool v) => SetVerbose(v))
.AddRoute("process {date:datetime}", (DateTime d) => Process(d))
.AddRoute("scale {factor:double}", (double f) => Scale(f))

Complex Scenarios

Build sophisticated CLIs with sub-commands and options:

// Git-style sub-commands
builder.AddRoute("git add {*files}", (string[] files) => Git.Add(files));
builder.AddRoute("git commit -m {message}", (string msg) => Git.Commit(msg));
builder.AddRoute("git push --force", () => Git.ForcePush());

// Docker-style with options
builder.AddRoute("run {image} --port {port:int} --detach", 
    (string image, int port) => Docker.Run(image, port, detached: true));

// Conditional routing based on options
builder.AddRoute("deploy {app} --env {environment} --dry-run", 
    (string app, string env) => DeployDryRun(app, env));
builder.AddRoute("deploy {app} --env {environment}", 
    (string app, string env) => DeployReal(app, env));

Automatic Help Generation

Enable automatic help for all your commands:

var app = new NuruAppBuilder()
    .AddRoute("deploy {env|Target environment} {tag?|Optional version tag}", 
        (string env, string? tag) => Deploy(env, tag))
    .AddRoute("backup {source} --compress,-c|Enable compression", 
        (string source, bool compress) => Backup(source, compress))
    .AddAutoHelp()  // Generates help for all commands
    .Build();

This automatically creates:

  • --help - Shows all available commands
  • deploy --help - Shows usage for the deploy command
  • Parameter and option descriptions using the | syntax

🏗️ Enterprise-Ready Patterns

Scale from simple scripts to complex applications:

// Commands as classes with nested handlers - perfect for complex logic
public class DeployCommand : IRequest
{
    public string Environment { get; set; }
    public string? Version { get; set; }
    public bool DryRun { get; set; }
    
    // Handler nested inside command for better organization
    public class Handler(IDeploymentService deployment, ILogger logger) 
        : IRequestHandler<DeployCommand>
    {
        public async Task Handle(DeployCommand cmd, CancellationToken ct)
        {
            if (cmd.DryRun)
                await deployment.ValidateAsync(cmd.Environment, cmd.Version);
            else  
                await deployment.ExecuteAsync(cmd.Environment, cmd.Version);
        }
    }
}

// Enable DI and register services
builder.AddDependencyInjection();
builder.Services.AddSingleton<IDeploymentService, DeploymentService>();

// Simple registration
builder.AddRoute<DeployCommand>("deploy {environment} --version {version?} --dry-run");

🔧 Advanced Features

Type Safety Built-In

// Automatic parameter conversion
builder.AddRoute("delay {seconds:int}", (int s) => Thread.Sleep(s * 1000));
builder.AddRoute("download {url:uri}", (Uri url) => Download(url));
builder.AddRoute("process {date:datetime}", (DateTime d) => Process(d));

Async Support

// Full async support for both Direct and Mediator approaches
builder.AddRoute("fetch {url}", async (string url) => {
    var data = await httpClient.GetStringAsync(url);
    await File.WriteAllTextAsync("result.txt", data);
});

// Async Mediator commands with nested handler
public class FetchCommand : IRequest<string> 
{ 
    public string Url { get; set; }
    
    public class Handler : IRequestHandler<FetchCommand, string>
    {
        public async Task<string> Handle(FetchCommand cmd, CancellationToken ct)
        {
            using var client = new HttpClient();
            return await client.GetStringAsync(cmd.Url, ct);
        }
    }
}

Output Handling & Console Streams

TimeWarp.Nuru gives you full control over output handling:

// Simple console output (stdout)
builder.AddRoute("hello", () => Console.WriteLine("Hello!"));

// Structured data - automatically serialized to JSON (stdout)
builder.AddRoute("info", () => new { Name = "MyApp", Version = "1.0" });

// Separate concerns: diagnostics to stderr, data to stdout
builder.AddRoute("process {file}", (string file) => 
{
    Console.Error.WriteLine($"Processing {file}...");  // Progress to stderr
    Thread.Sleep(1000);
    Console.Error.WriteLine("Complete!");
    return new { File = file, Lines = 42, Status = "OK" };  // Result as JSON to stdout
});

// With DI and logging
builder.AddDependencyInjection();
builder.Services.AddLogging(); // Add logging services

public class AnalyzeCommand : IRequest<AnalyzeResult>
{
    public string Path { get; set; }
    
    public class Handler(ILogger<Handler> logger) : IRequestHandler<AnalyzeCommand, AnalyzeResult>
    {
        public async Task<AnalyzeResult> Handle(AnalyzeCommand cmd, CancellationToken ct)
        {
            logger.LogInformation("Starting analysis of {Path}", cmd.Path);  // Structured logging
            var result = await AnalyzeAsync(cmd.Path);
            return result;  // Returned object → JSON to stdout
        }
    }
}

Best Practices:

  • Use Console.WriteLine() for human-readable output to stdout
  • Use Console.Error.WriteLine() for progress, diagnostics, and errors to stderr
  • Return objects from handlers to get automatic JSON serialization to stdout
  • This separation enables piping and scripting: ./myapp analyze data.csv | jq '.summary'

🚄 Native AOT Ready

Build ultra-fast native binaries with the right configuration:

For Direct approach:

<PropertyGroup>
  <PublishAot>true</PublishAot>
</PropertyGroup>

For Mediator/Mixed approach:

<PropertyGroup>
  <PublishAot>true</PublishAot>
  <TrimMode>partial</TrimMode>  
</PropertyGroup>
dotnet publish -c Release -r linux-x64
./myapp --help  # Instant startup, 3.3MB binary

Plus .NET 10 Script Mode:

#!/usr/bin/dotnet --
#:project TimeWarp.Nuru.csproj
// Write your CLI and run it directly!

⚡ Performance That Matters

TimeWarp.Nuru delivers where it counts:

  • Memory Efficient: Only 3,992 B allocated - minimal footprint
  • Fast Execution: 18.452 ms with highly optimized routing
  • Native AOT: Compile to 3.3 MB single-file binaries
  • Rich Functionality: Route patterns, type safety, DI, mixed approaches

Real-World Performance: 37 Integration Tests

Implementation Test Results Execution Time Speed Improvement
Direct (JIT) 37/37 ✓ 2.49s Baseline
Mediator (JIT) 37/37 ✓ 6.52s 161% slower
Direct (AOT) 37/37 ✓ 0.30s 🚀 88% faster than JIT
Mediator (AOT) 37/37 ✓ 0.42s 🚀 93% faster than JIT

Key Insights:

  • AOT is ridiculously fast: Sub-second execution for 37 complex CLI tests
  • Direct approach: Best for maximum performance (3.3 MB binary)
  • Mediator approach: Worth the overhead for DI/testability (4.8 MB binary)
  • Both scale beautifully: From simple scripts to enterprise applications

🌟 Working Examples

Don't just read about it - run the code:

📁 Calculator Samples

Three complete implementations you can run immediately:

  • calc-direct - Pure performance (Direct approach)
  • calc-mediator - Enterprise patterns (Mediator with DI)
  • calc-mixed - Hybrid approach (best of both)
# Try them now:
./Samples/Calculator/calc-mixed add 10 20     # Direct: fast
./Samples/Calculator/calc-mixed factorial 5   # Mediator: structured  
./Samples/Calculator/calc-mixed fibonacci 10  # Output: Fibonacci(10) = 55

Key Patterns Demonstrated

  • Route-based command definition
  • Type-safe parameter binding
  • Mixed Direct/Mediator approaches
  • Dependency injection integration
  • .NET 10 single-file executables

🤝 Contributing

We welcome contributions! Please see our Contributing Guide for details.

📄 License

This project is licensed under the Unlicense - see the LICENSE file for details.


<div align="center">

Ready to build powerful CLI applications?

Start Here: Calculator SamplesWorking Examples You Can Run Now

</div>

Product Compatible and additional computed target framework versions.
.NET net9.0 is compatible.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 was computed.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages (1)

Showing the top 1 NuGet packages that depend on TimeWarp.Nuru:

Package Downloads
TimeWarp.Nuru.Logging

Default console logging implementation for TimeWarp.Nuru CLI framework

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
2.1.0-beta.8 156 8/8/2025
2.1.0-beta.7 162 8/8/2025
2.1.0-beta.6 199 8/7/2025
2.1.0-beta.5 192 8/6/2025
2.1.0-beta.4 192 8/6/2025
2.1.0-beta.3 191 8/6/2025
2.1.0-beta.1 192 8/6/2025
2.0.0 165 8/4/2025
2.0.0-beta.4 122 8/4/2025
2.0.0-beta.3 44 8/3/2025
2.0.0-beta.2 92 7/31/2025
2.0.0-beta.1 93 7/31/2025
1.0.0 96 7/28/2025
1.0.0-beta.2 93 7/28/2025
1.0.0-beta.1 92 7/27/2025