This file provides guidance to Claude Code (claude.ai/claude-code) when working with this repository.
McMaster.Extensions.CommandLineUtils is a .NET library for building command-line applications. It simplifies parsing command-line arguments, validating user inputs, and generating help text. This is a fork of Microsoft.Extensions.CommandLineUtils.
- Package:
McMaster.Extensions.CommandLineUtilson NuGet - Targets: .NET 6.0+
- Status: Stable/maintenance mode (no major features planned)
- License: Apache 2.0
# Full build with tests (recommended)
./build.ps1
# CI mode (enforces formatting checks)
./build.ps1 -ci
# Build only
dotnet build
# Run tests
dotnet test
# Build sample projects
dotnet build docs/samples/samples.sln
# Generate documentation locally
./docs/generate.ps1
./docs/generate.ps1 -Serve # with local previewBuild outputs (NuGet packages) go to /artifacts/.
src/
CommandLineUtils/ # Main library
Attributes/ # Attribute-based API ([Option], [Argument], etc.)
Conventions/ # Convention system for processing attributes
Validation/ # Validation framework
IO/ # Console I/O abstractions (IConsole)
HelpText/ # Help text generation
Internal/ # Parsing engine, value parsers
Utilities/ # ArgumentEscaper, Prompt, DotNetExe
Hosting.CommandLine/ # Microsoft.Extensions.Hosting integration
test/
CommandLineUtils.Tests/ # xUnit tests for main library
Hosting.CommandLine.Tests/ # xUnit tests for hosting package
docs/
samples/ # 20+ example projects demonstrating various patterns
1. Attribute-based API:
public class Program
{
public static int Main(string[] args)
=> CommandLineApplication.Execute<Program>(args);
[Option(Description = "The subject")]
public string Subject { get; } = "world";
private void OnExecute() { /* command logic */ }
}2. Builder API:
var app = new CommandLineApplication();
app.HelpOption();
var subject = app.Option("-s|--subject <SUBJECT>", "desc", CommandOptionType.SingleValue);
app.OnExecute(() => { /* command logic */ });
return app.Execute(args);- Conventions: Extensible
IConventionimplementations process attributes and wire up behavior - Validation: Three approaches - attribute validators (
[Required],[FileExists]), fluent API (.IsRequired(),.Accepts()), andOnValidate()methods - Console abstraction:
IConsoleinterface enables testing; usePhysicalConsolefor real I/O - Response files: Support for
@filenamesyntax to read arguments from files
- 4-space indentation
- Nullable reference types enabled
- Warnings treated as errors
- Code style enforced in build (
EnforceCodeStyleInBuild=true) - Run
dotnet formatto auto-fix formatting before committing
Uses xUnit with FluentAssertions and Moq. Convention tests inherit from ConventionTestBase and use Create<T>() factory method.
# Quick test run (may not catch all issues)
dotnet test --collect:"XPlat Code Coverage"
# Full validation (REQUIRED before committing)
pwsh -File build.ps1IMPORTANT: Always run the full build.ps1 script before committing changes. dotnet test alone may pass while the full build fails due to:
- Sample project compilation issues
- Source generator output problems
- Integration test failures
- Code coverage requirements
The build script runs the complete validation pipeline including tests, samples, and packaging.
Test-Driven Development: When implementing new features or fixing bugs, prefer writing tests first:
- Write a failing test that demonstrates the desired behavior or reproduces the bug
- Run the test to confirm it fails as expected
- Implement the minimum code needed to make the test pass
- Run the full build script (
pwsh -File build.ps1) to verify the fix - Refactor if needed while keeping tests green
This approach ensures code correctness, prevents regressions, and validates that tests actually catch the issues they're meant to detect. The test suite already has good coverage and patterns to follow.
When asked to fix an issue or implement a change via GitHub, follow this workflow:
- Create a branch with the
claude/prefix (e.g.,claude/fix-null-ref,claude/issue-123). Never push directly tomain. - Make the changes, following the TDD approach described above when applicable.
- Run
pwsh -File build.ps1to validate the full build passes before pushing. - Push the branch and open a PR.
- Link the PR to the relevant issue using
Fixes #Nin the PR body. - Keep PRs focused — only change what's needed to address the issue. Don't refactor surrounding code or add unrelated improvements.
IMPORTANT: Use Conventional Commit format for all commit messages. This ensures consistency and enables automated changelog generation.
Format: <type>[optional scope]: <description>
Common types:
feat:New feature or enhancementfix:Bug fixdocs:Documentation changes onlytest:Adding or updating testsrefactor:Code changes that neither fix bugs nor add featuresperf:Performance improvementschore:Build scripts, dependencies, tooling
Examples:
feat: add support for nested subcommands
fix: resolve null reference in argument parser
docs: update getting started guide
test: add coverage for validation attributes
refactor: simplify help text generation logic
Multi-line commits: For complex changes, use a blank line followed by a detailed body:
fix: resolve race condition in async command execution
The ExecuteAsync method was not properly awaiting disposal of
resources, leading to intermittent failures in concurrent scenarios.
Added proper async/await pattern and additional test coverage.
Skipping CI: For commits that don't require CI validation (documentation, README updates, comment changes), add [ci skip] on its own line in the commit body. IMPORTANT: Never include [ci skip] in the first line of the commit message.
docs: update installation instructions
[ci skip]
docs: fix typo in API documentation
[ci skip]
This prevents unnecessary CI builds and saves resources for changes that don't affect code functionality.
Release notes are managed in two places:
src/CommandLineUtils/releasenotes.props- XML format for NuGet's<PackageReleaseNotes>CHANGELOG.md- Markdown format for GitHub
The /prepare-release skill automates release note generation by analyzing git history and formatting changes appropriately.