csharp-tools
Skill0 starsChanged 15 days agoMITView on GitHub
Use when writing a new project tool, script or CLI helper (anything past a one-liner), when a task rewrites or substantially changes a paired .sh + .ps1 script, when the user asks to port scripts to C#, or when adding unit tests to shell tooling. Project tools are C# console projects run with `dotnet` on Windows and macOS alike — one source instead of two drifting twins, compiled, unit-tested with xUnit. Covers layout, seams for testing, exit codes, shims and the step-by-step port of an existing pair. Not for Claude Code hook one-liners or the session-start sync, which must run before .NET exists.
- Installs packages
In this repository23 other files it gives its agents.
- AGENTS.mdAGENTS.md
- CLAUDE.mdCLAUDE.md
- .github/copilot-instructions.mdCopilot instructions
- apps-configSkill
- architect-flowSkill
- bootstrap-aiSkill
- code-healthSkill
- headless-ui-smokeSkill
- launch-and-deploySkill
- macos-local-codesignSkill
- mobile-webSkill
- portable-projectSkill
- review-sweepSkill
- tech-researchSkill
- test-tiersSkill
- threat-modelingSkill
- ui-craftSkill
- ui-doctorSkill
- ui-motionSkill
- ui-stress-testSkill
- ui-variantsSkill
- web-accessibilitySkill
- web-art-directionSkill
The file
We split this skill into the rules it gives an agent
2 rules. About 0 are common, 0 are distinctive, and 2 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈0
Distinctive · estimate
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 44
Commit the solution, the projects and a .gitignore with bin/ and obj/.
- Very specific: line 66
Files: write UTF-8 without BOM and \n line endings unless the format needs otherwise.
≈ “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
C# project tools
One C# source replaces a .sh + .ps1 pair: it compiles (the type checker catches what two
hand-synced scripts drift on), it runs the same on Windows and macOS, and its logic is
unit-tested like any code. Every project moves to it gradually: new tools start in C#, an
existing pair is ported the next time a task rewrites it — never a big-bang rewrite.
Stays shell: a hook one-liner in .claude/settings.json, the session-start sync and any
step that must run on a fresh machine before the SDK is installed, a command the human types
once. Everything else that would be a script is a tool.
Runner
The .NET 10 SDK (dotnet --list-sdks): Windows winget install Microsoft.DotNet.SDK.10,
macOS brew install --cask dotnet-sdk. doctor warns when it is missing.
dotnet run --project tools/<Name> -- <args> # builds on first use (seconds), then runs
dotnet test tools/ # every test project of the solutionNot csharp-run: it is a Windows-only work installer's runner and only discovers tools that
Claude Code plugins ship — a repo's tools/ projects are invisible to it, and macOS has none.
Layout
tools/
├── Directory.Build.props # net10.0, Nullable, ImplicitUsings, TreatWarningsAsErrors
├── Tools.slnx # every project below
├── <Name>/<Name>.csproj # Exe: Program.cs only parses args and wires the core
├── <Name>/<Feature>.cs # the logic, behind small interfaces
└── <Name>.Tests/<Name>.Tests.csproj # xUnit, references <Name>dotnet new sln -n Tools -o tools (writes Tools.slnx), dotnet new console -o
tools/<Name>, dotnet new xunit -o tools/<Name>.Tests, dotnet sln tools/Tools.slnx add
tools/<Name> tools/<Name>.Tests, dotnet add tools/<Name>.Tests reference tools/<Name>.
Commit the solution, the projects and a .gitignore with bin/ and obj/.
Write it testable
- Program.cs is wiring only: parse arguments, build the real implementations, call the
core, map the result to an exit code. Logic in
Program.csis logic without a test. - Seams for the outside world: the file system, processes, environment variables and the
clock go through small interfaces the tests fake (
TimeProviderfor time; own one-method interfaces for the rest — no mocking framework needed). - Tests: unit tests on the core with fakes; a few end-to-end tests that run the built tool
in a temp directory (
Directory.CreateTempSubdirectory()), one per command, sad path included.
Conventions
- Streams: stdout is the result (machine-readable when another tool reads it), stderr is
ERROR: <what failed> — <what to do>. Exit codes:0success,1failure,2usage error (unknown flag, missing argument). - Paths:
Path.Combine/Path.GetFullPath, never a hard-coded separator or drive; the code root fromAI_CODE_ROOTor derived from the tool's own location, never$HOME/Code. - Processes:
ProcessStartInfo.ArgumentList, never a command string through a shell — no quoting bugs, no injection. SetUseShellExecute = false, read both streams. - Files: write UTF-8 without BOM and
\nline endings unless the format needs otherwise. - Same bar as the scripts: loud actionable errors, no secrets in output, no network call without a timeout.
Porting a .sh + .ps1 pair
- Pin today's behavior: the project's existing tests for that script, else new end-to-end tests run against the current script — they are the spec.
- Port into
tools/<Name>with unit tests for the logic; same flags, same output, same exit codes. No behavior change in the port commit — a change is its own commit after. - Shims so callers keep working: the pair shrinks to one line each —
exec dotnet run --project "$(dirname "$0")/tools/<Name>" -- "$@"/dotnet run --project "$PSScriptRoot/tools/<Name>" -- @args; exit $LASTEXITCODE— and the pinned tests pass through them. - Gate:
dotnet test tools/joins the project's check (./check.sh, CI). CI runs onwindows-latestandmacos-latestwithactions/setup-dotnet(dotnet-version: 10.0.x). - Later, once callers and docs name the tool directly, delete the shims.
Inventory what is left to port: git ls-files '*.sh' '*.ps1'.
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.

