![]() |
VOOZH | about |
dotnet add package Functorium --version 1.0.0-alpha.3
NuGet\Install-Package Functorium -Version 1.0.0-alpha.3
<PackageReference Include="Functorium" Version="1.0.0-alpha.3" />
<PackageVersion Include="Functorium" Version="1.0.0-alpha.3" />Directory.Packages.props
<PackageReference Include="Functorium" />Project file
paket add Functorium --version 1.0.0-alpha.3
#r "nuget: Functorium, 1.0.0-alpha.3"
#:package Functorium@1.0.0-alpha.3
#addin nuget:?package=Functorium&version=1.0.0-alpha.3&prereleaseInstall as a Cake Addin
#tool nuget:?package=Functorium&version=1.0.0-alpha.3&prereleaseInstall as a Cake Tool
English |
Functorium is named from
functor + dominiumwith a touch offun. dominium is Latin for "dominion, ownership" β Domain is not just a scope, but the problem space we own and govern.Functorium is an AI Native .NET framework where AI agents directly guide domain design and generate code. The result compiles into production code with functional architecture + DDD + Observability built in.
6 specialist AI agents guide a 7-step workflow from requirements analysis to testing. At each step, design documents and compilable C# code are generated simultaneously. No need to manually make hundreds of architecture decisions.
Functorium is designed for .NET teams practicing enterprise DDD, teams seeking to bridge the language gap between development and operations, and architects systematically adopting functional DDD architecture.
These are not simply process problems β they are problems of design philosophy and structure.
Mediator, LanguageExt, FluentValidation, and OpenTelemetry are each excellent. But integrating them into a coherent DDD architecture requires hundreds of decisions about error propagation, pipeline ordering, observability boundaries, and type constraints. Functorium makes these decisions once, consistently β and AI agents automatically apply these decisions to your project.
| Value | Features |
|---|---|
| Domain Safety | Value Object hierarchy (6 types + Union), Entity/AggregateRoot, Specification Pattern, structured error codes |
| Functional Composition | Fin<T>/FinT<IO,T> Discriminated Union, LINQ composition, Bind/Apply validation, CQRS path-optimized |
| Advanced IO | Timeout, Retry (exponential backoff), Fork (parallel execution), Bracket (resource lifecycle management) |
| Automation | 5 Source Generators, Usecase Pipeline (Observability + Validation built-in), architecture rule tests |
| Observability | 3-Pillar automatic instrumentation, ctx.* business context propagation, automatic error classification (expected/exceptional/aggregate) |
What you write β 3 lines of business rules:
- Email cannot be empty
- Email cannot exceed 320 characters
- Email must be in a valid format
What AI generates β A type-safe, composable functional validation pipeline without exceptions:
public sealed partial class Email : SimpleValueObject<string>
{
public const int MaxLength = 320;
private Email(string value) : base(value) { }
public static Fin<Email> Create(string? value) =>
CreateFromValidation(Validate(value), v => new Email(v));
// Each validation condition failure auto-generates a corresponding error code:
// NotNull β "DomainErrors.Email.Null"
// NotEmpty β "DomainErrors.Email.Empty"
// MaxLength β "DomainErrors.Email.TooLong"
// Matches β "DomainErrors.Email.InvalidFormat"
// Composite Value Objects use the Apply pattern to validate multiple fields
// in parallel, collecting all errors at once.
public static Validation<Error, string> Validate(string? value) =>
ValidationRules<Email>
.NotNull(value)
.ThenNotEmpty()
.ThenNormalize(v => v.Trim().ToLowerInvariant())
.ThenMaxLength(MaxLength)
.ThenMatches(EmailRegex(), "Invalid email format");
// For ORM/Repository restoration β accepts only already-normalized data
public static Email CreateFromValidated(string value) => new(value);
public static implicit operator string(Email email) => email.Value;
}
Just define business rules in text. This complex but safe code is generated by AI agents.
<details> <summary><strong>Comparison with traditional C# exception handling</strong> β Why Fin<T> instead of exceptions?</summary>
Before β Traditional C# validation. Exceptions are landmines buried in control flow:
public class Email
{
public Email(string value)
{
if (string.IsNullOrWhiteSpace(value))
throw new ArgumentException("Email cannot be empty"); // Runtime bomb
// if the next developer forgets try-catch, the system dies
Value = value;
}
public string Value { get; }
}
After β Functorium's functional validation. Failure possibility is explicit in the return type β if you don't handle it, it won't compile:
public sealed partial class Email : SimpleValueObject<string>
{
public static Fin<Email> Create(string? value) => // Fin<T>: success or structured error
CreateFromValidation(Validate(value), v => new Email(v)); // Composable pipeline without exceptions
}
</details>
This is how AI generates exception-free, safe code structures automatically.
| Role | Responsibility | Concrete Artifacts |
|---|---|---|
| Human | Define business rules + ubiquitous language in text | PRD, invariant list, glossary |
| AI Agent | Build complex control flow, monad plumbing, boilerplate | Fin<T> pipelines, CQRS usecases, Source Generator code |
| Observability | Translate AI-generated code into human-readable diagnostics | Structured logs, dashboards, automatic error classification |
"Can I debug AI-written monad code at 2 AM?"
The framework's automatic error classification + structured context logs + dashboards β built into every Command/Query β translate code state into human language.
| Problem | Breakthrough Direction | AI Agent's Role | What the Framework Guarantees |
|---|---|---|---|
| Exceptions and implicit side effects | Exception-free pure domain | domain-architect classifies business invariants and maps them to types | Fin<T>, FinT<IO,T> make results and side effects explicit at the type level; LINQ composition structures domain flow |
| Development/operations language separation | Unified domain language | product-analyst extracts Ubiquitous Language and consistently reflects it across code/docs/metrics | Bounded Context clearly defined so domain concepts are consistently reflected in code, docs, and operational metrics. ctx.* field auto-propagation |
| Observability as afterthought | Observability by design | observability-engineer designs KPIβmetric mapping, dashboards, and alerts | OpenTelemetry-based Logging, Metrics, Tracing automatically applied to usecase pipelines. [GenerateObservablePort] |
From PRD writing to testing, 7 skills + 6 specialist agents guide the way.
project-spec : PRD writing, Ubiquitous Language, Aggregate boundary extraction
β architecture-design : Project structure, layer composition, infrastructure decisions
β domain-develop : Value Object, Entity, Aggregate, Specification implementation
β application-develop : CQRS usecase, Port design and implementation
β adapter-develop : Repository, Query Adapter, Endpoint, DI registration
β observability-develop : KPIβmetric mapping, dashboards, alerts, ctx.* propagation
β test-develop : Unit/integration/architecture rule test writing
domain-review : DDD review of existing code and improvement guidance (standalone skill)
Each step follows a 4-stage document pattern. Every design decision has traceable rationale:
00-business-requirements : Business rule definition
β 01-type-design-decisions : Invariant β type mapping
β 02-code-design : C# pattern design
β 03-implementation-results : Compilable code + tests
Each agent takes the output of the previous stage, adds its own expertise, and passes the baton to the next:
Human: Business requirements text
β
product-analyst β Ubiquitous Language + Aggregate boundaries
β
domain-architect β Invariant classification + type mapping (VO, Entity, Aggregate)
β
application-architect β CQRS usecases + Port interfaces
β
adapter-engineer β Repository, Endpoint, DI, Observable Port
β
observability-engineer β KPIβmetric mapping + dashboards + alerts
β
test-engineer β Unit/integration/architecture rule tests
| Step | Input | Agent | Output |
|---|---|---|---|
| 1 | Natural language requirements | product-analyst | Ubiquitous Language glossary, Aggregate boundaries, P0/P1/P2 priorities |
| 2 | Glossary + invariant list | domain-architect | Type mapping (SimpleValueObject, SmartEnum, etc.), Always-valid patterns |
| 3 | Type definitions + domain model | application-architect | CQRS usecases, Port interfaces, FinT LINQ composition |
| 4 | Port interfaces | adapter-engineer | EF Core Repository, Dapper Query, FastEndpoints, DI, Observable Port |
| 5 | Adapter implementation code | observability-engineer | KPIβmetric mapping, L1/L2 dashboards, alert rules, ctx.* propagation |
| 6 | Full codebase | test-engineer | Unit/integration/architecture rule tests, verification report |
Building on the Email implementation above, let's explore additional framework patterns. For CQRS Command/Query usecase implementation examples, see the .
<details> <summary><strong>Domain Model in Detail</strong> β Value Object, Entity, AggregateRoot, DomainError, Domain Event</summary>
The domain-architect agent of the domain-develop skill classifies business invariants and maps them to the Functorium type system. All core business logic resides within the domain model, and entities, value objects, aggregates, and domain services have clear responsibilities.
Value Object β Ensures value-based equality and immutability:
public abstract class AbstractValueObject : IValueObject, IEquatable<AbstractValueObject>
{
protected abstract IEnumerable<object> GetEqualityComponents();
// Value-based equality, cached hash code, ORM proxy handling
}
Entity / AggregateRoot β Provides Ulid-based IDs and domain event management:
public interface IEntityId<T> : IEquatable<T>, IComparable<T>
where T : struct, IEntityId<T>
{
Ulid Value { get; }
static abstract T New();
static abstract T Create(Ulid id);
static abstract T Create(string id);
}
public abstract class AggregateRoot<TId> : Entity<TId>, IDomainEventDrain
where TId : struct, IEntityId<TId>
{
protected void AddDomainEvent(IDomainEvent domainEvent);
public void ClearDomainEvents();
}
DomainError β Ensures recoverability through structured error codes:
// Auto-generated error code: "DomainErrors.Email.Empty"
DomainError.For<Email>(new Empty(), value, "Email cannot be empty");
// Auto-generated error code: "DomainErrors.Password.TooShort"
DomainError.For<Password>(new TooShort(MinLength: 8), value, "Password too short");
Domain Event β Integrates Mediator-based Pub/Sub with event tracking:
public interface IDomainEvent : INotification
{
DateTimeOffset OccurredAt { get; }
Ulid EventId { get; }
string? CorrelationId { get; }
string? CausationId { get; }
}
</details>
<details> <summary><strong>CQRS and Functional Composition in Detail</strong> β Repository, Query Port, Command/Query Interfaces</summary>
The application-develop skill assembles domain models into CQRS usecases. Core domain logic is composed of pure functions. By maintaining a structure where identical inputs always produce identical outputs, the logic becomes predictable and easy to test. Side effects (database, external APIs, messaging, file I/O) are handled outside the domain logic. The IO monad provides built-in advanced features such as Timeout, Retry (exponential backoff), Fork (parallel execution), and Bracket (resource lifecycle management), enabling type-safe fault tolerance configuration for external service calls.
Fin<T>, FinT<IO, T> β Handles errors with explicit result types instead of exceptions. The Command path Repository returns FinT<IO, T> to explicitly express side effects:
// Command: IRepository β Per-Aggregate Root CRUD, change tracking and transaction management via EF Core
public interface IRepository<TAggregate, TId> : IObservablePort
where TAggregate : AggregateRoot<TId>
where TId : struct, IEntityId<TId>
{
FinT<IO, TAggregate> Create(TAggregate aggregate);
FinT<IO, TAggregate> GetById(TId id);
FinT<IO, TAggregate> Update(TAggregate aggregate);
FinT<IO, int> Delete(TId id);
// Bulk operations
FinT<IO, Seq<TAggregate>> CreateRange(IReadOnlyList<TAggregate> aggregates);
FinT<IO, Seq<TAggregate>> GetByIds(IReadOnlyList<TId> ids);
FinT<IO, Seq<TAggregate>> UpdateRange(IReadOnlyList<TAggregate> aggregates);
FinT<IO, int> DeleteRange(IReadOnlyList<TId> ids);
}
CQRS β Structurally separates write and read paths, applying optimized data access strategies for each. Command uses IRepository + EF Core for Aggregate consistency and transactions, while Query uses IQueryPort + Dapper for direct DTO projection without Aggregate reconstruction. Both paths unify results through FinResponse<T>:
// Command
public interface ICommandRequest<TSuccess> : ICommand<FinResponse<TSuccess>> { }
public interface ICommandUsecase<in TCommand, TSuccess>
: ICommandHandler<TCommand, FinResponse<TSuccess>>
where TCommand : ICommandRequest<TSuccess> { }
// Query
public interface IQueryRequest<TSuccess> : IQuery<FinResponse<TSuccess>> { }
public interface IQueryUsecase<in TQuery, TSuccess>
: IQueryHandler<TQuery, FinResponse<TSuccess>>
where TQuery : IQueryRequest<TSuccess> { }
// Query: IQueryPort β Direct DTO projection without Aggregate reconstruction, lightweight SQL mapping via Dapper
public interface IQueryPort<TEntity, TDto> : IQueryPort
{
FinT<IO, PagedResult<TDto>> Search(
Specification<TEntity> spec, PageRequest page, SortExpression sort);
FinT<IO, CursorPagedResult<TDto>> SearchByCursor(
Specification<TEntity> spec, CursorPageRequest cursor, SortExpression sort);
IAsyncEnumerable<TDto> Stream(
Specification<TEntity> spec, SortExpression sort,
CancellationToken cancellationToken = default);
}
| Command (IRepository) | Query (IQueryPort) | |
|---|---|---|
| Purpose | Aggregate Root lifecycle management | Read-only DTO projection |
| Implementation | EF Core β change tracking, transactions, domain events | Dapper β pure SQL, lightweight mapping |
| Specification | PropertyMap β EF Core LINQ translation |
DapperSpecTranslator β SQL WHERE translation |
| Pagination | β | Offset/Limit, Cursor (keyset), Streaming |
</details>
<details> <summary><strong>Observability by Design in Detail</strong> β Pipeline, Observable Port, ctx.*, Error Classification</summary>
The observability-develop skill embeds operational stability from the design phase. All Commands and Queries automatically pass through a pipeline with built-in Observability (Logging, Metrics, Tracing) and validation. Developers do not need to write log code manually.
flowchart TD
A["Common: Observability + Validation
(Logging Β· Metrics Β· Tracing Β· Validation)"] --> B[Command Path]
A --> C[Query Path]
B --> D["Transaction + Domain Event Publishing"]
C --> E["Caching + Pagination"]
Command publishes domain events within transaction boundaries, and Query provides caching and pagination. For the exact pipeline stages and order, see the .
IObservablePort β All external dependencies are abstracted as observable ports:
public interface IObservablePort
{
string RequestCategory { get; }
}
ctx. 3-Pillar Enrichment* β The Source Generator automatically transforms Request/Response/DomainEvent properties into ctx.{snake_case} fields, propagating business context simultaneously to Logging, Tracing, and Metrics. Metrics tags can be opted in with [CtxTarget(CtxPillar.All)].
[GenerateObservablePort] β The Source Generator automatically creates Observable wrappers for Adapters, transparently providing OpenTelemetry-based Tracing, Logging, and Metrics:
[GenerateObservablePort] // β Observable{ClassName} auto-generated (e.g., ObservableOrderRepository)
public class OrderRepository : IRepository<Order, OrderId> { ... }
Automatic Error Classification β Business rule violations (e.g., "insufficient stock") are classified as expected, system failures (NullReferenceException) as exceptional, and compound validation failures as aggregate. The error.type field allows separate querying of business errors and system failures in Seq/Grafana.
</details>
# Load both plugins simultaneously
claude --plugin-dir ./.claude/plugins/functorium-develop --plugin-dir ./.claude/plugins/release-note
Start with "Write a PRD for an e-commerce platform" and the AI agents will guide you through the 7-step workflow.
# Core domain modeling β Value Object, Entity, AggregateRoot, Specification, error system
dotnet add package Functorium
# Infrastructure adapters β OpenTelemetry, Serilog, EF Core, Dapper, Pipeline
dotnet add package Functorium.Adapters
# Code generation β [GenerateObservablePort], [GenerateEntityId], CtxEnricher
dotnet add package Functorium.SourceGenerators
# Test utilities β ArchUnitNET, xUnit extensions, integration test fixtures
dotnet add package Functorium.Testing
5-Minute Quickstart: Build a Value Object β AggregateRoot β Command Usecase in 5 minutes at .
First Tutorial: Dive deep into Value Objects at the .
Full Documentation: https://hhko.github.io/Functorium
C# script-based data collection, Conventional Commits analysis, Breaking Changes detection, release note writing, and validation β a 5-step workflow automated by 1 skill + 1 agent.
| Principle | Description |
|---|---|
| Accuracy First | APIs not in the Uber file (all-api-changes.txt) are never documented |
| Value Delivery Required | All major features include a "Why this matters" section |
| Automatic Breaking Changes Detection | Git Diff analysis takes precedence over commit message patterns |
| Traceability | All features are tracked by commit SHA |
Detailed documentation: AX (AI Transformation)
The system is composed of three layers. The domain depends on nothing external, and dependencies always flow inward.
Functorium provides unified observability (Logging, Metrics, Tracing) based on OpenTelemetry.
| Observation Path | Target | Mechanism | Recorded Content |
|---|---|---|---|
| Usecase Pipeline | All Command/Query | Mediator IPipelineBehavior |
request/response fields + ctx.* + error classification |
| Observable Port | Repository, QueryAdapter, ExternalService | [GenerateObservablePort] Source Generator |
Same request/response field scheme |
| DomainEvent | Publisher + Handler | ObservableDomainEventPublisher |
Event type/count + partial failure tracking |
The Application layer (EventId 1001β1004) and Adapter layer (EventId 2001β2004) use identical request.* / response.* / error.* naming, enabling end-to-end request flow tracking with a single dashboard query.
For detailed specifications and guides, see the documentation site:
Why AI-generated code can be deployed to production β a triple verification gate blocks architecture violations, business rule errors, and observability gaps at build time.
If the domain layer depends on infrastructure? The build fails:
[Fact]
public void DomainLayer_ShouldNotDependOn_ApplicationLayer()
{
Types()
.That().ResideInNamespace(DomainNamespace)
.Should().NotDependOnAnyTypesThat()
.ResideInNamespace(ApplicationNamespace)
.Check(Architecture);
}
Functorium.Testing provides 6 TestSuite base classes β just inherit and 21+ architecture rules are automatically applied:
| TestSuite | Verification Target |
|---|---|
DomainArchitectureTestSuite |
sealed class, private constructors, Fin<T> return types, etc. |
ApplicationArchitectureTestSuite |
Command/Query Usecase structure |
AdapterArchitectureTestSuite |
virtual methods, Observable Port |
CqrsArchitectureTestSuite |
Command/Query separation |
DtoArchitectureTestSuite |
sealed record |
PortInterfaceArchitectureTestSuite |
Port interface rules |
The test-engineer agent automatically generates boundary condition tests for all Value Objects:
[Theory]
[InlineData("")]
[InlineData(null)]
public void Create_ShouldFail_WhenValueIsEmptyOrNull(string? value)
{
var actual = Email.Create(value);
actual.IsFail.ShouldBeTrue();
}
[Fact]
public void Create_ShouldFail_WhenValueExceedsMaxLength()
{
var value = new string('a', Email.MaxLength + 1);
var actual = Email.Create(value);
actual.IsFail.ShouldBeTrue();
}
When AI-generated code violates rules, the build pipeline blocks immediately:
FAILED ValueObject_ShouldBe_PublicSealedWithPrivateConstructors
ArchitectureRuleViolation:
Class 'Email' violates ValueObject Visibility Rule
β Expected: public sealed with all private constructors
β Actual: constructor 'Email(string)' is public
1 architecture rule violation(s) detected.
Generation is half the system; ruthless verification is the other half. Architecture rule tests verify AI-generated code and human-written code equally.
Full Documentation Site: https://hhko.github.io/Functorium
| Tutorial | Topic | Exercises |
|---|---|---|
| Value Object, Validation, Immutability | 29 | |
| Specification, Expression Tree | 18 | |
| CQRS, Repository, Query Adapter | 22 | |
| Generic Variance, IFinResponse, Pipeline Constraints | 20 | |
| Architecture Rules, ClassValidator | 16 | |
| Source Generator, Observable Wrapper | β | |
| AI Automation, Release Notes | β |
| Sample | Scope | Aggregates | Key Patterns |
|---|---|---|---|
| Domain | 1 | VO, Union, Composite, Specification | |
| Domain + Application | 5 | CQRS, EventHandler, DomainService, ApplyT | |
| Domain + Application + Adapter | 4 | EF Core/Dapper/InMemory, FastEndpoints, IO.Retry/Timeout/Fork/Bracket |
| Package | Description |
|---|---|
Functorium |
Core domain modeling β Value Object, Entity, AggregateRoot, Specification, error system |
Functorium.Adapters |
Infrastructure adapters β OpenTelemetry, Serilog, EF Core, Dapper, Pipeline |
Functorium.SourceGenerators |
Code generation β [GenerateObservablePort], [GenerateEntityId], CtxEnricherGenerator |
Functorium.Testing |
Test utilities β ArchUnitNET, xUnit extensions, integration test fixtures |
| Category | Key Libraries |
|---|---|
| Functional | LanguageExt.Core, Ulid, Ardalis.SmartEnum |
| Validation | FluentValidation |
| Mediator | Mediator (source-generated), Scrutor |
| Persistence | EF Core, Dapper |
| Observability | OpenTelemetry, Serilog |
| Testing | xUnit v3, ArchUnitNET, Verify.Xunit, Shouldly |
| 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 2 NuGet packages that depend on Functorium:
| Package | Downloads |
|---|---|
|
Functorium.Adapters
Functorium.Adapters - Infrastructure adapters for the Functorium framework |
|
|
Functorium.Testing
Functorium.Testing - Testing utilities for a functional domain framework for .NET |
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 1.0.0-alpha.4 | 72 | 4/27/2026 |
| 1.0.0-alpha.3 | 60 | 4/19/2026 |
| 1.0.0-alpha.2 | 73 | 4/9/2026 |