PicoActor.Abs 2026.1.0

There is a newer version of this package available.
See the version list below for details.
dotnet add package PicoActor.Abs --version 2026.1.0
                    
NuGet\Install-Package PicoActor.Abs -Version 2026.1.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="PicoActor.Abs" Version="2026.1.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="PicoActor.Abs" Version="2026.1.0" />
                    
Directory.Packages.props
<PackageReference Include="PicoActor.Abs" />
                    
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 PicoActor.Abs --version 2026.1.0
                    
#r "nuget: PicoActor.Abs, 2026.1.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 PicoActor.Abs@2026.1.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=PicoActor.Abs&version=2026.1.0
                    
Install as a Cake Addin
#tool nuget:?package=PicoActor.Abs&version=2026.1.0
                    
Install as a Cake Tool

PicoActor

AOT-compatible, in-memory Actor framework with Event Sourcing for .NET. Lightweight, zero-reflection, designed for agentic AI systems and workflow orchestration. Runs under NativeAOT and trimming.

CI NuGet License: MIT

English | 简体中文 | 日本語 | Español | Português | 繁體中文 | 한국어 | Français | Deutsch | Русский


Computational Model

┌─────────────────────────────────────────────────┐
│                  ActorSystem                     │
│  ┌─────────┐  ┌─────────┐  ┌─────────┐         │
│  │ Counter │  │  Agent  │  │ Session │  ...     │
│  │ (Actor) │  │ (Actor) │  │ (Actor) │         │
│  └────┬────┘  └────┬────┘  └────┬────┘         │
│       │            │            │               │
│       ▼            ▼            ▼               │
│  ┌─────────────────────────────────────────┐    │
│  │            IEventStore                   │    │
│  │   AppendAsync / LoadAsync               │    │
│  └─────────────────────────────────────────┘    │
└─────────────────────────────────────────────────┘

Each actor owns a mailbox (in-memory Channel<Envelope>), a UUID v7 identity, and a single-threaded consumption loop. Commands are delivered via Send (fire-and-forget) or AskAsync (request-reply).

Event-Sourced actors follow Persist-then-Mutate: OnMessageAsync → RaiseEvent → Persist to IEventStore → Mutate state. State is only mutated after successful persistence — the in-memory state is always consistent with the event stream.


Why PicoActor

Concern Existing Options PicoActor
AOT / Trimming ❌ Akka.NET, Proto.Actor, Orleans all require reflection ✅ Full NativeAOT support
Event Sourcing ❌ Proto.Actor, Orleans lack built-in ES ✅ Persist-then-Mutate, automatic rollback
Dependency Size ❌ Akka.NET (8+ packages), Orleans (10+ packages) ✅ 2 packages, zero dependency beyond Channels
DI Integration ❌ Tied to Microsoft.Extensions.DI ✅ Native PicoDI, zero-reflection resolution
netstandard2.0 ⚠️ Akka.NET / Proto.Actor only ✅ Abstractions target netstandard2.0
Learning Curve ❌ Steep — supervision trees, clustering, remoting ✅ Minimal — actors + events + mailbox

Quick Start

dotnet add package PicoActor
using PicoActor;
using PicoActor.Abs;

// 1. Setup
var store = new InMemoryEventStore();
var system = new ActorSystem(store);

// 2. Register actor factories
system.Register<Counter>(
    createFactory: cmd => cmd switch
    {
        CreateCounter c => new Counter(c),
        _ => throw new InvalidOperationException()
    },
    rebuildFactory: () => new Counter()
);

// 3. Create, message, stop, rebuild
var counter = await system.CreateAsync<Counter>(new CreateCounter(42));
system.Send(counter.Id, new Increment(5));
var value = await system.AskAsync<int>(counter.Id, new GetValue());
await system.StopAsync(counter.Id);
var rebuilt = await system.GetAsync<Counter>(counter.Id);

Module Details

PicoActor.Abs — Core Abstractions

Targets netstandard2.0 for maximum compatibility. Contains all interfaces and base classes.

Type Role
IActor Base interface — provides Id (UUID v7)
IActorSystem Runtime contract — Register, CreateAsync, GetAsync, Send, AskAsync, StopAsync
ICommand Marker interface for commands
IDomainEvent Marker interface for domain events
IEventSourcedActor Optional interface — Version, ReplayEvents, CommitEvents
IEventStore Persistence contract — AppendAsync (optimistic concurrency), LoadAsync
ICancelable Optional — CancelCurrentTurn for long-running operations
Actor Abstract base — mailbox, consumption loop, SignalReady, StopAsync
EventSourcedActor ES base — RaiseEvent, Mutate, Persist-then-Mutate pipeline
Envelope Internal — wraps ICommand with optional TaskCompletionSource
ActorOutputEvent Outbound notification — Type, Data, optional ToolCallId/ToolName/TurnId
ConcurrencyException Thrown by IEventStore on version mismatch

PicoActor — Runtime

Targets net10.0, AOT-compatible.

Type Role
ActorSystem Default IActorSystem — ConcurrentDictionary registry, factory registration, message routing, CancelTurn
InMemoryEventStore Lock-free in-memory store — ConcurrentDictionary-backed
ActorConfig Configuration POCO — bind from PicoCfg
ActorSystemOptions Options with optional IEventStore and ILogger
PicoActorDiExtensions AddPicoActor() extension method for PicoDI

Actor (Non-ES)

Inherit from Actor for pure in-memory operational actors.

public sealed class EchoActor : Actor
{
    protected override ValueTask<object?> OnMessageAsync(ICommand command)
        => new ValueTask<object?>(command);
}

Event-Sourced Actor

Inherit from EventSourcedActor. Override OnMessageAsync to call RaiseEvent, and Mutate to apply state changes.

public sealed class Counter : EventSourcedActor
{
    private int _value;

    public Counter(CreateCounter cmd) : base(cmd) { }
    public Counter() { }

    protected override ValueTask<object?> OnMessageAsync(ICommand command)
    {
        switch (command)
        {
            case Increment i:
                RaiseEvent(new CounterIncremented(i.Delta));
                break;
            case GetValue:
                return new ValueTask<object?>(_value);
        }
        return default;
    }

    protected override void Mutate(IDomainEvent @event)
    {
        switch (@event)
        {
            case CounterIncremented e: _value += e.Delta; break;
        }
    }
}

Persist-then-Mutate Pipeline

OnMessageAsync → RaiseEvent (record only, no state change)
              → AppendAsync (persist to IEventStore)
              → Mutate (apply events to in-memory state)
              → Reply to caller (only after success)

If AppendAsync fails, uncommitted events are discarded and Version is rolled back. The actor is not poisoned — the next message processes cleanly.

Messaging: Ask vs Send

Pattern Method Semantics
Request-Reply AskAsync<TResult>(id, command) Returns result after message processing
Fire-and-Forget Send(id, command) No reply; exceptions routed to UnhandledErrorHandler

OutputChannel

Actors broadcast ActorOutputEvent messages to external subscribers:

counter.OutputWriter = channel.Writer;
// Inside OnMessageAsync:
WriteOutput("Incremented", data: "Delta=5");

CancelTurn

Cancel long-running operations without stopping the actor:

public sealed class MyActor : Actor, ICancelable
{
    private CancellationTokenSource? _currentTurnCts;
    public void CancelCurrentTurn() => _currentTurnCts?.Cancel();

    protected override async ValueTask<object?> OnMessageAsync(ICommand command)
    {
        _currentTurnCts = CancellationTokenSource.CreateLinkedTokenSource(StopToken);
        // ... long-running work with _currentTurnCts.Token
    }
}
system.CancelTurn(actor.Id);

Spawn

Actors create child actors via System reference:

protected override async ValueTask<object?> OnMessageAsync(ICommand command)
{
    if (command is SpawnChild s)
    {
        var child = await System!.CreateAsync<Worker>(s.Cmd);
        return child.Id;
    }
    return default;
}

Module Integration

PicoDI

var container = new SvcContainer();
container.AddPicoActor();  // Registers IActorSystem + InMemoryEventStore

// Custom event store
var store = new InMemoryEventStore();
container.AddPicoActor(store);

// From PicoCfg
var cfg = CfgBind.Bind<ActorConfig>(configuration, "Actor");
container.AddPicoActor(cfg);

IActorSystem is a Singleton. If ILoggerFactory is registered, a logger is automatically injected.

Custom IEventStore

public sealed class PostgresEventStore : IEventStore
{
    public ValueTask<ulong> AppendAsync(Guid actorId, ulong expectedVersion,
        IReadOnlyList<IDomainEvent> events) { /* INSERT with concurrency check */ }

    public ValueTask<IReadOnlyList<IDomainEvent>> LoadAsync(Guid actorId)
    { /* SELECT ordered by version */ }
}

Design Philosophy (克制 / 专注 / 优雅 / 高效)

Principle In Practice
克制 (Restraint) No distributed consensus, no supervision trees — just actors and events.
专注 (Focus) Single-threaded per-actor. One message at a time.
优雅 (Elegance) Persist-then-Mutate: state changes only after persistence. Rollback is automatic.
高效 (Efficiency) AOT-compatible, zero reflection, netstandard2.0 abstractions.

Use Cases

  • Agentic AI systems — each AI agent is an actor with conversation state
  • Workflow orchestration — actors model long-running business processes
  • Game server state — event-sourced actors for player/game state
  • IoT device state — in-memory actors with periodic snapshotting

Packages

Package Target Description
PicoActor.Abs netstandard2.0 Core abstractions: IActor, IActorSystem, ICommand, IDomainEvent, IEventStore, Actor, EventSourcedActor
PicoActor net10.0 Runtime: ActorSystem, InMemoryEventStore, PicoDI integration

Comparison

Feature PicoActor Akka.NET Proto.Actor Orleans
In-memory only ✅ ✅ ✅ ❌
AOT / Trimming ✅ ❌ ❌ ❌
Event Sourcing ✅ ✅ ❌ ❌
netstandard2.0 abstractions ✅ ✅ ✅ ❌
PicoDI integration ✅ ❌ ❌ ❌
Persist-then-Mutate ✅ ❌ ❌ ❌
Distributed / Clustering ❌ ✅ ✅ ✅
Single-threaded per actor ✅ ✅ ✅ ❌
Packages 2 8+ 3+ 10+

License

MIT — see LICENSE.

Product Compatible and additional computed target framework versions.
.NET net5.0 was computed.  net5.0-windows was computed.  net6.0 was computed.  net6.0-android was computed.  net6.0-ios was computed.  net6.0-maccatalyst was computed.  net6.0-macos was computed.  net6.0-tvos was computed.  net6.0-windows was computed.  net7.0 was computed.  net7.0-android was computed.  net7.0-ios was computed.  net7.0-maccatalyst was computed.  net7.0-macos was computed.  net7.0-tvos was computed.  net7.0-windows was computed.  net8.0 was computed.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed.  net9.0 was computed.  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. 
.NET Core netcoreapp2.0 was computed.  netcoreapp2.1 was computed.  netcoreapp2.2 was computed.  netcoreapp3.0 was computed.  netcoreapp3.1 was computed. 
.NET Standard netstandard2.0 is compatible.  netstandard2.1 was computed. 
.NET Framework net461 was computed.  net462 was computed.  net463 was computed.  net47 was computed.  net471 was computed.  net472 was computed.  net48 was computed.  net481 was computed. 
MonoAndroid monoandroid was computed. 
MonoMac monomac was computed. 
MonoTouch monotouch was computed. 
Tizen tizen40 was computed.  tizen60 was computed. 
Xamarin.iOS xamarinios was computed. 
Xamarin.Mac xamarinmac was computed. 
Xamarin.TVOS xamarintvos was computed. 
Xamarin.WatchOS xamarinwatchos 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 PicoActor.Abs:

Package Downloads
PicoActor

In-memory Actor runtime for PicoNode. Provides ActorSystem (IActorSystem implementation), InMemoryEventStore, and PicoDI integration.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
2026.4.1 252 9/18/2026
2026.4.0 98 9/18/2026
2026.3.2 143 9/9/2026
2026.3.1 128 8/24/2026
2026.3.0 121 8/24/2026
2026.2.0 117 8/23/2026
2026.1.4 119 8/8/2026
2026.1.3 121 8/6/2026
2026.1.2 117 8/6/2026
2026.1.1 114 8/6/2026
2026.1.0 387 7/18/2026