Real-time Claude agent that connects to the Eventmodelers Platform and implements board slices as Cratis (Arc + Chronicle) vertical slices in a .NET / C# project.
- Install the Kit — Get started in 5 minutes
- Run Your First Slice — See a slice go from Planned to Done
- Connect a Board — Set up your Eventmodelers board credentials
- Documentation — Full documentation and guides
This kit bridges the gap between the Eventmodelers Platform and Cratis:
| Component | What It Does |
|---|---|
| Eventmodelers Platform | Manages board slices with statuses like Planned, InProgress, Done |
| This Kit | Automatically implements slices as Cratis vertical slices when marked Planned |
| Cratis Chronicle | Event sourcing engine that powers the generated slices |
| Cratis Arc | CQRS framework that provides commands, queries, and projections |
The kit follows the Eventmodelers Build Kits platform contract and generates slices that follow Cratis best practices.
When you design a slice on the Eventmodelers board, you're creating a model — a specification of what should happen. But that model doesn't exist anywhere executable. Someone (or something) needs to:
- Read the slice definition from the board
- Generate the actual C# code (commands, events, projections, read models, React components)
- Build and test the code
- Update the board status when complete
This kit automates that entire process. When you mark a slice as Planned on your board, the kit:
- Fetches the slice definition in real-time
- Generates a complete Cratis vertical slice
- Builds it with
dotnet build - Tests it with
dotnet test - Updates the board to
Done
All without manual intervention.
The kit implements the Eventmodelers Build Kits platform contract. Here's what happens:
The kit runs two separate loops that can fire independently:
-
tasks.jsonnon-empty → Runprompt.md(reacts to status changes)- When a slice status changes to
Planned, the kit picks it up - When a slice is marked
DoneorBlocked, the kit logs the result
- When a slice status changes to
-
Slice is
Plannedin.slices/*/index.json→ Runbackend-prompt.md(builds one slice)- When a slice is
Planned, the kit builds exactly one slice - Then stops so the loop can re-enter and check for more work
- When a slice is
The kit automatically routes to the correct build skill based on the slice definition:
| Condition | Skill |
|---|---|
sliceType === "TRANSLATION" |
build-automation (reactors / automation) |
processors[] non-empty |
build-automation |
projections / queries / readModel present |
build-state-view |
otherwise (commands / events) |
build-state-change |
Every generated slice follows these rules:
- One
.csper slice — All backend artifacts in a single file [Command]withHandle()on the record — No separate handler class[EventType]with no attribute arguments — Past-tense, self-describing names- No nullable event properties — Model optional facts as separate events
ConceptAs<T>/EventSourceId<T>instead of raw primitives — Type-safe domain values- Namespace mirrors folder structure — Clear navigation by feature
- No
IEventLoginjection — Express appends through return types
See Cratis Conventions for the full list.
Install from git (this package is private, so use the git install path):
npx github:Cratis/Eventmodelers-Build-Kit-CSharp installOr use the upstream CLI with this repository as a git stack:
npx @eventmodelers/cli init --stack cratis-csharp --git https://github.com/Cratis/Eventmodelers-Build-Kit-CSharpAfter installation, run:
node .build-kit/ralph-claude.jsHere's what happens when you mark a slice as Planned on your Eventmodelers board:
{
"id": "slice-123",
"title": "Register Author",
"status": "Planned",
"contextName": "Authors",
"sliceType": "StateChange",
"commands": ["RegisterAuthor"],
"events": ["AuthorRegistered"],
"description": "Register a new author with name and email"
}The kit saves the slice to .build-kit/.slices/Authors/register-author/slice.json:
{
"id": "slice-123",
"title": "Register Author",
"status": "Planned",
"contextName": "Authors",
"sliceType": "StateChange",
"commands": ["RegisterAuthor"],
"events": ["AuthorRegistered"],
"description": "Register a new author with name and email"
}The kit generates a complete Cratis vertical slice in Authors/Registration/RegisterAuthor.cs:
using Cratis.Chronicle.Concepts;
using Cratis.Fundamentals;
namespace Authors.Registration;
/// <summary>
/// Represents the unique identifier of an author.
/// </summary>
public record AuthorId(Guid Value) : EventSourceId<Guid>(Value)
{
public static readonly AuthorId NotSet = new(Guid.Empty);
public static AuthorId New() => new(Guid.NewGuid());
public static implicit operator AuthorId(Guid value) => new(value);
}
/// <summary>
/// Represents the name of an author.
/// </summary>
public record AuthorName(string Value) : ConceptAs<string>(Value)
{
public static implicit operator AuthorName(string value) => new(value);
}
/// <summary>
/// Command to register a new author.
/// </summary>
/// <param name="Id">The author's unique identifier.</param>
/// <param name="Name">The author's display name.</param>
[Command]
public record RegisterAuthor(AuthorId Id, AuthorName Name) : ICanProvideEventSourceId
{
public EventSourceId GetEventSourceId() => Id;
public AuthorRegistered Handle() => new(Id, Name);
}
/// <summary>
/// Emitted when an author is registered.
/// </summary>
/// <param name="Id">The author's unique identifier.</param>
/// <param name="Name">The author's display name.</param>
[EventType]
public record AuthorRegistered(AuthorId Id, AuthorName Name);dotnet build Authors.Registration
dotnet test Authors.Registration.SpecsThe kit updates the slice status to Done on the Eventmodelers board, completing the loop.
The kit provides these Claude skills:
| Skill | Purpose |
|---|---|
build-state-change |
Generate commands and events for State Change slices |
build-state-view |
Generate projections and read models for State View slices |
build-automation |
Generate reactors and automations for Automation slices |
connect |
Connect to the Eventmodelers Platform |
load-slice |
Load a slice from the board |
update-slice-status |
Update a slice's status on the board |
See Understanding the Loop for how these skills fit into the agent loop.
The kit includes a test project that mirrors your slice structure:
Tests/
└── SomeModule/
└── SomeFeature/
└── RegistrationTests.cs ← tests for Registration slice
dotnet test # run all tests
dotnet test --filter "FullyQualifiedName~Registration" # run specific slice testsTest conventions:
- Tests live in
Tests/<Module>/<Feature>/<SliceName>Tests.cs - Use
SpecificationFor<T>base class fromCratis.Testing - Tests are marked with
[Fact]attribute (xUnit) - Follow the Arrange-Act-Assert pattern
- Use
Cratis.Chronicle.Testingfor event sourcing tests - Maintain the same structure as your implementation slices
See CLAUDE.md for the full testing documentation.
If the kit can't find your credentials:
- Check
.eventmodelers/config.jsonexists in your project root - Verify the JSON is valid:
cat .eventmodelers/config.json | jq . - Ensure your credentials are correct: app.eventmodelers.ai/account
If a slice is stuck in InProgress:
- Check the kit logs for errors
- Verify the generated code builds:
dotnet build - Run tests:
dotnet test - Update the slice status manually: app.eventmodelers.ai
See The Loop and Triggers for how the build trigger behaves independently of board connectivity.
- Documentation — Full documentation and guides
- Platform Contract — The Eventmodelers platform specification
- Cratis Documentation — Cratis framework documentation
- Kotlin Kit — The Kotlin implementation
- Java Kit — The Java implementation
MIT License — see LICENSE for details.