dotnet-cqrs/.claude/skills/add-command/SKILL.md
Mathias Beaulieu-Duncan a4525bad6a Add Claude Code harness: rules, skills, hooks, and editorconfig
- Add path-specific rules for commands/queries, dynamic queries, validation, and gRPC
- Add /add-command, /add-query, /add-dynamic-query scaffolding skills
- Add project settings with post-edit formatting, proto validation, and build-gate hooks
- Add .editorconfig codifying existing code style conventions
- Trim CLAUDE.md from 414 to 130 lines (domain details moved to rules)
- Add .harness-version tracking for the shared claude-harness repo

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-12 03:30:27 -04:00

3.4 KiB

name description argument-hint
add-command Scaffold a new CQRS command with handler, validator, and DI registration. Use when the user wants to add a new command to a project. <description of the command in natural language>

Add Command

Scaffold a new command based on: $ARGUMENTS

Instructions

1. Determine the command name

The name must express domain intent, not CRUD. If the user's description sounds like CRUD, translate it:

  • "create a user" → RegisterUserCommand
  • "update the order status" → contextual: ShipOrderCommand, CancelOrderCommand, ApproveOrderCommand
  • "delete an account" → DeactivateAccountCommand or CloseAccountCommand

Ask the user to clarify if the intent is ambiguous (e.g., "update order" could mean many things).

2. Determine the feature folder

Place the file in the appropriate feature folder: Features/{DomainArea}/ If the folder doesn't exist, create it. If the project doesn't use Features/ yet, check the existing structure and follow the same pattern.

3. Create the file

Create a single file Features/{DomainArea}/{CommandName}Command.cs containing all three classes:

using FluentValidation;
using Svrnty.CQRS.Abstractions;

namespace {ProjectNamespace}.Features.{DomainArea};

// 1. Command POCO — record type, properties with defaults
public record {CommandName}Command
{
    // Properties based on user description
    // Strings default to string.Empty, collections to []
}

// 2. Validator — rules in constructor, always include .WithMessage()
public class {CommandName}CommandValidator : AbstractValidator<{CommandName}Command>
{
    public {CommandName}CommandValidator()
    {
        // Validation rules based on command properties
    }
}

// 3. Handler — always async with CancellationToken
public class {CommandName}CommandHandler : ICommandHandler<{CommandName}Command, {ResultType}>
{
    public Task<{ResultType}> HandleAsync({CommandName}Command command, CancellationToken cancellationToken = default)
    {
        throw new NotImplementedException();
    }
}

If the command has no return value, use ICommandHandler<{CommandName}Command> (single generic param) with Task HandleAsync(...).

4. Register in DI

Find the project's service registration (typically Program.cs or a dedicated registration method) and add:

// With validator (preferred)
builder.Services.AddCommand<{CommandName}Command, {ResultType}, {CommandName}CommandHandler, {CommandName}CommandValidator>();

// Without validator
builder.Services.AddCommand<{CommandName}Command, {ResultType}, {CommandName}CommandHandler>();

// No return value + validator
builder.Services.AddCommand<{CommandName}Command, {CommandName}CommandHandler, {CommandName}CommandValidator>();

Ensure the using Svrnty.CQRS.FluentValidation; namespace is imported if using the validator overload.

5. Proto message (if project uses gRPC)

If the project has a Protos/ directory, add the corresponding proto message:

// In the CommandService definition
rpc {CommandName} ({CommandName}CommandRequest) returns ({CommandName}CommandResponse);

// Request message
message {CommandName}CommandRequest {
  // fields matching command properties, snake_case, numbered sequentially
}

// Response message
message {CommandName}CommandResponse {
  {result_type} result = 1;  // omit if command has no return value
}

6. Summary

After creating everything, list what was created and where.