agentleFS
AttemainioAttemainio/dotnet-toolkit/CLAUDE.md

dotnet-toolkit

CLAUDE.md2 starsChanged 53 days agoMITView on GitHub

Guidance for Claude Code when working in this repository. This file is the operating contract: the rules that apply in every session, plus where to read the detail. It is not the repo's manual — anything needed only for a particular kind of task lives behind a pointer below. A Claude Code plugin for .NET repositories: a Roslyn-powered MCP server (DotnetToolkit.McpServer) exposing token-efficient symbol location, navigation and relationship tools, plus skills that teach Claude to locate with these tools, read…

The file

We split this CLAUDE.md into the rules it gives an agent

5 rules. About 0 are common, 1 is distinctive, and 4 are very specific to this project.

  • ≈0

    Common · estimate

    Many files like this have a rule of this kind.

  • ≈1

    Distinctive · estimate

    This author's own choices. Worth a look.

  • 4

    Very specific

    Tied to their project's names, files or tools. Probably skip.

  • Common
  • Distinctive
  • Very specific
  1. Very specific:

    stdout is reserved for MCP JSON-RPC: All logging goes to stderr.

    line 87
  2. Very specific:

    After changing a tool name, signature, or response contract — or a hook, script, skill, or documented workflow — invoke dotnet-consistency.

    line 111
  3. Very specific:

    Update every affected file in the same task as the change, and CHANGELOG.md for anything a consumer sees.

    line 115
  4. Distinctive:

    Update this file only when the change affects an always-applicable workflow, invariant, or route.

    line 117
  5. Very specific:

    When compacting, preserve: the concrete task in flight and its remaining steps.

    line 129

≈ “Common” is an estimate: at least 1 in 5 of the 26,980 CLAUDE.md 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
CLAUDE.md

CLAUDE.md

Guidance for Claude Code when working in this repository. This file is the operating contract: the rules that apply in every session, plus where to read the detail. It is not the repo's manual — anything needed only for a particular kind of task lives behind a pointer below.

What this is

A Claude Code plugin for .NET repositories: a Roslyn-powered MCP server (DotnetToolkit.McpServer) exposing token-efficient symbol location, navigation and relationship tools, plus skills that teach Claude to locate with these tools, read only the located range, and edit with Edit/Write while a hook keeps the index current. This repo is both the plugin's implementation and (via .mcp.json) a live consumer of its own server. Dogfooding is the point: if a tool is awkward or wrong for a real task here, that's a bug report about the tool, not a reason to fall back to shell.

Non-negotiable workflow

.claude/rules/dotnet-index.md is a router and nothing else: it names no tools, and maps an intent (read C#, write C#, explore, review) to the skill that owns it. It is always-loaded alongside this file, and is the same rule dotnet-init copies into consuming repos.

The protocol itself lives one level down, loaded only when the work needs it:

OwnsFile
Every retrieval tool, what each answers, the cheap-route table, limitedBy, TOONskills/dotnet-read/SKILL.md
The write path (Edit/Write on located text, rename_symbol), the standards step, how the index follows edits, failuresskills/dotnet-write/SKILL.md
Briefing and launching the dotnet-explore agentskills/dotnet-explore/SKILL.md
Partitioning and launching dotnet-code-reviewskills/dotnet-review/SKILL.md
Which coding standard applies when — shared by the writer and the reviewerstandards/index.md

None of it is repeated in CLAUDE.md: a rule that lives only here never reaches a consumer, and two copies always diverge.

What this repo adds on top, because it is the plugin's own source tree:

dist/ is what runs, and it is committed. The MCP server and the seven hooks execute from dist/, and a consuming machine gets a working plugin from git pull alone. So after any change under src/ or Hooks/: run dotnet test, run scripts/build-plugin.sh (never the bare publish — it leaves the source stamp stale), and commit the republished dist/ in the same commit as the change that required it. dotnet dist/DotnetToolkit.McpServer.dll doctor --no-probe fails when src/ has moved past the stamped build; run it before every commit that touches src/. A stale committed dist/ ships a stale binary to every consumer who pulls — a blocking error, the same as a failing test. Commits go straight to main.

Commands

dotnet build                        # build the solution
dotnet test                         # unit + MSBuildWorkspace integration tests (slower: loads a fixture solution)
dotnet test --filter FullyQualifiedName~ClassName   # a single test class
scripts/build-plugin.sh                 # required after any src/ or Hooks/ change
scripts/package-plugin.sh               # clean package/ for a LOCAL marketplace source — never point one at this tree
dotnet dist/DotnetToolkit.McpServer.dll doctor --no-probe   # pre-commit: is dist/ current?

TreatWarningsAsErrors is set repo-wide (Directory.Build.props), so a build with warnings fails. The root .editorconfig is deliberately near-empty and states why in its own header; silencing a rule there needs its reasoning in the same edit. If more than one net10 SDK is installed, build with the one the server registers for MSBuild (~/.dotnet/dotnet here) — a different one silently degrades the server's workspace; symptoms and repair in docs/design/architecture.md.

Where to read what

Everything a consumer needs is routed from .claude/rules/dotnet-index.md, not from here. These rows are the maintainer's routes — files a consuming repo does not have.

WhenRead
Changing server internals, startup order, a subsystem, packaging, or anything that shells outdocs/design/architecture.md
Changing the always-loaded rule, or what init ships.claude/rules/dotnet-index.md; skills/dotnet-init/SKILL.md copies it
Changing which tool answers what, or a route findingskills/dotnet-read/SKILL.md (reads) or skills/dotnet-write/SKILL.md (writes) — not the always-loaded rule
Changing a coding standardstandards/<name>.md, plus its row in standards/index.md
Reviewing code, or changing a review agentagents/dotnet-code-review.md (correctness, conventions) or agents/dotnet-architecture-review.md (stale code, compatibility, structure); design rationale in docs/design/agents.md
Why a hook is built the way it is, or why its off-switch expiresdocs/design/hooks.md (design notes — hooks fire from hooks/hooks.json)
Measuring the plugin against not having itskills/dotnet-performance/SKILL.md — runs at the default guard state; the only sanctioned caller of set_hook_guards (strict variant only)
Auditing the install procedure, or what a consumer ends up withdocs/install/audit.md (maintainer side, run by dotnet-consistency) and docs/install/verify.md (consumer side, run by dotnet-init)
Why the 1.x write path was removeddocs/design/navigation-only.md

.claude/rules/dotnet-index.md is the only always-loaded rule, because it is the only file in .claude/rules/ with no frontmatter. The standards under standards/ are read by explicit path only — paths: frontmatter would not reliably load them here (see docs/design/architecture.md), which is why they live outside .claude/rules/ and carry none.

Non-obvious invariants

  • stdout is reserved for MCP JSON-RPC. All logging goes to stderr; never write to Console.Out in server code.
  • Tool signature changes break in-process callers — the tests call these methods positionally — and any response-shape change needs Contracts/Contract.cs bumped.
  • Change detection is mtime-polling, not filesystem watchers, so it works on WSL /mnt/* where inotify doesn't fire. Don't "fix" it into a watcher.
  • .claude/rules/ holds exactly one file, and the standards live in standards/ with no frontmatter. A second unfrontmattered rule, or a paths: key reappearing on a standard, is a silent always-loaded regression paid by every session and every subagent.
  • Shelling out has three rules — drain both streams concurrently, scrub the inherited MSBuild registration before launching dotnet, and treat process exit (never EOF) as completion. Each was learned from a real hang or a silent failure; the full statement is "Shelling out to a child process" in docs/design/architecture.md. Read it before writing any Process.Start.
  • .gitattributes forces LF on *.sh/*.cs/*.csproj. Windows-side tooling once CRLF'd .cs files, breaking raw string literals in two tests — if a new file type needs the same protection, add it there rather than fixing line endings reactively.

Instruction consistency

The implemented tool surface (Tools/*.cs) is the ground truth for facts — names, signatures, return shapes — and every doc, skill, rule, and hook message describing it is downstream. Official Claude documentation is the ground truth for design — how a tool gets found, what is always loaded, what a rule or skill may contain — and there the code is what moves.

  • After changing a tool name, signature, or response contract — or a hook, script, skill, or documented workflow — invoke dotnet-consistency. It owns the authoritative list of files that describe the surface, the checklist against official Claude guidance, and the drift sweep. Don't silently patch one file and move on; two copies always diverge.
  • Update every affected file in the same task as the change, and CHANGELOG.md for anything a consumer sees.
  • Update this file only when the change affects an always-applicable workflow, invariant, or route. Anything operational that lives only here never reaches a consuming repo — a finding, not a convenience.

Context budget

This file and .claude/rules/dotnet-index.md are the only always-loaded files, and the only two under a size budget. Keep them declarations of when and where, not procedure. The policy is owned and enforced by dotnet-consistency (harness-compliance.md §D–§F); don't re-derive it here.

Compact instructions

When compacting, preserve: the concrete task in flight and its remaining steps; any symbolId or declarationSites range still in play; a dotnet build failure and what was being corrected; and decisions already settled with the user. Drop resolved tool output, file listings, and superseded drafts — they are re-fetchable from the MCP tools in one call.

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.