Nerve 2.0.0

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

Nerve ⚡

NuGet .NET License CI

In-process publish/subscribe for .NET 10, shaped like MQTT and about as expensive as a method call. Topics with + and # wildcards, retained messages, request/reply, async streams and per-route statistics — 21 ns and zero allocations per published message.

Built by Gravicode Studios, led by Kang Fadhil.

English · Bahasa Indonesia · Documentation · Benchmarks

The agent coordination simulator: one orchestrator, six specialists, impulses in flight


<a name="english"></a>

🇬🇧 English

Install

dotnet add package Nerve

Thirty seconds

using Nerve;

var nerve = new NerveHub();

// Subscribe. The handler runs on the thread that publishes.
using var reader = nerve.Subscribe<double>("sensor/tank-3/temperature",
    celsius => Console.WriteLine($"{celsius:N1} C"));

// One level with +, everything below with #.
using var all = nerve.Subscribe<double>("sensor/+/temperature", c => Log(c));

await nerve.PublishAsync("sensor/tank-3/temperature", 28.4);

// Ask a question and wait for the answer, over the same topics.
using var responder = nerve.Respond<string, int>("text/length", text => text.Length);
int length = await nerve.RequestAsync<string, int>("text/length", "gravicode");   // 9

What it does

Publish/subscribe Routed by topic and message type. Synchronous handlers run inline and have finished before PublishAsync returns.
Wildcards MQTT's + and #. Matching happens once, when a topic is first seen — a wildcard subscriber costs nothing per message afterwards.
Retained messages One value kept per topic and handed to whoever subscribes next, so a late joiner learns the current state without asking.
Request/reply RequestAsync with a deadline, errors that surface at the call site, and a missing responder reported immediately rather than after the timeout.
Streams IAsyncEnumerable<T> for consumers that need their own thread. Buffered, drop-oldest, and never able to block a publisher.
Statistics Published, delivered, unrouted, errors, drops, routes and subscriptions — counted per route so threads don't share a cache line.
Error isolation A subscriber that throws is reported and skipped; the others still get the message. Switch to Propagate if you want the failure at the publisher.

Measured on this machine

.NET 10.0.11, Windows 11, 8 logical cores. Full output in docs/benchmark-run.txt.

v1 v2
Publish by topic name 70.8 ns 32.4 ns 2.2×
Publish through a resolved handle 21.0 ns 3.4× vs v1
Allocated over 5,000,000 messages 267 MB 376 B
Gen0 collections over that run 66 0

Fan-out costs what fan-out costs — 8 subscribers is 83.9 ns, 32 subscribers is 300 ns — and a wildcard subscriber measures the same as an exact one, because the matching already happened.

Run it

dotnet run --project src/Nerve.Demo                        # every feature, end to end
dotnet run --project src/Nerve.AgentSim -- --demo 8        # the simulator below
dotnet test tests/Nerve.Tests                              # 79 tests, about a second
dotnet run --project src/Nerve.Benchmarks -c Release -- --quick

The agent coordination simulator

An orchestrator is handed a list of instructions. It plans each one from the words in it, dispatches the pieces to six specialists, and folds their answers back into a digest.

No agent holds a reference to another. Every arrow you see is a topic: the orchestrator publishes to agents/task/{specialty} and subscribes to agents/result/+, the specialists take work through StreamAsync so they genuinely run in parallel, and the panel itself is just a seventh subscriber watching the same traffic.

A finished mission, aggregated from three specialists

Every spark on the arbor is a message that was really published. Violet leaving the soma is a sub-task going out; a specialist's own colour returning is their answer coming back.

dotnet run --project src/Nerve.AgentSim -- --demo 8

Documentation

Getting started Install, publish, subscribe, and the two mistakes worth avoiding
Patterns Wildcards, retained messages, request/reply, streams, waiting
Architecture How a publish becomes a handler call, and why it allocates nothing
API reference Every public member
Performance What was measured, on what, and what it means
Agent simulator How the panel is put together
Migrating from v1 What changed and what to do about it

Bahasa Indonesia: docs/id/.


<a name="bahasa-indonesia"></a>

🇮🇩 Bahasa Indonesia

Instalasi

dotnet add package Nerve

Tiga puluh detik

using Nerve;

var nerve = new NerveHub();

// Berlangganan. Handler berjalan di thread yang mem-publish.
using var pembaca = nerve.Subscribe<double>("sensor/tank-3/temperature",
    celsius => Console.WriteLine($"{celsius:N1} C"));

// Satu level dengan +, seluruh sisanya dengan #.
using var semua = nerve.Subscribe<double>("sensor/+/temperature", c => Catat(c));

await nerve.PublishAsync("sensor/tank-3/temperature", 28.4);

// Bertanya dan menunggu jawabannya, lewat topik yang sama.
using var penjawab = nerve.Respond<string, int>("text/length", teks => teks.Length);
int panjang = await nerve.RequestAsync<string, int>("text/length", "gravicode");   // 9

Apa saja yang tersedia

Publish/subscribe Dirutekan berdasarkan topik dan tipe pesan. Handler sinkron berjalan langsung dan sudah selesai sebelum PublishAsync kembali.
Wildcard + dan # ala MQTT. Pencocokan dilakukan sekali, saat sebuah topik pertama kali muncul — setelah itu subscriber wildcard tidak menambah biaya per pesan.
Retained message Satu nilai disimpan per topik dan langsung diberikan kepada subscriber berikutnya, sehingga yang datang terlambat tahu keadaan terkini tanpa perlu bertanya.
Request/reply RequestAsync dengan batas waktu, error yang muncul di tempat pemanggilan, dan responder yang belum terdaftar dilaporkan seketika — bukan setelah timeout.
Stream IAsyncEnumerable<T> untuk consumer yang butuh thread sendiri. Ada buffer, membuang yang terlama, dan tidak pernah bisa memblokir publisher.
Statistik Published, delivered, unrouted, error, drop, route dan subscription — dihitung per route agar antar-thread tidak berebut cache line.
Isolasi error Subscriber yang melempar exception dilaporkan lalu dilewati; subscriber lain tetap menerima pesannya. Gunakan Propagate bila ingin kegagalan itu sampai ke publisher.

Hasil pengukuran di mesin ini

.NET 10.0.11, Windows 11, 8 core logis. Output lengkapnya di docs/benchmark-run.txt.

v1 v2
Publish lewat nama topik 70,8 ns 32,4 ns 2,2×
Publish lewat handle yang sudah di-resolve 21,0 ns 3,4× dari v1
Alokasi selama 5.000.000 pesan 267 MB 376 B
Koleksi Gen0 selama run tersebut 66 0

Fan-out tetap ada biayanya — 8 subscriber 83,9 ns, 32 subscriber 300 ns — dan subscriber wildcard terukur sama dengan subscriber eksak, karena pencocokannya sudah selesai sebelumnya.

Menjalankannya

dotnet run --project src/Nerve.Demo                        # seluruh fitur, dari ujung ke ujung
dotnet run --project src/Nerve.AgentSim -- --demo 8        # simulator di bawah ini
dotnet test tests/Nerve.Tests                              # 79 tes, sekitar satu detik
dotnet run --project src/Nerve.Benchmarks -c Release -- --quick

Simulator koordinasi multi-agent

Sebuah orchestrator menerima daftar instruksi. Ia menyusun rencana dari kata-kata di dalamnya, mengirim potongan pekerjaannya ke enam agen spesialis, lalu melipat kembali jawaban mereka menjadi satu ringkasan.

Tidak ada satu agen pun yang memegang referensi ke agen lain. Setiap panah yang terlihat adalah sebuah topik: orchestrator mem-publish ke agents/task/{specialty} dan berlangganan agents/result/+, para spesialis mengambil pekerjaan lewat StreamAsync sehingga benar-benar berjalan paralel, dan panelnya sendiri hanyalah subscriber ketujuh yang menonton lalu lintas yang sama.

Setiap kilatan pada arbor adalah pesan yang sungguh-sungguh di-publish. Warna ungu yang meninggalkan soma adalah sub-tugas yang dikirim keluar; warna khas seorang spesialis yang kembali adalah jawabannya.

dotnet run --project src/Nerve.AgentSim -- --demo 8

Dokumentasi

Versi Bahasa Indonesia ada di docs/id/:

Memulai Instalasi, publish, subscribe, dan dua kesalahan yang sebaiknya dihindari
Pola pemakaian Wildcard, retained message, request/reply, stream, menunggu
Arsitektur Bagaimana sebuah publish menjadi panggilan handler, dan mengapa tanpa alokasi
Referensi API Seluruh anggota publik
Performa Apa yang diukur, di mesin apa, dan artinya
Simulator agent Bagaimana panelnya dirakit
Migrasi dari v1 Apa yang berubah dan apa yang perlu dilakukan

License

MIT. See LICENSE.

Built by Gravicode Studios, led by Kang Fadhilstudios.gravicode.com

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.
  • net10.0

    • No dependencies.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
2.0.0 60 9/2/2026

v2.0.0 - Rewritten for throughput and memory: typed routes resolved once per topic (no boxing, no casts), copy-on-write subscriber arrays read without a lock, and a dispatch loop that allocates nothing until a handler actually suspends. Adds MQTT-style + and # wildcards, retained messages, request/reply, IAsyncEnumerable streams with drop-oldest buffering, per-route statistics, error isolation and pre-resolved topic handles. Targets .NET 10.