[{"data":1,"prerenderedAt":354},["ShallowReactive",2],{"post-\u002Fblog\u002Ftwo-dotnet-claude-skills":3},{"id":4,"title":5,"body":6,"book":342,"date":343,"description":344,"extension":345,"meta":346,"navigation":347,"path":348,"seo":349,"stem":350,"tags":351,"__hash__":353},"blog\u002Fblog\u002Ftwo-dotnet-claude-skills.md","Two Claude Code skills I wrote for .NET",{"type":7,"value":8,"toc":335},"minimark",[9,14,18,44,47,50,58,61,150,153,156,162,165,168,190,201,208,264,267,270,274,277,311,318,321,325,328,331],[10,11,13],"h2",{"id":12},"background","Background",[15,16,17],"p",{},"I use Claude Code a lot for .NET work. The code it produces is fine by default, just not in my style. A few patterns kept coming up that I'd manually rewrite every time:",[19,20,21,25,33],"ul",{},[22,23,24],"li",{},"Services that should use primary constructors but don't.",[22,26,27,28,32],{},"DTOs and records without ",[29,30,31],"code",{},"required"," + init-only properties.",[22,34,35,36,39,40,43],{},"Minimal API endpoints registered one by one in ",[29,37,38],{},"Program.cs"," instead of being auto-scanned via an ",[29,41,42],{},"IEndpoint"," interface.",[15,45,46],{},"None of those are bugs. They're reasonable defaults, just not mine. So I wrote two skills to nudge Claude toward the way I'd actually write the code.",[10,48,49],{"id":49},"dotnet-skills",[15,51,52],{},[53,54,55],"a",{"href":55,"rel":56},"https:\u002F\u002Fgithub.com\u002Fhaiilong\u002Fdotnet-skills",[57],"nofollow",[15,59,60],{},"A collection of opinionated .NET 10 \u002F C# 14 conventions, packaged as Markdown skill files. Roughly the stuff that comes up on a normal day at work:",[19,62,63,74,77,84,99,109,115,122,132,138,141,147],{},[22,64,65,66,69,70,73],{},"C# coding standards (records with ",[29,67,68],{},"required { get; init; }",", primary constructors for services, ",[29,71,72],{},"sealed"," by default)",[22,75,76],{},"Type design (class vs record vs struct vs readonly record struct)",[22,78,79,80,83],{},"Value objects (",[29,81,82],{},"readonly record struct"," patterns)",[22,85,86,87,90,91,94,95,98],{},"Concurrency (",[29,88,89],{},"TimeProvider",", ",[29,92,93],{},"PeriodicTimer",", bounded ",[29,96,97],{},"Channel\u003CT>",")",[22,100,101,102,105,106,98],{},"Error handling (",[29,103,104],{},"Result\u003CT>",", RFC 9457 ",[29,107,108],{},"ProblemDetails",[22,110,111,112,114],{},"ASP.NET Core minimal APIs with auto-registered ",[29,113,42],{}," implementations",[22,116,117,118,121],{},"Dependency injection with ",[29,119,120],{},"extension(IServiceCollection)"," blocks",[22,123,124,125,128,129],{},"Configuration with ",[29,126,127],{},"IOptions\u003CT>"," and ",[29,130,131],{},"ValidateOnStart",[22,133,134,135],{},"Resilient HTTP clients via ",[29,136,137],{},"Microsoft.Extensions.Http.Resilience",[22,139,140],{},"Serialization (System.Text.Json source gen, MessagePack)",[22,142,143,144],{},"Structured logging with ",[29,145,146],{},"[LoggerMessage]",[22,148,149],{},"Testing (xUnit, NSubstitute, FluentAssertions, TestContainers, Verify)",[15,151,152],{},"Very opinionated, and the opinions are good ones (in my opinion). The other reason: it doubles as onboarding material for the team. \"Read this folder\" is a faster answer than explaining the same conventions one PR at a time.",[10,154,155],{"id":155},"dotnet-performance-skill",[15,157,158],{},[53,159,160],{"href":160,"rel":161},"https:\u002F\u002Fgithub.com\u002Fhaiilong\u002Fdotnet-performance-skill",[57],[15,163,164],{},"The second skill has a different goal: it runs through code that already exists and flags performance problems.",[15,166,167],{},"It walks a catalog of around 90 anti-patterns, grouped by severity:",[19,169,170,177,180],{},[22,171,172,173,176],{},"High: thread pool starvation, sync over async (",[29,174,175],{},".Result","), N+1 queries, LOH allocation. The stuff that takes a service down as soon as real load shows up.",[22,178,179],{},"Medium: missing pooling, cancellation propagation, middleware ordering.",[22,181,182,183,185,186,189],{},"Low: micro-optimizations like ",[29,184,72],{},", SIMD, ",[29,187,188],{},"stackalloc",". Only worth touching inside a measured hot path.",[15,191,192,193,196,197,200],{},"Each entry has a name, a short paragraph on why it matters, and a ",[29,194,195],{},"\u002F\u002F BAD"," \u002F ",[29,198,199],{},"\u002F\u002F GOOD"," code pair you can copy from. When you ask the skill to apply a fix, it pulls from the catalog instead of inventing one, which keeps the output predictable run to run.",[15,202,203,204,207],{},"The goal is to find places where the existing code is doing something dumb, not to lecture about architecture. The clearest example is multiple enumeration on ",[29,205,206],{},"IEnumerable",".",[209,210,215],"pre",{"className":211,"code":212,"language":213,"meta":214,"style":214},"language-csharp shiki shiki-themes one-light one-dark-pro","\u002F\u002F BAD: enumerates the IEnumerable twice (and the source might be a database query)\nif (items.Any()) return items.Count();\n","csharp","",[29,216,217,226],{"__ignoreMap":214},[218,219,222],"span",{"class":220,"line":221},"line",1,[218,223,225],{"class":224},"sW2Sy","\u002F\u002F BAD: enumerates the IEnumerable twice (and the source might be a database query)\n",[218,227,229,233,237,241,243,247,250,253,256,258,261],{"class":220,"line":228},2,[218,230,232],{"class":231},"sLKXg","if",[218,234,236],{"class":235},"s5ixo"," (",[218,238,240],{"class":239},"s7GmK","items",[218,242,207],{"class":235},[218,244,246],{"class":245},"sAdtL","Any",[218,248,249],{"class":235},"()) ",[218,251,252],{"class":231},"return",[218,254,255],{"class":239}," items",[218,257,207],{"class":235},[218,259,260],{"class":245},"Count",[218,262,263],{"class":235},"();\n",[15,265,266],{},"One thing that's still unclear: it sometimes surfaces stuff that isn't really a performance issue at all. Style nits, design smells, that kind of thing. The catalog and the skill description are both pretty explicit about scope, so it's not obvious why this happens. For now, read the High tier closely and treat the rest as suggestions.",[15,268,269],{},"EF Core isn't covered either, because it's not something I've used in production, so the catalog doesn't include it. Fork and add your own if you want it.",[10,271,273],{"id":272},"install","Install",[15,275,276],{},"Both are manual clone. No plugin marketplace entry, and I don't plan to publish one.",[209,278,282],{"className":279,"code":280,"language":281,"meta":214,"style":214},"language-bash shiki shiki-themes one-light one-dark-pro","git clone https:\u002F\u002Fgithub.com\u002Fhaiilong\u002Fdotnet-skills ~\u002F.claude\u002Fskills\u002Fdotnet-skills\ngit clone https:\u002F\u002Fgithub.com\u002Fhaiilong\u002Fdotnet-performance-skill ~\u002F.claude\u002Fskills\u002Fdotnet-performance\n","bash",[29,283,284,299],{"__ignoreMap":214},[218,285,286,289,293,296],{"class":220,"line":221},[218,287,288],{"class":245},"git",[218,290,292],{"class":291},"sDhpE"," clone",[218,294,295],{"class":291}," https:\u002F\u002Fgithub.com\u002Fhaiilong\u002Fdotnet-skills",[218,297,298],{"class":291}," ~\u002F.claude\u002Fskills\u002Fdotnet-skills\n",[218,300,301,303,305,308],{"class":220,"line":228},[218,302,288],{"class":245},[218,304,292],{"class":291},[218,306,307],{"class":291}," https:\u002F\u002Fgithub.com\u002Fhaiilong\u002Fdotnet-performance-skill",[218,309,310],{"class":291}," ~\u002F.claude\u002Fskills\u002Fdotnet-performance\n",[15,312,313,314,317],{},"Restart Claude Code or ",[29,315,316],{},"\u002Freload"," and they show up.",[15,319,320],{},"I'm not publishing as a plugin because these aren't broad enough for a general .NET audience. No ORM (EF Core, Dapper, Marten), no Razor, no Blazor, no MVC, plus a handful of other slices of the ecosystem I just don't touch at work. They reflect my own habits in the corner of .NET I actually live in. If your taste happens to overlap, fine. If it doesn't, the skills will spend their time fighting your defaults instead of helping, which is worse than not installing them at all.",[10,322,324],{"id":323},"closing","Closing",[15,326,327],{},"Honestly the main audience here is me and my team. Me, because I want Claude Code to produce .NET that already passes my own review. The team, because \"go read this folder\" turns out to be a faster onboarding answer than \"watch me review your first ten PRs and pick it up by osmosis\".",[15,329,330],{},"If you happen to share the taste, take a look. Otherwise fork it and rewrite the bits you disagree with. The files are short enough that this is realistic, not a project.",[332,333,334],"style",{},"html pre.shiki code .sW2Sy, html code.shiki .sW2Sy{--shiki-default:#A0A1A7;--shiki-default-font-style:italic;--shiki-dark:#7F848E;--shiki-dark-font-style:italic}html pre.shiki code .sLKXg, html code.shiki .sLKXg{--shiki-default:#A626A4;--shiki-dark:#C678DD}html pre.shiki code .s5ixo, html code.shiki .s5ixo{--shiki-default:#383A42;--shiki-dark:#ABB2BF}html pre.shiki code .s7GmK, html code.shiki .s7GmK{--shiki-default:#383A42;--shiki-dark:#E5C07B}html pre.shiki code .sAdtL, html code.shiki .sAdtL{--shiki-default:#4078F2;--shiki-dark:#61AFEF}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sDhpE, html code.shiki .sDhpE{--shiki-default:#50A14F;--shiki-dark:#98C379}",{"title":214,"searchDepth":228,"depth":228,"links":336},[337,338,339,340,341],{"id":12,"depth":228,"text":13},{"id":49,"depth":228,"text":49},{"id":155,"depth":228,"text":155},{"id":272,"depth":228,"text":273},{"id":323,"depth":228,"text":324},null,"2026-04-22","A pair of opinionated .NET skills for Claude Code, one for coding conventions, one for performance review.","md",{},true,"\u002Fblog\u002Ftwo-dotnet-claude-skills",{"title":5,"description":344},"blog\u002Ftwo-dotnet-claude-skills",[352],"tech","fLktajBLLWzDSUexby1GQwpzY-A1sEKpRjmahBoJRec",1778998257279]