Open Source Initiative

Sophisticated patterns.
Accessible to everyone.

Advanced software patterns—CQRS, event sourcing, vector search—are locked behind walls of complexity and configuration. We believe these patterns should be learnable by building, not by reading academic papers. Our tools take your hand and show you the path.

The Pattern Paradox

Enterprise patterns solve real problems. CQRS prevents read/write bottlenecks. Event sourcing enables audit trails and time-travel debugging. Vector search powers semantic understanding. These patterns exist because they work. But they're trapped behind walls of complexity.

Want to try CQRS? First, spend 3 days understanding MediatR, handlers, pipelines, validation, and dependency injection. Then do it again for the next project. Advanced patterns are locked behind walls of boilerplate—you can't experiment until you've invested weeks learning the setup. Every new capability means new services to configure, new connection strings, new docker-compose files. Want semantic search? Great, here are 12 decisions to make first.

Complex patterns should reveal themselves through simple code. Write Todo.Save() and discover repositories, validation, event publishing. See it work, then understand why. Add one package, write one entity, get CQRS, multi-provider data access, auto-generated APIs, and event-driven architecture. Experiment freely, learn as you build.

Want vector search? Add [Embedding] to a property. Need Postgres? Reference the connector. Your intent is clear, infrastructure disappears.

Take your hand and show you the path. That's Sylin.

Six pillars, zero configuration

Entity-first development, multi-provider data access, native AI, auto-generated APIs, event-driven messaging, and container orchestration. Add a package reference, write an entity, watch it work. That's Koan.

Entity-First Development

1Define your entity

public class Todo : Entity<Todo>
{
    public string Title { get; set; } = "";
    public bool IsCompleted { get; set; }
}

2It just works

// Auto-generated GUID v7 IDs
var todo = new Todo { Title = "Try Koan Framework" };
await todo.Save();

// Query naturally
var all = await Todo.Query();
var pending = await Todo.Where(t => !t.IsCompleted);
Read the Core documentation →

Multi-Provider Transparency

1Add any database

# Reference = Intent (zero configuration)
dotnet add package Koan.Data.Connector.Postgres
# Or: Sqlite, Mongo, Redis, SqlServer, Couchbase...

2Same code, different stores

// Routes to Postgres automatically
await product.Save();

// Switch providers via config - code unchanged
// appsettings.json: "Data:Provider": "Mongo"

// Even mix providers in the same app
[StoreIn("Redis")]
public class Session : Entity<Session> { }
Read the Data documentation →

Native AI Integration

1Enable semantic search

public class Document : Entity<Document>
{
    public string Title { get; set; } = "";
    public string Content { get; set; } = "";

    [Embedding]  // Auto-generates embeddings
    public string SearchableText => $"{Title} {Content}";
}

2Search semantically

// Natural language queries
var results = await Document.SemanticSearch(
    "kubernetes deployment strategies",
    limit: 10
);

// Vector operations feel like LINQ
var similar = await doc.FindSimilar(threshold: 0.8);
Read the AI documentation →

Auto-Generated APIs

1Define controller

[ApiController, Route("api/[controller]")]
public class ProductsController : EntityController<Product>
{
    // That's it. Full REST API generated.
}

2Full CRUD out of the box

GET    /api/products          # List with filtering
GET    /api/products/{id}     # Get by ID
POST   /api/products          # Create
PUT    /api/products/{id}     # Update
PATCH  /api/products/{id}     # Partial update
DELETE /api/products/{id}     # Delete

// Plus: filtering, sorting, pagination, field selection
Read the Web documentation →

Event-Driven Architecture

1Send events

// Same Entity<T> pattern extends to messaging
await new OrderCompleted
{
    OrderId = order.Id,
    Total = order.Total
}.Send();

2Handle events

public class OrderCompletedHandler : IMessageHandler<OrderCompleted>
{
    public async Task Handle(OrderCompleted evt)
    {
        // Auto-discovered via Reference = Intent
        await SendConfirmationEmail(evt.OrderId);
    }
}
Read the Messaging documentation →

Container Management

1Define dependencies

// appsettings.json
{
  "Orchestration": {
    "Services": ["postgres", "redis", "rabbitmq"]
  }
}

2Auto-generated compose files

# Koan discovers dependencies and generates docker-compose.yml
dotnet run

# Health checks, networking, volumes - all handled
# Or use the CLI:
koan compose generate
koan compose up
Read the Orchestration documentation →

Built to feel natural

Every feature designed to eliminate boilerplate, reduce cognitive load, and let you focus on what matters—your domain logic.

Zero-Code REST APIs

Inherit from EntityController<T> and get full CRUD + Query + Patch API automatically.

public class MembersController :
  EntityController<Member> { }

✓ Eliminates 100+ lines of boilerplate per controller

No Repository Injection

CRUD operations as static methods directly on entities. No DI, no interfaces, no service layers.

var member = await Member.Get(id);
await member.Save();

✓ Just call the method

One-Line Framework Setup

Single method call auto-discovers and registers everything.

builder.Services.AddKoan();
// That's it.

✓ Zero manual registration

Lifecycle Events

BeforeUpsert/AfterUpsert hooks with declarative field protection.

Reading.Events
  .Setup(ctx => ctx.ProtectAll())
  .BeforeUpsert(async ctx => { })

✓ Type-safe, co-located with entity

Instant Relationships

Declare FK relationships with a single attribute.

[Parent(typeof(Member))]
public string? MemberId { get; set; }

✓ No Fluent API needed

Built-in File Handling

MediaEntity<T> with automatic storage integration.

var stream = await photo.OpenRead();
return File(stream, photo.ContentType);

✓ Entity IS the file handle

Automatic Vector Detection

float[] properties automatically become embeddings—no attribute needed.

public float[]? Embedding { get; set; }
// Vector search enabled automatically

✓ Convention over configuration

Reference = Intent

Add package reference, get functionality—no registration needed.

<PackageReference
  Include="Koan.Data.Connector.Postgres" />

✓ Auto-discovered and registered

Smart Property Detection

No [NotMapped] attributes—framework detects computed properties automatically.

public string FullName =>
  $"{FirstName} {LastName}";

✓ Just write C# naturally

Built-In Batch Operations

Get multiple entities with single call, optimized by provider.

var photos = await Photo.Get(ids);
var all = await Photo.All();

✓ No N+1 queries

Custom ID Types

Use any type as primary key with Entity<T, TKey>.

public class Sensor :
  Entity<Sensor, string> { }

✓ Natural keys without extra fields

Prior State Access

Compare current vs previous entity state in lifecycle hooks.

var prior = await ctx.Prior.Get();
if (prior?.PlotId != ctx.Current.PlotId)
  // Handle change

✓ No manual state tracking