一键导入
add-business-rule
Use this skill when asked to add a validation rule, business rule, or uniqueness constraint to an existing command in a Cratis-based project.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
菜单
Use this skill when asked to add a validation rule, business rule, or uniqueness constraint to an existing command in a Cratis-based project.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
Step-by-step guidance for building a React page in a Cratis Arc application — listing data with DataPage, toolbar actions with CommandDialog, row selection, detail panels, observable queries, and MVVM. Use whenever building or modifying a React page that lists or displays data, adding a table or grid, wiring up Add/Edit/Delete actions, using DataPage, DataTableForQuery, CommandDialog, or any @cratis/components. Also trigger when connecting a React component to a proxy-generated query or observable query.
Use this skill when asked to add a Chronicle reactor (automation or translation) to a Cratis-based project. Reactors observe events and produce side effects.
Diátaxis Documentation Expert for Cratis projects. Writes high-quality DocFX documentation guided by the Diátaxis framework — classifying every page as a Tutorial, How-to Guide, Reference, or Explanation.
Use this skill when changing, fixing, or improving Cratis documentation whose source file is under `Documentation/**` in a product or contributing repo. The content is split across repos (each product owns its docs in its own `Documentation/` folder; the `Documentation` repo aggregates them), so this skill finds the real source file, edits it, syncs, and verifies. Trigger whenever someone asks to edit/update/fix/reword a docs page, fix a broken link, correct a code example, update a guide or tutorial or reference page, or says a docs page is wrong/outdated — for Chronicle, Arc, Components, CLI, Fundamentals, or the contributing docs.
Use this skill to visually QA rendered docs site pages after changes to source files under `Documentation/**` — screenshot pages headless in light AND dark, evaluate how they look against the aspire.dev bar, check diagrams/tables/code blocks render, and diagnose layout-shift ("flicker"/"twitch"/"pop") bugs. Trigger when someone asks to screenshot the docs, check how a docs page looks, review the docs visually, verify a diagram or table renders, compare the docs to aspire.dev, or investigate a flicker/jump/layout-shift on the docs site.
Use this skill when creating a NEW Cratis documentation page under `Documentation/**` in a product or contributing repo — a new tutorial chapter, how-to/guide, explanation/concept page, reference page, or scenario/recipe. Handles where the file goes (which product repo), wiring it into the sidebar nav (toc.yml + Diátaxis bucket), and verifying it renders. Trigger when someone asks to add/create/write a new docs page, document a new feature, add a guide/tutorial/recipe/concept to the docs, or add a new section to a product's documentation.
| name | add-business-rule |
| description | Use this skill when asked to add a validation rule, business rule, or uniqueness constraint to an existing command in a Cratis-based project. |
Add a business rule or event-store constraint to an existing command.
| Scenario | Use |
|---|---|
| Single-event uniqueness (most cases) | [Unique] attribute on the event type |
Multi-event uniqueness or needs RemovedWith | IConstraint |
| Rule requiring Chronicle event-sourced state | ReadModel as Handle() parameter (DCB) |
| Simple sync invariant (format, range, required) | CommandValidator<T> |
Use when the rule depends on Chronicle event-sourced state (e.g. current count, accumulated value).
This is the DCB (Dynamic Consistency Boundary) pattern: add a read model parameter to the Handle() method.
The framework fetches and injects the current read model snapshot before Handle() runs.
The read model must already exist in the slice (decorated with [ReadModel] and a model-bound projection).
If it doesn't, add it first — see the new-vertical-slice skill.
[Command]
public record <Command>(<KeyProperty> <Key>, ...)
{
/// <summary>
/// Handles the command.
/// </summary>
/// <param name="readModelParam">The current state.</param>
/// <returns>The resulting event.</returns>
public <Event> Handle(<ReadModel> <readModelParam>)
{
if (<readModelParam>.<StateProperty> <violatesRule>)
throw new <ViolationException>(<meaningful message>);
return new <Event>(...);
}
}
Example — limit items in cart to 3:
[Command]
public record AddItemToCart(CartId CartId, ItemId ItemId)
{
/// <summary>
/// Adds the item; throws if the cart already holds 3 items.
/// </summary>
/// <param name="cart">The current cart summary.</param>
/// <returns>The <see cref="ItemAddedToCart"/> event.</returns>
/// <exception cref="CartIsFull">Thrown when the cart already contains the maximum number of items.</exception>
public ItemAddedToCart Handle(CartSummary cart)
{
if (cart.ItemCount >= 3)
throw new CartIsFullException(CartId);
return new ItemAddedToCart(ItemId);
}
}
Key rules:
[ReadModel]-decorated type in the same feature.[Unique] attribute (preferred)For the common case of enforcing uniqueness on a single event type, adorn the event type class or one of its properties with [Unique]. No separate constraint class is needed.
Event-type uniqueness — only one event of this type per event source:
[EventType]
[Unique(message: "A project with this name already exists.")]
public record ProjectCreated(string Name, string Description);
Property uniqueness — the value of a specific property must be unique:
[EventType]
public record UserRegistered([Unique(name: "UniqueEmail", message: "Email already registered.")] string Email, string DisplayName);
Releasing a constraint — apply [RemoveConstraint] to the event that deletes the domain object:
[EventType]
[RemoveConstraint("UniqueEmail")]
public record UserRemoved(UserId UserId);
Multiple attributes can be stacked to release more than one constraint from the same event type.
Constraints are discovered and enforced automatically — no registration or attribute on the command needed.
IConstraint (advanced)Use IConstraint when the uniqueness rule spans event types with different property names, or when a RemovedWith event must release the constraint.
public class Unique<PropertyName> : IConstraint
{
public void Define(IConstraintBuilder builder) =>
builder.Unique(unique =>
unique
.On<<EventType>>(e => e.<UniqueProperty>)
.RemovedWith<<RemovedEventType>>()); // omit if there is no remove event
}
Example — unique project name with removal:
public class UniqueProjectName : IConstraint
{
public void Define(IConstraintBuilder builder) =>
builder.Unique(unique =>
unique
.On<ProjectRegistered>(e => e.Name)
.RemovedWith<ProjectRemoved>());
}
Constraints are discovered and enforced automatically — no registration or attribute on the command needed.
write-specs skilldotnet build and dotnet test