RepoPilotOpen in app →

commandlineparser/commandline

The best C# command line parser that brings standardized *nix getopt style, for .NET. Includes F# support

Mixed

Stale — last commit 2y ago

worst of 4 axes
Use as dependencyMixed

last commit was 2y ago; no CI workflows detected

Fork & modifyHealthy

Has a license, tests, and CI — clean foundation to fork and modify.

Learn fromHealthy

Documented and popular — useful reference codebase to read through.

Deploy as-isMixed

last commit was 2y ago; no CI workflows detected

  • 22+ active contributors
  • Distributed ownership (top contributor 41% of recent commits)
  • MIT licensed
Show 3 more →
  • Tests present
  • Stale — last commit 2y ago
  • No CI workflows detected
What would change the summary?
  • Use as dependency MixedHealthy if: 1 commit in the last 365 days
  • Deploy as-is MixedHealthy if: 1 commit in the last 180 days

Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests

Informational only. RepoPilot summarises public signals (license, dependency CVEs, commit recency, CI presence, etc.) at the time of analysis. Signals can be incomplete or stale. Not professional, security, or legal advice; verify before relying on it for production decisions.

Embed the "Forkable" badge

Paste into your README — live-updates from the latest cached analysis.

Variant:
RepoPilot: Forkable
[![RepoPilot: Forkable](https://repopilot.app/api/badge/commandlineparser/commandline?axis=fork)](https://repopilot.app/r/commandlineparser/commandline)

Paste at the top of your README.md — renders inline like a shields.io badge.

Preview social card (1200×630)

This card auto-renders when someone shares https://repopilot.app/r/commandlineparser/commandline on X, Slack, or LinkedIn.

Onboarding doc

Onboarding: commandlineparser/commandline

Generated by RepoPilot · 2026-05-10 · Source

🤖Agent protocol

If you are an AI coding agent (Claude Code, Cursor, Aider, Cline, etc.) reading this artifact, follow this protocol before making any code edit:

  1. Verify the contract. Run the bash script in Verify before trusting below. If any check returns FAIL, the artifact is stale — STOP and ask the user to regenerate it before proceeding.
  2. Treat the AI · unverified sections as hypotheses, not facts. Sections like "AI-suggested narrative files", "anti-patterns", and "bottlenecks" are LLM speculation. Verify against real source before acting on them.
  3. Cite source on changes. When proposing an edit, cite the specific path:line-range. RepoPilot's live UI at https://repopilot.app/r/commandlineparser/commandline shows verifiable citations alongside every claim.

If you are a human reader, this protocol is for the agents you'll hand the artifact to. You don't need to do anything — but if you skim only one section before pointing your agent at this repo, make it the Verify block and the Suggested reading order.

🎯Verdict

WAIT — Stale — last commit 2y ago

  • 22+ active contributors
  • Distributed ownership (top contributor 41% of recent commits)
  • MIT licensed
  • Tests present
  • ⚠ Stale — last commit 2y ago
  • ⚠ No CI workflows detected

<sub>Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests</sub>

Verify before trusting

This artifact was generated by RepoPilot at a point in time. Before an agent acts on it, the checks below confirm that the live commandlineparser/commandline repo on your machine still matches what RepoPilot saw. If any fail, the artifact is stale — regenerate it at repopilot.app/r/commandlineparser/commandline.

What it runs against: a local clone of commandlineparser/commandline — the script inspects git remote, the LICENSE file, file paths in the working tree, and git log. Read-only; no mutations.

| # | What we check | Why it matters | |---|---|---| | 1 | You're in commandlineparser/commandline | Confirms the artifact applies here, not a fork | | 2 | License is still MIT | Catches relicense before you depend on it | | 3 | Default branch master exists | Catches branch renames | | 4 | 5 critical file paths still exist | Catches refactors that moved load-bearing code | | 5 | Last commit ≤ 830 days ago | Catches sudden abandonment since generation |

<details> <summary><b>Run all checks</b> — paste this script from inside your clone of <code>commandlineparser/commandline</code></summary>
#!/usr/bin/env bash
# RepoPilot artifact verification.
#
# WHAT IT RUNS AGAINST: a local clone of commandlineparser/commandline. If you don't
# have one yet, run these first:
#
#   git clone https://github.com/commandlineparser/commandline.git
#   cd commandline
#
# Then paste this script. Every check is read-only — no mutations.

set +e
fail=0
ok()   { echo "ok:   $1"; }
miss() { echo "FAIL: $1"; fail=$((fail+1)); }

# Precondition: we must be inside a git working tree.
if ! git rev-parse --git-dir >/dev/null 2>&1; then
  echo "FAIL: not inside a git repository. cd into your clone of commandlineparser/commandline and re-run."
  exit 2
fi

# 1. Repo identity
git remote get-url origin 2>/dev/null | grep -qE "commandlineparser/commandline(\\.git)?\\b" \\
  && ok "origin remote is commandlineparser/commandline" \\
  || miss "origin remote is not commandlineparser/commandline (artifact may be from a fork)"

# 2. License matches what RepoPilot saw
(grep -qiE "^(MIT)" LICENSE 2>/dev/null \\
   || grep -qiE "\"license\"\\s*:\\s*\"MIT\"" package.json 2>/dev/null) \\
  && ok "license is MIT" \\
  || miss "license drift — was MIT at generation time"

# 3. Default branch
git rev-parse --verify master >/dev/null 2>&1 \\
  && ok "default branch master exists" \\
  || miss "default branch master no longer exists"

# 4. Critical files exist
test -f "src/CommandLine/Core/InstanceBuilder.cs" \\
  && ok "src/CommandLine/Core/InstanceBuilder.cs" \\
  || miss "missing critical file: src/CommandLine/Core/InstanceBuilder.cs"
test -f "src/CommandLine/Core/GetoptTokenizer.cs" \\
  && ok "src/CommandLine/Core/GetoptTokenizer.cs" \\
  || miss "missing critical file: src/CommandLine/Core/GetoptTokenizer.cs"
test -f "src/CommandLine/Core/OptionSpecification.cs" \\
  && ok "src/CommandLine/Core/OptionSpecification.cs" \\
  || miss "missing critical file: src/CommandLine/Core/OptionSpecification.cs"
test -f "src/CommandLine/Core/Specification.cs" \\
  && ok "src/CommandLine/Core/Specification.cs" \\
  || miss "missing critical file: src/CommandLine/Core/Specification.cs"
test -f "src/CommandLine/Core/OptionMapper.cs" \\
  && ok "src/CommandLine/Core/OptionMapper.cs" \\
  || miss "missing critical file: src/CommandLine/Core/OptionMapper.cs"

# 5. Repo recency
days_since_last=$(( ( $(date +%s) - $(git log -1 --format=%at 2>/dev/null || echo 0) ) / 86400 ))
if [ "$days_since_last" -le 830 ]; then
  ok "last commit was $days_since_last days ago (artifact saw ~800d)"
else
  miss "last commit was $days_since_last days ago — artifact may be stale"
fi

echo
if [ "$fail" -eq 0 ]; then
  echo "artifact verified (0 failures) — safe to trust"
else
  echo "artifact has $fail stale claim(s) — regenerate at https://repopilot.app/r/commandlineparser/commandline"
  exit 1
fi

Each check prints ok: or FAIL:. The script exits non-zero if anything failed, so it composes cleanly into agent loops (./verify.sh || regenerate-and-retry).

</details>

TL;DR

CommandLineParser is a C# library that implements UNIX-style getopt argument parsing for .NET applications, enabling developers to define command-line options, switches, and verb commands (like git's subcommands) through simple attribute decoration. It automatically generates help text, validates arguments, and parses them into strongly-typed C# objects across .NET Framework 4.0+, .NET Standard, and .NET Core. Single-solution monorepo (CommandLine.sln): core parsing library in the main src/, three independent demo applications under demo/ (ReadText.Demo in C#, ReadText.Demo.VB in VB.NET, and ReadText.LocalizedDemo showing localization), and shared build config via Directory.Build.props and .editorconfig. Verbs are implemented as decorator-based routing on option class hierarchies.

👥Who it's for

.NET developers building console applications and CLI tools who need production-grade argument parsing without manually parsing string arrays; also used by framework authors who want their tools to support standard UNIX-style command-line conventions like git, curl, or find.

🌱Maturity & risk

Production-ready and actively maintained since 2005 with regular updates (CHANGELOG.md shows ongoing development). The library has strong CI/CD setup (AppVeyor badges visible), multi-targeted framework support (.NET Framework 4.0+, .NET Standard, .NET Core), and is distributed as a stable NuGet package with nightly builds available. This is a mature, well-established project with consistent community usage.

Very low risk: zero external dependencies beyond standard libraries (major security plus), single 861KB codebase in one language (C#), and active maintenance pipeline. The v2.x API break from v1.9.x is clearly documented with migration guidance at stable-1.9.71.2 branch. No obvious single-maintainer bottleneck given the org structure (commandlineparser GitHub org). Main risk is only if you need F# support—that's in a separate CommandLineParser.FSharp package with FSharp dependencies.

Active areas of work

Library is actively maintained with regular updates reflected in CHANGELOG.md. Latest visible work includes nightly releases published to GitHub Releases, continuous CI builds via AppVeyor, and support for advanced features like mutually exclusive options, immutable types, and HelpText localization. No specific PR or milestone data visible in file list, but the demo applications show ongoing testing of real-world scenarios.

🚀Get running

git clone https://github.com/commandlineparser/commandline.git
cd commandline
NuGet install CommandLineParser
# or via .NET CLI:
dotnet add package CommandLineParser

Then explore demo/ReadText.Demo/Program.cs for a C# example or demo/ReadText.Demo.VB/Program.vb for VB.NET usage.

Daily commands:

dotnet build CommandLine.sln
dotnet test

To run a demo:

cd demo/ReadText.Demo
dotnet run -- --help

🗺️Map of the codebase

  • src/CommandLine/Core/InstanceBuilder.cs — Core orchestrator that builds option instances from parsed tokens; every option/verb parsing flow routes through this file.
  • src/CommandLine/Core/GetoptTokenizer.cs — Implements Unix getopt-style tokenization; this is the entry point that converts raw command-line strings into structured tokens.
  • src/CommandLine/Core/OptionSpecification.cs — Defines the metadata structure for all command-line options; understanding this is essential for grasping how options are defined and validated.
  • src/CommandLine/Core/Specification.cs — Abstract base for option/value specifications; foundational abstraction used across all parsing logic.
  • src/CommandLine/Core/OptionMapper.cs — Maps parsed tokens to option instances using reflection; bridges tokenization and instance building.
  • src/CommandLine/HelpTextExtensions.cs — Generates help text from option metadata; critical for understanding how the library exposes configuration to end users.
  • src/CommandLine/Core/TypeConverter.cs — Handles conversion of string arguments to target .NET types; essential for value parsing and validation.

🛠️How to make changes

Add a new command-line option

  1. Define an option property in your Options class with the [Option] attribute, specifying short/long names and help text (demo/ReadText.Demo/Options.cs)
  2. The OptionSpecification will be auto-discovered from reflection during Parser.Default.ParseArguments<Options>(args) (src/CommandLine/Core/ReflectionExtensions.cs)
  3. The GetoptTokenizer will match incoming arguments against your option names (--name or -n style) (src/CommandLine/Core/GetoptTokenizer.cs)
  4. OptionMapper will bind matched tokens to your property using TypeConverter (src/CommandLine/Core/OptionMapper.cs)

Add a new verb (subcommand)

  1. Create separate Option classes for each verb, mark them with [Verb("name")] attribute (src/CommandLine/BaseAttribute.cs)
  2. Call Parser.Default.ParseArguments(args, typeof(VerbA), typeof(VerbB)) or use generic overload (src/CommandLine/Parser.cs)
  3. GetoptTokenizer will partition tokens when it encounters a recognized verb name (src/CommandLine/Core/GetoptTokenizer.cs)
  4. InstanceChooser will select the matching verb type and pass its tokens to InstanceBuilder (src/CommandLine/Core/InstanceChooser.cs)
  5. Your ParserResult will contain the populated verb instance (cast to appropriate type) (src/CommandLine/ParserResult.cs)

Support a custom type in option values

  1. Identify where TypeConverter handles your type; it uses TypeLookup to categorize input types (src/CommandLine/Core/TypeConverter.cs)
  2. Add logic to TypeDescriptor to describe your type's structure (enumerable, sequence, nullable) (src/CommandLine/Core/TypeDescriptor.cs)
  3. Implement a static TryParse(string value, out YourType result) method on your custom type (src/CommandLine/Core/TypeConverter.cs)
  4. TypeConverter will automatically invoke TryParse during ValueMapper binding (src/CommandLine/Core/ValueMapper.cs)

Generate localized help text

  1. Use HelpTextExtensions.AutoBuild() to extract help text from [Option] and [Value] attributes (src/CommandLine/HelpTextExtensions.cs)
  2. Override the HelpText property in your Options class or provide a custom ResourceManager (demo/ReadText.LocalizedDemo/Options.cs)
  3. Call HelpText.SetLocales() with your CultureInfo before parsing to switch localization (src/CommandLine/HelpTextExtensions.cs)

🔧Why these technologies

  • Unix getopt-style syntax (--long-name, -s, verbs) — Industry standard CLI convention; makes .NET apps feel native on Unix/Linux and familiar to bash users
  • C# attributes ([Option], [Value], [Verb]) — Declarative, type-safe; enables compile-time checking and auto-discovery via reflection without external config files
  • Either<TLeft, TRight> monad (CSharpx) — Functional error handling; avoids exceptions for expected validation failures; enables fluent result composition
  • Reflection for type discovery & instantiation — Allows the library to work with arbitrary user-defined types without code generation; core to the declarative model
  • TryParse pattern for type conversion — Standard .NET convention; enables extensibility without custom converters; integrates naturally with int, bool, enum, etc.

⚖️Trade-offs already made

  • Reflection-based discovery vs. source generation
    • Why: Reflection is runtime-flexible, works with all .NET versions, allows dynamic option definitions
    • Consequence: Slight startup overhead (~tens of ms); not ahead

🪤Traps & gotchas

Strong-named assembly (CommandLine.snk present) means downstream libraries must either also use strong names or trust the assembly—this is rarely an issue in modern .NET but can cause binding issues with legacy projects. The F# support is in a separate NuGet package (CommandLineParser.FSharp), not in this repo, so attempting to use F# types here will fail silently. Verb command routing is case-sensitive by default (git-style semantics). The v2.x break from v1.9.x is major; old code using ParseArguments<T>() without the new verb/immutable patterns will not compile without refactoring.

🏗️Architecture

💡Concepts to learn

  • Attribute-Driven Metadata Decoration — The entire library's public API relies on C# attributes ([Option], [Verb]) to declaratively define CLI structure; understanding reflection-driven attribute parsing is critical to extending or debugging the parser.
  • Verb Commands (Subcommand Routing) — CommandLineParser's killer feature is verb support (git commit, docker run style); it requires understanding how the parser dispatches different option classes based on the first positional argument.
  • Type Mapping via String Constructors — The library can parse into any type with a string constructor (Uri, TimeSpan, custom types); this is a clever pattern for extensibility but requires understanding reflection and constructor resolution at parse time.
  • IEnumerable<T> Sequence Collection — Options can map to sequences (arrays, lists) via IEnumerable<T>, allowing repeated flags like -v -v -v or --file a.txt --file b.txt; understanding the enumeration contract is essential for multi-value options.
  • Mutually Exclusive Option Sets (SetName Pattern) — Options can be grouped into mutually exclusive sets via SetName attribute parameter; parsing fails if conflicting options appear together—a validation pattern that requires understanding the parser's constraint engine.
  • Help Text Localization via Custom Sentence Builder — ReadText.LocalizedDemo shows how to override SentenceBuilder to produce help text in non-English languages; requires understanding the builder pattern and resource-driven localization (resx files).
  • UNIX getopt Style Conventions — The library enforces UNIX argument conventions (--long-form, -s short, -- to stop parsing); understanding these standards is required to appreciate why CommandLineParser exists and what problems it solves.
  • NDesk/ndesk-options — Earlier .NET argument parsing library using similar decorator/fluent API; predecessor and inspiration for CommandLineParser's design approach
  • spectre-console/spectre.console — Modern .NET console UI library that includes argument parsing (via CliFx internally) and pairs well with CommandLineParser for rich terminal output
  • microsoft/dotnet-cli — The .NET CLI itself uses verb-based command structure that CommandLineParser enables—real-world reference implementation of this library's patterns
  • gsscoder/regparse — Same author (gsscoder) created a regex-based argument parser; represents an alternative parsing approach in the same ecosystem
  • docopt/docopt.net — Alternative .NET argument parser using docstring-driven DSL instead of attributes; shows contrasting design philosophy for the same problem domain

🪄PR ideas

To work on one of these in Claude Code or Cursor, paste: Implement the "<title>" PR idea from CLAUDE.md, working through the checklist as the task list.

Migrate AppVeyor CI to GitHub Actions workflow

The repo currently uses AppVeyor (appveyor.yml) for CI/CD, which is outdated. GitHub Actions is now the standard for GitHub-hosted projects and would provide better integration, visibility, and cost efficiency. This involves creating a .github/workflows/ directory with build/test/publish configurations for the .NET solution.

  • [ ] Create .github/workflows/build.yml to run tests on CommandLine.sln across multiple .NET framework versions
  • [ ] Create .github/workflows/publish.yml to automate NuGet package publishing on release tags
  • [ ] Test that both C# and F# demo projects build successfully (demo/ReadText.Demo and demo/fsharp-demo.fsx)
  • [ ] Verify AppVeyor can be safely removed or marked deprecated in repo documentation

Add comprehensive unit tests for F# support validation

The repo claims F# support (mentioned in README and demo/fsharp-demo.fsx exists), but there's no evidence of dedicated test coverage for F# specific scenarios. A test project validating F# integration would ensure the library works correctly with F# consumers and prevent regressions.

  • [ ] Create a new test project (e.g., CommandLine.Tests.FSharp.fsproj) in the tests directory
  • [ ] Add F# unit tests validating attribute parsing, verb handling, and option binding with F# records/discriminated unions
  • [ ] Test the demo/fsharp-demo.fsx script against the test suite to ensure F# DSL works as documented
  • [ ] Integrate F# test execution into CI pipeline

Create API documentation for localization/customization (LocalizableSentenceBuilder pattern)

The repo includes demo/ReadText.LocalizedDemo/ showing a LocalizableSentenceBuilder.cs pattern for custom help text rendering, but this advanced feature is not documented in docs/content/ or README.md. New contributors and users don't know this capability exists.

  • [ ] Add a new section to docs/content/tutorial.fsx (or README.md) titled 'Customizing Help Text and Localization'
  • [ ] Document the ISentenceBuilder interface and provide the LocalizableSentenceBuilder example from the demo with explanation
  • [ ] Include code snippets showing how to implement custom sentence builders for other languages
  • [ ] Link from the main README to this documentation section

🌿Good first issues

  • Add comprehensive unit tests for the LocalizableSentenceBuilder.cs in ReadText.LocalizedDemo—currently only shown as a demo but lacks isolated test coverage verifying all localization paths (HelpText generation in multiple languages).
  • Document the exact sequence type constraints (does IEnumerable<T> work for List<T>, HashSet<T>, ImmutableList<T>?) with a matrix in README and add test cases for each; currently the feature is mentioned but constraints are implied.
  • Create a demo showing mutual exclusion of options (the wiki links to it but no demo/*.cs currently demonstrates [Option(..., SetName="...")] patterns) in a new demo/MutualExclusiveDemo/ project with test coverage.

Top contributors

Click to expand

📝Recent commits

Click to expand
  • 1e3607b — Update bug_report.md (ericnewton76)
  • 6514645 — Update issue templates (ericnewton76)
  • 91cebaa — Merge pull request #869 from bjartelund/master (ericnewton76)
  • 72677c5 — A minor spelling mistake (with few items => with fewer items) (bjartelund)
  • cd915be — Merge pull request #825 from gorsheninmv/make-cast-extensions-internal (ericnewton76)
  • 5ece267 — mark CastExtensions as internal class (Горшенин Михаил (Gorshenin_MV))
  • b0b0ec9 — update appveyor, remove github deployment for now, bump version to 2.9.1 (ericnewton76)
  • bfc2ca8 — Merge branch 'develop' (ericnewton76)
  • dffb751 — update nuget api key (ericnewton76)
  • 1830608 — Merge pull request #758 from gorsheninmv/resourcetype-with-implicit-cast (ericnewton76)

🔒Security observations

The CommandLine Parser codebase has a relatively secure posture for a command-line parsing library. The primary concern is the potential exposure of the strong name key file (CommandLine.snk) in version control, which is a critical secret management issue. Secondary concerns include the need to audit CI/CD configuration and demo applications for hardcoded credentials. No SQL injection, XSS, or direct dependency vulnerabilities were identified in the provided file structure. The library's purpose (command-line parsing) and .NET focus minimize typical web vulnerability risks. Recommendations focus on secret management practices and configuration security reviews.

  • Medium · Strong Name Key File Exposed — CommandLine.snk. The presence of CommandLine.snk (strong name key file) in the repository root suggests that the cryptographic key for assembly signing may be version controlled. If this is a private key, it should never be committed to source control. Fix: Remove CommandLine.snk from version control immediately. Use secure key management practices such as Azure Key Vault, GitHub Secrets, or local machine storage for signing keys. Add *.snk to .gitignore.
  • Low · AppVeyor Configuration Exposed — appveyor.yml. The appveyor.yml file in the repository may contain build secrets, API keys, or sensitive configuration. CI/CD configuration files should be carefully reviewed for exposed credentials. Fix: Audit appveyor.yml for any hardcoded secrets, API keys, or credentials. Use AppVeyor's secure variables feature for sensitive data instead of committing them to the repository.
  • Low · Demo Applications May Contain Example Credentials — demo/ directory (Options.cs, Options.vb, Program.cs). Multiple demo applications exist in the demo/ directory (ReadText.Demo, ReadText.Demo.VB, ReadText.LocalizedDemo) that may contain hardcoded example credentials or configuration that could serve as a reference for bad practices. Fix: Review all demo applications to ensure they do not contain hardcoded credentials, API keys, or sensitive configuration. Use environment variables or configuration files for sensitive data in examples.

LLM-derived; treat as a starting point, not a security audit.


Generated by RepoPilot. Verdict based on maintenance signals — see the live page for receipts. Re-run on a new commit to refresh.

Mixed signals · commandlineparser/commandline — RepoPilot