Skip to content

Code analysis

The Cratis Stack

The build enforces the conventions

Cratis leans on conventions: model-bound commands, [EventType] events, declarative projections, generated proxies, vertical slices, and thin React views. Conventions only help if something catches you when you stray. Cratis does that with Roslyn analyzers in dotnet build and ESLint rules in the JavaScript build, so the feedback lands where you, or an AI agent, can act on it.

If you can break a convention silently, it is a suggestion. Append a type that isn’t marked [EventType], or write a reactor method with the wrong signature, and the framework cannot discover it. The failure shows up at runtime as “nothing happened.” The analyzers move that failure to build time: the build reports which rule you broke and how to fix it, and several rules ship an editor code fix.

The frontend has the same kind of rules. Generated proxy files should not produce lint noise, view models should not call React hooks, and Components consumers should import from component subpaths and use the Cratis dialog wrappers. Those are architectural choices, so Cratis packages them as ESLint rules instead of leaving them as tribal knowledge.

This matters twice over in the AI-native workflow. When an agent scaffolds a slice, a wrong shape fails the build, the agent reads the diagnostic, and it corrects itself. Cratis AI teaches the conventions; the build gates enforce them.

The Arc analyzers come in as dependencies of the Arc packages they check: reference the package and the rules are active on your next build. The Chronicle analyzers arrive the same way with Cratis.Chronicle (and with Cratis.Chronicle.AspNetCore) from 19.4.8. Only the Architecture analyzers are a separate, opt-in package.

Each rule page lists the current rules and their default severity. The rule sets grow between releases, so check the page for the version you use instead of relying on a count.

TypeScript and React projects get the same kind of feedback from a shared flat-config preset and two product plugins:

PackageSourceWhat it checks
@cratis/eslint-configFundamentalsThe consumer preset: TypeScript and React hygiene, plus relaxations for for_* BDD spec files. (The internal preset adds the Cratis license-header rule for Cratis’s own repositories.)
@cratis/eslint-plugin-arcArcSkips generated Arc proxies, forbids React hook calls inside MVVM view models, and forbids importing mobx-react directly.
@cratis/eslint-plugin-componentsComponentsRequires component subpath imports instead of the @cratis/components root, forbids Dialog from primereact/dialog in favor of the Cratis wrappers, requires onBeforeExecute to return the command values, and forbids hooks in view models and hand-written CommandForm markers.

Install the ones you need as development dependencies, then compose them in eslint.config.mjs:

import cratis from '@cratis/eslint-config';
import arc from '@cratis/eslint-plugin-arc';
import components from '@cratis/eslint-plugin-components';
export default [
...cratis.configs.consumer,
...arc.configs.recommended,
...components.configs.recommended,
];

Keep @cratis/eslint-plugin-components on the same major version as the Components package you use; see its README for the supported range.

Inside the Cratis product repositories, CI runs these as lint gates.

The architecture and coding guidance lives in Cratis AI: C#, TypeScript, vertical slices, React components, BDD specs, Chronicle reactors, review agents, and task-specific skills. That layer tells an assistant what good Cratis code looks like.

Code analysis is the enforcement layer. Roslyn analyzers and ESLint rules run after the assistant writes code, catch what drifted, and produce concrete diagnostics it can fix in the same loop. Instructions reduce bad output; build gates make the remaining mistakes visible. Neither proves the code does the right thing. Specs do that.