Hugo 2.0.0

dotnet add package Hugo --version 2.0.0
                    
NuGet\Install-Package Hugo -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="Hugo" Version="2.0.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Hugo" Version="2.0.0" />
                    
Directory.Packages.props
<PackageReference Include="Hugo" />
                    
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 Hugo --version 2.0.0
                    
#r "nuget: Hugo, 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 Hugo@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=Hugo&version=2.0.0
                    
Install as a Cake Addin
#tool nuget:?package=Hugo&version=2.0.0
                    
Install as a Cake Tool

Hugo

Hugo hero banner

CI NuGet NuGet Diagnostics

Go-style concurrency primitives and functional result pipelines for 10 applications.

Table of contents

Highlights

  • Deterministic concurrency: Channels, wait groups, mutexes, RW locks, timers, defer, and select-style helpers mirror Go semantics while respecting CancellationToken and TimeProvider.
  • Railway-oriented results: Result<T> pipelines keep success/failure explicit with Then, Map, Recover, Ensure, streaming helpers, sagas, and tiered fallbacks. ValueTask-first extensions such as ThenValueTaskAsync, MapValueTaskAsync, and TapValueTaskAsync keep async pipelines allocation-free when your delegates already return ValueTask<Result<T>>.
  • Observability first: GoDiagnostics ships counters, histograms, and activity sources that plug directly into OpenTelemetry exporters or custom meter providers.
  • Source-generated error catalog: Hugo’s well-known error codes are generated at compile time, ensuring consistent metadata for logs, metrics, and documentation.
  • Batteries included: Prioritised channels, task queue leasing, retry policies, deterministic version gates, workflow telemetry, and profiling recipes ship alongside the core library.
  • Testability: Fakeable time providers, deterministic effect capture, structured errors, and cancellation metadata keep async workflows reproducible in CI.

When to use Hugo

  • You need Go-like coordination primitives (channels/select/wait groups) without leaving C#.
  • You want predictable error handling with structured metadata instead of exceptions for control flow.
  • You are building workflow orchestrations that must replay deterministically across retries and recoveries.
  • You plan to publish metrics and traces for concurrency-heavy workloads without custom instrumentation.
  • You require reusable timeout/retry/cancellation playbooks that can be enforced across teams.

Supported runtimes

  • Targets net10.0.
  • Works with generic host builders, ASP.NET background services, worker services, and isolated Azure Functions workers.
  • Verified with the .NET 10 SDK;

Trimming & AOT considerations

Hugo is tested with the .NET NativeAOT toolchain and ships with trimming/AOT analyzers enabled, but two APIs depend on System.Text.Json to round-trip arbitrary runtime types:

  • DeterministicEffectStore and VersionGate persist workflow payloads as JSON.
  • Error/ErrorJsonConverter preserve metadata dictionaries that can contain any CLR object.

When publishing with PublishTrimmed=true or PublishAot=true, make sure the types you capture in effect stores or error metadata aren’t trimmed away. Typical approaches include:

  1. Prefer source generation – register a JsonSerializerContext that lists the effect payloads and pass it to DeterministicEffectStore/VersionGate.
  2. Root the types manually – use DynamicDependency, PreserveDependency, or reflection registration files to keep rare payloads alive.
  3. Keep metadata simple – favor primitive types, records, or known DTOs in Error.Metadata so the linker can see them.

If the linker/AOT compiler warns about RequiresUnreferencedCode on these APIs, it means a payload needs to be preserved before trimming continues.

Install

dotnet add package Hugo
  • Plays nicely with central package management (Directory.Packages.props).
  • To iterate locally, run dotnet pack src/Hugo/Hugo.csproj -o ./artifacts and point a local feed at the generated .nupkg.

Quick start

These steps mirror the getting started tutorial but demonstrate channels, fan-in coordination, and Result<T> in a single console app.

  1. Bootstrap a sample

    dotnet new console -n HugoQuickstart
    cd HugoQuickstart
    dotnet add package Hugo
    
  2. Compose channels, wait groups, and results

    Replace Program.cs with:

    using Hugo;
    using static Hugo.Go;
    
    using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(5));
    
    var metrics = MakeChannel<int>(capacity: 8);
    var jobs = MakeChannel<string>(capacity: 8);
    var merged = MakeChannel<object>(capacity: 16);
    var workers = new WaitGroup();
    
    workers.Go(async () =>
    {
        using var complete = Defer(() => metrics.Writer.TryComplete());
    
        for (var i = 0; i < 3; i++)
        {
            await metrics.Writer.WriteAsync(i, cts.Token).ConfigureAwait(false);
        }
    });
    
    workers.Go(async () =>
    {
        using var complete = Defer(() => jobs.Writer.TryComplete());
    
        foreach (var name in new[] { "build", "deploy", "notify" })
        {
            await jobs.Writer.WriteAsync(name, cts.Token).ConfigureAwait(false);
        }
    });
    
    var relay = FanInAsync(
        sources: new[] { metrics.Reader, jobs.Reader },
        destination: merged.Writer,
        completeDestination: true,
        cancellationToken: cts.Token);
    
    var messages = new List<string>();
    
    await foreach (var payload in merged.Reader.ReadAllAsync(cts.Token))
    {
        var result = payload switch
        {
            int sample => Ok(sample)
                .Ensure(static value => value >= 0, value =>
                    Error.From($"negative sample {value}", "error.validation"))
                .Map(static value => $"metric={value}"),
            string job => Ok(job)
                .Ensure(static value => !string.IsNullOrWhiteSpace(value))
                .Map(static value => $"job={value}"),
            _ => Err<string>("unsupported payload", "error.validation")
        };
    
        var handled = await result
            .TapAsync(static (value, token) =>
            {
                Console.WriteLine($"processed {value}");
                return ValueTask.CompletedTask;
            }, cts.Token);
    
        if (handled.IsSuccess)
        {
            messages.Add(handled.Value);
        }
        else
        {
            Console.WriteLine($"skipped: {handled.Error}");
        }
    }
    
    var fanInResult = await relay;
    if (fanInResult.IsFailure)
    {
        Console.WriteLine($"fan-in failed: {fanInResult.Error}");
    }
    
    await workers.WaitAsync(cts.Token);
    
    Console.WriteLine(string.Join(", ", messages));
    
  3. Run it

    dotnet run
    

    Lower the timeout or cancel manually to see how Error.Canceled flows through the pipeline without throwing.

Extend the sample

Observability in one call

using Hugo.Diagnostics.OpenTelemetry;
using Microsoft.Extensions.Hosting;

var builder = Host.CreateApplicationBuilder(args);

builder.Services
    .AddOpenTelemetry()
    .AddHugoDiagnostics(options =>
    {
        options.ServiceName = builder.Environment.ApplicationName;
        options.OtlpEndpoint = new Uri("http://localhost:4317");
        options.AddPrometheusExporter = true;
    });

var app = builder.Build();
app.Run();
  • Metrics: waitgroup.*, channel.select.*, taskqueue.*, workflow.*, result.*, and more (see Diagnostics reference).
  • Traces: rate-limited spans that carry workflow metadata and channel coordination tags.
  • Ready-made collector recipes live in the worker sample walkthrough.

Documentation

Hugo follows the Divio documentation system so you can find the right level of guidance quickly:

Start at docs/index.md for navigation and search hints.

Samples & benchmarks

  • samples/Hugo.WorkerSample – a background worker showcasing task queues, deterministic workflows, and OpenTelemetry integration.
  • benchmarks/Hugo.Benchmarks – BenchmarkDotNet suites comparing Hugo primitives to baseline .NET constructs (mutex vs SemaphoreSlim, prioritized channels, result pipelines, select latency, object pools, timers).

Run the worker sample with a local collector:

docker run --rm \
    -p 4317:4317 -p 4318:4318 -p 9464:9464 \
    -v "${PWD}/otel-collector.yaml:/etc/otelcol/config.yaml" \
    otel/opentelemetry-collector:0.103.1

dotnet run --project samples/Hugo.WorkerSample/Hugo.WorkerSample.csproj

Benchmark results are written to BenchmarkDotNet.Artifacts/results/.

Project layout

  • src/ – library source for concurrency primitives, result pipelines, policies, sagas, deterministic coordination, and diagnostics.
  • tests/ – unit, integration, and deterministic timing tests.
  • docs/ – tutorials, how-to guides, references, explanations, roadmap, and audit trackers (rendered via DocFX).
  • samples/ – runnable end-to-end scenarios.
  • benchmarks/ – performance harnesses executed with BenchmarkDotNet.
  • tools/ – profiling scripts, analyzers, and auxiliary automation.

Support

  • Questions & bugs: open an issue on GitHub.
  • Security disclosures: contact the maintainer privately before filing a public issue.

Contributing

  • Review CONTRIBUTING.md for environment setup, coding standards, and workflow expectations.
  • Run dotnet build Hugo.slnx and dotnet test for tests/Hugo.UnitTests, tests/Hugo.IntegrationTests, and tests/Hugo.FeatureTests before submitting a pull request.
  • Collect coverage with dotnet test --collect:"XPlat Code Coverage" to match CI.

License

Hugo is licensed under the MIT License. Use, modify, and distribute it within those terms.

Product Compatible and additional computed target framework versions.
.NET net10.0 is compatible.  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 (7)

Showing the top 5 NuGet packages that depend on Hugo:

Package Downloads
Hugo.Diagnostics.OpenTelemetry

OpenTelemetry extensions and defaults for Hugo diagnostics instrumentation.

Hugo.TaskQueues.Replication

Replication helpers, deterministic coordinators, and checkpointing sinks for Hugo task queues.

Hugo.Deterministic.Cosmos

Azure Cosmos DB deterministic state store for Hugo workflows.

Hugo.Deterministic.Redis

Redis-backed deterministic state store for Hugo workflows.

Hugo.TaskQueues.Diagnostics

TaskQueue diagnostics helpers (meters, activity sources, sampling, adapters) for Hugo hosts.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
2.0.0 485 11/21/2025
2.0.0-rc.7 308 11/21/2025
2.0.0-rc.6 414 11/18/2025
2.0.0-rc.5 359 11/18/2025
2.0.0-rc.3 346 11/18/2025
1.4.11 249 11/14/2025
1.4.10 341 11/13/2025
1.4.9 357 11/12/2025
1.4.8 337 11/10/2025
1.4.7 270 11/10/2025
1.4.5 259 11/10/2025
1.4.4 219 11/9/2025
1.4.3 207 11/9/2025
1.4.2 254 10/30/2025
1.4.1 187 10/30/2025
1.4.0 189 10/27/2025
1.3.6 191 10/27/2025
1.3.5 174 10/26/2025
1.3.4 171 10/26/2025
1.3.3 142 10/25/2025
1.3.2 142 10/25/2025
1.3.0 111 10/25/2025
1.1.0 153 10/24/2025
1.0.2 225 10/23/2025
1.0.1 180 10/23/2025
1.0.0 244 10/21/2025
0.5.8 179 10/21/2025
0.5.7 178 10/21/2025
0.5.6 175 10/21/2025
0.5.5 172 10/21/2025
0.5.4 166 10/21/2025
0.5.3 174 10/21/2025
0.5.2 178 10/21/2025
0.5.0 174 10/20/2025
0.4.0 175 10/20/2025
0.3.1 178 10/20/2025
0.3.0 170 10/19/2025
0.2.0 182 10/19/2025
0.1.2 175 10/19/2025
0.1.0 185 10/19/2025