The JVM has bytecode and .NET has IL. Over the last couple of weeks Screenplay became that for the business: one .play model that people, AI assistants, Studio and your C# code all write, and that VS Code, your MCP host, your running Arc application and the Cratis CLI all draw as the same event model board.
From an empty folder to a running Cratis application with dotnet new cratis or cratis new, the samples and what each leaves out, and the smaller tools around the stack: Fundamentals, Specifications, Synopsis, Narrator, Lens and the docs. It closes with where to start and the full series index.
Where an assistant meets Cratis: the AI corpus and its hooks, the CLI's effect labels, Chronicle MCP, Screenplay MCP and the docs assistant. What each one lets an assistant read, propose or change, and the checks that run whether it listened or not.
How a person admits agent work in Cratis Direct, what each gate records, and who merges the pull request. The control plane we run our own engineering on, followed through one issue, and where it stops.
A shared board and canvas where people and AI agents work on the same event model, Screenplay text you can diff, and opt-in code for one slice in your own repository. What Cratis Studio does at each step, and where each step stops.
Prologue stands beside a running system, records the metadata of what it does, and proposes a Screenplay model for a person to correct. What it watches, what it never records, how it groups what it sees, and what a language model may and may not change.
Stage renders a narrow slice of a Screenplay model into C# on Arc and Chronicle, boots a throwaway sandbox and runs the model's examples, and refuses with a code whatever it can't express. Scene is the UI model between a screen in the model and React.
The .play language for writing an event model down next to the code, a compiler whose diagnostic codes don't change, personal data declared once on a value, and an MCP server that lets an assistant propose changes a person applies.
Replays you can stop and resume, what a crash in the middle of one delivers twice, how events reach observers without making appends wait, and what running Chronicle on more than one node does and doesn't promise.
What Chronicle's production image won't start without, how the storage choice changes where read models land, what a client trusts until you tell it otherwise, where a trace stops today, and the backup order that decides whether a restore can be read.
A diagnostic summary that fails on a failed partition and not on lag, a full-screen terminal workbench for the box you reached over SSH, and a command catalog that tells an agent which commands change the server.
The Chronicle server serves its own browser tool on the port your clients already use. What each screen shows, how to follow a failed partition back to one author, and which screens can change a store.
Three places Arc's conventions make a decision you might not see: a validator that runs in the browser and on the server but not identically, a proxy folder the generator owns, and routes, event identities and mappings chosen by a name. What each one does, and the fix.
A new event shape, a new view over old events, a correction to a stored fact and an observer stuck on one stream look alike, and they aren't. What each one changes in Chronicle, what the kernel works out on its own, and what an operator still decides.
Chronicle has clients for .NET, Kotlin and Java, TypeScript and Elixir, and Arc has servers on ASP.NET Core, Spring Boot and, as a source preview, Node.js. What each one gives you today, which registry it comes from, and the defaults that still differ from .NET.
Most specs in a Cratis application can call a method and compare the event it returns. What the in-process scenarios add on top, the ways a green spec proves nothing, and the few tests that still need a real Chronicle and a running host.
AuthProxy signs the user in, picks a tenant and forwards it as Tenant-ID. Arc reads a header called x-cratis-tenant-id until you tell it otherwise, and Chronicle turns the tenant into a namespace. Every hop from the edge to storage, what a missing tenant becomes at each one, and what stays yours to check.
The author list and the register dialog from the cratis template, built with Cratis Components 4. Which parts come from Components and which from Arc, how a field binds to a generated command, how a taken name gets back to the Name field, theming and renderer adapters, and where the library stops.
In Arc, a query that loads once and a query that keeps pushing results to React differ by one return type, given data that notifies on change. The whole path from a write to the screen, the transport underneath, the hook and its states, command dialogs, view models and live tables, and which hop is live and which is a snapshot.
Every place a rule can live in a Cratis application, from the rules copied into the browser to Chronicle's append. What each layer can and can't guarantee, why a taken author name is caught in only one of them, and which rejections find their way back to a form field.
A command is a record with a Handle method and a query is a static method on the read model it returns. What Arc builds from those two shapes, in which order it checks a request, what reaches the generated TypeScript, and what stays the application's job.
Checking a read model before you append enforces nothing. Constraints, concurrency scopes, decision reads and Arc aggregates check at write time, and each reaches a different set of appends.
Reactors, webhooks and outbox-to-inbox subscriptions carry what happened to whoever cares. A failing handler stops one partition, a reactor can return its follow-up facts, and a stable delivery id is what lets a side effect survive running twice.
One attribute turns AuthorRegistered into a list on a screen. Model-bound, fluent and PDL projections, reducers for when attributes can't say it, where read models are stored, how a live list learns about changes, and what Chronicle does when a projection changes or has to be rebuilt.
Chronicle's append returns without waiting for a single projection. What the kernel does inside that call, how observers and partitions pick the event up afterwards, and what happens when one of them fails.
An event records something that happened, and no event is taken out of the log afterwards. How to name and shape events that still read in five years, and what Chronicle stores with each one: a sequence number, its source, the operation it belonged to, who caused it and why.
The sticky-note feature followed from its model to production, into year two and to agents writing its code, through every Cratis product this post names, with 26 more posts that take each one all the way down.
The zero-to-first-projection walkthrough again — same store, same domain, same destination — but this time Claude Code does the typing, using the official .NET templates and the Cratis AI `cratis/application` profile installed with `cratis ai install`, with Arc commands carrying the full loop. Every step was executed against the versions it names.
An append-only event log is the worst possible place to keep personal data — unless the store itself knows which values are personal and can make them disappear without rewriting history. How Chronicle's [PII] adornments, per-subject keys, and crypto-shredding resolve the collision.
Scaffold a full-stack Cratis application from the official .NET templates, model a small library with Arc commands and a Chronicle read model, and see it live in a React UI — every command in this post was executed against the exact versions it names.
Chronicle's kernel sits behind a language-agnostic gRPC/protobuf boundary — 26 canonical .proto contracts that any language can implement. Here's how the contract is layered, how the existing clients are built on it, and what a new client implements.
Most event sourcing comparisons reduce to popularity. We compiled a version-pinned, source-cited comparison of KurrentDB, Marten, and Cratis Chronicle instead — every row reproducible from public documentation, with the same rules applied to our own product. Here's how to use it.
What Cratis is, what Chronicle covers, and how Arc, Components, the CLI, Workbench, and the model-first layer fit together — all open source and MIT licensed.