AI – Claude Skill

By | 04/03/2026

In this post we will see what a Claude Skill is, how to create one and how to use it.
A Skill in Claude is a specialized capability that enhances Claude’s performance in specific domains by providing detailed instructions, best practices, and context-specific guidelines. Think of it as a expert-level instruction manual that Claude consults before tackling domain-specific tasks.


HOW SKILLS WORK
Skills are stored as markdown (.md) files in specific directories that Claude can access.
When we ask Claude to perform a task that triggers a skill, Claude:

  1. Detects the relevant skill based on our request
  2. Reads the skill file using the view tool
  3. Applies the guidelines from the skill to our task
  4. Produces output following the best practices defined in the skill


WHAT IS INSIDE A SKILL?
A well-designed skill contains:

  • Trigger conditions (when to use the skill)
  • Best practices accumulated through trial and error
  • Domain-specific workflows and methodologies
  • Quality standards and patterns to follow
  • Common pitfalls to avoid
  • Examples and templates


WHY CREATE A SKILL?
While Claude comes with built-in skills for common tasks (documents, spreadsheets, presentations), custom skills unlock powerful capabilities:

[Codify our team’s standards]
Stop copy and past our coding conventions into every conversation. Embed them once in a skill, and Claude will follow them automatically.

[Ensure consistency]
Every team member gets the same high-quality output following the same patterns and practices.

[Reduce repetition]
Never explain “use CQRS pattern” or “follow SOLID principles” again. The skill handles it.

[Improve code quality]
Leverage accumulated knowledge and proven patterns instead of ‘ad hoc’ responses.

[Specialize Claude]
Transform Claude into an expert in our specific domain whether that’s C# development, React architecture, or DevOps automation.


The Anatomy of a Skill File
A skill is a markdown file with a specific structure:

# Skill Name

## Overview
Brief description of what this skill does and when to use it

## When to Use This Skill
Clear triggers and use cases that activate the skill

## Core Principles
Fundamental guidelines and philosophies to follow

## Step-by-Step Workflow
Detailed instructions for completing tasks

## Best Practices
Proven approaches and quality standards

## Common Pitfalls
Mistakes to avoid with examples

## Examples
Concrete examples demonstrating the skill in action


Let’s build a production-ready skill for C# development that embodies modern best practices. Our goal is to create a skill that ensures:

  • Clean, maintainable code following SOLID principles
  • Modern C# 12+ features and patterns
  • Clean Architecture and CQRS implementation
  • Entity Framework best practices
  • Proper API design patterns

[csharp_ckill.md]

---
name: csharp-development-excellence
description: Guides creation of high-quality, maintainable C# code following modern best practices, SOLID principles, and proven design patterns
license:
---

# C# Development Excellence Skill

## Overview

This skill guides the creation of high-quality, maintainable C# code following modern best practices, SOLID principles, and proven design patterns. Use this skill for any C# development task including API development, business logic, data access, and application architecture.

## When to Use This Skill

- Writing C# classes, methods, or complete applications
- Implementing business logic or domain models
- Creating APIs (REST, gRPC, minimal APIs)
- Working with Entity Framework or database access
- Implementing design patterns
- Refactoring existing C# code
- Code reviews or architectural decisions

## Core Principles

### 1. SOLID Principles (Non-Negotiable)

- **Single Responsibility**: Each class/method does ONE thing well
- **Open/Closed**: Open for extension, closed for modification
- **Liskov Substitution**: Derived classes must be substitutable for base classes
- **Interface Segregation**: Many specific interfaces > one general interface
- **Dependency Inversion**: Depend on abstractions, not concretions

### 2. Clean Code Standards

- **Meaningful names**: `CalculateMonthlyRevenue()` not `Calc()` or `DoStuff()`
- **Small methods**: 5-15 lines ideally, max 30 lines
- **Shallow nesting**: Max 2-3 levels of indentation
- **Fail fast**: Validate inputs early, throw exceptions clearly
- **No magic numbers**: Use named constants or enums

### 3. Modern C# Features (Embrace C# 12+)

- Record types for DTOs and value objects
- Pattern matching and switch expressions
- Nullable reference types (always enabled)
- Primary constructors
- Collection expressions
- Required members
- File-scoped namespaces
- Global usings

## Architecture Patterns

### Clean Architecture Structure

```
YourProject/
├── Domain/               # Enterprise business rules
│   ├── Entities/        # Core business objects
│   ├── ValueObjects/    # Immutable value objects
│   ├── Enums/
│   └── Exceptions/      # Domain-specific exceptions
├── Application/          # Application business rules
│   ├── Features/        # Feature-based organization
│   │   ├── Users/
│   │   │   ├── Commands/
│   │   │   │   └── CreateUser/
│   │   │   │       ├── CreateUserCommand.cs
│   │   │   │       ├── CreateUserCommandHandler.cs
│   │   │   │       └── CreateUserCommandValidator.cs
│   │   │   └── Queries/
│   │   └── Orders/
│   ├── Interfaces/      # Abstractions for infrastructure
│   └── DTOs/
├── Infrastructure/       # External concerns
│   ├── Persistence/     # EF Core, repositories
│   ├── Identity/        # Authentication/Authorization
│   └── Services/        # External service integrations
└── API/                 # Presentation layer
    └── Controllers/     # Or Endpoints for minimal APIs
```

### CQRS with MediatR

**Commands** (Write operations):

```csharp
public record CreateUserCommand(
    string Email,
    string FirstName,
    string LastName
) : IRequest<Result<Guid>>;

public class CreateUserCommandHandler
    : IRequestHandler<CreateUserCommand, Result<Guid>>
{
    private readonly IApplicationDbContext _context;
    private readonly IPasswordHasher _passwordHasher;

    public CreateUserCommandHandler(
        IApplicationDbContext context,
        IPasswordHasher passwordHasher)
    {
        _context = context;
        _passwordHasher = passwordHasher;
    }

    public async Task<Result<Guid>> Handle(
        CreateUserCommand request,
        CancellationToken cancellationToken)
    {
        // Validate business rules
        if (await _context.Users
            .AnyAsync(u => u.Email == request.Email, cancellationToken))
        {
            return Result<Guid>.Failure("User with this email already exists");
        }

        // Create entity
        var user = User.Create(
            request.Email,
            request.FirstName,
            request.LastName);

        // Persist
        _context.Users.Add(user);
        await _context.SaveChangesAsync(cancellationToken);

        return Result<Guid>.Success(user.Id);
    }
}
```

**Queries** (Read operations):

```csharp
public record GetUserByIdQuery(Guid UserId) : IRequest<Result<UserDto>>;

public class GetUserByIdQueryHandler
    : IRequestHandler<GetUserByIdQuery, Result<UserDto>>
{
    private readonly IApplicationDbContext _context;

    public GetUserByIdQueryHandler(IApplicationDbContext context)
    {
        _context = context;
    }

    public async Task<Result<UserDto>> Handle(
        GetUserByIdQuery request,
        CancellationToken cancellationToken)
    {
        var user = await _context.Users
            .AsNoTracking()
            .Where(u => u.Id == request.UserId)
            .Select(u => new UserDto(
                u.Id,
                u.Email,
                u.FirstName,
                u.LastName,
                u.CreatedAt))
            .FirstOrDefaultAsync(cancellationToken);

        return user is null
            ? Result<UserDto>.Failure("User not found")
            : Result<UserDto>.Success(user);
    }
}
```

## Essential Design Patterns

### 1. Repository Pattern (with Specification)

```csharp
public interface IRepository<T> where T : class
{
    Task<T?> GetByIdAsync(Guid id, CancellationToken cancellationToken = default);
    Task<List<T>> ListAsync(CancellationToken cancellationToken = default);
    Task<List<T>> ListAsync(ISpecification<T> spec, CancellationToken cancellationToken = default);
    Task<T> AddAsync(T entity, CancellationToken cancellationToken = default);
    Task UpdateAsync(T entity, CancellationToken cancellationToken = default);
    Task DeleteAsync(T entity, CancellationToken cancellationToken = default);
}

// Specification pattern for complex queries
public interface ISpecification<T>
{
    Expression<Func<T, bool>>? Criteria { get; }
    List<Expression<Func<T, object>>> Includes { get; }
    Expression<Func<T, object>>? OrderBy { get; }
    Expression<Func<T, object>>? OrderByDescending { get; }
}
```

### 2. Result Pattern (No Exceptions for Business Logic)

```csharp
public class Result<T>
{
    public bool IsSuccess { get; }
    public bool IsFailure => !IsSuccess;
    public T? Value { get; }
    public string Error { get; }

    private Result(bool isSuccess, T? value, string error)
    {
        IsSuccess = isSuccess;
        Value = value;
        Error = error;
    }

    public static Result<T> Success(T value)
        => new(true, value, string.Empty);

    public static Result<T> Failure(string error)
        => new(false, default, error);

    public TResult Match<TResult>(
        Func<T, TResult> onSuccess,
        Func<string, TResult> onFailure)
        => IsSuccess ? onSuccess(Value!) : onFailure(Error);
}
```

### 3. Factory Pattern for Complex Object Creation

```csharp
public static class User
{
    public static User Create(
        string email,
        string firstName,
        string lastName)
    {
        // Validation
        if (string.IsNullOrWhiteSpace(email))
            throw new ArgumentException("Email is required", nameof(email));

        if (!email.Contains('@'))
            throw new ArgumentException("Invalid email format", nameof(email));

        // Business rules
        var user = new User
        {
            Id = Guid.NewGuid(),
            Email = email.ToLowerInvariant(),
            FirstName = firstName.Trim(),
            LastName = lastName.Trim(),
            CreatedAt = DateTime.UtcNow,
            IsActive = true
        };

        // Domain events could be added here
        // user.AddDomainEvent(new UserCreatedEvent(user));

        return user;
    }
}
```

## Entity Framework Best Practices

### 1. Configuration Over Attributes

```csharp
public class UserConfiguration : IEntityTypeConfiguration<User>
{
    public void Configure(EntityTypeBuilder<User> builder)
    {
        builder.ToTable("Users");

        builder.HasKey(u => u.Id);

        builder.Property(u => u.Email)
            .IsRequired()
            .HasMaxLength(256);

        builder.HasIndex(u => u.Email)
            .IsUnique();

        builder.Property(u => u.FirstName)
            .IsRequired()
            .HasMaxLength(100);

        builder.Property(u => u.LastName)
            .IsRequired()
            .HasMaxLength(100);

        // Value object configuration
        builder.OwnsOne(u => u.Address, address =>
        {
            address.Property(a => a.Street).HasMaxLength(200);
            address.Property(a => a.City).HasMaxLength(100);
            address.Property(a => a.PostalCode).HasMaxLength(20);
        });
    }
}
```

### 2. Optimized Queries

```csharp
// BAD: N+1 query problem
var users = await _context.Users.ToListAsync();
foreach (var user in users)
{
    var orders = user.Orders.ToList(); // Separate query per user!
}

// GOOD: Eager loading
var users = await _context.Users
    .Include(u => u.Orders)
    .AsNoTracking() // For read-only scenarios
    .ToListAsync();

// GOOD: Projection to DTO (even better)
var userDtos = await _context.Users
    .Select(u => new UserWithOrdersDto(
        u.Id,
        u.Email,
        u.Orders.Select(o => new OrderDto(o.Id, o.Total)).ToList()))
    .ToListAsync();
```

### 3. Transaction Management

```csharp
public async Task<Result> ProcessOrderAsync(CreateOrderCommand command)
{
    using var transaction = await _context.Database.BeginTransactionAsync();
    try
    {
        // Create order
        var order = Order.Create(command.UserId, command.Items);
        _context.Orders.Add(order);
        await _context.SaveChangesAsync();

        // Update inventory
        foreach (var item in command.Items)
        {
            await _inventoryService.ReserveStockAsync(
                item.ProductId,
                item.Quantity);
        }

        await transaction.CommitAsync();
        return Result.Success();
    }
    catch (Exception ex)
    {
        await transaction.RollbackAsync();
        return Result.Failure($"Order processing failed: {ex.Message}");
    }
}
```

## API Development Patterns

### 1. Minimal APIs (Modern Approach)

```csharp
public static class UserEndpoints
{
    public static void MapUserEndpoints(this IEndpointRouteBuilder app)
    {
        var group = app.MapGroup("/api/users")
            .WithTags("Users")
            .RequireAuthorization();

        group.MapPost("/", CreateUserAsync)
            .WithName("CreateUser")
            .Produces<UserDto>(StatusCodes.Status201Created)
            .ProducesValidationProblem();

        group.MapGet("/{id:guid}", GetUserByIdAsync)
            .WithName("GetUserById")
            .Produces<UserDto>()
            .Produces(StatusCodes.Status404NotFound);
    }

    private static async Task<IResult> CreateUserAsync(
        CreateUserCommand command,
        ISender sender)
    {
        var result = await sender.Send(command);

        return result.Match(
            onSuccess: userId => Results.CreatedAtRoute(
                "GetUserById",
                new { id = userId },
                userId),
            onFailure: error => Results.BadRequest(new { error }));
    }

    private static async Task<IResult> GetUserByIdAsync(
        Guid id,
        ISender sender)
    {
        var query = new GetUserByIdQuery(id);
        var result = await sender.Send(query);

        return result.Match(
            onSuccess: user => Results.Ok(user),
            onFailure: error => Results.NotFound(new { error }));
    }
}
```

### 2. Versioning and Swagger

```csharp
// Program.cs
builder.Services.AddApiVersioning(options =>
{
    options.DefaultApiVersion = new ApiVersion(1, 0);
    options.AssumeDefaultVersionWhenUnspecified = true;
    options.ReportApiVersions = true;
});

builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen(c =>
{
    c.SwaggerDoc("v1", new OpenApiInfo
    {
        Title = "Restaurant Management API",
        Version = "v1",
        Description = "Comprehensive restaurant management system"
    });

    // JWT Authentication
    c.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme
    {
        Description = "JWT Authorization header using the Bearer scheme",
        Name = "Authorization",
        In = ParameterLocation.Header,
        Type = SecuritySchemeType.ApiKey,
        Scheme = "Bearer"
    });
});
```

## Code Quality Checklist

Before considering code complete, verify:

### Naming Conventions

- [ ] Classes: `PascalCase` (e.g., `OrderProcessor`)
- [ ] Interfaces: `IPascalCase` (e.g., `IOrderRepository`)
- [ ] Methods: `PascalCase` (e.g., `CalculateTotal()`)
- [ ] Variables/fields: `camelCase` (e.g., `totalAmount`)
- [ ] Constants: `PascalCase` (e.g., `MaxRetryAttempts`)
- [ ] Private fields: `_camelCase` (e.g., `_dbContext`)

### Structure

- [ ] Each class has single responsibility
- [ ] Methods are small (< 30 lines)
- [ ] No deep nesting (< 3 levels)
- [ ] Dependencies injected via constructor
- [ ] Async methods end with `Async` suffix

### Safety

- [ ] Nullable reference types enabled
- [ ] All inputs validated
- [ ] Exceptions are specific and meaningful
- [ ] Resources disposed properly (using/IDisposable)
- [ ] CancellationTokens used in async methods

### Testing Readiness

- [ ] Interfaces defined for all dependencies
- [ ] Business logic separated from infrastructure
- [ ] Pure functions where possible
- [ ] Side effects isolated and explicit

## Common Pitfalls to Avoid

### Don't: God Classes

```csharp
// 3000 lines, does everything
public class OrderService
{
    public void CreateOrder() { }
    public void ValidateOrder() { }
    public void ProcessPayment() { }
    public void SendEmail() { }
    public void UpdateInventory() { }
    public void GenerateInvoice() { }
    // ... 50 more methods
}
```

### Do: Single Responsibility

```csharp
public class OrderCreationService { }
public class OrderValidator { }
public class PaymentProcessor { }
public class EmailNotificationService { }
public class InventoryManager { }
public class InvoiceGenerator { }
```

### Don't: Primitive Obsession

```csharp
public class Order
{
    public string Email { get; set; } // What validates this?
    public decimal Price { get; set; } // What currency?
    public string Status { get; set; } // Typos possible
}
```

### Do: Value Objects and Enums

```csharp
public class Order
{
    public Email Email { get; set; }
    public Money Price { get; set; }
    public OrderStatus Status { get; set; }
}

public record Email
{
    public string Value { get; }

    private Email(string value) => Value = value;

    public static Result<Email> Create(string value)
    {
        if (string.IsNullOrWhiteSpace(value))
            return Result<Email>.Failure("Email is required");

        if (!value.Contains('@'))
            return Result<Email>.Failure("Invalid email format");

        return Result<Email>.Success(new Email(value.ToLowerInvariant()));
    }
}

public enum OrderStatus
{
    Pending = 0,
    Confirmed = 1,
    Processing = 2,
    Shipped = 3,
    Delivered = 4,
    Cancelled = 5
}
```

### Don't: Leaky Abstractions

```csharp
// Repository returns EF entities directly
public interface IOrderRepository
{
    Task<DbSet<Order>> GetOrdersAsync(); // Exposes EF Core!
}
```

### Do: Clean Abstractions

```csharp
public interface IOrderRepository
{
    Task<List<Order>> GetOrdersAsync(OrderFilter filter);
    Task<Order?> GetByIdAsync(Guid id);
}
```

## Performance Optimization

### 1. Async/Await Best Practices

```csharp
// GOOD: ValueTask for frequently synchronous results
public async ValueTask<User?> GetCachedUserAsync(Guid id)
{
    if (_cache.TryGetValue(id, out var user))
        return user; // Synchronous path, no Task allocation

    return await _repository.GetByIdAsync(id);
}

// GOOD: ConfigureAwait(false) in library code
public async Task<Order> GetOrderAsync(Guid id)
{
    var order = await _repository
        .GetByIdAsync(id)
        .ConfigureAwait(false); // Don't capture context

    return order;
}
```

### 2. String Handling

```csharp
// BAD: String concatenation in loops
string result = "";
foreach (var item in items)
{
    result += item.ToString(); // Creates new string each iteration!
}

// GOOD: StringBuilder
var sb = new StringBuilder();
foreach (var item in items)
{
    sb.Append(item.ToString());
}
string result = sb.ToString();

// BETTER: String interpolation or collection expression
string result = string.Join(", ", items.Select(i => i.ToString()));
```

### 3. LINQ Performance

```csharp
// BAD: Multiple enumerations
var list = GetExpensiveData();
var count = list.Count(); // Enumerates once
var first = list.First(); // Enumerates again!

// GOOD: Materialize once
var list = GetExpensiveData().ToList(); // Single enumeration
var count = list.Count; // O(1) property access
var first = list[0];
```

## Testing Patterns

### Unit Test Structure (AAA Pattern)

```csharp
public class CreateUserCommandHandlerTests
{
    [Fact]
    public async Task Handle_WithValidCommand_ReturnsSuccessWithUserId()
    {
        // Arrange
        var command = new CreateUserCommand(
            "test@example.com",
            "John",
            "Doe");

        var mockContext = new Mock<IApplicationDbContext>();
        var mockPasswordHasher = new Mock<IPasswordHasher>();

        var handler = new CreateUserCommandHandler(
            mockContext.Object,
            mockPasswordHasher.Object);

        // Act
        var result = await handler.Handle(command, CancellationToken.None);

        // Assert
        result.IsSuccess.Should().BeTrue();
        result.Value.Should().NotBeEmpty();
        mockContext.Verify(
            x => x.SaveChangesAsync(It.IsAny<CancellationToken>()),
            Times.Once);
    }
}
```

## Final Quality Standards

Every piece of C# code should be:

1. **Readable**: A junior developer should understand it in < 2 minutes
2. **Maintainable**: Changes require minimal code modifications
3. **Testable**: Can be unit tested without complex setup
4. **Performant**: No obvious performance issues
5. **Secure**: No SQL injection, XSS, or security vulnerabilities
6. **Documented**: Complex logic has XML comments

## Resources and References

- **Official C# Docs**: https://learn.microsoft.com/en-us/dotnet/csharp/
- **Clean Architecture**: https://blog.cleancoder.com/uncle-bob/2012/08/13/the-clean-architecture.html
- **Design Patterns**: "Design Patterns: Elements of Reusable Object-Oriented Software" (Gang of Four)
- **EF Core Best Practices**: https://learn.microsoft.com/en-us/ef/core/performance/

---

**Version**: 1.0  
**Last Updated**: February 2026  
**Maintained By**: Damiano


Finally, we have to upload the file in Claude:


Now that the skill is installed, let’s verify it’s actually being used by Claude.
We’ll ask Claude to create a repository interface and implementation for managing Orders, including support for filtering by date range and customer ID.

What We Should See:
Before Claude generates any code, we’ll notice it automatically reads the C# development skill.




Category: AI Tags:

Leave a Reply

Your email address will not be published. Required fields are marked *