TimeWarp.Nuru 2.0.0-beta.4

Prefix Reserved
This is a prerelease version of TimeWarp.Nuru.
There is a newer version of this package available.
See the version list below for details.
dotnet add package TimeWarp.Nuru --version 2.0.0-beta.4
                    
NuGet\Install-Package TimeWarp.Nuru -Version 2.0.0-beta.4
                    
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-beta.4" />
                    
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-beta.4" />
                    
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-beta.4
                    
#r "nuget: TimeWarp.Nuru, 2.0.0-beta.4"
                    
#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-beta.4
                    
#: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-beta.4&prerelease
                    
Install as a Cake Addin
#tool nuget:?package=TimeWarp.Nuru&version=2.0.0-beta.4&prerelease
                    
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));

🏗️ 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 (2)

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

Package Downloads
TimeWarp.Nuru.Logging

Default console logging implementation for TimeWarp.Nuru CLI framework

TimeWarp.Multiavatar

A .NET library for generating unique, deterministic avatars from any text input. Creates beautiful SVG avatars with 48 billion unique variations based on SHA256 hashing.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
2.1.0-beta.11 11 9/13/2025
2.1.0-beta.10 151 8/30/2025
2.1.0-beta.9 166 8/28/2025
2.1.0-beta.8 173 8/8/2025
2.1.0-beta.7 165 8/8/2025
2.1.0-beta.6 200 8/7/2025
2.1.0-beta.5 193 8/6/2025
2.1.0-beta.4 193 8/6/2025
2.1.0-beta.3 192 8/6/2025
2.1.0-beta.1 193 8/6/2025
2.0.0 184 8/4/2025
2.0.0-beta.4 123 8/4/2025
2.0.0-beta.3 46 8/3/2025
2.0.0-beta.2 94 7/31/2025
2.0.0-beta.1 95 7/31/2025
1.0.0 98 7/28/2025
1.0.0-beta.2 96 7/28/2025
1.0.0-beta.1 94 7/27/2025