csharp
Skill1 starsChanged 13 days agoMITView on GitHub
Use when writing or reviewing C# code, scaffolding a .csproj, designing a data model or DTO, writing an async method, expressing a conditional, or deciding whether a static helper should be an extension method. Trigger words - GlobalUsings.cs, C# 14, .NET 10, required, init, record, CancellationToken, extension method, boolean expression.
8 other projects use a version of this.
Adopted by
Most recently taken up by
- TheLunchTrae/claude-code-configstheir own version, first seen Nov 8, 2026
- testdino-hq/google-styleguides-skillstheir own version, first seen Nov 8, 2026
- G1Joshi/Agent-Skillstheir own version, first seen Oct 13, 2026
- EntitySystems/DysonHarnesstheir own version, first seen Oct 13, 2026
- jnotsknab/mux-swarmtheir own version, first seen Oct 11, 2026
- authdog/agent-skillstheir own version, first seen Sep 18, 2026
Other versions8 projects use a version of this.
Word for word · 0
None found.
Edited · 0
None found.
Wrote their own version · 8
- G1Joshi/Agent-Skills★ 15same name
- testdino-hq/google-styleguides-skills★ 15same name
- jnotsknab/mux-swarm★ 9same name
- EntitySystems/DysonHarness★ 4same name
- ffsshhttiikk/opencode-agents-skills★ 2same name
- kimtth/agent-skill-100-lines-or-less★ 2same name
- authdog/agent-skills★ 0same name
- TheLunchTrae/claude-code-configs★ 0same name
How matches are found. Word for word: the exact same text. Edited: shares passages with this file (“99% same” means 99% of its five-word phrases also appear here; 10% or more counts). Their own version: similar meaning, or, weakest, the same name. We can’t tell which project had it first. Projects are counted among the 200 most-starred candidates, and mentions are links to the repository we found, up to 50 per site, so both counts are a floor.
In this repository30 other files it gives its agents.
- angular-crud-gotchasSkill
- aws-lightsail-container-deploySkill
- bannerlord-decompileSkill
- codegen-t4-templatesSkill
- delphi-code-smellsSkill
- delphi-firedacSkill
- delphiSkill
- delphi-types-and-unitsSkill
- difftasticSkill
- dockerSkill
- efcore-aspnet-reviewSkill
- git-bash-editingSkill
- github-issue-creatorSkill
- microsoft-docsSkill
- minimal-comments-and-docsSkill
- msbuildSkill
- mssqlSkill
- mstest-assertionsSkill
- mysqlSkill
- nginx-config-testingSkill
- odata-generated-gridsSkill
- postgresSkill
- powershellSkill
- react-crud-gotchasSkill
- sanitize-for-open-sourceSkill
- self-contained-deploymentSkill
- skill-writerSkill
- ui-conventionsSkill
- verify-in-running-appSkill
- winui3Skill
The file
We split this skill into the rules it gives an agent
2 rules. 0 are common, 0 are distinctive, and 2 are very specific to this project.
0
Common
Most of the 7 edited versions we read keep these.
0
Distinctive
This author's own choices. Worth a look.
2
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Very specific: line 10
Every C# project (each .csproj) should have one GlobalUsings.cs file at its project root — not the same handful of using statements …
- Very specific: line 29
Prefer a single, well-named boolean variable over scattering the same logic across multiple nested if checks or throwaway intermediate …
“Common” is measured: kept by at least 6 in 10 of the 7 edited versions of this file we could read. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
C# Conventions
GlobalUsings.cs
Every C# project (each .csproj) should have one GlobalUsings.cs file at its project root — not the same handful of using statements repeated at the top of dozens of files. It should contain nothing but global using directives:
global using System.Text.Json;
global using Microsoft.EntityFrameworkCore;Scope it per-project, not per-solution — put a namespace in a project's GlobalUsings.cs only if it genuinely shows up across most files in that project (an EF-heavy Infrastructure project's list looks different from a controller-heavy Api project's). Don't treat it as a dumping ground for every namespace the project happens to use anywhere — that just trades explicit-but-scattered for implicit-and-unclear, losing the point of the file.
This is separate from <ImplicitUsings>enable</ImplicitUsings> in the .csproj, which the SDK already uses to auto-include a baseline set of BCL/framework namespaces (more of them for Microsoft.NET.Sdk.Web than plain Microsoft.NET.Sdk) via a generated obj/GlobalUsings.g.cs — leave that on, and let the hand-written GlobalUsings.cs cover the project-specific namespaces beyond that baseline.
Language version
Default to modern C# — currently C# 14 (ships with .NET 10 / Visual Studio 2026). Check the project's actual <TargetFramework> before assuming this applies — a Desktop app (WPF, WinForms) or a library constrained by a dependency that hasn't moved off .NET Framework may still be pinned to something like net48, where newer C# syntax and APIs either aren't available or aren't worth the friction. When in doubt, read the .csproj's <TargetFramework>/<TargetFrameworks> value rather than assuming — don't reach for the newest syntax in a codebase that turns out to still be net48.
When the target framework does support it, prefer current idioms over older equivalents doing the same job less clearly — primary constructors, collection expressions ([1, 2, 3]), target-typed new, switch expressions, and property patterns over the more verbose pre-C#-8-12 patterns they replace. Don't chase novelty for its own sake if an older, already-idiomatic form is just as clear — the goal is clarity, not a language-feature showcase.
Boolean expressions
Prefer a single, well-named boolean variable over scattering the same logic across multiple nested if checks or throwaway intermediate booleans — a good name turns a business rule into self-documenting code instead of something a reader has to reconstruct from several branches:
bool canStream4KContent = !isBanned && (userAge >= 18 || hasPremiumAccount);
bool isEligibleForDiscount = user is { Age: > 65, IsPremiumMember: true };Property patterns (is { Prop: condition, ... }) are usually the clearest option once a check involves more than one property off the same object — reach for them over a chain of &&-joined property accesses. The point is readability, not literally minimizing line count — if collapsing a check into one expression makes it harder to read (too many clauses, mixed precedence that needs parentheses to untangle), it's fine to split it back into a couple of named intermediate booleans instead.
Object construction: required/init over mutable setters
When a type has properties that must be set at construction and shouldn't change afterward, use required + init instead of a mutable auto-property or a constructor overload juggling optional parameters — the compiler then enforces that every required value is supplied, and the object can't drift out of a valid state after creation:
public class User
{
public required string Email { get; init; }
public required Guid TenantId { get; init; }
}This is about construction-time safety, not a blanket "make everything immutable" rule — a type that legitimately needs to mutate after creation (a view model tracking UI-editable state, an entity EF Core updates) should keep ordinary settable properties.
Records for DTOs
Default to record (or record struct for small, frequently-allocated ones) for types that exist purely to carry data — API request/response shapes, EF Core projection targets, message payloads — rather than a plain class. Value-based equality and a concise positional-or-init syntax come for free, and there's rarely a reason a DTO needs reference identity or mutability:
public record UserSummary(Guid Id, string Email, DateTimeOffset CreatedAt);Keep using a plain class for anything with actual behavior (methods that do real work, EF Core entities that need identity semantics tied to a database key, not just structural equality) — the point is picking the type that matches what the type is, not defaulting to record everywhere.
Propagate CancellationToken through async call chains
An async method that calls other async methods should accept a CancellationToken parameter and pass it down the chain, not swallow it at the top or omit it because "it's just an internal helper":
public async Task<User> GetUserAsync(Guid id, CancellationToken cancellationToken)
{
return await _dbContext.Users.FirstAsync(u => u.Id == id, cancellationToken);
}This is easy to forget because the code compiles fine without it — a dropped token doesn't cause an error, it just means a caller's cancellation (request aborted, timeout, user navigated away) silently stops propagating partway down the stack and the expensive operation keeps running anyway. Default to threading it through; the exception is a genuinely fire-and-forget background operation that's supposed to outlive the caller's request.
Prefer extension methods over static helpers with an obvious subject
When a static helper method has one parameter that's clearly "the thing being acted on," write it as an extension method on that type instead of a plain static method taking it as an argument. The author prefers this specifically for IntelliSense: typing thing. surfaces thing.DoSomething(), but a static Helper.DoSomething(thing) call is invisible until you already know the helper class exists and go looking for it.
// Preferred -- discoverable by typing "name."
public static class StringExtensions
{
public static bool IsNameBad(this string name) => ...;
}
if (name.IsNameBad()) ...
// Avoid when the extension-method form above reads equally naturally
public static class StringHelpers
{
public static bool IsNameBad(string name) => ...;
}
if (StringHelpers.IsNameBad(name)) ...Don't force it. Only make something an extension method when the method genuinely reads as an operation on that one parameter. Skip it when there's no single obvious subject — several equally-important inputs (a diff between two objects of the same type, where neither is more "the subject" than the other), a static factory building a new instance from a primitive (TemplateConfig.Load(path): path is just a generic string, not conceptually a TemplateConfig, so a path.LoadAsTemplateConfig() extension would be a non-obvious method to find hanging off every string in the codebase), or a method that's really about the type itself rather than a particular instance. Test: "if I were about to type parameterName., would I actually expect this method to show up there?" If yes, make it an extension method. If the honest answer is "not really, I'd go looking for a helper class instead," leave it a plain static method — a forced this parameter makes the subject arbitrary and can read less clearly than the plain static call.
Checking a claim about the compiler
When you are not sure a snippet compiles, or which error it gives, run it instead of reasoning about it: python C:\Github\tools\cs_snippet_check.py -e "<code>" (or files) builds it in a throwaway net10.0 project and prints each error once as CODE file(line,col) message. --run also runs it, --warnings lists warnings, --package ID@VERSION --offline adds a cached NuGet package. Examples checked: var a = new[] { }; is CS0826; a generic type with where T : class used with an unconstrained TOutput is CS0452; catch ... when (await ...) is CS7094.
Nullable lists
.Select(...FirstOrDefault...).OfType<T>().ToList() drops the nulls and gives a non-nullable List<T>; a ! on a List<T?> does not change its type and still triggers CS8620.
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.

