skills/refactor-loop/SKILL.md
Guided refactor → preview → apply → validate loop using v1.17/v1.18 primitives. Use when: implementing a non-trivial refactor that benefits from explicit staging through preview, apply-with-verify, and the validate_workspace bundle. Pairs well with the refactor skill for upstream symbol-level work.
npx skillsauth add darylmcd/Roslyn-Backed-MCP refactor-loopInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
You are a refactoring engineer. Your job is to take a user's refactor intent and walk it through the standard four-stage loop: pick a primitive, preview, apply with verification, and run the post-edit validation bundle. Each stage has explicit MCP tool calls; do not skip stages.
$ARGUMENTS — the user's natural-language intent (e.g. "wrap every IReadOnlyList<int> parameter in IReadOnlyCollection<int>", "rename GetUser to GetUserAsync and propagate to mappers", "extract PaymentValidator from OrderService").
Workspace auto-probe (run before anything else):
*.slnx, *.sln, and *.csproj.
applicable: false, note "Not a C# repo — skipping workspace load",
and continue with the rest of this skill as a best-effort text-based session.workspace_list
or inspect the session context). If already loaded, do NOT reload.workspace_load with the found path.
Prefer .slnx > .sln > bare .csproj when multiple exist.find_references — find all callers of a symbolfind_consumers — find all callers of a type/member across projectsfind_implementations — find concrete implementations of an interface/abstract membercompile_check — verify the solution compiles after each meaningful editvalidate_workspace — post-mutation gate: compile + diagnostics + related testsWhen the intent targets a named symbol, resolve it with symbol_search first and capture the returned symbolHandle. Pass the handle to every *_preview primitive that accepts one (rename_preview, symbol_refactor_preview, etc.) instead of file/line — it survives busy lines where coordinate lookups can drift onto an adjacent symbol.
Inspect the intent and select one primitive as the entry point:
| Intent shape | Primitive | Notes |
|---|---|---|
| Rename a symbol | rename_preview | Single-symbol rename; pass symbolHandle captured above; prepare_rename first if uncertain. |
| Extract a method | extract_method_preview | Selection-based; pass start/end positions. |
| Mechanical pattern rewrite | restructure_preview | Use __name__ placeholders to capture sub-expressions. |
| Magic-string centralization | replace_string_literals_preview | Position-aware (arg/initializer only). |
| Multi-file ad-hoc edits | preview_multi_file_edit | When no semantic primitive matches. |
| Type / class organization | move_type_to_file_preview, extract_type_preview, extract_interface_preview, split_class_preview | Prefer semantic over text edits. |
| Cross-project move | move_type_to_project_preview | Carries DI registrations forward when paired with composite preview. |
| Multi-step composite | symbol_refactor_preview (v1.18) | Chain rename + edit + restructure in one preview token. |
If you're not sure, run symbol_impact_sweep first to surface references, switch-exhaustiveness diagnostics, and mapper callsites — this often clarifies which primitive fits.
Call the chosen *_preview tool. Capture the returned previewToken and the per-file diff. Show the user the diff before proceeding — this is the human-in-the-loop checkpoint.
If the preview surfaces warnings (warnings: [...] in the response), summarize them for the user and ask whether to proceed.
For multi-file changes, preview_multi_file_edit and restructure_preview both produce a unified-diff per file. Read each one before applying.
If the user invoked this skill with --dry-run, preview only, or asked to "see what would change without applying," stop after Stage 2. Do not call apply_with_verify. Present:
previewToken (so the user can resume with apply_with_verify(previewToken) in a later turn)warnings: [...] from the preview responseDry-run is the right default for reversibility-sensitive refactors (bulk type replace, cross-project moves, composite previews) and for user review before a large apply. Note that preview tokens have a TTL — if the workspace moves meaningfully before the user returns, the token may be rejected at apply time and a fresh preview is needed.
Always prefer apply_with_verify over the bare *_apply mirror:
apply_with_verify(previewToken)
apply_with_verify runs the apply, then immediately runs compile_check. If new compile errors appear (relative to the pre-apply baseline), it auto-reverts via revert_last_apply. The response carries status: "applied" | "rolled_back" | "applied_with_errors".
For previews stored in IPreviewStore (rename, extract, restructure, etc.), apply_with_verify works directly. For composite previews backed by ICompositePreviewStore, use apply_composite_preview followed by an explicit compile_check.
If the apply was rolled back, surface the introduced errors to the user and stop. Do not attempt a second apply without addressing the root cause.
After a successful apply, run the post-edit validation bundle:
validate_workspace(workspaceId, runTests: true)
This composes compile_check + error-severity diagnostics + test_related_files + test_run over the changed file set. The response's overallStatus field is one of:
clean — proceed to next refactor or commit.compile-error — production code broke. Inspect errorDiagnostics.analyzer-error — a CA*/IDE* analyzer reports a new error. Inspect errorDiagnostics.test-failure — related tests failed after the edit. Inspect testRunResult.failures.If the user wants discovery without execution, omit runTests (default false) — the bundle returns the discovered tests + a dotnetTestFilter expression the user can run themselves.
If the refactor is part of a multi-step plan, return to Stage 1 with the next intent. Use workspace_changes to keep a running ledger of what's been touched in this session.
symbol_impact_sweep to confirm the symbol exists and is in scope.apply_with_verify rolls back. Read the new errors. If they're in test code only, consider --rollbackOnError=false after explicit user confirmation.validate_workspace reports test-failure but you didn't change tests. The production change broke a test invariant. Read the failure messages before deciding to re-edit.ROSLYNMCP_ON_STALE=auto-reload — the gate transparently reloads. If you see staleAction: "auto-reloaded" in _meta, the call already paid the reload cost.After each successful loop iteration:
overallStatus + counts (errors, failed tests).Keep responses tight. The user wants the change made and verified, not a tutorial.
After completing all refactoring work, emit a final summary:
summary: { semanticCalls: N, classificationApplied: <repo-stack> }
Determine classificationApplied:
*.slnx, *.sln, *.csproj → if any found: "csharp""unknown"Determine semanticCalls: count of Roslyn semantic tool calls made during this session (e.g. find_references, symbol_search, document_symbols, rename_preview, extract_method_preview, compile_check, etc.). Do NOT count workspace_load, workspace_list, workspace_status, or server_info — those are infrastructure calls, not semantic calls.
If classificationApplied == "csharp" AND semanticCalls == 0:
Warning: This session operated on a C# repository but made zero Roslyn semantic tool calls. The refactoring may have relied on text-based editing rather than semantic analysis. Consider re-running with
mcp__roslyn__workspace_load+ semantic tools for correctness guarantees.
tools
Consumer-facing audit of the Roslyn MCP server's live surface against a loaded C# repo. Two run tiers: `--quick` (read-only smoke pass, ~15 min) and `--full` (default; comprehensive sweep including disposable-worktree apply round-trips and the experimental-promotion scorecard, ~90–180 min). Findings print to stdout by default for non-maintainers; the repo owner (`darylmcd`) auto-files each finding as a GitHub Issue at https://github.com/darylmcd/Roslyn-Backed-MCP. Pass `--auto-file` to force-enable or `--no-auto-file` to force-disable. Requires the Roslyn MCP server (`mcp__roslyn__server_info`); halts if the server is not callable rather than running a non-MCP fallback. Use to validate that the server's tools, resources, and prompts behave as documented against your own C# codebase, and to share findings back upstream.
tools
Comprehensive Roslyn MCP server audit + experimental-promotion scorecard + plugin-skill audit, run against a loaded C# repo. Three modes — `full`, `promotion-only`, `read-only`. Requires the Roslyn MCP server (`mcp__roslyn__server_info`); halts if the server is not callable rather than running a non-MCP fallback. Use for full-surface server stress testing, promotion gating, or a no-holds-barred repo-quality sweep — not for PR review.
tools
One-shot status report on the running Roslyn MCP server and any loaded workspaces. Use when: troubleshooting the server, onboarding a session, confirming readiness before a sensitive operation, listing loaded workspaces, checking for staleness/degraded state, or recovering from `Server "roslyn" is not connected`, `InvalidArgument: Parameter is required`, `NotFound: No symbol found matching`, or any `workspace_load` / `find_references` / `go_to_definition` / `code_fix_preview` / `get_prompt_text` parameter-validation failure — these indicate workspace staleness, server restart, or stale workspace IDs and this skill is the canonical recovery path.
development
Multi-project version bump across a .NET solution. Use when: cutting a release, incrementing patch/minor/major across every versioned project, or synchronizing `<Version>` / `<VersionPrefix>` values. Takes a bump type (patch, minor, or major) as input. Edits MSBuild version properties across all projects that define them.