The Cratis Web Application template
The cratis template is the full-stack starting point for a Cratis application. One command gives you a running application with the whole stack wired: Arc for commands and queries over HTTP, Chronicle for the event log, MongoDB for read models, and a React frontend that talks to generated TypeScript proxies.
dotnet new cratis -n MyStoreMongoDB is the default database. Pass --Database to scaffold against PostgreSQL, MsSql, or SQLite instead — the template then references Cratis.Arc.EntityFrameworkCore instead of Cratis.Arc.MongoDB, and docker-compose.yml provisions a matching database for the Chronicle kernel:
dotnet new cratis -n MyStore --Database PostgreSQLWhat you get
Section titled “What you get”MyStore/├── Program.cs — app setup: Arc, Chronicle, Swagger, static files├── appsettings.json — Chronicle and MongoDB connection settings├── docker-compose.yml — Chronicle dev container + Aspire dashboard├── package.json — frontend tooling (Vite, React, Tailwind)├── .frontend/ — Vite and TypeScript configuration├── App.tsx, Home.tsx — frontend application shell└── SomeModule/ — a sample domain module └── SomeFeature/ — a feature with two vertical slices ├── SomeName.cs — a ConceptAs<T> value type ├── SomeId.cs — an EventSourceId<T> identity type ├── Registration/ — command slice: Register command, event, reactor ├── Listing/ — read-model slice: Listing projected from events ├── SomeFeature.tsx — the feature's composition page └── index.ts — TypeScript barrel exportThe sample slices teach the conventions
Section titled “The sample slices teach the conventions”The Registration slice shows the command side — a model-bound command that returns the event source id it decided on plus the event to append. No controller, no handler class, no route registration:
[Command]public record Register(SomeName Name){ public (SomeId, Registered) Handle() { var eventSourceId = SomeId.New();
return (eventSourceId, new(Name)); }}SomeId is a strongly-typed identity — a Guid-backed value deriving from EventSourceId<Guid> — rather than a raw Guid. Every feature gets its own identity type this way instead of passing bare Guids around.
The Listing slice shows the read side — a read model projected from events, with a query for all instances:
[ReadModel][FromEvent<Registered>]public record Listing(Guid Id, SomeName Name, EventSourceId EventSourceId){ public static ISubject<IEnumerable<Listing>> AllListings(IMongoCollection<Listing> collection) => collection.Observe();}Post to the command route and the whole loop runs — command handled, event appended to Chronicle, reactor notified, read model updated in MongoDB:
curl -X POST http://localhost:5000/api/some-module/some-feature/registration \ -H "Content-Type: application/json" \ -d '{ "name": "Cratis" }'TypeScript proxies are generated at build time
Section titled “TypeScript proxies are generated at build time”Every dotnet build regenerates typed TypeScript proxies for your commands and queries next to their C# sources. The frontend imports them and gets compile-time safety across the stack — change a C# property and the frontend stops compiling until it catches up:
import { Register } from './Registration';
const command = new Register({ name: 'Cratis' });await command.execute();Add your first feature
Section titled “Add your first feature”Copy the SomeFeature folder shape: one folder per feature, one folder per slice, C# and TypeScript side by side. A typical feature holds a command slice, a query slice, and the React components that use them. The Cratis AI skills follow this same structure when an assistant scaffolds slices for you.
AI assistance
Section titled “AI assistance”The scaffolded project includes a .cratis/ai.json with the Cratis AI profiles, languages, and coding agent harnesses for this template — the full-stack selection covering Arc, Chronicle, Components, C#, and TypeScript. Make sure the Cratis CLI is installed, then run:
cratis ai updateThat installs the AI rules, skills, and harness integration for the coding agents you selected — AGENTS.md instructions plus .claude/, .cursor/, .github/, .opencode/, and .pi/ integration — and records what it installed in .cratis/ai.manifest.json. dotnet new prints this reminder after scaffolding, and re-running the command only refreshes Cratis-managed files, never yours. See the CLI AI documentation for the full command reference.