| name | code-writer |
| description | Validate C# code through Roslyn compiler before writing to disk. Attempts to fix compilation errors automatically. Use when writing new code to ensure it compiles before committing to disk. |
Code Writer Skill
This skill validates C# code through the Roslyn compiler BEFORE writing to disk, attempts automatic fixes, and only writes when code compiles successfully.
When to Use This Skill
- When generating new C# files
- When you want code validated before writing
- "Write this code but validate it first"
- "Create a new service class (validated)"
- Before writing potentially breaking changes
- When you want compilation feedback before disk commit
Why This Exists
Traditional approach:
Generate code → Write to disk → Build → Find errors → Fix → Repeat
Code-writer approach:
Generate code → Validate with Roslyn (in-memory) → Auto-fix → Write to disk ✓
Benefits:
- ✅ No broken code on disk
- ✅ Real compiler diagnostics (not guesses)
- ✅ Auto-fix common errors before writing
- ✅ Faster feedback loop
- ✅ Safe exploratory coding
CRITICAL: Pre-Write Safety Checks
ALWAYS run these checks BEFORE generating code:
type-collision-detector - Check if type name already exists
- If collision found → Ask user for different name
- If name available → Proceed
namespace-explorer - Check target namespace patterns
- Understand naming conventions
- Match existing patterns
type-finder (if implementing interface) - Find interface definition
- Get exact interface location
- Use member-identifier to see required members
code-reader - When reading files for context
- ALWAYS use code-reader instead of Read for .cs files
- Strips XML docs automatically (30-50% context savings)
- Preserves important comments (TODO, HACK, etc.)
These checks are MANDATORY. Do not skip them.
CRITICAL: Reading C# Files
ALWAYS use code-reader tool instead of Read for C# files.
Exception: Only if user explicitly asks for documentation.
API Endpoint
POST /generation/code
Request:
{
"template": "class",
"name": "ProductService",
"namespace": "MyApp.Services",
"members": [
{
"kind": "method",
"name": "GetById",
"returnType": "IGenericResult<Product>",
"parameters": [{"type": "int", "name": "id"}]
}
]
}
Response:
{
"isSuccess": true,
"data": {
"generatedCode": "...",
"diagnostics": [],
"filePath": "src/Services/ProductService.cs"
}
}
How It Works
1. Start the Server
dotnet run --project D:\FractalDataworks\RoslynTools\src\CyberdineDevelopment.RoslynTools.Server
2. Load Solution
using CyberdineDevelopment.RoslynTools.Client;
var client = new RoslynWorkspaceClient("http://localhost:5000");
await client.LoadSolution(@"D:\MyProject\MyProject.sln");
3. Generate and Validate Code
// Generate code in-memory
var result = await client.GenerateCode(
template: "class",
name: "ProductService",
namespaceName: "MyApp.Services"
);
if (result.IsSuccess)
{
// Code validated successfully
Console.WriteLine("Code generated and validated:");
Console.WriteLine(result.Data.GeneratedCode);
// Check diagnostics
if (!result.Data.Diagnostics.Any())
{
Console.WriteLine("No errors!");
}
}
4. Edit and Commit
// Add generated code to workspace
await client.EditDocument(
projectName: "MyApp.Services",
filePath: "src/Services/ProductService.cs",
content: result.Data.GeneratedCode
);
// Validate in workspace
var diagnostics = await client.GetDiagnostics();
// If no errors, commit to disk
if (!diagnostics.Data.Any(d => d.Severity == "Error"))
{
await client.Commit();
}
Process Flow
┌─────────────────────────────────────────────────────────┐
│ 0. PRE-WRITE CHECKS (MANDATORY) │
│ - type-collision-detector │
│ - namespace-explorer │
│ - type-finder (if needed) │
└────────────────┬────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────┐
│ 1. GENERATE CODE VIA SERVER API │
│ POST /generation/code │
└────────────────┬────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────┐
│ 2. SERVER VALIDATES WITH WORKSPACE │
│ - Add to in-memory workspace │
│ - Get compilation diagnostics │
│ - Try auto-fixes if needed │
└────────────────┬────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────┐
│ 3. CHECK DIAGNOSTICS │
│ Errors? → Try to fix (up to 3 attempts) │
│ Still errors? → Return diagnostics │
│ No errors? → Return generated code │
└────────────────┬────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────┐
│ 4. COMMIT TO DISK (transaction-safe) │
│ ✅ Code compiles → client.Commit() │
│ ❌ Code doesn't compile → Show diagnostics │
└─────────────────────────────────────────────────────────┘
Semantic Analysis Benefits
Using the Server API provides significant advantages:
- Workspace Validation: Generated code validated against entire solution context
- Full Type Resolution: Uses semantic model to ensure all types are resolved
- Cross-Project References: Automatically detect and use types from other projects
- Transaction Safety: Changes only committed if everything validates
- Auto-Fix Intelligence: Better fixes using semantic understanding
- No File Locking: Work in-memory until ready to commit
What Gets Validated
Compilation Errors (CS errors)
- CS0246: Type or namespace not found
- CS0103: Name does not exist
- CS0246: Missing using statements
- CS0535: Missing interface implementation
- CS0161: Not all code paths return value
- CS8600-CS8629: Nullable reference warnings
- All other C# compiler errors
Code Quality Checks
- Syntax correctness
- Type resolution
- Member accessibility
- Return type matching
- Parameter types
- Generic constraints
What's NOT Validated
- Runtime behavior
- Logic correctness
- Performance
- Business rules
- Integration with external systems
Auto-Fix Capabilities
The skill attempts these fixes automatically:
Fix 1: Add Missing Using Statements
// Error: CS0246 - Type 'List' not found
// Fix: Add using System.Collections.Generic;
Fix 2: Add Missing References
// Error: CS0012 - Assembly reference missing
// Fix: Add reference to required assembly
Fix 3: Fix Nullable Warnings
// Error: CS8600 - Possible null reference
// Fix: Add null check or null-forgiving operator
Fix 4: Add Missing Return Statements
// Error: CS0161 - Not all paths return value
// Fix: Add return statement or throw
Fix 5: Fix Access Modifiers
// Error: CS0122 - Inaccessible due to protection level
// Fix: Change to public if appropriate
Fix 6: Implement Missing Members
// Error: CS0535 - Missing interface implementation
// Fix: Add method stub with NotImplementedException
Output Format
Success Case
=== CODE WRITER REPORT ===
File: src/Services/ProductService.cs
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
VALIDATION (Attempt 1)
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Submitting to Roslyn compiler...
Diagnostics found: 3 errors
1. CS0246: Type 'IRepository' not found
Line 15: private readonly IRepository<Product> _repository;
2. CS0103: Name 'Result' does not exist
Line 22: return Result.Ok(products);
3. CS8618: Non-nullable field must contain non-null value
Line 15: private readonly IRepository<Product> _repository;
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
AUTO-FIX (Attempt 1)
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Fixing CS0246: Adding using MyApp.Abstractions;
Fixing CS0103: Adding using MyApp.Core;
Fixing CS8618: Adding constructor parameter
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
VALIDATION (Attempt 2)
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Submitting to Roslyn compiler...
✅ No errors found!
✅ Code compiles successfully
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
WRITING TO DISK
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
✅ File written: src/Services/ProductService.cs
Final code:
────────────────────────────────────────────────────────
using MyApp.Abstractions;
using MyApp.Core;
namespace MyApp.Services;
public class ProductService
{
private readonly IRepository<Product> _repository;
public ProductService(IRepository<Product> repository)
{
_repository = repository;
}
public IGenericResult<List<Product>> GetAll()
{
var products = _repository.GetAll();
return Result.Ok(products);
}
}
────────────────────────────────────────────────────────
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
SUMMARY
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
✅ Code validated and written successfully
Initial errors: 3
Fixed automatically: 3
Validation attempts: 2
Status: SUCCESS
Fixes applied:
✓ Added 2 using statements
✓ Added constructor parameter
Failure Case (after 3 attempts)
=== CODE WRITER REPORT ===
File: src/Services/OrderService.cs
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
VALIDATION (Attempt 3)
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Submitting to Roslyn compiler...
❌ Errors remain after 3 fix attempts
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
DIAGNOSTICS
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
1. CS0029: Cannot implicitly convert type 'int' to 'string'
Line 45: return totalAmount;
Severity: Error
Context:
public string CalculateTotal()
{
decimal totalAmount = CalculateAmount();
return totalAmount; // ← Error here
}
SUGGESTION: Change return type to 'decimal' or convert value
2. CS1061: 'Order' does not contain definition for 'GetTotal'
Line 52: var total = order.GetTotal();
Severity: Error
Context:
public void ProcessOrder(Order order)
{
var total = order.GetTotal(); // ← Error here
}
SUGGESTION:
- Add GetTotal() method to Order class
- Or use order.Total property
- Check if method was renamed
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
FILE NOT WRITTEN
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
❌ Code contains errors that require manual intervention
Code was NOT written to disk.
Please fix the errors above and try again, or provide guidance
on how to resolve them.
Would you like me to:
1. Try a different approach
2. Generate alternative implementation
3. Write the file anyway (not recommended)
Roslyn Workspace Integration
How Workspace Validation Works
// 1. Get project from workspace
var project = workspace.CurrentSolution
.Projects.First(p => p.Name == targetProject);
// 2. Create new document or update existing
var document = project.AddDocument(fileName, codeText);
// 3. Get updated project with new document
var updatedProject = document.Project;
// 4. Get compilation with all references already configured
var compilation = await updatedProject.GetCompilationAsync();
// 5. Get diagnostics (includes cross-project references)
var diagnostics = compilation.GetDiagnostics()
.Where(d => d.Severity == DiagnosticSeverity.Error)
.ToList();
// 6. If errors, attempt semantic-aware fixes
if (diagnostics.Any())
{
foreach (var diagnostic in diagnostics)
{
// Use semantic model to understand error context
var semanticModel = await document.GetSemanticModelAsync();
// Apply intelligent fixes based on semantic understanding
}
}
Reference Resolution
The workspace automatically includes:
- All project references from the loaded solution
- NuGet packages configured in each project
- .NET runtime assemblies
- Project-to-project dependencies
- Analyzer references
This ensures validation is accurate to your actual solution context, not a standalone compilation.
Fix Attempt Strategy
Attempt 1: Add Missing Using Statements
Parse error → Identify missing type → Search codebase → Add using
Attempt 2: Fix Common Patterns
Nullable warnings → Add null checks or constructors
Missing returns → Add return statements
Access modifiers → Adjust if safe
Attempt 3: Structural Changes
Missing implementations → Add stubs
Generic constraints → Add constraints
Interface mismatches → Implement missing members
After 3 Attempts: Report Back
If still errors → Return detailed diagnostics with context and suggestions
Integration with Other Skills
Workflow 1: New Class Generation
1. code-writer → Generate + validate class
✅ Success → File written
2. complexity-analyzer → Check complexity
3. dotnet-test-automation → Generate tests
4. build → Full solution build
Workflow 2: Code Generation with Type Safety
1. type-collision-detector → Check name available
2. namespace-explorer → Check target namespace
3. code-writer → Generate + validate code
✅ Success → File written
4. build → Verify integration
Workflow 3: Failed Validation
1. code-writer → Generate + validate
❌ Errors found after 3 attempts
2. Review diagnostics
3. Provide guidance
4. code-writer → Try again with corrections
Example Usage
Example 1: Simple Class
User: "Write a ProductValidator class"
Skill:
- Generates class code
- Validates with Roslyn → Missing using FluentValidation
- Auto-fixes → Adds using statement
- Validates again → Success!
- Writes to disk
Example 2: Service with Dependencies
User: "Write an OrderService with repository injection"
Skill:
- Generates service code
- Validates → Missing IRepository reference
- Searches codebase → Finds IRepository in Abstractions
- Adds using MyApp.Abstractions
- Validates → Missing Result type
- Adds using MyApp.Core
- Validates → Success!
- Writes to disk
Example 3: Complex Logic (Manual Intervention)
User: "Write a PaymentProcessor with validation"
Skill:
- Generates processor code
- Validates → Type conversion error (decimal to string)
- Attempts fix → Can't safely determine intent
- Returns diagnostics with suggestion
- You provide guidance: "Return type should be decimal"
- Regenerates with correct type
- Validates → Success!
- Writes to disk
Configuration Options
Strictness Levels
Strict Mode (default):
- Must compile with zero errors
- Warnings allowed (but reported)
- All types must resolve
Lenient Mode:
- Allow warnings
- Allow some nullable warnings
- Proceed if only warnings exist
Experimental Mode:
- Write even with minor errors
- Report all diagnostics
- Trust manual review
Max Fix Attempts
max_attempts: 3 # Default
# Can be set to 1, 2, 3, 4, or 5
Auto-Fix Categories
auto_fix:
using_statements: true
nullable_warnings: true
missing_returns: true
interface_stubs: true
access_modifiers: false # Require manual decision
Safety Features
Before writing:
- ✅ Compiles without errors
- ✅ All types resolve
- ✅ References are valid
Never writes if:
- ❌ Compilation errors exist
- ❌ Fix attempts exhausted
- ❌ User wants manual review
Always provides:
- ✅ Full diagnostic information
- ✅ Context around errors
- ✅ Actionable suggestions
- ✅ Option to retry with changes
Performance
Fast validation:
- In-memory compilation (no disk I/O)
- Incremental fixes
- Parallel reference loading
- Cached assemblies
Typical times:
- Simple class: <1 second
- Complex service: 1-2 seconds
- With auto-fixes: 2-4 seconds
Limitations
Cannot validate:
- Runtime behavior
- External API calls
- Database queries
- File system operations
- Network requests
Cannot auto-fix:
- Logic errors
- Algorithm mistakes
- Design flaws
- Complex type mismatches
- Business rule violations
These need manual intervention
Advanced Features
Preview Mode
Show what would be written without writing
Diff View
Show original vs fixed code side-by-side
Incremental Validation
Validate as you type (for interactive use)
Batch Validation
Validate multiple files at once
Notes
- Uses Roslyn Workspace API with full semantic model
- Validates against actual solution context (all projects loaded)
- Respects project's target framework and settings
- Honors nullable reference settings
- Faster than full build (in-memory compilation)
- No side effects until commit (transaction-safe)
- Can be used for "dry run" code generation
- Cross-project type resolution
- Server maintains workspace state