dotnet-onion-api
Skill1 starsChanged 3 months agoMITView on GitHub
Scaffold a new .NET solution (Web API + Worker microservices) using ONION architecture and EF Core, codifying battle-tested layered patterns and explicitly avoiding the common pitfalls of legacy stored-procedure-centric codebases. Use this skill whenever the user asks to "create a new dotnet project", "scaffold a .NET API", "new C# solution", "add a worker microservice", "add a feature end-to-end", or mentions "ONION", "Clean Architecture", "Onion Architecture", or "the layered .NET patterns I like". Three modes — (1) full solution scaffold, (2) add a feature slice through all layers, (3) add a BackgroundService worker microservice.
In this repository38 other files it gives its agents.
- CLAUDE.mdCLAUDE.md
- api-contract-reviewSkill
- autopilotSkill
- backlog-plannerSkill
- codebase-explainerSkill
- code-reviewSkill
- context-dietSkill
- conventional-commitsSkill
- create-prSkill
- design-briefSkill
- diagnoseSkill
- dotnet-conventionsSkill
- draw-optionsSkill
- e2e-verifySkill
- githubSkill
- goal-runnerSkill
- grill-with-docsSkill
- handoffSkill
- humanizerSkill
- improve-codebase-architectureSkill
- maestro-mobile-testSkill
- migration-safetySkill
- model-inventorySkill
- nextjs-app-routerSkill
- plan-and-buildSkill
- record-browser-testSkill
- regression-huntSkill
- safe-refactorSkill
- security-reviewSkill
- ship-itSkill
- sql-reviewSkill
- task-executorSkill
- tauri-2-appSkill
- think-like-fableSkill
- upgrade-depsSkill
- worktree-sandboxSkill
- write-a-skillSkill
- write-testsSkill
The file
Show its rules and text
We split this skill into the rules it gives an agent
27 rules. About 0 are common, 6 are distinctive, and 21 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈6
Distinctive · estimate
This author's own choices. Worth a look.
21
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Distinctive: line 22
If unsure whether the user wants a brand-new solution vs.
- Very specific: line 38
Never bake a hard-coded <TargetFramework> into generated projects — resolve it at scaffold time.
- Very specific: line 40
Check the user's environment first: run dotnet --list-sdks to see installed SDKs.
- Very specific: line 41
If a current LTS SDK is installed, prefer the highest installed LTS (net8.0, net10.0, etc.).
- Very specific: line 42
If unsure which is the current LTS, fetch the latest .NET support policy via context7 (mcp__plugin_context7_context7__resolve-library-id → …
- Very specific: line 53
Test stack majors: xunit v3 ships as the xunit.v3 package with different runner wiring than xunit 2.x.
- Very specific: line 55
If you are not certain a symbol exists in the resolved version, verify it (context7 docs lookup, or read the restored package surface under …
- Very specific: line 64
Include any Workers now?: If yes, ask for their names (comma-separated, e.g.
- Very specific: line 73
Use the templates in references/templates/ as the source of truth for file contents.
- Very specific: line 75
Use Write for new files. Never use Edit on files you're creating fresh.
- Very specific: line 77
Create directories before files.
- Very specific: line 78
After scaffolding, run dotnet sln add for every project and dotnet build to verify the solution compiles.
- Very specific: line 79
Do not run dotnet new to create the projects — write the .csproj and .cs files directly from templates so the layout matches exactly.
- Very specific: line 84
Run dotnet build from the solution root.
- Very specific: line 85
Run dotnet test if any test project exists.
- Very specific: line 86
Do not run dotnet ef migrations add or dotnet ef database update yourself unless the user confirmed a reachable database — report the …
- Very specific: line 115
Use these exact patterns when generating files.
- Very specific: line 132
Every one of these is forbidden in generated code.
- Distinctive: line 155
Ask the inputs per Step 2.
- Distinctive: line 170
If a first feature was requested, immediately run Mode 2 for that entity.
- Very specific: line 181
Use-case service: Application/{{Feature}}s/{{Feature}}Service.cs + interface I{{Feature}}Service.cs.
- Very specific: line 195
After generating: dotnet build then dotnet test.
- Very specific: line 207
Add to .sln. dotnet build.
- Distinctive: line 212
Look these up via context7 — do not hand-paste versions:
- Distinctive: line 272
If any check fails, fix before reporting.
- Distinctive: line 302
Don't over-engineer: don't add MediatR, CQRS, MassTransit, Polly, MinimalAPI conversions, Result<T> patterns, or domain events unless the …
- Very specific: line 304
Multi-tenancy: if the new project needs it, generate a TenantContext mirroring IUserContext and use EF Core query filters (HasQueryFilter) …
≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
.NET ONION API Scaffolder
Generate a production-grade .NET solution that keeps the good layered patterns (Api → Application → Infrastructure → Domain separation, base classes for cross-cutting concerns, extension-method wiring in Program.cs, JWT, AutoMapper, auto-DI, unified error responses) and eliminates the bad ones often seen in legacy .NET codebases (stored-procedure-centric reflection repositories, EF6 on netstandard2.1, polling console-app workers, swallowed exceptions, mutable per-request state on base service classes, mixed ADO/Dapper/EF6 data access, missing CancellationToken plumbing).
When to use this skill
Trigger on any of:
- "create a new dotnet project / .NET solution / C# project"
- "scaffold a .NET Web API"
- "new microservice in .NET" / "add a worker service"
- "use the patterns I like" / "use my layered .NET conventions" (in a .NET context)
- "ONION architecture" / "Clean Architecture" / "layered .NET project"
- "add a feature end-to-end" / "add a slice" (API + service + repository + EF entity + tests)
- The user pastes a feature spec and asks you to wire it through the layers of a .NET solution
If unsure whether the user wants a brand-new solution vs. an addition to an existing one, ask once — don't guess.
Three operating modes
Pick the mode from the user's request. If ambiguous, ask.
| Mode | Trigger | Output |
scaffold-solution | "new project", "scaffold solution", empty directory | Full ONION solution: Domain, Application, Infrastructure, Api, Workers (optional), Tests. |
add-feature | "add <Entity> end-to-end", "wire up <feature> through all layers" | Entity + EF config + repository (port + adapter) + use-case service + DTO + controller + AutoMapper profile + unit test. |
add-worker | "new worker", "add microservice for queue X" | New Workers.<Name> project (BackgroundService) referencing Application + Infrastructure, with queue/service-bus consumer and graceful shutdown. |
Workflow
Step 1 — Determine the target framework (don't hard-code)
Never bake a hard-coded <TargetFramework> into generated projects — resolve it at scaffold time. Before generating .csproj files:
- Check the user's environment first: run
dotnet --list-sdksto see installed SDKs. - If a current LTS SDK is installed, prefer the highest installed LTS (
net8.0,net10.0, etc.). - If unsure which is the current LTS, fetch the latest .NET support policy via context7 (
mcp__plugin_context7_context7__resolve-library-id→query-docsfor ".NET release schedule" / "dotnet support policy") or WebFetchhttps://dotnet.microsoft.com/en-us/platform/support/policy/dotnet-core. Quote the version you picked back to the user before generating. - Pin EF Core, ASP.NET Core, and
Microsoft.Extensions.*package versions to the latest stable for that TFM — look them up via context7 (Microsoft.EntityFrameworkCore,Microsoft.AspNetCore.Authentication.JwtBearer, etc.) rather than guessing. Never hand-paste a version you don't have a source for. - State the chosen TFM and package versions in your reply before writing files, so the user can object before scaffolding.
- Concrete resolution commands when context7 is unavailable:
dotnet package search <PackageId> --take 1or WebFetchhttps://api.nuget.org/v3-flatcontainer/<package-id-lowercase>/index.json(last non-preview entry = latest stable). Never write a version string you did not just resolve this session — no versions from memory, no wildcards, no invented numbers.
API-drift guard. The version you resolved in this step decides the API shape — training-data memory is the least trustworthy source in this workflow. Highest-risk hallucination zones:
- EF Core APIs across majors (e.g.
HasCheckConstraintmoved intoToTable(t => t.HasCheckConstraint(...))in EF7; query/interceptor APIs get renamed between majors). - Hosted-service and
Hostbuilder idioms —Host.CreateApplicationBuilder(post-.NET 7) vs the olderCreateDefaultBuildercallback style; don't mix the two. - TFM defaults: newer TFMs flip
<Nullable>/<ImplicitUsings>behavior — templates must match the resolved TFM, not a remembered one. - OpenAPI/Swagger: .NET 9+ templates dropped Swashbuckle for built-in
Microsoft.AspNetCore.OpenApi(AddOpenApi()/MapOpenApi()). Pick the approach matching the resolved TFM; never wire both. - Test stack majors: xunit v3 ships as the
xunit.v3package with different runner wiring thanxunit2.x; AutoMapper 13+ self-registers (no.Extensions.Microsoft.DependencyInjectionpackage). Match templates to what you resolved, not to package names from memory.
If you are not certain a symbol exists in the resolved version, verify it (context7 docs lookup, or read the restored package surface under ~/.nuget/packages/) before writing code that depends on it.
Step 2 — Gather inputs (ask once, in one batch)
For scaffold-solution, use AskUserQuestion to collect:
- Solution name (e.g.
Acme.Billing). Used for namespace root and.sln. - First feature/entity (optional, e.g.
Customer) — if provided, also runadd-featurefor it after scaffold. - Auth: JWT bearer with HS256 (symmetric) or JWT with asymmetric (RS256/JWKS) or none-yet.
- Include any Workers now? If yes, ask for their names (comma-separated, e.g.
EmailSender, PdfPrinter). - Optional extras: Serilog + OpenTelemetry? Dockerfile? GitHub Actions CI? Testcontainers integration tests? (Default: skip — only add if asked.)
For add-feature: entity name, properties (name + C# type + nullability), whether it needs CRUD controller or only specific endpoints.
For add-worker: worker name, trigger source (Azure Storage Queue / Service Bus / Timer), message DTO type (if known).
Step 3 — Generate files
Use the templates in references/templates/ as the source of truth for file contents. Apply these rules:
- Use
Writefor new files. Never useEditon files you're creating fresh. - Replace all
{{Solution}},{{Feature}},{{Worker}}placeholders consistently. - Create directories before files. On Windows shell use PowerShell
New-Item -ItemType Directory -Force. - After scaffolding, run
dotnet sln addfor every project anddotnet buildto verify the solution compiles. Report build output to the user. - Do not run
dotnet newto create the projects — write the.csprojand.csfiles directly from templates so the layout matches exactly. - If a
dotnet newtemplate IS run anyway (user's insistence): the SDK wins on formats it owns (.slncontents,obj//bin/artifacts), this skill wins on everything else — overwrite template boilerplate with the skill's templates, keep this skill's project split and folder names. Reconcile deliberately and list every deviation in your report; never silently abandon the skill's patterns, never fight the SDK on formats it owns.
Step 4 — Verify and report
- Run
dotnet buildfrom the solution root. If it fails, fix the first error (later errors are usually cascade) and rebuild — never leave a broken scaffold. - Run
dotnet testif any test project exists. - Do not run
dotnet ef migrations addordotnet ef database updateyourself unless the user confirmed a reachable database — report the migration command as a next step instead. The delivery bar is the build gate, not the migration. - Known failure signature:
NETSDK1045("The current .NET SDK does not support targeting …") means the TFM you picked outruns the installed SDK — re-rundotnet --list-sdksand re-pin to the highest installed LTS; do not install a new SDK unprompted. - A scaffold that hasn't compiled is not delivered. Paste the actual proof lines in your report (
Build succeeded./0 Error(s), and thePassed! - Failed: 0test summary). Never report success from memory of the steps you intended, and never report partial success as success — if something is red, say exactly what is red. - CLI failure protocol (applies to
dotnet new,dotnet sln add,dotnet build,dotnet test): read the full error output, change exactly one thing, retry once. If the same step fails twice, stop scaffolding and surface the verbatim error to the user — do not keep generating files on top of a broken base, and do not re-run the identical command hoping for a different result. - Reply with a short summary: solution path, projects created, TFM chosen, package versions, next steps (e.g. "run
dotnet ef migrations add Initial -p src/{{Solution}}.Infrastructure -s src/{{Solution}}.Api").
Solution layout (canonical)
See references/solution-layout.md for the full tree and dependency rules.
{{Solution}}/
{{Solution}}.sln
src/
{{Solution}}.Domain # entities, value objects, domain events. NO project refs.
{{Solution}}.Application # use-case services + ports (interfaces) + DTOs + validators. refs Domain.
{{Solution}}.Infrastructure # EF Core DbContext, repository adapters, external clients (Azure, email, auth). refs Application+Domain.
{{Solution}}.Api # Controllers, Middleware, Filters, Program.cs. refs Application+Infrastructure.
{{Solution}}.Workers.<Name> # BackgroundService microservices. refs Application+Infrastructure.
{{Solution}}.Contracts # (optional) public DTOs / API contracts shared with clients.
tests/
{{Solution}}.UnitTests # xUnit + NSubstitute. Tests Application use-cases with mocked ports.
{{Solution}}.IntegrationTests# WebApplicationFactory + Testcontainers (SQL Server). Real DB + real pipeline.Dependency rule (enforced): outer → inner only. Domain has zero project references. Application references Domain only. Infrastructure may reference both. Api/Workers reference Application + Infrastructure but never each other.
Required code patterns
Use these exact patterns when generating files. Full templates are in references/templates/.
Keep
BaseControllerwith[ApiController],[Route("api/[controller]")],[Authorize], injectedIUserContext— seereferences/templates/base-controller.cs.md.- Base use-case service with constructor-injected
IUserContext(no public mutable user property — a common bug in legacy bases). - Thin
Program.csthat calls only extension methods (AddApplication,AddInfrastructure,AddApiServices,AddJwtAuth,AddSwaggerDocs,AddCorsPolicies). Seereferences/templates/program-cs.md. - Auto-registration via
Scrutorfor ports → adapters (replacesNetCore.AutoRegisterDi, modern + maintained). Singletons/options registered explicitly. - Strongly-typed
AppSettings+ConnectionStringsbound viaIOptions<T>(don't register the raw POCO as singleton — useservices.Configure<T>(...)and injectIOptions<T>). - AutoMapper with assembly scan:
services.AddAutoMapper(typeof(ApplicationAssemblyMarker).Assembly). - Centralized exception middleware with env-aware response — see
references/templates/exception-middleware.cs.md. - Unified validation error response via
InvalidModelStateResponseFactory. - JWT auth wiring in a
RegisterAuthextension method. - Minimal comments in generated code. Default to no comments. Only add one when the why is non-obvious — a workaround for a specific framework bug (with a link), a subtle invariant the code depends on, a domain rule that isn't visible from the names. Never write XML doc-comment blocks (
/// <summary>...) on internal members; reserve them for genuinely public API surface that ships to consumers. Never restate what the next line does, never leave// TODOwithout an issue link. One short line max — no multi-line comment blocks. Well-named identifiers carry the what; comments earn their place only when they carry why.
Eliminate (anti-patterns)
Every one of these is forbidden in generated code. See references/anti-patterns.md for the rationale of each.
- ❌ Stored-procedure-first data access. Use EF Core with LINQ; only drop to raw SQL via
FromSqlInterpolated/ExecuteSqlInterpolatedfor legitimate perf/legacy reasons, and never with reflection-based parameter mapping. - ❌
dynamic/ExpandoObjectfor query parameters. - ❌ Reflection-based
DataRow → objectmappers. EF Core handles this. - ❌ EF6 +
netstandard2.1. Use EF Core (latest) on the chosen TFM. - ❌ Empty
catch {}blocks. Either handle the exception meaningfully or let it propagate to the middleware. - ❌ Mutable
public User { get; set; }on a service base class — request-scoped state belongs in the scopedIUserContextonly. - ❌ Polling
while (true) { Task.Delay(5s) }console-app workers. UseBackgroundServicewithCancellationToken stoppingTokenand SDK-native receive loops — seereferences/templates/worker-program.cs.md. - ❌ Booting hosted services with
serviceProvider.GetService<T>()inProgram.cs. Register them viaservices.AddHostedService<T>(). - ❌ Auto-registering everything as
Scopedindiscriminately. Use Scrutor's lifetime selectors, and register Azure SDK clients /IHttpClientFactoryclients / options as singletons explicitly. - ❌ Newtonsoft.Json +
DefaultContractResolver(PascalCase). Use System.Text.Json withJsonNamingPolicy.CamelCaseby default. Add Newtonsoft only if a specific dependency demands it. - ❌ Missing
CancellationTokenparameters. Every async public method takesCancellationToken ctas the last parameter and forwards it. - ❌ Per-tenant repositories under
Repositories/{TenantName}/. Multi-tenant behavior goes through a strategy injected via DI, not folder forks. - ❌ Hard-coded multi-tenant magic fallbacks (e.g. defaulting
ClientIdto a literal string when claims are missing). Multi-tenancy comes fromIUserContextor fails fast. - ❌ Commented-out dead code in generated files.
- ❌ Controllers that bypass
BaseController(consistency is mandatory; if a public endpoint needs[AllowAnonymous], declare it on the action).
Operating-mode playbooks
Mode 1 — scaffold-solution
- Pick TFM and package versions per Step 1. Quote them.
- Ask the inputs per Step 2. Wait for answers.
- Generate, in this order:
.slnfile (usedotnet new sln -n {{Solution}}only to produce the sln; everything else is hand-written from templates).src/{{Solution}}.Domain/(csproj +DomainAssemblyMarker.cs+ sampleEntitybase if relevant).src/{{Solution}}.Application/(csproj + assembly marker +Common/withIUserContext,Result<T>if requested,IUnitOfWorkport,IRepository<T>port).src/{{Solution}}.Infrastructure/(csproj +Persistence/AppDbContext.cs+Persistence/EntityConfigurations/folder +Persistence/UnitOfWork.cs+Auth/UserContext.cs+DependencyInjection.cswithAddInfrastructure).src/{{Solution}}.Api/(csproj +Program.cs+Extensions/folder +Middlewares/ExceptionHandlerMiddleware.cs+Controllers/BaseController.cs+appsettings.json/appsettings.Development.json).Checkpoint:
dotnet sln additems 1–5 anddotnet buildnow, before generating workers and tests — a failure here localizes to the core projects; a failure after the full tree does not. Apply the Step-4 failure protocol at this checkpoint too.src/{{Solution}}.Workers.<Name>/per worker requested.tests/{{Solution}}.UnitTests/(csproj + xUnit + NSubstitute + AutoFixture).tests/{{Solution}}.IntegrationTests/(csproj +Microsoft.AspNetCore.Mvc.Testing+Testcontainers.MsSql) — only if user asked for it.
dotnet sln {{Solution}}.sln addevery project (one command, all projects).dotnet build— must succeed.- If a first feature was requested, immediately run Mode 2 for that entity.
- Report.
Mode 2 — add-feature
For entity {{Feature}} (e.g. Customer):
- Domain:
src/{{Solution}}.Domain/{{Feature}}s/{{Feature}}.cs— POCO entity with a private parameterless ctor for EF, a public ctor for invariants, and behavior methods (avoid anemic models). Add domain events only if asked. - Application:
- Port:
src/{{Solution}}.Application/{{Feature}}s/I{{Feature}}Repository.cs(interface with CRUD methods that takeCancellationToken). - DTOs:
Application/{{Feature}}s/Dtos/{{Feature}}Dto.cs,Create{{Feature}}Request.cs,Update{{Feature}}Request.cs. - Use-case service:
Application/{{Feature}}s/{{Feature}}Service.cs+ interfaceI{{Feature}}Service.cs. Service depends onI{{Feature}}Repository,IUnitOfWork,IMapper. Pure orchestration — no EF references. - AutoMapper profile:
Application/{{Feature}}s/Mapping/{{Feature}}Profile.cs. - FluentValidation validator (only if user asked for FluentValidation; otherwise rely on DataAnnotations + the validation factory).
- Port:
- Infrastructure:
- EF configuration:
Infrastructure/Persistence/EntityConfigurations/{{Feature}}Configuration.cs(implementsIEntityTypeConfiguration<{{Feature}}>). - Repository adapter:
Infrastructure/Persistence/Repositories/{{Feature}}Repository.cs(implementsI{{Feature}}RepositoryusingAppDbContext). - Register the DbSet on
AppDbContext.
- EF configuration:
- Api:
- Controller:
Api/Controllers/{{Feature}}sController.csinheritingBaseController, injectingI{{Feature}}Service. Standard REST endpoints, returning DTOs only.
- Controller:
- Tests:
tests/{{Solution}}.UnitTests/{{Feature}}s/{{Feature}}ServiceTests.cs— xUnit + NSubstitute, covers the service's happy path + one validation/edge case.
Template for the full slice is in references/templates/feature-slice.md.
After generating: dotnet build then dotnet test. Both must pass — apply the Step-4 proof-and-failure protocol (paste the green lines; the same step failing twice = stop and surface the verbatim error).
Mode 3 — add-worker
For worker {{Worker}} (e.g. EmailSender):
- Create
src/{{Solution}}.Workers.{{Worker}}/:csprojperreferences/templates/worker-csproj.md.Program.csusingHost.CreateApplicationBuilderperreferences/templates/worker-program.cs.md.Worker.cs—BackgroundServicesubclass; loop driven bystoppingToken; respects graceful shutdown.appsettings.json+appsettings.Development.json.
- Reference
Application+Infrastructure(neverApi). - Add to
.sln.dotnet build. - No
while (true) { ... await Task.Delay(5s) }— use the SDK's receive loop (e.g.await foreach (var msg in receiver.ReceiveMessagesAsync(stoppingToken))for Service Bus, orawait queueClient.ReceiveMessagesAsync(maxMessages, ct: stoppingToken)inside awhile (!stoppingToken.IsCancellationRequested)loop).
NuGet packages (resolve latest stable at scaffold time)
Look these up via context7 — do not hand-paste versions:
Api project
Microsoft.AspNetCore.Authentication.JwtBearerMicrosoft.AspNetCore.OpenApiSwashbuckle.AspNetCoreAutoMapper.Extensions.Microsoft.DependencyInjection(orAutoMapper13+ which self-registers)Scrutor(assembly-scanning DI)Serilog.AspNetCore+Serilog.Sinks.Console(only if user opted into Serilog)
Application project
MediatRonly if user explicitly asks for CQRS; default is plain service classesFluentValidationonly if requested
Infrastructure project
Microsoft.EntityFrameworkCore.SqlServerMicrosoft.EntityFrameworkCore.Design(PrivateAssets="all")Microsoft.EntityFrameworkCore.Tools(PrivateAssets="all")Microsoft.Data.SqlClientAzure.Storage.Blobs,Azure.Storage.Queues,Azure.Messaging.ServiceBus(only if used)
Worker projects
Microsoft.Extensions.Hosting- Same Azure SDK packages as Infrastructure (only what the worker actually uses)
Test projects
Microsoft.NET.Test.Sdkxunit,xunit.runner.visualstudioNSubstitute(preferred over Moq — cleaner API, actively maintained)FluentAssertionsTestcontainers.MsSql(integration tests only)Microsoft.AspNetCore.Mvc.Testing(integration tests only)
Final self-audit (mechanical — grep, don't recall)
The Eliminate list is easy to hold at file 1 and forgotten by file 30. After generating and before the final build, grep the generated tree — every command must return nothing:
grep -rn "Thread.Sleep\|while (true)" src/ # polling-loop workers
grep -rnE "catch\s*(\(\s*Exception[^)]*\))?\s*\{\s*\}" src/ # swallowed exceptions
grep -rn "ExpandoObject\|DataRow\|SqlDataAdapter" src/ # sproc-era / reflection data access
grep -rn "GetService<" src/*/Program.cs # hosted services booted by hand
grep -rn "Newtonsoft" src/ # unless a dependency demanded it
grep -rln "public async Task" src/ | xargs grep -Ln "CancellationToken" # async surface with no ct anywhere
grep -rn "System.Data.Entity\|\"EntityFramework\"" src/ # EF6 leaking into an EF Core solution
grep -rn "CreateDefaultBuilder" src/ # mixed host-builder idioms
grep -rn "/// <summary>" src/ # XML doc blocks on internal membersA hit means fix it and re-run the grep — never rationalize it away or report it as acceptable.
Verification checklist before reporting "done"
dotnet buildexits 0.dotnet testexits 0 (if tests were generated).- No
.csprojreferences violate the ONION rule. Concrete check:grep "ProjectReference" src/*/*.csproj— Domain shows zero hits, Application references only Domain, Api/Workers never reference each other. - No file contains any pattern from the Eliminate list.
Program.csis under ~50 lines (everything else is in extension methods).- Domain project's
.csprojhas zero<ProjectReference>entries.
If any check fails, fix before reporting. Don't claim success with a known-broken scaffold.
Examples
Example 1: Fresh solution
User: "Scaffold a new dotnet API project called Acme.Billing using my ONION patterns. Add a Customer feature too."
Claude:
- Runs
dotnet --list-sdks, checks context7 for current LTS, picks (e.g.)net8.0. - Reports chosen TFM + package versions; waits for confirmation if anything looks off.
- Asks the Step-2 questions (auth flavor, workers, extras).
- Generates the full solution + the
Customerfeature slice. - Runs
dotnet buildanddotnet test. - Reports the tree and the EF migration command.
Example 2: Add a feature
User: "Add an Invoice feature end-to-end to the existing solution."
Claude: Runs Mode 2 only — generates Domain entity, Application port + service + DTOs, Infrastructure config + repository, Api controller, unit test. Builds and tests.
Example 3: Add a worker
User: "Add a worker that processes the print-jobs Azure Storage queue."
Claude: Runs Mode 3 — generates Workers.PrintJobs project with a BackgroundService that receives messages with stoppingToken, calls into an Application service, deletes on success. Wires it into the .sln. Builds.
Notes
- Don't over-engineer: don't add MediatR, CQRS, MassTransit, Polly, MinimalAPI conversions, Result
<T>patterns, or domain events unless the user asks. Pragmatic > pure. - Don't rewrite the user's existing codebase as part of this skill. This skill is for new scaffolds, not migrations. If the user wants a migration plan, that's a different conversation.
- Multi-tenancy: if the new project needs it, generate a
TenantContextmirroringIUserContextand use EF Core query filters (HasQueryFilter) rather than per-tenant repositories. - Always quote the TFM and package versions you chose before writing files — they are resolved at scaffold time, never hard-coded.
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

