skills/cqrs/command-generator/SKILL.md
Use when creating a new CQRS command with handler and FluentValidation validator.
npx skillsauth add faysilalshareef/dotnet-ai-kit command-generatorInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
namespace {Company}.{Domain}.Application.Features.Orders.Commands.Create;
public sealed record CreateOrderCommand(
string CustomerName,
decimal Total,
List<CreateOrderItemDto> Items) : IRequest<Result<Guid>>;
public sealed record CreateOrderItemDto(
string ProductName,
int Quantity,
decimal UnitPrice);
namespace {Company}.{Domain}.Application.Features.Orders.Commands.Create;
internal sealed class CreateOrderCommandValidator
: AbstractValidator<CreateOrderCommand>
{
public CreateOrderCommandValidator()
{
RuleFor(x => x.CustomerName)
.NotEmpty().WithMessage("Customer name is required")
.MaximumLength(200);
RuleFor(x => x.Total)
.GreaterThan(0).WithMessage("Total must be positive");
RuleFor(x => x.Items)
.NotEmpty().WithMessage("At least one item is required");
RuleForEach(x => x.Items).ChildRules(item =>
{
item.RuleFor(i => i.ProductName).NotEmpty();
item.RuleFor(i => i.Quantity).GreaterThan(0);
item.RuleFor(i => i.UnitPrice).GreaterThan(0);
});
}
}
namespace {Company}.{Domain}.Application.Features.Orders.Commands.Create;
internal sealed class CreateOrderCommandHandler(
IUnitOfWork unitOfWork)
: IRequestHandler<CreateOrderCommand, Result<Guid>>
{
public async Task<Result<Guid>> Handle(
CreateOrderCommand request, CancellationToken cancellationToken)
{
var order = Order.Create(
request.CustomerName,
request.Total,
request.Items.Select(i => new OrderItem(
i.ProductName, i.Quantity, i.UnitPrice)).ToList());
await unitOfWork.Orders.AddAsync(order, cancellationToken);
await unitOfWork.SaveChangesAsync(cancellationToken);
return Result<Guid>.Success(order.Id);
}
}
public sealed record UpdateOrderCommand(
Guid Id,
string CustomerName,
decimal Total) : IRequest<Result>;
internal sealed class UpdateOrderCommandHandler(
IUnitOfWork unitOfWork)
: IRequestHandler<UpdateOrderCommand, Result>
{
public async Task<Result> Handle(
UpdateOrderCommand request, CancellationToken cancellationToken)
{
var order = await unitOfWork.Orders.FindAsync(
request.Id, cancellationToken);
if (order is null)
return Result.Failure("Order not found");
order.Update(request.CustomerName, request.Total);
await unitOfWork.SaveChangesAsync(cancellationToken);
return Result.Success();
}
}
public sealed record DeleteOrderCommand(Guid Id) : IRequest<Result>;
internal sealed class DeleteOrderCommandHandler(
IUnitOfWork unitOfWork)
: IRequestHandler<DeleteOrderCommand, Result>
{
public async Task<Result> Handle(
DeleteOrderCommand request, CancellationToken cancellationToken)
{
var order = await unitOfWork.Orders.FindAsync(
request.Id, cancellationToken);
if (order is null)
return Result.Failure("Order not found");
unitOfWork.Orders.Remove(order);
await unitOfWork.SaveChangesAsync(cancellationToken);
return Result.Success();
}
}
Application/Features/Orders/Commands/
├── Create/
│ ├── CreateOrderCommand.cs
│ ├── CreateOrderCommandValidator.cs
│ └── CreateOrderCommandHandler.cs
├── Update/
│ ├── UpdateOrderCommand.cs
│ ├── UpdateOrderCommandValidator.cs
│ └── UpdateOrderCommandHandler.cs
└── Delete/
├── DeleteOrderCommand.cs
└── DeleteOrderCommandHandler.cs
| Anti-Pattern | Correct Approach |
|---|---|
| Command with mutable properties | Use sealed record (immutable) |
| Validation in handler | Use FluentValidation + pipeline behavior |
| Returning domain entity from handler | Return Result<T> with ID or DTO |
| Handler accessing DbContext directly | Use IUnitOfWork or IRepository |
grep -r "IRequest<\|IRequestHandler<" --include="*.cs"
grep -r "AbstractValidator<" --include="*.cs"
AddMediatR and AddValidatorsFromAssemblyValidationBehavior<,> pipeline behaviordata-ai
Use when about to claim work is complete, fixed, passing, or ready — before committing, creating PRs, or moving to the next task. Requires running verification commands and confirming output before making any success claims.
development
Use when encountering any bug, test failure, build error, or unexpected behavior — before proposing fixes or making changes.
development
Use when checkpointing, wrapping up, or handing off an AI-assisted development session.
development
Use when following the Specification-Driven Development lifecycle from plan through ship.