[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill:01M6FSS3VF3JZHF78NST6NEBFV":3,"skill-same:01M6FSS3VF3JZHF78NST6NEBFV":98},{"skillNo":4,"name":5,"nameZh":6,"description":7,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":15,"categories":16,"keywords":27,"publishedAt":48,"linkOnly":49,"markdownContent":50,"markdownBody":51,"frontMatter":52,"refName":71,"commitSha":72,"skillDirectory":73,"forksCount":74,"repositoryHtmlUrl":75,"repositoryHomepageUrl":6,"ownerHtmlUrl":76,"ownerBlogUrl":6,"ownerDescription":6,"updatedAt":77,"install":78,"resources":91},"01M6FSS3VF3JZHF78NST6NEBFV","dotnet-expert",null,"Use when building .NET 8\u002F9 applications, ASP.NET Core APIs, Entity Framework Core, MediatR CQRS, modular monolith architecture, FluentValidation, Result pattern, JWT authentication, or any C# backend development question.","kbarbel640-del\u002Fskills","kbarbel640-del","https:\u002F\u002Favatars.githubusercontent.com\u002Fu\u002F255315490?v=4","01M6CJPPQGCCESXMG3K7BBGQ5J","01M6CJPPX2PB2BCZERFVM2C2B3",1,"MIT","https:\u002F\u002Fgithub.com\u002Fkbarbel640-del\u002Fskills\u002Fblob\u002Fmain\u002Fskills\u002Fjgarrison929\u002Fdotnet-expert\u002FSKILL.md",[17,22],{"categoryNo":18,"categoryName":19,"taxonomyType":20,"taxonomyTypeDesc":21},"01JBSEEDCAT000000000000010","后端与接口","SCENARIO","使用场景",{"categoryNo":23,"categoryName":24,"taxonomyType":25,"taxonomyTypeDesc":26},"01JBSEEDCAT000000000000030","开发工程师","PROFESSION","适用职业",[28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47],"dotnet expert","expert","dotnet","applications","pattern","cqrs","minimal","framework core","use","question","api","controller","ef core","framework","authentication","code","core","development","modular","architecture","2026-11-10 10:12:30",false,"---\nname: dotnet-expert\nversion: 1.0.0\ndescription: Use when building .NET 8\u002F9 applications, ASP.NET Core APIs, Entity Framework Core, MediatR CQRS, modular monolith architecture, FluentValidation, Result pattern, JWT authentication, or any C# backend development question.\ntriggers:\n  - .NET\n  - dotnet\n  - C#\n  - ASP.NET\n  - Entity Framework\n  - EF Core\n  - MediatR\n  - CQRS\n  - FluentValidation\n  - Minimal API\n  - controller\n  - DbContext\n  - migration\n  - Pitbull\n  - modular monolith\n  - Result pattern\nrole: specialist\nscope: implementation\noutput-format: code\n---\n\n# .NET Expert\n\nSenior .NET 9 \u002F ASP.NET Core specialist with expertise in clean architecture, CQRS, and modular monolith patterns.\n\n## Role Definition\n\nYou are a senior .NET engineer building production-grade APIs with ASP.NET Core, Entity Framework Core 9, MediatR, and FluentValidation. You follow clean architecture principles with a pragmatic approach.\n\n## Core Principles\n\n1. **Result pattern over exceptions** for business logic — exceptions for infrastructure only\n2. **CQRS with MediatR** — separate commands (writes) from queries (reads)\n3. **FluentValidation** for all input validation in the pipeline\n4. **Modular monolith** — organized by feature\u002Fdomain, not by technical layer\n5. **Strongly-typed IDs** to prevent primitive obsession\n6. **Async all the way** — never `.Result` or `.Wait()`\n\n---\n\n## Project Structure (Modular Monolith)\n\n```\nsrc\u002F\n├── Api\u002F                          # ASP.NET Core host\n│   ├── Program.cs\n│   ├── appsettings.json\n│   └── Endpoints\u002F                # Minimal API endpoint definitions\n├── Modules\u002F\n│   ├── Users\u002F\n│   │   ├── Users.Core\u002F           # Domain entities, interfaces\n│   │   ├── Users.Application\u002F    # Commands, queries, handlers\n│   │   └── Users.Infrastructure\u002F # EF Core, external services\n│   ├── Orders\u002F\n│   │   ├── Orders.Core\u002F\n│   │   ├── Orders.Application\u002F\n│   │   └── Orders.Infrastructure\u002F\n│   └── Shared\u002F\n│       ├── Shared.Core\u002F          # Common abstractions\n│       └── Shared.Infrastructure\u002F# Cross-cutting concerns\n└── Tests\u002F\n    ├── Users.Tests\u002F\n    └── Orders.Tests\u002F\n```\n\n---\n\n## Minimal API Patterns\n\n### Basic Endpoint Group\n\n```csharp\n\u002F\u002F Api\u002FEndpoints\u002FUserEndpoints.cs\npublic static class UserEndpoints\n{\n    public static void MapUserEndpoints(this IEndpointRouteBuilder app)\n    {\n        var group = app.MapGroup(\"\u002Fapi\u002Fusers\")\n            .WithTags(\"Users\")\n            .RequireAuthorization();\n\n        group.MapGet(\"\u002F\", GetUsers);\n        group.MapGet(\"\u002F{id:guid}\", GetUserById);\n        group.MapPost(\"\u002F\", CreateUser);\n        group.MapPut(\"\u002F{id:guid}\", UpdateUser);\n        group.MapDelete(\"\u002F{id:guid}\", DeleteUser);\n    }\n\n    private static async Task\u003CIResult> GetUsers(\n        [AsParameters] GetUsersQuery query,\n        ISender mediator,\n        CancellationToken ct)\n    {\n        var result = await mediator.Send(query, ct);\n        return result.Match(\n            success => Results.Ok(success),\n            error => Results.Problem(error.ToProblemDetails()));\n    }\n\n    private static async Task\u003CIResult> GetUserById(\n        Guid id,\n        ISender mediator,\n        CancellationToken ct)\n    {\n        var result = await mediator.Send(new GetUserByIdQuery(id), ct);\n        return result.Match(\n            success => Results.Ok(success),\n            error => error.Type == ErrorType.NotFound\n                ? Results.NotFound()\n                : Results.Problem(error.ToProblemDetails()));\n    }\n\n    private static async Task\u003CIResult> CreateUser(\n        CreateUserCommand command,\n        ISender mediator,\n        CancellationToken ct)\n    {\n        var result = await mediator.Send(command, ct);\n        return result.Match(\n            success => Results.Created($\"\u002Fapi\u002Fusers\u002F{success.Id}\", success),\n            error => Results.Problem(error.ToProblemDetails()));\n    }\n}\n```\n\n### Program.cs Setup\n\n```csharp\nvar builder = WebApplication.CreateBuilder(args);\n\n\u002F\u002F Add modules\nbuilder.Services.AddUsersModule(builder.Configuration);\nbuilder.Services.AddOrdersModule(builder.Configuration);\n\n\u002F\u002F Add shared infrastructure\nbuilder.Services.AddMediatR(cfg =>\n    cfg.RegisterServicesFromAssemblies(\n        typeof(UsersModule).Assembly,\n        typeof(OrdersModule).Assembly));\n\nbuilder.Services.AddValidatorsFromAssemblies(new[]\n{\n    typeof(UsersModule).Assembly,\n    typeof(OrdersModule).Assembly,\n});\n\n\u002F\u002F Add validation pipeline behavior\nbuilder.Services.AddTransient(typeof(IPipelineBehavior\u003C,>), typeof(ValidationBehavior\u003C,>));\n\nbuilder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)\n    .AddJwtBearer(options =>\n    {\n        options.TokenValidationParameters = new TokenValidationParameters\n        {\n            ValidateIssuer = true,\n            ValidateAudience = true,\n            ValidateLifetime = true,\n            ValidateIssuerSigningKey = true,\n            ValidIssuer = builder.Configuration[\"Jwt:Issuer\"],\n            ValidAudience = builder.Configuration[\"Jwt:Audience\"],\n            IssuerSigningKey = new SymmetricSecurityKey(\n                Encoding.UTF8.GetBytes(builder.Configuration[\"Jwt:Key\"]!)),\n        };\n    });\n\nbuilder.Services.AddAuthorization();\n\nvar app = builder.Build();\n\napp.UseAuthentication();\napp.UseAuthorization();\n\napp.MapUserEndpoints();\napp.MapOrderEndpoints();\n\napp.Run();\n```\n\n---\n\n## Result Pattern\n\n### Result Type\n\n```csharp\n\u002F\u002F Shared.Core\u002FResult.cs\npublic sealed class Result\u003CT>\n{\n    public T? Value { get; }\n    public Error? Error { get; }\n    public bool IsSuccess { get; }\n\n    private Result(T value) { Value = value; IsSuccess = true; }\n    private Result(Error error) { Error = error; IsSuccess = false; }\n\n    public static Result\u003CT> Success(T value) => new(value);\n    public static Result\u003CT> Failure(Error error) => new(error);\n\n    public TResult Match\u003CTResult>(\n        Func\u003CT, TResult> onSuccess,\n        Func\u003CError, TResult> onFailure) =>\n        IsSuccess ? onSuccess(Value!) : onFailure(Error!);\n}\n\npublic sealed record Error(string Code, string Message, ErrorType Type = ErrorType.Failure)\n{\n    public static Error NotFound(string code, string message) => new(code, message, ErrorType.NotFound);\n    public static Error Validation(string code, string message) => new(code, message, ErrorType.Validation);\n    public static Error Conflict(string code, string message) => new(code, message, ErrorType.Conflict);\n    public static Error Forbidden(string code, string message) => new(code, message, ErrorType.Forbidden);\n\n    public ProblemDetails ToProblemDetails() => new()\n    {\n        Title = Code,\n        Detail = Message,\n        Status = Type switch\n        {\n            ErrorType.NotFound => StatusCodes.Status404NotFound,\n            ErrorType.Validation => StatusCodes.Status400BadRequest,\n            ErrorType.Conflict => StatusCodes.Status409Conflict,\n            ErrorType.Forbidden => StatusCodes.Status403Forbidden,\n            _ => StatusCodes.Status500InternalServerError,\n        },\n    };\n}\n\npublic enum ErrorType { Failure, NotFound, Validation, Conflict, Forbidden }\n```\n\n### Usage in Handlers\n\n```csharp\n\u002F\u002F No exceptions for business logic!\npublic sealed class CreateUserHandler : IRequestHandler\u003CCreateUserCommand, Result\u003CUserResponse>>\n{\n    private readonly AppDbContext _db;\n\n    public CreateUserHandler(AppDbContext db) => _db = db;\n\n    public async Task\u003CResult\u003CUserResponse>> Handle(\n        CreateUserCommand command, CancellationToken ct)\n    {\n        \u002F\u002F Business rule validation returns errors, not exceptions\n        var existingUser = await _db.Users\n            .AnyAsync(u => u.Email == command.Email, ct);\n\n        if (existingUser)\n            return Result\u003CUserResponse>.Failure(\n                Error.Conflict(\"User.DuplicateEmail\", \"A user with this email already exists\"));\n\n        var user = new User\n        {\n            Id = Guid.NewGuid(),\n            Email = command.Email,\n            Name = command.Name,\n            CreatedAt = DateTime.UtcNow,\n        };\n\n        _db.Users.Add(user);\n        await _db.SaveChangesAsync(ct);\n\n        return Result\u003CUserResponse>.Success(user.ToResponse());\n    }\n}\n```\n\n---\n\n## MediatR CQRS\n\n### Commands (Write Operations)\n\n```csharp\n\u002F\u002F Users.Application\u002FCommands\u002FCreateUserCommand.cs\npublic sealed record CreateUserCommand(\n    string Email,\n    string Name,\n    string Password) : IRequest\u003CResult\u003CUserResponse>>;\n```\n\n### Queries (Read Operations)\n\n```csharp\n\u002F\u002F Users.Application\u002FQueries\u002FGetUsersQuery.cs\npublic sealed record GetUsersQuery(\n    int Page = 1,\n    int PageSize = 20,\n    string? Search = null) : IRequest\u003CResult\u003CPagedResult\u003CUserResponse>>>;\n\npublic sealed class GetUsersHandler : IRequestHandler\u003CGetUsersQuery, Result\u003CPagedResult\u003CUserResponse>>>\n{\n    private readonly AppDbContext _db;\n\n    public GetUsersHandler(AppDbContext db) => _db = db;\n\n    public async Task\u003CResult\u003CPagedResult\u003CUserResponse>>> Handle(\n        GetUsersQuery query, CancellationToken ct)\n    {\n        var dbQuery = _db.Users.AsNoTracking();\n\n        if (!string.IsNullOrWhiteSpace(query.Search))\n            dbQuery = dbQuery.Where(u =>\n                u.Name.Contains(query.Search) || u.Email.Contains(query.Search));\n\n        var total = await dbQuery.CountAsync(ct);\n\n        var users = await dbQuery\n            .OrderBy(u => u.Name)\n            .Skip((query.Page - 1) * query.PageSize)\n            .Take(query.PageSize)\n            .Select(u => u.ToResponse())\n            .ToListAsync(ct);\n\n        return Result\u003CPagedResult\u003CUserResponse>>.Success(\n            new PagedResult\u003CUserResponse>(users, total, query.Page, query.PageSize));\n    }\n}\n```\n\n### Validation Pipeline Behavior\n\n```csharp\npublic sealed class ValidationBehavior\u003CTRequest, TResponse> : IPipelineBehavior\u003CTRequest, TResponse>\n    where TRequest : IRequest\u003CTResponse>\n{\n    private readonly IEnumerable\u003CIValidator\u003CTRequest>> _validators;\n\n    public ValidationBehavior(IEnumerable\u003CIValidator\u003CTRequest>> validators)\n        => _validators = validators;\n\n    public async Task\u003CTResponse> Handle(\n        TRequest request,\n        RequestHandlerDelegate\u003CTResponse> next,\n        CancellationToken ct)\n    {\n        if (!_validators.Any()) return await next();\n\n        var context = new ValidationContext\u003CTRequest>(request);\n        var results = await Task.WhenAll(\n            _validators.Select(v => v.ValidateAsync(context, ct)));\n\n        var failures = results\n            .SelectMany(r => r.Errors)\n            .Where(f => f != null)\n            .ToList();\n\n        if (failures.Count > 0)\n            throw new ValidationException(failures);\n\n        return await next();\n    }\n}\n```\n\n---\n\n## FluentValidation\n\n```csharp\npublic sealed class CreateUserValidator : AbstractValidator\u003CCreateUserCommand>\n{\n    public CreateUserValidator()\n    {\n        RuleFor(x => x.Email)\n            .NotEmpty().WithMessage(\"Email is required\")\n            .EmailAddress().WithMessage(\"Invalid email format\")\n            .MaximumLength(255);\n\n        RuleFor(x => x.Name)\n            .NotEmpty().WithMessage(\"Name is required\")\n            .MinimumLength(2)\n            .MaximumLength(100)\n            .Matches(@\"^[a-zA-Z\\s'-]+$\").WithMessage(\"Name contains invalid characters\");\n\n        RuleFor(x => x.Password)\n            .NotEmpty()\n            .MinimumLength(8)\n            .Matches(\"[A-Z]\").WithMessage(\"Password must contain uppercase letter\")\n            .Matches(\"[a-z]\").WithMessage(\"Password must contain lowercase letter\")\n            .Matches(\"[0-9]\").WithMessage(\"Password must contain a number\")\n            .Matches(\"[^a-zA-Z0-9]\").WithMessage(\"Password must contain a special character\");\n    }\n}\n```\n\n---\n\n## Entity Framework Core 9\n\n### DbContext\n\n```csharp\npublic sealed class AppDbContext : DbContext\n{\n    public DbSet\u003CUser> Users => Set\u003CUser>();\n    public DbSet\u003COrder> Orders => Set\u003COrder>();\n    public DbSet\u003COrderItem> OrderItems => Set\u003COrderItem>();\n\n    public AppDbContext(DbContextOptions\u003CAppDbContext> options) : base(options) { }\n\n    protected override void OnModelCreating(ModelBuilder modelBuilder)\n    {\n        modelBuilder.ApplyConfigurationsFromAssembly(typeof(AppDbContext).Assembly);\n    }\n\n    public override async Task\u003Cint> SaveChangesAsync(CancellationToken ct = default)\n    {\n        \u002F\u002F Auto-set audit fields\n        foreach (var entry in ChangeTracker.Entries\u003CIAuditable>())\n        {\n            if (entry.State == EntityState.Added)\n                entry.Entity.CreatedAt = DateTime.UtcNow;\n\n            if (entry.State == EntityState.Modified)\n                entry.Entity.UpdatedAt = DateTime.UtcNow;\n        }\n\n        return await base.SaveChangesAsync(ct);\n    }\n}\n```\n\n### Entity Configuration\n\n```csharp\npublic sealed class UserConfiguration : IEntityTypeConfiguration\u003CUser>\n{\n    public void Configure(EntityTypeBuilder\u003CUser> builder)\n    {\n        builder.ToTable(\"users\");\n\n        builder.HasKey(u => u.Id);\n\n        builder.Property(u => u.Email)\n            .HasMaxLength(255)\n            .IsRequired();\n\n        builder.HasIndex(u => u.Email).IsUnique();\n\n        builder.Property(u => u.Name)\n            .HasMaxLength(100)\n            .IsRequired();\n\n        builder.Property(u => u.PasswordHash)\n            .HasMaxLength(255)\n            .IsRequired();\n\n        builder.HasMany(u => u.Orders)\n            .WithOne(o => o.User)\n            .HasForeignKey(o => o.UserId)\n            .OnDelete(DeleteBehavior.Cascade);\n\n        \u002F\u002F Query filter for soft delete\n        builder.HasQueryFilter(u => u.DeletedAt == null);\n    }\n}\n```\n\n### Migrations\n\n```bash\n# Create migration\ndotnet ef migrations add AddUserTable -p src\u002FUsers.Infrastructure -s src\u002FApi\n\n# Apply migration\ndotnet ef database update -p src\u002FUsers.Infrastructure -s src\u002FApi\n\n# Generate SQL script (for production)\ndotnet ef migrations script -p src\u002FUsers.Infrastructure -s src\u002FApi -o migrations.sql --idempotent\n```\n\n### Query Optimization\n\n```csharp\n\u002F\u002F ❌ BAD: N+1 queries\nvar users = await _db.Users.ToListAsync(ct);\nforeach (var user in users)\n{\n    var orders = await _db.Orders.Where(o => o.UserId == user.Id).ToListAsync(ct);\n}\n\n\u002F\u002F ✅ GOOD: Eager loading\nvar users = await _db.Users\n    .Include(u => u.Orders)\n    .ToListAsync(ct);\n\n\u002F\u002F ✅ BEST: Projection (only load what you need)\nvar users = await _db.Users\n    .AsNoTracking()\n    .Select(u => new UserResponse\n    {\n        Id = u.Id,\n        Name = u.Name,\n        Email = u.Email,\n        OrderCount = u.Orders.Count,\n    })\n    .ToListAsync(ct);\n```\n\n---\n\n## ASP.NET Identity + JWT Auth\n\n### Identity Setup\n\n```csharp\nbuilder.Services.AddIdentity\u003CApplicationUser, IdentityRole\u003CGuid>>(options =>\n{\n    options.Password.RequireDigit = true;\n    options.Password.RequiredLength = 8;\n    options.Password.RequireUppercase = true;\n    options.Password.RequireNonAlphanumeric = true;\n    options.Lockout.DefaultLockoutTimeSpan = TimeSpan.FromMinutes(15);\n    options.Lockout.MaxFailedAccessAttempts = 5;\n})\n.AddEntityFrameworkStores\u003CAppDbContext>()\n.AddDefaultTokenProviders();\n```\n\n### JWT Token Generation\n\n```csharp\npublic sealed class TokenService : ITokenService\n{\n    private readonly IConfiguration _config;\n\n    public TokenService(IConfiguration config) => _config = config;\n\n    public string GenerateAccessToken(ApplicationUser user, IList\u003Cstring> roles)\n    {\n        var claims = new List\u003CClaim>\n        {\n            new(ClaimTypes.NameIdentifier, user.Id.ToString()),\n            new(ClaimTypes.Email, user.Email!),\n            new(ClaimTypes.Name, user.UserName!),\n        };\n\n        claims.AddRange(roles.Select(role => new Claim(ClaimTypes.Role, role)));\n\n        var key = new SymmetricSecurityKey(\n            Encoding.UTF8.GetBytes(_config[\"Jwt:Key\"]!));\n\n        var token = new JwtSecurityToken(\n            issuer: _config[\"Jwt:Issuer\"],\n            audience: _config[\"Jwt:Audience\"],\n            claims: claims,\n            expires: DateTime.UtcNow.AddMinutes(15),\n            signingCredentials: new SigningCredentials(key, SecurityAlgorithms.HmacSha256));\n\n        return new JwtSecurityTokenHandler().WriteToken(token);\n    }\n\n    public string GenerateRefreshToken()\n    {\n        var randomBytes = new byte[64];\n        using var rng = RandomNumberGenerator.Create();\n        rng.GetBytes(randomBytes);\n        return Convert.ToBase64String(randomBytes);\n    }\n}\n```\n\n---\n\n## Domain Entity Pattern\n\n```csharp\npublic sealed class Order : IAuditable\n{\n    public Guid Id { get; private set; }\n    public Guid UserId { get; private set; }\n    public OrderStatus Status { get; private set; }\n    public decimal Total { get; private set; }\n    public DateTime CreatedAt { get; set; }\n    public DateTime? UpdatedAt { get; set; }\n\n    private readonly List\u003COrderItem> _items = [];\n    public IReadOnlyCollection\u003COrderItem> Items => _items.AsReadOnly();\n\n    private Order() { } \u002F\u002F EF Core\n\n    public static Order Create(Guid userId)\n    {\n        return new Order\n        {\n            Id = Guid.NewGuid(),\n            UserId = userId,\n            Status = OrderStatus.Pending,\n            Total = 0,\n        };\n    }\n\n    public Result\u003COrderItem> AddItem(Guid productId, int quantity, decimal unitPrice)\n    {\n        if (Status != OrderStatus.Pending)\n            return Result\u003COrderItem>.Failure(\n                Error.Validation(\"Order.NotPending\", \"Cannot add items to a non-pending order\"));\n\n        if (quantity \u003C= 0)\n            return Result\u003COrderItem>.Failure(\n                Error.Validation(\"Order.InvalidQuantity\", \"Quantity must be positive\"));\n\n        var item = new OrderItem(Guid.NewGuid(), Id, productId, quantity, unitPrice);\n        _items.Add(item);\n        RecalculateTotal();\n\n        return Result\u003COrderItem>.Success(item);\n    }\n\n    public Result\u003Cbool> Submit()\n    {\n        if (_items.Count == 0)\n            return Result\u003Cbool>.Failure(\n                Error.Validation(\"Order.Empty\", \"Cannot submit an empty order\"));\n\n        Status = OrderStatus.Submitted;\n        return Result\u003Cbool>.Success(true);\n    }\n\n    private void RecalculateTotal()\n    {\n        Total = _items.Sum(i => i.Quantity * i.UnitPrice);\n    }\n}\n\npublic enum OrderStatus { Pending, Submitted, Processing, Shipped, Delivered, Cancelled }\n```\n\n---\n\n## Anti-Patterns to Avoid\n\n1. ❌ Throwing exceptions for validation\u002Fbusiness logic — use Result pattern\n2. ❌ Anemic domain models (entities with only properties) — put behavior in entities\n3. ❌ Fat controllers\u002Fendpoints — delegate to MediatR handlers\n4. ❌ `.Result` or `.Wait()` on async calls — async all the way\n5. ❌ Returning `IQueryable` from repositories — materialize queries in the handler\n6. ❌ Using `AutoMapper` for simple mappings — manual mapping or extension methods\n7. ❌ Catching `Exception` broadly — catch specific exceptions at infrastructure boundaries\n8. ❌ Hard-coding connection strings — use `IConfiguration` and environment variables\n9. ❌ Missing `CancellationToken` — pass it through the entire call chain\n10. ❌ Using `DbContext` without `AsNoTracking()` for read queries\n","# .NET Expert\n\nSenior .NET 9 \u002F ASP.NET Core specialist with expertise in clean architecture, CQRS, and modular monolith patterns.\n\n## Role Definition\n\nYou are a senior .NET engineer building production-grade APIs with ASP.NET Core, Entity Framework Core 9, MediatR, and FluentValidation. You follow clean architecture principles with a pragmatic approach.\n\n## Core Principles\n\n1. **Result pattern over exceptions** for business logic — exceptions for infrastructure only\n2. **CQRS with MediatR** — separate commands (writes) from queries (reads)\n3. **FluentValidation** for all input validation in the pipeline\n4. **Modular monolith** — organized by feature\u002Fdomain, not by technical layer\n5. **Strongly-typed IDs** to prevent primitive obsession\n6. **Async all the way** — never `.Result` or `.Wait()`\n\n---\n\n## Project Structure (Modular Monolith)\n\n```\nsrc\u002F\n├── Api\u002F                          # ASP.NET Core host\n│   ├── Program.cs\n│   ├── appsettings.json\n│   └── Endpoints\u002F                # Minimal API endpoint definitions\n├── Modules\u002F\n│   ├── Users\u002F\n│   │   ├── Users.Core\u002F           # Domain entities, interfaces\n│   │   ├── Users.Application\u002F    # Commands, queries, handlers\n│   │   └── Users.Infrastructure\u002F # EF Core, external services\n│   ├── Orders\u002F\n│   │   ├── Orders.Core\u002F\n│   │   ├── Orders.Application\u002F\n│   │   └── Orders.Infrastructure\u002F\n│   └── Shared\u002F\n│       ├── Shared.Core\u002F          # Common abstractions\n│       └── Shared.Infrastructure\u002F# Cross-cutting concerns\n└── Tests\u002F\n    ├── Users.Tests\u002F\n    └── Orders.Tests\u002F\n```\n\n---\n\n## Minimal API Patterns\n\n### Basic Endpoint Group\n\n```csharp\n\u002F\u002F Api\u002FEndpoints\u002FUserEndpoints.cs\npublic static class UserEndpoints\n{\n    public static void MapUserEndpoints(this IEndpointRouteBuilder app)\n    {\n        var group = app.MapGroup(\"\u002Fapi\u002Fusers\")\n            .WithTags(\"Users\")\n            .RequireAuthorization();\n\n        group.MapGet(\"\u002F\", GetUsers);\n        group.MapGet(\"\u002F{id:guid}\", GetUserById);\n        group.MapPost(\"\u002F\", CreateUser);\n        group.MapPut(\"\u002F{id:guid}\", UpdateUser);\n        group.MapDelete(\"\u002F{id:guid}\", DeleteUser);\n    }\n\n    private static async Task\u003CIResult> GetUsers(\n        [AsParameters] GetUsersQuery query,\n        ISender mediator,\n        CancellationToken ct)\n    {\n        var result = await mediator.Send(query, ct);\n        return result.Match(\n            success => Results.Ok(success),\n            error => Results.Problem(error.ToProblemDetails()));\n    }\n\n    private static async Task\u003CIResult> GetUserById(\n        Guid id,\n        ISender mediator,\n        CancellationToken ct)\n    {\n        var result = await mediator.Send(new GetUserByIdQuery(id), ct);\n        return result.Match(\n            success => Results.Ok(success),\n            error => error.Type == ErrorType.NotFound\n                ? Results.NotFound()\n                : Results.Problem(error.ToProblemDetails()));\n    }\n\n    private static async Task\u003CIResult> CreateUser(\n        CreateUserCommand command,\n        ISender mediator,\n        CancellationToken ct)\n    {\n        var result = await mediator.Send(command, ct);\n        return result.Match(\n            success => Results.Created($\"\u002Fapi\u002Fusers\u002F{success.Id}\", success),\n            error => Results.Problem(error.ToProblemDetails()));\n    }\n}\n```\n\n### Program.cs Setup\n\n```csharp\nvar builder = WebApplication.CreateBuilder(args);\n\n\u002F\u002F Add modules\nbuilder.Services.AddUsersModule(builder.Configuration);\nbuilder.Services.AddOrdersModule(builder.Configuration);\n\n\u002F\u002F Add shared infrastructure\nbuilder.Services.AddMediatR(cfg =>\n    cfg.RegisterServicesFromAssemblies(\n        typeof(UsersModule).Assembly,\n        typeof(OrdersModule).Assembly));\n\nbuilder.Services.AddValidatorsFromAssemblies(new[]\n{\n    typeof(UsersModule).Assembly,\n    typeof(OrdersModule).Assembly,\n});\n\n\u002F\u002F Add validation pipeline behavior\nbuilder.Services.AddTransient(typeof(IPipelineBehavior\u003C,>), typeof(ValidationBehavior\u003C,>));\n\nbuilder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)\n    .AddJwtBearer(options =>\n    {\n        options.TokenValidationParameters = new TokenValidationParameters\n        {\n            ValidateIssuer = true,\n            ValidateAudience = true,\n            ValidateLifetime = true,\n            ValidateIssuerSigningKey = true,\n            ValidIssuer = builder.Configuration[\"Jwt:Issuer\"],\n            ValidAudience = builder.Configuration[\"Jwt:Audience\"],\n            IssuerSigningKey = new SymmetricSecurityKey(\n                Encoding.UTF8.GetBytes(builder.Configuration[\"Jwt:Key\"]!)),\n        };\n    });\n\nbuilder.Services.AddAuthorization();\n\nvar app = builder.Build();\n\napp.UseAuthentication();\napp.UseAuthorization();\n\napp.MapUserEndpoints();\napp.MapOrderEndpoints();\n\napp.Run();\n```\n\n---\n\n## Result Pattern\n\n### Result Type\n\n```csharp\n\u002F\u002F Shared.Core\u002FResult.cs\npublic sealed class Result\u003CT>\n{\n    public T? Value { get; }\n    public Error? Error { get; }\n    public bool IsSuccess { get; }\n\n    private Result(T value) { Value = value; IsSuccess = true; }\n    private Result(Error error) { Error = error; IsSuccess = false; }\n\n    public static Result\u003CT> Success(T value) => new(value);\n    public static Result\u003CT> Failure(Error error) => new(error);\n\n    public TResult Match\u003CTResult>(\n        Func\u003CT, TResult> onSuccess,\n        Func\u003CError, TResult> onFailure) =>\n        IsSuccess ? onSuccess(Value!) : onFailure(Error!);\n}\n\npublic sealed record Error(string Code, string Message, ErrorType Type = ErrorType.Failure)\n{\n    public static Error NotFound(string code, string message) => new(code, message, ErrorType.NotFound);\n    public static Error Validation(string code, string message) => new(code, message, ErrorType.Validation);\n    public static Error Conflict(string code, string message) => new(code, message, ErrorType.Conflict);\n    public static Error Forbidden(string code, string message) => new(code, message, ErrorType.Forbidden);\n\n    public ProblemDetails ToProblemDetails() => new()\n    {\n        Title = Code,\n        Detail = Message,\n        Status = Type switch\n        {\n            ErrorType.NotFound => StatusCodes.Status404NotFound,\n            ErrorType.Validation => StatusCodes.Status400BadRequest,\n            ErrorType.Conflict => StatusCodes.Status409Conflict,\n            ErrorType.Forbidden => StatusCodes.Status403Forbidden,\n            _ => StatusCodes.Status500InternalServerError,\n        },\n    };\n}\n\npublic enum ErrorType { Failure, NotFound, Validation, Conflict, Forbidden }\n```\n\n### Usage in Handlers\n\n```csharp\n\u002F\u002F No exceptions for business logic!\npublic sealed class CreateUserHandler : IRequestHandler\u003CCreateUserCommand, Result\u003CUserResponse>>\n{\n    private readonly AppDbContext _db;\n\n    public CreateUserHandler(AppDbContext db) => _db = db;\n\n    public async Task\u003CResult\u003CUserResponse>> Handle(\n        CreateUserCommand command, CancellationToken ct)\n    {\n        \u002F\u002F Business rule validation returns errors, not exceptions\n        var existingUser = await _db.Users\n            .AnyAsync(u => u.Email == command.Email, ct);\n\n        if (existingUser)\n            return Result\u003CUserResponse>.Failure(\n                Error.Conflict(\"User.DuplicateEmail\", \"A user with this email already exists\"));\n\n        var user = new User\n        {\n            Id = Guid.NewGuid(),\n            Email = command.Email,\n            Name = command.Name,\n            CreatedAt = DateTime.UtcNow,\n        };\n\n        _db.Users.Add(user);\n        await _db.SaveChangesAsync(ct);\n\n        return Result\u003CUserResponse>.Success(user.ToResponse());\n    }\n}\n```\n\n---\n\n## MediatR CQRS\n\n### Commands (Write Operations)\n\n```csharp\n\u002F\u002F Users.Application\u002FCommands\u002FCreateUserCommand.cs\npublic sealed record CreateUserCommand(\n    string Email,\n    string Name,\n    string Password) : IRequest\u003CResult\u003CUserResponse>>;\n```\n\n### Queries (Read Operations)\n\n```csharp\n\u002F\u002F Users.Application\u002FQueries\u002FGetUsersQuery.cs\npublic sealed record GetUsersQuery(\n    int Page = 1,\n    int PageSize = 20,\n    string? Search = null) : IRequest\u003CResult\u003CPagedResult\u003CUserResponse>>>;\n\npublic sealed class GetUsersHandler : IRequestHandler\u003CGetUsersQuery, Result\u003CPagedResult\u003CUserResponse>>>\n{\n    private readonly AppDbContext _db;\n\n    public GetUsersHandler(AppDbContext db) => _db = db;\n\n    public async Task\u003CResult\u003CPagedResult\u003CUserResponse>>> Handle(\n        GetUsersQuery query, CancellationToken ct)\n    {\n        var dbQuery = _db.Users.AsNoTracking();\n\n        if (!string.IsNullOrWhiteSpace(query.Search))\n            dbQuery = dbQuery.Where(u =>\n                u.Name.Contains(query.Search) || u.Email.Contains(query.Search));\n\n        var total = await dbQuery.CountAsync(ct);\n\n        var users = await dbQuery\n            .OrderBy(u => u.Name)\n            .Skip((query.Page - 1) * query.PageSize)\n            .Take(query.PageSize)\n            .Select(u => u.ToResponse())\n            .ToListAsync(ct);\n\n        return Result\u003CPagedResult\u003CUserResponse>>.Success(\n            new PagedResult\u003CUserResponse>(users, total, query.Page, query.PageSize));\n    }\n}\n```\n\n### Validation Pipeline Behavior\n\n```csharp\npublic sealed class ValidationBehavior\u003CTRequest, TResponse> : IPipelineBehavior\u003CTRequest, TResponse>\n    where TRequest : IRequest\u003CTResponse>\n{\n    private readonly IEnumerable\u003CIValidator\u003CTRequest>> _validators;\n\n    public ValidationBehavior(IEnumerable\u003CIValidator\u003CTRequest>> validators)\n        => _validators = validators;\n\n    public async Task\u003CTResponse> Handle(\n        TRequest request,\n        RequestHandlerDelegate\u003CTResponse> next,\n        CancellationToken ct)\n    {\n        if (!_validators.Any()) return await next();\n\n        var context = new ValidationContext\u003CTRequest>(request);\n        var results = await Task.WhenAll(\n            _validators.Select(v => v.ValidateAsync(context, ct)));\n\n        var failures = results\n            .SelectMany(r => r.Errors)\n            .Where(f => f != null)\n            .ToList();\n\n        if (failures.Count > 0)\n            throw new ValidationException(failures);\n\n        return await next();\n    }\n}\n```\n\n---\n\n## FluentValidation\n\n```csharp\npublic sealed class CreateUserValidator : AbstractValidator\u003CCreateUserCommand>\n{\n    public CreateUserValidator()\n    {\n        RuleFor(x => x.Email)\n            .NotEmpty().WithMessage(\"Email is required\")\n            .EmailAddress().WithMessage(\"Invalid email format\")\n            .MaximumLength(255);\n\n        RuleFor(x => x.Name)\n            .NotEmpty().WithMessage(\"Name is required\")\n            .MinimumLength(2)\n            .MaximumLength(100)\n            .Matches(@\"^[a-zA-Z\\s'-]+$\").WithMessage(\"Name contains invalid characters\");\n\n        RuleFor(x => x.Password)\n            .NotEmpty()\n            .MinimumLength(8)\n            .Matches(\"[A-Z]\").WithMessage(\"Password must contain uppercase letter\")\n            .Matches(\"[a-z]\").WithMessage(\"Password must contain lowercase letter\")\n            .Matches(\"[0-9]\").WithMessage(\"Password must contain a number\")\n            .Matches(\"[^a-zA-Z0-9]\").WithMessage(\"Password must contain a special character\");\n    }\n}\n```\n\n---\n\n## Entity Framework Core 9\n\n### DbContext\n\n```csharp\npublic sealed class AppDbContext : DbContext\n{\n    public DbSet\u003CUser> Users => Set\u003CUser>();\n    public DbSet\u003COrder> Orders => Set\u003COrder>();\n    public DbSet\u003COrderItem> OrderItems => Set\u003COrderItem>();\n\n    public AppDbContext(DbContextOptions\u003CAppDbContext> options) : base(options) { }\n\n    protected override void OnModelCreating(ModelBuilder modelBuilder)\n    {\n        modelBuilder.ApplyConfigurationsFromAssembly(typeof(AppDbContext).Assembly);\n    }\n\n    public override async Task\u003Cint> SaveChangesAsync(CancellationToken ct = default)\n    {\n        \u002F\u002F Auto-set audit fields\n        foreach (var entry in ChangeTracker.Entries\u003CIAuditable>())\n        {\n            if (entry.State == EntityState.Added)\n                entry.Entity.CreatedAt = DateTime.UtcNow;\n\n            if (entry.State == EntityState.Modified)\n                entry.Entity.UpdatedAt = DateTime.UtcNow;\n        }\n\n        return await base.SaveChangesAsync(ct);\n    }\n}\n```\n\n### Entity Configuration\n\n```csharp\npublic sealed class UserConfiguration : IEntityTypeConfiguration\u003CUser>\n{\n    public void Configure(EntityTypeBuilder\u003CUser> builder)\n    {\n        builder.ToTable(\"users\");\n\n        builder.HasKey(u => u.Id);\n\n        builder.Property(u => u.Email)\n            .HasMaxLength(255)\n            .IsRequired();\n\n        builder.HasIndex(u => u.Email).IsUnique();\n\n        builder.Property(u => u.Name)\n            .HasMaxLength(100)\n            .IsRequired();\n\n        builder.Property(u => u.PasswordHash)\n            .HasMaxLength(255)\n            .IsRequired();\n\n        builder.HasMany(u => u.Orders)\n            .WithOne(o => o.User)\n            .HasForeignKey(o => o.UserId)\n            .OnDelete(DeleteBehavior.Cascade);\n\n        \u002F\u002F Query filter for soft delete\n        builder.HasQueryFilter(u => u.DeletedAt == null);\n    }\n}\n```\n\n### Migrations\n\n```bash\n# Create migration\ndotnet ef migrations add AddUserTable -p src\u002FUsers.Infrastructure -s src\u002FApi\n\n# Apply migration\ndotnet ef database update -p src\u002FUsers.Infrastructure -s src\u002FApi\n\n# Generate SQL script (for production)\ndotnet ef migrations script -p src\u002FUsers.Infrastructure -s src\u002FApi -o migrations.sql --idempotent\n```\n\n### Query Optimization\n\n```csharp\n\u002F\u002F ❌ BAD: N+1 queries\nvar users = await _db.Users.ToListAsync(ct);\nforeach (var user in users)\n{\n    var orders = await _db.Orders.Where(o => o.UserId == user.Id).ToListAsync(ct);\n}\n\n\u002F\u002F ✅ GOOD: Eager loading\nvar users = await _db.Users\n    .Include(u => u.Orders)\n    .ToListAsync(ct);\n\n\u002F\u002F ✅ BEST: Projection (only load what you need)\nvar users = await _db.Users\n    .AsNoTracking()\n    .Select(u => new UserResponse\n    {\n        Id = u.Id,\n        Name = u.Name,\n        Email = u.Email,\n        OrderCount = u.Orders.Count,\n    })\n    .ToListAsync(ct);\n```\n\n---\n\n## ASP.NET Identity + JWT Auth\n\n### Identity Setup\n\n```csharp\nbuilder.Services.AddIdentity\u003CApplicationUser, IdentityRole\u003CGuid>>(options =>\n{\n    options.Password.RequireDigit = true;\n    options.Password.RequiredLength = 8;\n    options.Password.RequireUppercase = true;\n    options.Password.RequireNonAlphanumeric = true;\n    options.Lockout.DefaultLockoutTimeSpan = TimeSpan.FromMinutes(15);\n    options.Lockout.MaxFailedAccessAttempts = 5;\n})\n.AddEntityFrameworkStores\u003CAppDbContext>()\n.AddDefaultTokenProviders();\n```\n\n### JWT Token Generation\n\n```csharp\npublic sealed class TokenService : ITokenService\n{\n    private readonly IConfiguration _config;\n\n    public TokenService(IConfiguration config) => _config = config;\n\n    public string GenerateAccessToken(ApplicationUser user, IList\u003Cstring> roles)\n    {\n        var claims = new List\u003CClaim>\n        {\n            new(ClaimTypes.NameIdentifier, user.Id.ToString()),\n            new(ClaimTypes.Email, user.Email!),\n            new(ClaimTypes.Name, user.UserName!),\n        };\n\n        claims.AddRange(roles.Select(role => new Claim(ClaimTypes.Role, role)));\n\n        var key = new SymmetricSecurityKey(\n            Encoding.UTF8.GetBytes(_config[\"Jwt:Key\"]!));\n\n        var token = new JwtSecurityToken(\n            issuer: _config[\"Jwt:Issuer\"],\n            audience: _config[\"Jwt:Audience\"],\n            claims: claims,\n            expires: DateTime.UtcNow.AddMinutes(15),\n            signingCredentials: new SigningCredentials(key, SecurityAlgorithms.HmacSha256));\n\n        return new JwtSecurityTokenHandler().WriteToken(token);\n    }\n\n    public string GenerateRefreshToken()\n    {\n        var randomBytes = new byte[64];\n        using var rng = RandomNumberGenerator.Create();\n        rng.GetBytes(randomBytes);\n        return Convert.ToBase64String(randomBytes);\n    }\n}\n```\n\n---\n\n## Domain Entity Pattern\n\n```csharp\npublic sealed class Order : IAuditable\n{\n    public Guid Id { get; private set; }\n    public Guid UserId { get; private set; }\n    public OrderStatus Status { get; private set; }\n    public decimal Total { get; private set; }\n    public DateTime CreatedAt { get; set; }\n    public DateTime? UpdatedAt { get; set; }\n\n    private readonly List\u003COrderItem> _items = [];\n    public IReadOnlyCollection\u003COrderItem> Items => _items.AsReadOnly();\n\n    private Order() { } \u002F\u002F EF Core\n\n    public static Order Create(Guid userId)\n    {\n        return new Order\n        {\n            Id = Guid.NewGuid(),\n            UserId = userId,\n            Status = OrderStatus.Pending,\n            Total = 0,\n        };\n    }\n\n    public Result\u003COrderItem> AddItem(Guid productId, int quantity, decimal unitPrice)\n    {\n        if (Status != OrderStatus.Pending)\n            return Result\u003COrderItem>.Failure(\n                Error.Validation(\"Order.NotPending\", \"Cannot add items to a non-pending order\"));\n\n        if (quantity \u003C= 0)\n            return Result\u003COrderItem>.Failure(\n                Error.Validation(\"Order.InvalidQuantity\", \"Quantity must be positive\"));\n\n        var item = new OrderItem(Guid.NewGuid(), Id, productId, quantity, unitPrice);\n        _items.Add(item);\n        RecalculateTotal();\n\n        return Result\u003COrderItem>.Success(item);\n    }\n\n    public Result\u003Cbool> Submit()\n    {\n        if (_items.Count == 0)\n            return Result\u003Cbool>.Failure(\n                Error.Validation(\"Order.Empty\", \"Cannot submit an empty order\"));\n\n        Status = OrderStatus.Submitted;\n        return Result\u003Cbool>.Success(true);\n    }\n\n    private void RecalculateTotal()\n    {\n        Total = _items.Sum(i => i.Quantity * i.UnitPrice);\n    }\n}\n\npublic enum OrderStatus { Pending, Submitted, Processing, Shipped, Delivered, Cancelled }\n```\n\n---\n\n## Anti-Patterns to Avoid\n\n1. ❌ Throwing exceptions for validation\u002Fbusiness logic — use Result pattern\n2. ❌ Anemic domain models (entities with only properties) — put behavior in entities\n3. ❌ Fat controllers\u002Fendpoints — delegate to MediatR handlers\n4. ❌ `.Result` or `.Wait()` on async calls — async all the way\n5. ❌ Returning `IQueryable` from repositories — materialize queries in the handler\n6. ❌ Using `AutoMapper` for simple mappings — manual mapping or extension methods\n7. ❌ Catching `Exception` broadly — catch specific exceptions at infrastructure boundaries\n8. ❌ Hard-coding connection strings — use `IConfiguration` and environment variables\n9. ❌ Missing `CancellationToken` — pass it through the entire call chain\n10. ❌ Using `DbContext` without `AsNoTracking()` for read queries\n",{"name":5,"role":53,"scope":54,"version":55,"triggers":56,"description":7,"output-format":43},"specialist","implementation","1.0.0",[57,30,58,59,60,61,62,63,64,65,39,66,67,68,69,70],".NET","C#","ASP.NET","Entity Framework","EF Core","MediatR","CQRS","FluentValidation","Minimal API","DbContext","migration","Pitbull","modular monolith","Result pattern","main","e7e336ac628c3e3bd771aff1aaa469c93778f94a","skills\u002Fjgarrison929\u002Fdotnet-expert",0,"https:\u002F\u002Fgithub.com\u002Fkbarbel640-del\u002Fskills","https:\u002F\u002Fgithub.com\u002Fkbarbel640-del","2026-08-23 22:39:37",{"source":8,"skillName":5,"commands":79,"prompt":89,"zipAvailable":90},[80,83,86],{"tool":81,"command":82},"npx","npx skills add kbarbel640-del\u002Fskills --skill dotnet-expert",{"tool":84,"command":85},"bunx","bunx skills add kbarbel640-del\u002Fskills --skill dotnet-expert",{"tool":87,"command":88},"pnpm","pnpm dlx skills add kbarbel640-del\u002Fskills --skill dotnet-expert","安装技能，技能地址：https:\u002F\u002Fgithub.com\u002Fkbarbel640-del\u002Fskills\u002Fblob\u002Fmain\u002Fskills\u002Fjgarrison929\u002Fdotnet-expert\u002FSKILL.md",true,[92],{"path":93,"resourceType":94,"resourceTypeDesc":95,"sizeBytes":96,"sourceHtmlUrl":97},"_meta.json","REFERENCE","参考文档",284,"https:\u002F\u002Fgithub.com\u002Fkbarbel640-del\u002Fskills\u002Fblob\u002Fmain\u002Fskills\u002Fjgarrison929\u002Fdotnet-expert\u002F_meta.json",[99,127,153,174,180,200],{"skillNo":100,"name":101,"nameZh":6,"description":102,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":103,"categories":104,"keywords":108,"publishedAt":48},"01M6G8J55967D6281ACMKAKTEQ","crowd-prompting","A marketplace where AI agents improve prompts, system instructions, tool descriptions, and other text-based content with domain expertise from real-world operations — and earn tokens for valuable contributions.","https:\u002F\u002Fgithub.com\u002Fkbarbel640-del\u002Fskills\u002Fblob\u002Fmain\u002Fskills\u002Fzzadrian\u002Fcrowd-prompting\u002FSKILL.md",[105],{"categoryNo":106,"categoryName":107,"taxonomyType":25,"taxonomyTypeDesc":26},"01JBSEEDCAT000000000000036","内容创作者",[109,110,38,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126],"crowd prompting","prompting","with","tokens","domain","world","prompts","operations","instructions","text","tool","system","improve","productivity","marketplace","https","content","ai agents",{"skillNo":128,"name":129,"nameZh":6,"description":130,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":131,"categories":132,"keywords":136,"publishedAt":48},"01M6G8J0PKPAYVET6BWE8W4C26","dilemm-ai","Compete in DilemmAI, the prisoner's dilemma AI arena at dilemm.ai. Use when an OpenClaw agent wants to create an account, design and submit strategy prompts for their bot, enter matchmaking, analyze historical matches and leaderboards, and iterate on bot strategy. Requires headless browser automation (no API available yet).","https:\u002F\u002Fgithub.com\u002Fkbarbel640-del\u002Fskills\u002Fblob\u002Fmain\u002Fskills\u002Fzyori\u002Fdilemm-ai\u002FSKILL.md",[133],{"categoryNo":134,"categoryName":135,"taxonomyType":20,"taxonomyTypeDesc":21},"01JBSEEDCAT000000000000023","Skill与智能体开发",[137,38,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152,115,36],"dilemm ai","arena","analyze","browser","openclaw agent","create","automation","browser automation","bot","openclaw","design","strategy","headless","compete","submit","matchmaking",{"skillNo":154,"name":155,"nameZh":6,"description":156,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":157,"categories":158,"keywords":162,"publishedAt":48},"01M6G8HWAF3K9SW7NP3Z83CPJ6","arxiv-paper-reviews","Interact with arXiv Crawler API to fetch papers, read reviews, and submit comments. Use when working with arXiv papers, fetching paper lists by date\u002Fcategory\u002Finterest, viewing paper details with comments, or submitting paper reviews via API at http:\u002F\u002F150.158.152.82:8000.","https:\u002F\u002Fgithub.com\u002Fkbarbel640-del\u002Fskills\u002Fblob\u002Fmain\u002Fskills\u002Fzxrys\u002Fweak-accept\u002FSKILL.md",[159],{"categoryNo":160,"categoryName":161,"taxonomyType":20,"taxonomyTypeDesc":21},"01JBSEEDCAT000000000000021","资料检索与研究",[163,164,165,166,167,168,169,111,170,151,36,171,38,172,173],"arxiv paper reviews","reviews","arxiv","paper","crawler","papers","comments","fetch","read","http","via",{"skillNo":175,"name":155,"nameZh":6,"description":156,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":176,"categories":177,"keywords":179,"publishedAt":48},"01M6G8HQJ7N7WMY6YV7D7SSJ16","https:\u002F\u002Fgithub.com\u002Fkbarbel640-del\u002Fskills\u002Fblob\u002Fmain\u002Fskills\u002Fzxrys\u002Farxiv-paper-reviews\u002FSKILL.md",[178],{"categoryNo":160,"categoryName":161,"taxonomyType":20,"taxonomyTypeDesc":21},[166,165,164,163,173,168,169,111,167,151,36,170,171,38,172],{"skillNo":181,"name":182,"nameZh":6,"description":183,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":184,"categories":185,"keywords":186,"publishedAt":48},"01M6G8HM95Y64JNVFC2HN4E2BG","git-summary","Get a quick summary of the current Git repository including status, recent commits, branches, and contributors.","https:\u002F\u002Fgithub.com\u002Fkbarbel640-del\u002Fskills\u002Fblob\u002Fmain\u002Fskills\u002Fzweack\u002Fgit-summary\u002FSKILL.md",[],[187,188,189,190,191,192,193,194,195,196,197,198,199],"git","summary","git summary","commits","repository","win32","status","linux","contributors","true","quick","get","branches",{"skillNo":201,"name":202,"nameZh":6,"description":203,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":204,"categories":205,"keywords":210,"publishedAt":48},"01M6G8HGEGF05CNEJCGVYFSC4R","agent-constitution","Interact with AgentConstitution governance contracts on Base Sepolia. Check compliance, read rules, log actions, query governance state.","https:\u002F\u002Fgithub.com\u002Fkbarbel640-del\u002Fskills\u002Fblob\u002Fmain\u002Fskills\u002Fztsalexey\u002Fagent-constitution\u002FSKILL.md",[206,207],{"categoryNo":134,"categoryName":135,"taxonomyType":20,"taxonomyTypeDesc":21},{"categoryNo":208,"categoryName":209,"taxonomyType":25,"taxonomyTypeDesc":26},"01JBSEEDCAT000000000000037","律师与法务",[211,212,213,214,111,215,216,71,217,171,218,219,220,221,222,124,223,224,225],"agent constitution","constitution","contracts","tree","query","base","log","check","Rules","projects","compliance","actions","state","governance","github"]