koan-entity-first
About
This skill provides an Entity<T> pattern that eliminates manual repository boilerplate by making entities self-persisting. It features automatic GUID v7 generation and provides both instance methods like `entity.Save()` and static queries like `Entity.All()`. Use this for provider-agnostic data access that works across SQL, NoSQL, and other stores with minimal code.
Quick Install
Claude Code
Recommended/plugin add https://github.com/sylin-org/koan-frameworkgit clone https://github.com/sylin-org/koan-framework.git ~/.claude/skills/koan-entity-firstCopy and paste this command in Claude Code to install this skill
Documentation
Koan Entity-First Development
Core Principle
Entity<T> replaces manual repositories. Every entity is self-aware and self-persisting. This pattern eliminates repository boilerplate while maintaining provider transparency.
Revolutionary Approach
- GUID v7 Auto-Generation: IDs generated automatically with chronological ordering
- Instance Methods:
await entity.Save(),await entity.Remove() - Static Queries:
await Entity.All(),await Entity.Get(id),await Entity.Query() - Provider Agnostic: Same code works across SQL, NoSQL, Vector, JSON stores
Quick Reference Card
Basic Operations
// Create entity
public class Todo : Entity<Todo>
{
public string Title { get; set; } = "";
public bool Completed { get; set; }
// Id automatically generated as GUID v7 on first access
}
// Save (create or update)
var todo = new Todo { Title = "Buy milk" };
await todo.Save();
// Retrieve by ID
var loaded = await Todo.Get(id);
// Query all
var allTodos = await Todo.All();
// Filter with LINQ
var completed = await Todo.Query(t => t.Completed);
// Remove
await todo.Remove();
Custom Keys (When Needed)
// For non-GUID keys: Entity<T, TKey>
public class NumericEntity : Entity<NumericEntity, int>
{
public override int Id { get; set; }
public string Title { get; set; } = "";
}
// Manual key management
var entity = new NumericEntity { Id = 42, Title = "Meaningful" };
await entity.Save();
Batch Operations
Batch Retrieval (Prevents N+1 Queries)
// ✅ EFFICIENT: Single bulk query with IN clause
var ids = new[] { id1, id2, id3, id4 };
var todos = await Todo.Get(ids, ct);
// Result: [Todo?, Todo?, null, Todo?] - preserves order, null for missing
// ❌ INEFFICIENT: N database round-trips
var todos = new List<Todo?>();
foreach (var id in ids)
{
todos.Add(await Todo.Get(id, ct)); // N queries!
}
Use Cases:
- Collection/playlist pagination - fetch page of items by stored IDs
- Relationship navigation - fetch all related entities at once
- Bulk validation - check which IDs exist in single query
Performance: Single query vs N queries = 10-100x faster for typical datasets
Batch Persistence
// Bulk save - efficient provider-specific batching
var todos = Enumerable.Range(0, 1000)
.Select(i => new Todo { Title = $"Task {i}" })
.ToList();
await todos.Save();
// Batch operations - add/update/delete in one transaction
await Todo.Batch()
.Add(new Todo { Title = "New task" })
.Update(existingId, todo => todo.Completed = true)
.Delete(oldId)
.SaveAsync();
Pagination & Streaming
Pagination (Web APIs)
// Basic pagination
var page = await Todo.Page(pageNumber: 1, pageSize: 20);
// With total count for UI
var result = await Todo.QueryWithCount(
t => t.ProjectId == projectId,
new DataQueryOptions(
orderBy: nameof(Todo.Created),
descending: true
),
ct);
Console.WriteLine($"Showing {result.Items.Count} of {result.TotalCount}");
Streaming (Large Datasets)
// Stream to avoid loading everything into memory
await foreach (var todo in Todo.AllStream(batchSize: 1000, ct))
{
// Process in batches - memory-efficient
await ProcessTodo(todo);
}
// Stream with filter
await foreach (var reading in Reading.QueryStream(
"plot == 'A1'",
batchSize: 200,
ct))
{
await ProcessReading(reading);
}
When to Stream: Large datasets (>10k records), background jobs, ETL pipelines
Anti-Patterns to Avoid
❌ WRONG: Manual Repository Pattern
// DON'T create repository interfaces
public interface ITodoRepository
{
Task<Todo> GetAsync(string id);
Task SaveAsync(Todo todo);
Task<List<Todo>> GetAllAsync();
}
// DON'T inject repositories
public class TodoService
{
private readonly ITodoRepository _repo; // Unnecessary!
public TodoService(ITodoRepository repo) => _repo = repo;
}
Why wrong? Entity<T> already provides all repository functionality. Manual repositories:
- Duplicate framework features
- Break provider transparency
- Add unnecessary abstraction layers
- Increase maintenance burden
✅ CORRECT: Entity Service Pattern
// Business logic services use Entity<T> directly
public class TodoService
{
public async Task<Todo> CompleteAsync(string id)
{
var todo = await Todo.Get(id); // Direct entity usage
if (todo is null)
throw new InvalidOperationException("Todo not found");
todo.Completed = true;
return await todo.Save(); // Instance save method
}
public async Task<List<Todo>> GetCompletedAsync()
{
return await Todo.Query(t => t.Completed); // Static query
}
}
When This Skill Applies
Invoke this skill when:
- ✅ Creating new entities
- ✅ Adding data access code
- ✅ Refactoring repositories to Entity<T>
- ✅ Building CRUD operations
- ✅ Reviewing data access patterns
- ✅ Troubleshooting entity persistence
- ✅ Optimizing queries (batch operations, streaming)
Advanced: Count Operations
// Default: framework chooses best strategy (usually optimized)
var total = await Todo.Count;
// Explicit exact count (guaranteed accuracy, may be slower)
var exact = await Todo.Count.Exact(ct);
// Explicit fast count (metadata estimate, extremely fast)
var fast = await Todo.Count.Fast(ct);
// Filtered count
var completed = await Todo.Count.Where(t => t.Completed);
Performance: Fast counts use database metadata (1000-20000x faster on large tables)
- Postgres:
pg_stat_user_tables(~5ms vs 25s for 10M rows) - SQL Server:
sys.dm_db_partition_stats(~1ms vs 20s) - MongoDB:
estimatedDocumentCount()(~10ms vs 15s)
When to Use:
- Fast: Pagination UI, dashboard summaries, estimates acceptable
- Exact: Critical business logic, inventory counts, reports requiring accuracy
Bundled Resources
examples/entity-crud.cs- Complete CRUD patternsexamples/entity-relationships.cs- Navigation helpersexamples/batch-operations.cs- Bulk loading and savinganti-patterns/manual-repositories.md- What NOT to do with detailed explanations
Reference Documentation
- Full Guide:
docs/guides/entity-capabilities-howto.md - Data Modeling:
docs/guides/data-modeling.md - ADR: DATA-0059 (Entity-first facade decision)
- Sample:
samples/S1.Web/(Relationship patterns) - Sample:
samples/S0.ConsoleJsonRepo/(Minimal 20-line example)
Framework Compliance
Entity<T> patterns are mandatory in Koan Framework. Manual repositories break:
- Provider transparency
- Framework auto-registration
- Capability detection
- Multi-tenant context routing
Always prefer Entity<T> patterns over custom data access abstractions.
GitHub Repository
Related Skills
content-collections
MetaThis skill provides a production-tested setup for Content Collections, a TypeScript-first tool that transforms Markdown/MDX files into type-safe data collections with Zod validation. Use it when building blogs, documentation sites, or content-heavy Vite + React applications to ensure type safety and automatic content validation. It covers everything from Vite plugin configuration and MDX compilation to deployment optimization and schema validation.
creating-opencode-plugins
MetaThis skill provides the structure and API specifications for creating OpenCode plugins that hook into 25+ event types like commands, files, and LSP operations. It offers implementation patterns for JavaScript/TypeScript modules that intercept and extend the AI assistant's lifecycle. Use it when you need to build event-driven plugins for monitoring, custom handling, or extending OpenCode's capabilities.
langchain
MetaLangChain is a framework for building LLM applications using agents, chains, and RAG pipelines. It supports multiple LLM providers, offers 500+ integrations, and includes features like tool calling and memory management. Use it for rapid prototyping and deploying production systems like chatbots, autonomous agents, and question-answering services.
cloudflare-turnstile
MetaThis skill provides comprehensive guidance for implementing Cloudflare Turnstile as a CAPTCHA-alternative bot protection system. It covers integration for forms, login pages, API endpoints, and frameworks like React/Next.js/Hono, while handling invisible challenges that maintain user experience. Use it when migrating from reCAPTCHA, debugging error codes, or implementing token validation and E2E tests.
