C

Execute these commands after EVERY implementation (see AGENT_AUTOMATION module for full workflow).

11 stars

Best use case

C is best used when you need a repeatable AI agent workflow instead of a one-off prompt.

Execute these commands after EVERY implementation (see AGENT_AUTOMATION module for full workflow).

Teams using C should expect a more consistent output, faster repeated execution, less prompt rewriting.

When to use this skill

  • You want a reusable workflow that can be run more than once with consistent structure.

When not to use this skill

  • You only need a quick one-off answer and do not need a reusable workflow.
  • You cannot install or maintain the underlying files, dependencies, or repository context.

Installation

Claude Code / Cursor / Codex

$curl -o ~/.claude/skills/csharp/SKILL.md --create-dirs "https://raw.githubusercontent.com/hivellm/rulebook/main/templates/skills/languages/csharp/SKILL.md"

Manual Installation

  1. Download SKILL.md from GitHub
  2. Place it in .claude/skills/csharp/SKILL.md inside your project
  3. Restart your AI agent — it will auto-discover the skill

How C Compares

Feature / AgentCStandard Approach
Platform SupportNot specifiedLimited / Varies
Context Awareness High Baseline
Installation ComplexityUnknownN/A

Frequently Asked Questions

What does this skill do?

Execute these commands after EVERY implementation (see AGENT_AUTOMATION module for full workflow).

Where can I find the source code?

You can find the source code on GitHub using the link provided at the top of the page.

SKILL.md Source

<!-- CSHARP:START -->
# C# Project Rules

## Agent Automation Commands

**CRITICAL**: Execute these commands after EVERY implementation (see AGENT_AUTOMATION module for full workflow).

```bash
# Complete quality check sequence:
dotnet format --verify-no-changes  # Format check
dotnet build              # Build + compile check
dotnet test               # All tests (100% pass)
dotnet test --collect:"XPlat Code Coverage"  # Coverage (95%+ required)

# Security audit:
dotnet list package --vulnerable  # Vulnerability scan
dotnet list package --outdated    # Check outdated deps
```

## C# Configuration

**CRITICAL**: Use .NET 8+ with C# 12+.

- **Version**: .NET 8.0+
- **C# Version**: 12+
- **Target**: net8.0
- **Nullable**: Enabled
- **LangVersion**: latest

### Project File Requirements

```xml
<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <TargetFramework>net8.0</TargetFramework>
    <LangVersion>latest</LangVersion>
    <Nullable>enable</Nullable>
    <ImplicitUsings>enable</ImplicitUsings>
    <TreatWarningsAsErrors>true</TreatWarningsAsErrors>
    <AnalysisMode>All</AnalysisMode>
    <EnforceCodeStyleInBuild>true</EnforceCodeStyleInBuild>
    
    <!-- Package Metadata -->
    <PackageId>Your.Package.Name</PackageId>
    <Version>1.0.0</Version>
    <Authors>Your Name</Authors>
    <Company>Your Company</Company>
    <Description>A short description of your package</Description>
    <PackageLicenseExpression>MIT</PackageLicenseExpression>
    <PackageProjectUrl>https://github.com/your-org/your-project</PackageProjectUrl>
    <RepositoryUrl>https://github.com/your-org/your-project</RepositoryUrl>
    <RepositoryType>git</RepositoryType>
    <PackageTags>your;tags</PackageTags>
    
    <!-- Documentation -->
    <GenerateDocumentationFile>true</GenerateDocumentationFile>
    <NoWarn>$(NoWarn);1591</NoWarn>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="Microsoft.CodeAnalysis.NetAnalyzers" Version="8.0.0">
      <PrivateAssets>all</PrivateAssets>
      <IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
    </PackageReference>
  </ItemGroup>
</Project>
```

## Code Quality Standards

### Mandatory Quality Checks

**CRITICAL**: After implementing ANY feature, you MUST run these commands in order.

**IMPORTANT**: These commands MUST match your GitHub Actions workflows to prevent CI/CD failures!

```bash
# Pre-Commit Checklist (MUST match .github/workflows/*.yml)

# 1. Format check (matches workflow - use --verify-no-changes!)
dotnet format --verify-no-changes

# 2. Build (MUST pass with no warnings - matches workflow)
dotnet build --no-incremental --warnaserror

# 3. Run all tests (MUST pass 100% - matches workflow)
dotnet test --no-build

# 4. Check coverage (MUST meet threshold)
dotnet test /p:CollectCoverage=true /p:CoverletOutputFormat=opencover

# If ANY fails: ❌ DO NOT COMMIT - Fix first!
```

**If ANY of these fail, you MUST fix the issues before committing.**

**Why This Matters:**
- CI/CD failures happen when local commands differ from workflows
- Example: Using `dotnet format` locally but `dotnet format --verify-no-changes` in CI = failure
- Example: Missing `--warnaserror` flag = warnings pass locally but fail in CI

### Code Style

Use `.editorconfig` for consistent code style:

```ini
root = true

[*]
charset = utf-8
indent_style = space
indent_size = 4
insert_final_newline = true
trim_trailing_whitespace = true

[*.{cs,csx,vb,vbx}]
indent_size = 4

# C# Code Style Rules
[*.cs]
# Organize usings
dotnet_sort_system_directives_first = true
dotnet_separate_import_directive_groups = false

# this. preferences
dotnet_style_qualification_for_field = false:warning
dotnet_style_qualification_for_property = false:warning
dotnet_style_qualification_for_method = false:warning
dotnet_style_qualification_for_event = false:warning

# Language keywords vs BCL types preferences
dotnet_style_predefined_type_for_locals_parameters_members = true:warning
dotnet_style_predefined_type_for_member_access = true:warning

# Modifier preferences
dotnet_style_require_accessibility_modifiers = always:warning
csharp_preferred_modifier_order = public,private,protected,internal,static,extern,new,virtual,abstract,sealed,override,readonly,unsafe,volatile,async:warning

# Expression preferences
csharp_style_var_for_built_in_types = true:warning
csharp_style_var_when_type_is_apparent = true:warning
csharp_style_var_elsewhere = true:warning

# Pattern matching
csharp_style_pattern_matching_over_is_with_cast_check = true:warning
csharp_style_pattern_matching_over_as_with_null_check = true:warning

# Null-checking preferences
csharp_style_throw_expression = true:warning
csharp_style_conditional_delegate_call = true:warning

# Code block preferences
csharp_prefer_braces = true:warning
csharp_prefer_simple_using_statement = true:warning

# Naming conventions
dotnet_naming_rule.interface_should_be_begins_with_i.severity = warning
dotnet_naming_rule.interface_should_be_begins_with_i.symbols = interface
dotnet_naming_rule.interface_should_be_begins_with_i.style = begins_with_i

dotnet_naming_rule.types_should_be_pascal_case.severity = warning
dotnet_naming_rule.types_should_be_pascal_case.symbols = types
dotnet_naming_rule.types_should_be_pascal_case.style = pascal_case

dotnet_naming_rule.non_field_members_should_be_pascal_case.severity = warning
dotnet_naming_rule.non_field_members_should_be_pascal_case.symbols = non_field_members
dotnet_naming_rule.non_field_members_should_be_pascal_case.style = pascal_case

# Symbol specifications
dotnet_naming_symbols.interface.applicable_kinds = interface
dotnet_naming_symbols.interface.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected

dotnet_naming_symbols.types.applicable_kinds = class, struct, interface, enum
dotnet_naming_symbols.types.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected

dotnet_naming_symbols.non_field_members.applicable_kinds = property, event, method
dotnet_naming_symbols.non_field_members.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected

# Naming styles
dotnet_naming_style.begins_with_i.required_prefix = I
dotnet_naming_style.begins_with_i.required_suffix = 
dotnet_naming_style.begins_with_i.word_separator = 
dotnet_naming_style.begins_with_i.capitalization = pascal_case

dotnet_naming_style.pascal_case.required_prefix = 
dotnet_naming_style.pascal_case.required_suffix = 
dotnet_naming_style.pascal_case.word_separator = 
dotnet_naming_style.pascal_case.capitalization = pascal_case
```

### Testing

- **Framework**: xUnit (recommended) or NUnit
- **Location**: Separate test project
- **Coverage**: Coverlet
- **Coverage Threshold**: 95%+

Example test structure:
```csharp
using Xunit;

namespace YourProject.Tests;

public class MyClassTests
{
    [Fact]
    public void Process_ValidInput_ReturnsExpectedResult()
    {
        // Arrange
        var sut = new MyClass();
        var input = "test";

        // Act
        var result = sut.Process(input);

        // Assert
        Assert.Equal("TEST", result);
    }

    [Theory]
    [InlineData("")]
    [InlineData(null)]
    public void Process_InvalidInput_ThrowsArgumentException(string input)
    {
        // Arrange
        var sut = new MyClass();

        // Act & Assert
        Assert.Throws<ArgumentException>(() => sut.Process(input));
    }
}
```

### Documentation

- Use XML documentation comments
- Document all public APIs
- Include `<summary>`, `<param>`, `<returns>`, `<exception>`

Example:
```csharp
namespace YourProject;

/// <summary>
/// Provides functionality for processing data.
/// </summary>
public class MyClass
{
    /// <summary>
    /// Processes the input string and converts it to uppercase.
    /// </summary>
    /// <param name="input">The input string to process.</param>
    /// <returns>The processed string in uppercase.</returns>
    /// <exception cref="ArgumentException">Thrown when input is null or empty.</exception>
    /// <example>
    /// <code>
    /// var processor = new MyClass();
    /// var result = processor.Process("hello");
    /// // result is "HELLO"
    /// </code>
    /// </example>
    public string Process(string input)
    {
        if (string.IsNullOrEmpty(input))
        {
            throw new ArgumentException("Input cannot be null or empty.", nameof(input));
        }

        return input.ToUpperInvariant();
    }
}
```

## Project Structure

```
project/
├── src/
│   └── YourProject/
│       ├── YourProject.csproj
│       ├── Class1.cs
│       └── ...
├── tests/
│   └── YourProject.Tests/
│       ├── YourProject.Tests.csproj
│       ├── Class1Tests.cs
│       └── ...
├── docs/                    # Project documentation
├── .editorconfig            # Code style configuration
├── Directory.Build.props    # Shared MSBuild properties
├── Directory.Packages.props # Central package management
├── YourProject.sln          # Solution file
├── README.md                # Project overview (allowed in root)
├── CHANGELOG.md             # Version history (allowed in root)
└── LICENSE                  # Project license (allowed in root)
```

## Nullable Reference Types

- Enable nullable reference types
- Use `?` for nullable types
- Use null-forgiving operator `!` sparingly

Example:
```csharp
public class UserService
{
    private readonly ILogger<UserService> _logger;

    public UserService(ILogger<UserService> logger)
    {
        _logger = logger ?? throw new ArgumentNullException(nameof(logger));
    }

    public User? FindUser(string? username)
    {
        if (string.IsNullOrEmpty(username))
        {
            return null;
        }

        // Implementation
        return new User { Username = username };
    }

    public User GetUser(string username)
    {
        var user = FindUser(username);
        return user ?? throw new InvalidOperationException("User not found");
    }
}
```

## Async/Await Best Practices

- Use `async`/`await` for I/O operations
- Don't block on async code
- Use `ConfigureAwait(false)` in libraries
- Return `Task` or `ValueTask`

Example:
```csharp
public class DataService
{
    private readonly HttpClient _httpClient;

    public async Task<string> FetchDataAsync(string url, CancellationToken cancellationToken = default)
    {
        var response = await _httpClient.GetAsync(url, cancellationToken).ConfigureAwait(false);
        response.EnsureSuccessStatusCode();
        
        return await response.Content.ReadAsStringAsync(cancellationToken).ConfigureAwait(false);
    }
}
```

## CI/CD Requirements

Must include GitHub Actions workflows for:

1. **Testing** (`dotnet-test.yml`):
   - Test on ubuntu-latest, windows-latest, macos-latest
   - Test on .NET 8.0
   - Upload coverage reports

2. **Linting** (`dotnet-lint.yml`):
   - Format check: `dotnet format --verify-no-changes`
   - Build: `dotnet build --no-incremental`
   - Analyzers enabled

## Package Publication

### Publishing to NuGet

**Prerequisites:**
1. Create account at https://www.nuget.org
2. Generate API key from account settings
3. Add `NUGET_API_KEY` to GitHub repository secrets

**Publishing Workflow:**

1. Update version in .csproj
2. Update CHANGELOG.md
3. Run quality checks:
   ```bash
   dotnet format --verify-no-changes
   dotnet build --configuration Release
   dotnet test --configuration Release
   ```

4. Pack: `dotnet pack --configuration Release`
5. Create git tag: `git tag v1.0.0 && git push --tags`
6. GitHub Actions automatically publishes to NuGet
7. Or manual publish: `dotnet nuget push bin/Release/*.nupkg --api-key $NUGET_API_KEY --source https://api.nuget.org/v3/index.json`

**Publishing Checklist:**

- ✅ All tests passing
- ✅ Code formatted (`dotnet format`)
- ✅ No build warnings
- ✅ Version updated in .csproj
- ✅ CHANGELOG.md updated
- ✅ README.md up to date
- ✅ LICENSE file present
- ✅ XML documentation generated
- ✅ Package metadata complete
- ✅ Verify with `dotnet pack`

**Semantic Versioning:**

Use `<Version>` in .csproj with SemVer:
- **MAJOR**: Breaking API changes
- **MINOR**: New features (backwards compatible)
- **PATCH**: Bug fixes (backwards compatible)

<!-- CSHARP:END -->