# Add Command

> Scaffold a new CQRS command with handler, validator, and POST endpoint following project conventions. Use whenever the user wants to add a write operation, mutation, POST/PUT/DELETE endpoint, or any state-changing action to a microservice.

- Skill: `makigjuro/add-command` (Agent Skill)
- Install (CLI): `npx skillmds@latest add makigjuro/add-command`
- Raw SKILL.md: https://api.skillmd.com/api/skills/makigjuro/add-command/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Coding & Dev Tools
- Author: makigjuro (https://skillmd.com/u/makigjuro)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/makigjuro/add-command

---


# Add CQRS Command

When the user asks to add a new command, scaffold the following files in the correct microservice. Ask which service if ambiguous.

If the command involves non-trivial FluentValidation rules (async validators, cross-field validation, collection rules) or WolverineFx middleware, use context7 to look up the current docs before writing.

## Arguments

- `{Name}` -- Command name in PascalCase (e.g., `CreateOrder`, `AssignRole`)
- `{Service}` -- Target microservice. Ask if ambiguous.

## Configuration

Read `cloudstack.json` from the project root at the start of execution. Extract:
- `NAMESPACE` = `project.namespace` (default: detect from `*.sln` name or first `*.csproj` root namespace)
- `SERVICES` = `backend.services[]` (default: discover from `src/*/` directories containing `.Application/` subfolders)
- `SOLUTION` = `backend.solutionPath` (default: find `*.sln` in `src/`)

If `cloudstack.json` does not exist, auto-detect by scanning the project structure.

## Prerequisites

- The target microservice must exist under `src/`
- An Endpoints file should exist at `Host/Endpoints/` (if not, create one)
- If the command operates on an entity that doesn't exist yet, run `/add-entity` first

## 1. Command Record (`Application/Commands/{CommandName}.cs`)

```csharp
namespace {Namespace}.{Service}.Application.Commands;

public record {Name}Command({parameters});
```

## 2. Response Record (same file or `Application/Contracts/`)

```csharp
public record {Name}Response({response fields});
```

## 3. Handler (`Application/Commands/{Name}Handler.cs`)

```csharp
namespace {Namespace}.{Service}.Application.Commands;

public class {Name}Handler
{
    // Constructor-inject repositories and services

    public async Task<Result<{Name}Response>> Handle({Name}Command command, CancellationToken cancellationToken)
    {
        // 1. Validate business rules
        // 2. Create/modify domain entities via factory methods or aggregate methods
        // 3. Persist via repository
        // 4. Return Result.Success or Result.Failure with SCREAMING_SNAKE error code
    }
}
```

## 4. Validator (`Application/Validators/{Name}Validator.cs`)

```csharp
namespace {Namespace}.{Service}.Application.Validators;

public class {Name}Validator : AbstractValidator<{Name}Command>
{
    public {Name}Validator()
    {
        // RuleFor(x => x.Field).NotEmpty().WithErrorCode("ERROR_CODE");
    }
}
```

## 5. Endpoint (add to existing `Host/Endpoints/{Domain}Endpoints.cs`)

```csharp
group.MapPost("/{route}", {Name})
    .WithName("{Name}")
    .WithSummary("...")
    .WithDescription("...")
    .Produces<{Name}Response>(StatusCodes.Status201Created)
    .ProducesProblem(StatusCodes.Status400BadRequest)
    .ProducesProblem(StatusCodes.Status409Conflict);

private static async Task<IResult> {Name}(
    [FromBody] {Name}Request request,
    [FromServices] {Name}Handler handler,
    CancellationToken cancellationToken)
{
    var command = new {Name}Command(...);
    var result = await handler.Handle(command, cancellationToken);
    return result.ToHttpResult();
}
```

## 6. DI Registration

Register the handler in the service's `AddInfrastructure` or `Program.cs`:
```csharp
services.AddScoped<{Name}Handler>();
```

## Checklist
- [ ] Command record is immutable
- [ ] Handler returns `Result<T>`, no thrown exceptions for business logic
- [ ] Error codes are SCREAMING_SNAKE_CASE
- [ ] Validator uses FluentValidation
- [ ] Endpoint has OpenAPI metadata (WithName, WithSummary, Produces)
- [ ] Handler registered in DI
- [ ] CancellationToken propagated through all async calls

## Output

After scaffolding, report:
```
## Scaffolded: {Name}Command

Files created/modified:
- `src/{Service}/{Service}.Application/Commands/{Name}Command.cs`
- `src/{Service}/{Service}.Application/Commands/{Name}Handler.cs`
- `src/{Service}/{Service}.Application/Validators/{Name}Validator.cs`
- `src/{Service}/{Service}.Host/Endpoints/{Domain}Endpoints.cs` (modified)
- `src/{Service}/{Service}.Host/Program.cs` or DI registration (modified)

Next: Run `/run-tests` to verify, or `/add-query` if you also need a read endpoint.
```

## Error Handling

- **Endpoints file doesn't exist:** Create a new `{Domain}Endpoints.cs` with the route group boilerplate.
- **DI registration file not found:** Add `services.AddScoped<{Name}Handler>()` directly to `Program.cs`.
- **Namespace conflicts:** Check existing commands in the folder before creating -- prompt the user if a similar command already exists.

## Related Skills

- `/add-entity` if the command creates a new entity type
- `/add-event-handler` to react to domain events raised by this command
- `/add-query` if you also need a read endpoint for the same resource

