![]() |
VOOZH | about |
dotnet add package Nagare.Testing --version 0.15.2
NuGet\Install-Package Nagare.Testing -Version 0.15.2
<PackageReference Include="Nagare.Testing" Version="0.15.2" />
<PackageVersion Include="Nagare.Testing" Version="0.15.2" />Directory.Packages.props
<PackageReference Include="Nagare.Testing" />Project file
paket add Nagare.Testing --version 0.15.2
#r "nuget: Nagare.Testing, 0.15.2"
#:package Nagare.Testing@0.15.2
#addin nuget:?package=Nagare.Testing&version=0.15.2Install as a Cake Addin
#tool nuget:?package=Nagare.Testing&version=0.15.2Install as a Cake Tool
Event sourcing for .NET — flow in, truth out.
Events are the natural language of change. Something happened. Then something else. The stream moves forward, never backward, and the truth is always the whole story.
Nagare is an event sourcing framework for .NET that gets out of your way. Define what your domain means, and let the framework carry the rest.
public class BookAggregate : Aggregate<BookCommand, BookEvent, BookState>
{
private readonly EventHandlers<BookEvent, BookState> _events =
new EventHandlersBuilder<BookEvent, BookState>()
.On<BookAdded>((state, e) =>
state with { Exists = true, Title = e.Title })
.On<BookBorrowed>((state, e) =>
state with { IsBorrowed = true, BorrowerId = e.BorrowerId })
.Build();
private readonly CommandHandlers<BookCommand, BookEvent, BookState> _commands =
new CommandHandlersBuilder<BookCommand, BookEvent, BookState>()
.On<AddBook>((state, cmd) =>
state.Exists
? Then.Reject("Book already exists")
: Then.Persist(new BookAdded(cmd.Title, cmd.Author, cmd.Isbn)))
.On<BorrowBook>((state, cmd) =>
!state.Exists ? Then.Reject("Book does not exist")
: state.IsBorrowed ? Then.Reject("Book is already borrowed")
: Then.Persist(new BookBorrowed(cmd.BorrowerId, DateTimeOffset.UtcNow)))
.Build();
protected override EventHandlers<BookEvent, BookState> RegisterEventHandlers() => _events;
protected override CommandHandlers<BookCommand, BookEvent, BookState> RegisterCommandHandlers() => _commands;
}
Commands say what you want. Events say what happened. State is what's true right now. That's it.
harness
.Given(new BookAdded("Dune", "Herbert", "978-0441172719"))
.When(new BorrowBook("user-42"))
.ThenAccepted()
.ThenExpect<BookBorrowed>(e => e.BorrowerId == "user-42");
harness
.Given(new BookAdded(...), new BookBorrowed(...))
.When(new BorrowBook("user-99"))
.ThenRejected("already borrowed");
No database. No DI container. Just the domain, speaking for itself.
| Package | NuGet | Purpose |
|---|---|---|
Nagare |
👁 NuGet |
Core — aggregates, events, projections, subscriptions |
Nagare.Dashboard |
👁 NuGet |
Embedded operational dashboard — journal, time machine, processes, outbox |
Nagare.SqlServer |
👁 NuGet |
SQL Server stores |
Nagare.Sqlite |
👁 NuGet |
SQLite stores |
Nagare.PostgreSql |
👁 NuGet |
PostgreSQL stores |
Nagare.MySql |
👁 NuGet |
MySQL stores |
Nagare.Messaging |
👁 NuGet |
Pub/sub messaging abstractions |
Nagare.Messaging.Kafka |
👁 NuGet |
Kafka implementation |
Nagare.Testing |
👁 NuGet |
Given-When-Then harness, Eventually for projection polling |
Nagare ships a Claude Code plugin with skills for aggregate design, event naming, projections, testing, and store adapters.
# Add the marketplace
/plugin marketplace add ceracare/nagare
# Install the plugin
/plugin install nagare@ceracare-nagare
# Reload to activate
/reload-plugins
builder.Services.AddNagare();
builder.Services.AddAggregate<BookAggregate, BookCommand, BookEvent, BookState>();
See for a complete example, or read the full documentation.
Nagare.Dashboard is an embedded operational UI — a single NuGet package mounted as ASP.NET Core middleware. Live event tail, time-machine timeline per stream, provenance lens for individual events, process inspector, projections + checkpoints, outbox + dead-letter triage with gated replay. Hangfire-style mounting; dark-first Linear/Stripe-school aesthetic; prose-explained events via the optional IEventExplainer<TEvent> contract.
builder.Services.AddNagareDashboard();
builder.Services.UseLocalDevAuthorization(); // dev only — production needs an INagareDashboardAuthorizationFilter
app.MapNagareDashboard(); // mounts at /_nagare
Fail-closed by default — the dashboard returns 403 to every request unless the host registers an authorization filter. Three presets ship: NagareLocalDevFilter, NagareReadOnlyFilter, and a declarative NagareCapabilityFilter for claim/role gating.
See the dashboard guide and event explainers.
Nagare (流れ) — the flow of water, the passage of time, the course of events.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net10.0 net10.0 is compatible. net10.0-android net10.0-android was computed. net10.0-browser net10.0-browser was computed. net10.0-ios net10.0-ios was computed. net10.0-maccatalyst net10.0-maccatalyst was computed. net10.0-macos net10.0-macos was computed. net10.0-tvos net10.0-tvos was computed. net10.0-windows net10.0-windows was computed. |
Showing the top 1 NuGet packages that depend on Nagare.Testing:
| Package | Downloads |
|---|---|
|
Nagare.Streams.Testing
TestKit and shared test bases for Nagare.Streams pipelines |
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 0.15.2 | 1,096 | 6/4/2026 |
| 0.15.1 | 118 | 6/4/2026 |
| 0.15.0 | 110 | 6/4/2026 |
| 0.14.3 | 176 | 6/3/2026 |
| 0.14.2 | 464 | 5/30/2026 |
| 0.14.1 | 103 | 5/29/2026 |
| 0.14.0 | 116 | 5/28/2026 |
| 0.13.3 | 115 | 5/26/2026 |
| 0.13.1 | 108 | 5/25/2026 |
| 0.12.1 | 476 | 5/22/2026 |
| 0.12.0 | 135 | 5/22/2026 |
| 0.11.4 | 528 | 5/20/2026 |
| 0.11.3 | 105 | 5/20/2026 |
| 0.11.2 | 180 | 5/19/2026 |
| 0.11.1 | 119 | 5/18/2026 |
| 0.11.0 | 156 | 5/18/2026 |
| 0.10.7 | 105 | 5/18/2026 |
| 0.10.6 | 194 | 5/17/2026 |
| 0.10.5 | 454 | 5/11/2026 |
| 0.10.4 | 104 | 5/11/2026 |