configuration — Claude Code skill: what it does, how to install
Guides .NET 10 configuration with typed options, validation, and secret handling. Use it when working with appsettings files or environment variables.
npx skills add codewithmukesh/dotnet-claude-kit --skill configuration -a claude-codeWhat configuration does
This skill sets configuration patterns for .NET 10 applications. It binds settings sections to typed classes with BindConfiguration, uses attribute validation, and applies ValidateOnStart() so invalid values fail during startup.
It maps immutable settings to IOptions<T>, request-scoped reloadable settings to IOptionsSnapshot<T>, and watched background-service settings to IOptionsMonitor<T>. Named options cover separate configurations of the same type.
For development secrets, it points to dotnet user-secrets; production secrets use environment variables or Azure Key Vault. Reading IConfiguration directly inside services is treated as an anti-pattern, so existing service code deserves a check.
What it helps with
- bind an
appsettings.jsonsection to a typed class - validate required settings at startup
- choose between
IOptions<T>andIOptionsSnapshot<T> - move secrets out of
appsettings.json - configure named SMTP option instances
Example prompts for the agent
- Set up database configuration with
DatabaseOptionsandBindConfiguration. - Add
JwtOptionsvalidation withValidateDataAnnotations()andValidateOnStart(). - Configure SMTP settings for
internalandcustomerwith named options.
How to install configuration
1Skills CLI (Vercel)
npx skills add codewithmukesh/dotnet-claude-kit --skill configuration -a claude-code2Manually: put the files in place
~/.claude/skills/configuration/SKILL.mdCopy the whole skill folder; for one project use .claude/skills/configuration/
1Skills CLI (Vercel)
npx skills add codewithmukesh/dotnet-claude-kit --skill configuration -a codex2Manually: put the files in place
.agents/skills/configuration/SKILL.mdFor all projects use ~/.agents/skills/
1Skills CLI (Vercel)
npx skills add codewithmukesh/dotnet-claude-kit --skill configuration -a cursor2Manually: put the files in place
.cursor/skills/configuration/SKILL.mdCursor also reads .agents/skills/ and .claude/skills/
1GitHub CLI
gh skill install codewithmukesh/dotnet-claude-kit configuration2Manually: put the files in place
.github/skills/configuration/SKILL.md1Skills CLI (Vercel)
npx skills add codewithmukesh/dotnet-claude-kit --skill configuration -a gemini-cli2Platform CLI
gemini skills install https://github.com/codewithmukesh/dotnet-claude-kit --path skills/configurationManually: put the files in place
.devin/skills/configuration/SKILL.mdThe legacy .windsurf/skills/ path still works
Skills CLI (Vercel)
npx skills add codewithmukesh/dotnet-claude-kit --skill configuration -a opencodeClaude.ai
Zip the folder and upload it in Settings → Capabilities → Skills
Step by step, with commands for each platform: How to install skills in Claude Code: five ways
From the same set46
Similar
Questions about configuration
How do I install configuration in Claude Code?
Run npx skills add codewithmukesh/dotnet-claude-kit --skill configuration -a claude-code, then run npx skills add codewithmukesh/dotnet-claude-kit --skill configuration -a claude-code again. The skill file is placed at ~/.claude/skills/configuration/SKILL.md.
What does configuration do?
It provides .NET 10 patterns for the Options pattern, startup validation, configuration layers, and secret handling. It also guides the choice of an options interface for each scenario.
What is the difference between IOptions<T>, IOptionsSnapshot<T>, and IOptionsMonitor<T>?
IOptions<T> reads values at startup for immutable configuration. IOptionsSnapshot<T> reloads settings per request, while IOptionsMonitor<T> watches changes and exposes current values to a background service.
Source text
SKILL.md · MIT
---
name: configuration
description: >
Configuration patterns for .NET 10 applications. Covers the Options pattern,
IOptionsSnapshot vs IOptions, secrets management, and environment-based
configuration.
Load this skill when setting up application configuration, managing secrets,
binding configuration sections, or when the user mentions "configuration",
"appsettings", "Options pattern", "IOptions", "IOptionsSnapshot", "secrets",
"user secrets", "environment variables", "connection string", or "config binding".
---
# Configuration
## Core Principles
1. **Options pattern always** — Never read `IConfiguration` directly in services. Bind configuration sections to strongly-typed classes with validation.
2. **Validate on startup** — Use `ValidateDataAnnotations()` and `ValidateOnStart()` to catch misconfiguration before the first request.
3. **Secrets never in source** — Use user secrets in development, Azure Key Vault or environment variables in production. Never commit secrets to git.
4. **Configuration layering** — `appsettings.json` → `appsettings.{Environment}.json` → environment variables → user secrets. Later sources override earlier ones.
## Patterns
### Options Pattern
```csharp
// Options class with validation attributes
public class DatabaseOptions
{
public const string SectionName = "Database";
[Required]
public required string ConnectionString { get; init; }
[Range(1, 100)]
public int MaxRetryCount { get; init; } = 3;
[Range(1, 60)]
public int CommandTimeoutSeconds { get; init; } = 30;
}
// Registration with validation
builder.Services.AddOptions<DatabaseOptions>()
.BindConfiguration(DatabaseOptions.SectionName)
.ValidateDataAnnotations()
.ValidateOnStart(); // Fails at startup if configuration is invalid
```
```json
// appsettings.json
{
"Database": {
"ConnectionString": "",
"MaxRetryCount": 3,
"CommandTimeoutSeconds": 30
}
}
```
### Injecting Options
```csharp
// IOptions<T> — singleton, read once at startup, doesn't change
public class OrderService(IOptions<DatabaseOptions> options)
{
private readonly DatabaseOptions _db = options.Value;
}
// IOptionsSnapshot<T> — scoped, re-reads per request (for reloadable config)
public class OrderService(IOptionsSnapshot<DatabaseOptions> options)
{
private readonly DatabaseOptions _db = options.Value;
}
// IOptionsMonitor<T> — singleton, actively watches for changes
public class BackgroundWorker(IOptionsMonitor<WorkerOptions> options)
{
public void DoWork()
{
var current = options.CurrentValue; // Always latest
}
}
```
### Custom Validation (Complex Rules)
```csharp
builder.Services.AddOptions<JwtOptions>()
.BindConfiguration("Jwt")
.Validate(options =>
{
if (string.IsNullOrEmpty(options.Key) || options.Key.Length < 32)
return false;
if (options.ExpirationMinutes <= 0)
return false;
return true;
}, "JWT key must be at least 32 characters and expiration must be positive")
.ValidateOnStart();
```
### Azure Key Vault (Production)
```csharp
// Program.cs — add Key Vault as a configuration source
if (builder.Environment.IsProduction())
{
var keyVaultUri = new Uri(builder.Configuration["KeyVault:Uri"]!);
builder.Configuration.AddAzureKeyVault(keyVaultUri, new DefaultAzureCredential());
}
```
### Configuration for Multiple Environments
```csharp
// Named options — different config per named instance
builder.Services.AddOptions<SmtpOptions>("internal")
.BindConfiguration("Smtp:Internal");
builder.Services.AddOptions<SmtpOptions>("customer")
.BindConfiguration("Smtp:Customer");
// Usage
public class EmailService(IOptionsSnapshot<SmtpOptions> options)
{
public async Task SendInternalEmail(string to, string body)
{
var smtp = options.Get("internal");
// ...
}
}
```
## Anti-patterns
### Don't Read IConfiguration Directly
```csharp
// BAD — stringly-typed, no validation, hard to test
public class OrderService(IConfiguration config)
{
public void Process()
{
var timeout = int.Parse(config["Database:CommandTimeout"]!);
}
}
// GOOD — strongly-typed options
public class OrderService(IOptions<DatabaseOptions> options)
{
public void Process()
{
var timeout = options.Value.CommandTimeoutSeconds;
}
}
```
### Don't Put Secrets in appsettings.json
```json
// BAD — committed to source control
{
"Jwt": { "Key": "super-secret-key" },
"Database": { "ConnectionString": "Server=prod;Password=secret" }
}
// GOOD — appsettings.json has defaults/structure only
{
"Jwt": { "Key": "", "Issuer": "myapp", "Audience": "myapp" },
"Database": { "ConnectionString": "" }
}
// Secrets provided via user-secrets (dev) or env vars / Key Vault (prod)
```
### Don't Skip Startup Validation
```csharp
// BAD — misconfiguration discovered at runtime
builder.Services.Configure<JwtOptions>(builder.Configuration.GetSection("Jwt"));
// GOOD — fail fast at startup
builder.Services.AddOptions<JwtOptions>()
.BindConfiguration("Jwt")
.ValidateDataAnnotations()
.ValidateOnStart();
```
## Decision Guide
| Scenario | Recommendation |
|----------|---------------|
| Binding config to class | Options pattern with `BindConfiguration` |
| Simple, immutable config | `IOptions<T>` |
| Config that changes per request | `IOptionsSnapshot<T>` |
| Background service watching config | `IOptionsMonitor<T>` |
| Development secrets | `dotnet user-secrets` |
| Production secrets | Azure Key Vault or environment variables |
| Validating config | `ValidateDataAnnotations()` + `ValidateOnStart()` |
| Multiple configs of same type | Named options with `IOptionsSnapshot<T>.Get(name)` |
© codewithmukesh · MIT · codewithmukesh/dotnet-claude-kit