refactoring-csharp

$npx mdskill add CodeAlive-AI/ai-driven-development/refactoring-csharp

Renames C# symbols in .NET solutions or multi-solution monorepos using Roslyn CLI

  • Solves the problem of renaming and refactoring C# symbols across a solution or multiple solutions.
  • Depends on Roslyn for parsing and modifying C# code, and uses command-line tools for execution.
  • Decides based on user input to rename, preview changes, or refactor shared projects within a .NET environment.
  • Delivers results by applying renames directly in the specified solution(s) or directory structure.

SKILL.md

.github/skills/refactoring-csharpView on GitHub ↗
---
name: refactoring-csharp
description: Rename and refactor C# symbols in a .NET solution or multi-solution monorepo with a one-shot Roslyn CLI. Use when the user asks to rename a symbol, preview impact, update references across a solution, or refactor shared projects across several solutions.
---

# Refactoring C# Symbols

This skill ships a Roslyn-based C# rename CLI in `src/`. It is intentionally one-shot and
stateless: one call resolves the target, validates the request, and returns either a preview
or an applied rename. There is no public prepare step.

## Contents

- [Canonical CLI](#canonical-cli)
- [Contract](#contract)
- [How To Use It](#how-to-use-it)
- [Monorepo Directory Mode](#monorepo-directory-mode)
- [Important Behavioral Rules](#important-behavioral-rules)
- [Supported Targets](#supported-targets)
- [File Rename Nuance](#file-rename-nuance)
- [Error Handling](#error-handling)
- [Success Criteria](#success-criteria)
- [Recommended Output Style](#recommended-output-style)

## Canonical CLI

If the skill was installed by `install.sh`, prefer the prebuilt CLI:

```bash
bin/csharp-refactor rename-symbol <sln|slnx|directory> <file> <line> <oldName> <newName> [dryRun=false|true]
```

Otherwise run the bundled source CLI from the skill directory:

```bash
dotnet run --project src/CSharpRefactoring.Cli -- rename-symbol <sln|slnx|directory> <file> <line> <oldName> <newName> [dryRun=false|true]
```

When invoked from outside the skill directory, use an absolute project path:

```bash
/<skill-dir>/bin/csharp-refactor rename-symbol <sln|slnx|directory> <file> <line> <oldName> <newName> [dryRun=false|true]
# or, if no prebuilt binary is installed:
dotnet run --project /path/to/refactoring-csharp/src/CSharpRefactoring.Cli -- rename-symbol <sln|slnx|directory> <file> <line> <oldName> <newName> [dryRun=false|true]
```

The tool project may create normal `bin/` and `obj/` directories under the skill. That is
expected and useful: it lets repeated runs reuse the .NET build cache instead of rebuilding
the CLI from scratch.

The target solution is not redirected to a temporary build output. The CLI opens the solution
from the solution directory and lets Roslyn/MSBuild use the target project's normal build
cache (`obj/`, `bin/`, or the repository's configured artifacts layout). This is intentional:
it avoids creating a second cache tree for the project being refactored and lets repeated
renames benefit from the project's existing MSBuild/Roslyn design-time build cache.

## Contract

| Field | Required | Default | Notes |
| --- | --- | --- | --- |
| `solution_path` | yes | - | Absolute path to the `.sln`/`.slnx` file, or a repository directory for monorepo-wide refactoring. |
| `file_path` | yes | - | Absolute path to a file inside the solution. |
| `line_number` | yes | - | 1-based line number. Use the value reported by `rg -n`. |
| `old_name` | yes | - | Exact current identifier on that line. This is the anchor. |
| `new_name` | yes | - | Must be a valid C# identifier. |
| `dry_run` | no | `false` | Apply changes by default. Preview only when explicitly set to `true`. |
| `rename_overloads` | no | `false` | Keep overloads unchanged by default. |
| `rename_in_strings` | no | `false` | String literals stay untouched by default. |
| `rename_in_comments` | no | `true` | Comments are renamed by default. |
| `rename_file` | no | `true` | Safe file move for supported named types. Never recreate the file as delete+add. |

## How To Use It

1. Use `rg -n` to locate the symbol and copy the 1-based line number directly.
2. Call `rename-symbol` once without the `dryRun` argument for normal rename requests. This applies the rename.
3. Use `dryRun=true` only when the user explicitly asks for preview, when the target is ambiguous, or when the rename is unusually broad/risky and applying immediately would be irresponsible. The CLI also accepts `true`, `--dry-run`, `dryRun=false`, `false`, and `--no-dry-run`; invalid values fail fast and must never silently apply.
4. Do not run a dry run just because the tool supports it. The tool loads the solution on every call, so preview+apply doubles the cost on large projects.
5. Summarize the result by reporting the original name, new name, changed document count, total text changes, changed files, and any file move.

## Monorepo Directory Mode

Use directory mode only when a repository contains multiple `.sln`/`.slnx` files or shared
projects that are not all present in one normal solution. For ordinary repositories, pass the
specific solution file because it is faster and avoids scanning unrelated projects.

When `solution_path` is a directory:

- Pass the repository or workspace root as `solution_path`.
- Keep `file_path` as the absolute path to the target source file.
- The tool recursively discovers `.sln`, `.slnx`, and supported project files under the directory.
- It merges them into one temporary `.slnx`, opens that aggregate solution, performs the rename, and deletes the temporary solution directory before returning.
- The temporary aggregate solution lives outside the target repository; source files and normal project build caches remain in their original locations.

## Important Behavioral Rules

- The tool is stateless. It loads the solution on every call.
- If `solution_path` is a directory, the tool scans it recursively, merges discovered `.sln`, `.slnx`, and project files into one temporary `.slnx`, opens that solution, runs the rename, and deletes the temporary solution directory before returning.
- A preview does not reserve state. If the workspace changes between preview and apply, rerun the preview.
- Prefer one apply call over preview+apply when the user already asked to perform the rename.
- For a `.sln`/`.slnx` input, the tool runs Roslyn from the target solution directory. For a directory input, it runs Roslyn from that directory while opening the temporary aggregate solution. In both modes, project files stay in place and use the target project's normal MSBuild outputs.
- Do not invent a session or hidden prepare state.
- Do not ask for a column number. The tool resolves from `file_path`, `line_number`, and `old_name`.
- `old_name` is mandatory because it disambiguates the target when a line contains more than one renameable identifier.
- The bundled source requires .NET 10 and restores NuGet packages on first run.
- Let the tool keep its own normal `bin/` and `obj/` cache unless the user explicitly asks for a clean/no-cache run.
- If the tool returns a preview, say preview. If it returns applied changes, say applied.
- Keep responses concise and action-oriented. Tell the user what changed and whether a file move happened.

## Supported Targets

Treat these as supported rename targets when the Roslyn symbol is source-backed and
`CanBeReferencedByName`:

- `NamedType`
- `Method`
- `Property`
- `Field`
- `Event`
- `Parameter`
- `Local`
- `TypeParameter`
- `Namespace`

Do not rename constructors, destructors, static constructors, or indexers.

## File Rename Nuance

`rename_file=true` is a convenience default, but it only produces a real safe move when the
symbol is a single-declaration named type and the file stem matches the current type name.

If the tool does not return `file_move_from_path` and `file_move_to_path`, the symbol rename is still valid,
but the file itself was not moved. Do not claim a file rename happened unless the tool reports it.

This is intentionally conservative so git sees a tracked rename instead of a delete+add pair.

## Error Handling

Use the tool's error codes as actionable guidance:

| Error code | Meaning | What to do |
| --- | --- | --- |
| `invalid_solution_path` | Solution path is missing, does not exist, or is neither `.sln`/`.slnx` nor a directory. | Ask for a real solution path or repository directory. |
| `invalid_file_path` | File path is missing or not present on disk. | Ask for the correct file path. |
| `file_not_in_solution` | The file is not part of the loaded solution. | Ask for the correct file or solution. |
| `invalid_line_number` | Line number is outside file bounds or not 1-based. | Ask for the correct line. |
| `invalid_old_name` | `old_name` was empty or whitespace. | Ask for the exact current name. |
| `old_name_not_found_on_line` | No renameable symbol with that name exists on the line. | Ask for a better line or file. |
| `ambiguous_old_name_on_line` | More than one renameable symbol matches that name on the line. | Narrow the target or use a different line. |
| `unsupported_symbol_kind` | Roslyn found a symbol, but this kind is not renameable here. | Move to a supported symbol kind. |
| `symbol_not_in_source` | The symbol is not declared in source. | Pick a source-backed target. |
| `invalid_new_name` | `new_name` is not a valid C# identifier. | Propose a valid identifier. |
| `same_name` | New name equals the current name. | Ask for a different name. |
| `no_changes` | Roslyn produced no text edits. | Re-check the target or the new name. |
| `apply_failed` | Workspace apply failed. | Treat as a runtime failure and retry only if the state is unchanged. |
| `operation_timeout` | The rename timed out. | Retry with a larger timeout or a narrower target. |

## Success Criteria

A rename workflow is complete when:

- The target was resolved from `line_number` + `old_name`.
- The user approved the rename, or explicitly requested a dry run only.
- The tool returned changed documents, total text changes, and any file move details.
- The final answer makes the applied scope clear enough for the user to trust the change.

## Recommended Output Style

- For previews, say what would change and that nothing was applied.
- For applied changes, say what changed and whether the file was moved.
- If the file move fields are present, mention them explicitly.
- If the tool returned an error code, echo the code and the human-readable reason.

More from CodeAlive-AI/ai-driven-development

SkillDescription
agentic-readinessAudit and improve repositories for reliable agentic work across Codex and Codex App, Claude Code, and OpenCode. Use when reviewing AGENTS.md or CLAUDE.md quality and discovery, instruction routing in monorepos or meta-repos, agent settings, MCP configuration, skills, subagents, context budgets, or repository organization for coding agents.
agents-consiliumQuery external AI agents (Codex, Gemini, OpenCode, Claude Code headless) in parallel for independent second opinions, code review, bug investigation, and consensus on high-stakes decisions. Agents and models are configurable in config.json. Use for architecture choices, security review, or ambiguous problems where independent perspectives matter. Not for simple questions answerable from docs or the codebase — use web search or repo exploration instead.
bug-fix-protocol8-step disciplined bug-fix protocol that treats every production bug as two failures — the code defect itself and the testing system that allowed it through. Use when fixing a production bug, investigating a regression, writing a post-mortem, or auditing a missed defect. Triggers on "fix this bug", "production bug", "regression test", "post-mortem", "test gap", "why did the tests miss this".
code-that-fits-in-your-headSoftware engineering heuristics from Mark Seemann's book Code That Fits in Your Head (2021). Use when writing new code, reviewing code, refactoring, designing APIs, handling validation and invariants, writing unit tests, debugging defects, performing security review (STRIDE), or setting up a new code base. Covers decomposition (cyclomatic complexity, 80/24 rule, cohesion, fractal architecture), encapsulation (invariants, parse-don't-validate, Postel's law), outside-in TDD (walking skeleton, AAA, triangulation, devil's advocate), API design (affordance, poka-yoke, CQS), git/PR hygiene (50/72 commits, small commits, code review), feature flags, Strangler pattern, bisection debugging, logging with decorators, and STRIDE threat modelling. Not for language-specific syntax, framework tutorials, production incident response, or performance profiling.
fetch-url-as-markdownFetch a web page (URL) and return clean Markdown via local trafilatura, with Exa MCP as a fallback for JS-rendered or anti-bot pages. Use when the user asks to read, fetch, scrape, summarize, or quote a URL — prefer this over the built-in WebFetch tool. Don't use for binary files (PDFs, images, archives) or for fetching API/JSON endpoints.
fpf-problem-solvingFirst Principles Framework (FPF) — thinking amplifier. Use when user wants to think through a complex problem, architect a system, evaluate alternatives, decompose complexity, classify problems, define quality attributes, plan rigorously, apply an FPF pattern to a first useful result, decide under uncertainty, establish causality, reason about time and trends, describe or synthesize architecture, check mathematical model fit, distinguish relation kinds or occurrences, govern ontic/U-kind admission, publish multi-view artifacts, refresh SoTA packs, trace provenance, or improve pattern quality. Also triggers on: FPF, bounded contexts, SoTA packs, assurance calculus, decision theory, causal reasoning, temporal reasoning, architecture description, modularity, constraint-governed unfolding, narrative rendering, structural adequacy, cultural evolution, quality gates, lexical discipline, FPF Parts A-I. Not for simple task planning, general philosophy, or Agile unrelated to FPF.
hooks-managementManage hooks and automation for coding agents (Claude Code, Codex CLI, OpenCode). Use when users want to add, list, remove, update, or validate hooks. Triggers on requests like "add a hook", "create a hook that...", "list my hooks", "remove the hook", "validate hooks", or any mention of automating agent behavior with shell commands or plugins.
investigating-repository-historyInvestigate GitHub repository history before risky code changes using git blame/log, GitHub PRs, review comments, squash/rebase/cherry-pick/rename heuristics, and cited evidence. Use when asking why code exists, whether a change is safe, what PR introduced behavior, or before editing API, compatibility, security, concurrency, persistence, migration, or performance-sensitive code.
maintaining-macos-healthHands-on playbook for macOS disk cleanup, dev-machine optimization, and proactive health alerting. Use when the Mac is full or slow, when a process persistently burns CPU, when a kernel panic / watchdog timeout / vm-compressor-space-shortage / Jetsam event happened, when the user asks to free disk space, audit storage, set up disk/memory/CPU alerts, or restore the same monitoring on a new Mac. Built around Mole (`mo` CLI) for safety guards plus a custom LaunchAgent-based alerter for active warnings. Covers Apple Silicon laptops with heavy AI/Docker workloads. Not for general macOS support, hardware diagnostics, networking issues, GUI / window-manager bugs, Time Machine recovery, or broken app installs.
maintaining-windows-healthHands-on playbook for Windows 11 disk cleanup, dev-machine optimization, and proactive health alerting. Use when the PC is full or slow, when a BSOD / Kernel-Power 41 / crash dump / commit-memory pressure happened, when the user asks to free disk space, audit storage, set up disk/memory alerts, or restore the same monitoring on a new PC. Built around native Microsoft-supported tooling (Storage Sense, cleanmgr, DISM, pnputil, vssadmin, wevtutil, powercfg) as the safety floor, a drift-protected HTML cleanup UI, and a Task Scheduler + BurntToast alerter. Covers dev machines with heavy AI/Docker/WSL workloads. Not for general Windows support, hardware diagnostics, GPU/driver troubleshooting, antivirus/malware removal, Windows Update repair, networking, or app-specific performance problems unrelated to disk or memory pressure.