Skip to content
OpenSmartRoute
Skillv1.0.0

clap

Build production Rust CLIs with Clap: subcommands, config layering, validation, exit codes, shell completions, and testable command surfaces

by bobmatnyc(0) 0 installs
Free
Sign in to install

Free account. Installing gives you the manifest plus copy-paste snippets.

See reviews

About

Imported from bobmatnyc/claude-mpm-skills (toolchains/rust/cli/clap/SKILL.md). Install upstream with npx skills add bobmatnyc/claude-mpm-skills --skill clap. Copyright stays with the author (MIT).

Clap (Rust) - Production CLI Patterns

Overview

Clap provides declarative command-line parsing with strong help output, validation, and subcommand support. Use it to build CLIs with predictable UX and testable execution paths.

Quick Start

Minimal CLI

Correct: derive Parser

use clap::Parser;

#[derive(Parser, Debug)]
#[command(name = "mytool", version, about = "Example CLI")]
struct Args {
    /// Enable verbose output
    #[arg(long)]
    verbose: bool,

    /// Input file path
    #[arg(value_name = "FILE")]
    input: String,
}

fn main() {
    let args = Args::parse();
    if args.verbose {
        eprintln!("verbose enabled");
    }
    println!("input={}", args.input);
}

Wrong: parse multiple times

fn main() {
    let _a = Args::parse();
    let _b = Args::parse(); // duplicate parsing and inconsistent behavior
}

Subcommands (real tools)

Model multi-mode CLIs with subcommands and shared global flags.

Correct: global flags + subcommands

use clap::{Parser, Subcommand, ValueEnum};

#[derive(Parser, Debug)]
struct Args {
    #[arg(long, global = true)]
    verbose: bool,

    #[arg(long, global = true, env = "MYTOOL_CONFIG")]
    config: Option<String>,

    #[command(subcommand)]
    cmd: Command,
}

#[derive(Subcommand, Debug)]
enum Command {
    Serve { #[arg(long, default_value_t = 3000)] port: u16 },
    Migrate { #[arg(long, value_enum, default_value_t = Mode::Up)] mode: Mode },
}

#[derive(Copy, Clone, Debug, ValueEnum)]
enum Mode { Up, Down }

fn main() {
    let args = Args::parse();
    match args.cmd {
        Command::Serve { port } => println!("serve on {}", port),
        Command::Migrate { mode } => println!("migrate: {:?}", mode),
    }
}

Config layering (CLI + env + config file)

Prefer explicit precedence:

  1. CLI flags
  2. Environment variables
  3. Config file
  4. Defaults

Correct: merge config with CLI overrides

use clap::Parser;
use serde::Deserialize;

#[derive(Parser, Debug)]
struct Args {
    #[arg(long, env = "APP_PORT")]
    port: Option<u16>,
}

#[derive(Deserialize)]
struct FileConfig {
    port: Option<u16>,
}

fn effective_port(args: &Args, file: &FileConfig) -> u16 {
    args.port.or(file.port).unwrap_or(3000)
}

Exit codes and error handling

Map failures to stable exit codes. Return Result from command handlers and centralize printing.

Correct: command returns Result

use std::process::ExitCode;

fn main() -> ExitCode {
    match run() {
        Ok(()) => ExitCode::SUCCESS,
        Err(e) => {
            eprintln!("{e}");
            ExitCode::from(1)
        }
    }
}

fn run() -> Result<(), String> {
    Ok(())
}

Testing (assert_cmd)

Test the binary surface (arguments, output, exit codes) without coupling to internals.

Correct: integration test

use assert_cmd::Command;

#[test]
fn shows_help() {
    Command::cargo_bin("mytool")
        .unwrap()
        .arg("--help")
        .assert()
        .success();
}

Shell completions (optional)

Generate completions for Bash/Zsh/Fish.

Correct: emit completions

use clap::{CommandFactory, Parser};
use clap_complete::{generate, shells::Zsh};
use std::io;

fn print_zsh_completions() {
    let mut cmd = super::Args::command();
    generate(Zsh, &mut cmd, "mytool", &mut io::stdout());
}

Anti-Patterns

  • Parse arguments in library code; parse once in main and pass a typed config down.
  • Hide failures behind unwrap; return stable exit codes and structured errors.
  • Overload one command with flags; use subcommands for distinct modes.

Resources

Use it

Copy one of these into your project. Installing also returns the manifest and these snippets.

yaml
targets:
  - https://api.opensmartroute.ai/api/v1/registry/bobmatnyc-claude-mpm-skills-clap/manifest   # or paste the manifest below

Manifest

An Open Capability Manifest: the router reads it to know what this does, what it costs and when to pick it.

bobmatnyc-claude-mpm-skills-clap.ocm.jsonjson
{
  "ocm": "1",
  "id": "bobmatnyc-claude-mpm-skills-clap",
  "kind": "skill",
  "name": "clap",
  "description": "Build production Rust CLIs with Clap: subcommands, config layering, validation, exit codes, shell completions, and testable command surfaces",
  "publisher": "bobmatnyc",
  "version": "1.0.0",
  "capabilities": {
    "domains": [
      "coding"
    ],
    "tags": [
      "skill-md",
      "rust",
      "cli",
      "clap",
      "config",
      "testing",
      "skills-sh"
    ],
    "languages": [
      "en"
    ]
  },
  "quality_prior": 0.6,
  "examples": [
    "Build production Rust CLIs with Clap: subcommands, config layering, validation, exit codes, shell completions, and testable command surfaces"
  ],
  "primary": false,
  "metadata": {
    "source": {
      "provider": "skills.sh",
      "repository": "https://github.com/bobmatnyc/claude-mpm-skills",
      "path": "toolchains/rust/cli/clap/SKILL.md",
      "ref": "HEAD",
      "url": "https://github.com/bobmatnyc/claude-mpm-skills/blob/HEAD/toolchains/rust/cli/clap/SKILL.md",
      "key": "bobmatnyc/claude-mpm-skills/toolchains/rust/cli/clap/SKILL.md"
    },
    "license": "MIT"
  },
  "instructions": "# Clap (Rust) - Production CLI Patterns\n\n## Overview\n\nClap provides declarative command-line parsing with strong help output, validation, and subcommand support. Use it to build CLIs with predictable UX and testable execution paths.\n\n## Quick Start\n\n### Minimal CLI\n\n✅ **Correct: derive Parser**\n```rust\nuse clap::Parser;\n\n#[derive(Parser, Debug)]\n#[command(name = \"mytool\", version, about = \"Example CLI\")]\nstruct Args {\n    /// Enable verbose output\n    #[arg(long)]\n    verbose: bool,\n\n    /// Input file path\n    #[arg(value_name = \"FILE\")]\n    input: String,\n}\n\nfn main() {\n    let args = Args::",
  "cost": {
    "context_tokens": 943
  }
}

Fetch it by URL: GET /api/v1/registry/bobmatnyc-claude-mpm-skills-clap/manifest?version=1.0.0

Reviews

Star ratings from people who tried it. One review per account; edit yours any time.

No reviews yet. Install it, try it, and be the first to rate it.