agentleFS
neijixneijix/AICodeFactory/skills/csharp-tools/SKILL.md

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

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
  1. Very specific:

    Commit the solution, the projects and a .gitignore with bin/ and obj/.

    line 44
  2. Very specific:

    Files: write UTF-8 without BOM and \n line endings unless the format needs otherwise.

    line 66

≈ “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.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
SKILL.md

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 solution

Not 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.cs is 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 (TimeProvider for 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: 0 success, 1 failure, 2 usage error (unknown flag, missing argument).
  • Paths: Path.Combine / Path.GetFullPath, never a hard-coded separator or drive; the code root from AI_CODE_ROOT or 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. Set UseShellExecute = false, read both streams.
  • Files: write UTF-8 without BOM and \n line 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

  1. 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.
  2. 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.
  3. 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.
  4. Gate: dotnet test tools/ joins the project's check (./check.sh, CI). CI runs on windows-latest and macos-latest with actions/setup-dotnet (dotnet-version: 10.0.x).
  5. Later, once callers and docs name the tool directly, delete the shims.

Inventory what is left to port: git ls-files '*.sh' '*.ps1'.

Download now (ZIP)

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
What did you use it for? e.g. Reviewing pull requests in a Rails app

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.