This skill guides creation of command-line interfaces that respect users' time and intelligence. Implement real working CLIs with exceptional attention to ergonomics, error handling, and composability.
The user provides CLI requirements: a tool, script, or terminal application to build. They may include context about the purpose, target users, or technical constraints.
Before coding, understand the context and commit to a clear interaction model:
- Purpose: What task does this tool accomplish? How often will users run it?
- Users: Power users who'll alias it? Occasional users who'll forget flags? Scripts and automation?
- Scope: Single-purpose tool or multi-command suite? Pipes and composition or standalone?
- Personality: Minimal and silent? Friendly and helpful? Technical and precise?
CLIs are conversations. Every invocation is a turn in a dialogue. Design for the user who runs your command wrong the first time—that's the normal case.
Then implement working code that is:
- Production-grade and robust to unexpected input
- Respectful of platform conventions (POSIX, GNU, XDG)
- Helpful when things go wrong
- Composable with pipes, scripts, and other tools
Progressive Disclosure
Simple by default, power available. The 90% use case should require zero flags. Advanced options exist but don't clutter basic usage.
Process files efficiently.
Options: -o, --output Output location (default: stdout) -h, --help Show this help
Run 'mytool --help-all' for advanced options.
Error Messages
Errors are teaching moments. Tell users what went wrong, why, and how to fix it.
Did you mean one of these? ./configs/config.yaml ./config.yml
Run 'mytool --help' for usage.
Output Design
Human-readable by default. Machine-readable on request.
Machine (--json)
$ mytool status --json {"database":{"ok":true,"latency_ms":15},"cache":{"ok":true,"latency_ms":3},"api":{"ok":false,"error":"timeout"}}
Respect TTY detection—no colors in pipes. Confirm state changes ("Created config.json"). Show progress for anything over 1 second.
Flag Conventions
- Long flags for clarity (
--output), short flags for frequency (-o) - Standard names:
--help,--version,--verbose,--quiet,--dry-run,--force,--json - Boolean flags don't take values
- Order-independent flags
$ mytool -v process data.csv # -v = --verbose $ mytool process data.csv -v # same result, order doesn't matter $ mytool --dry-run delete old/ # shows what would be deleted
Argument Design
- Prefer flags over positional args for non-obvious inputs
- Support
-for stdin/stdout - Validate early, fail fast with clear messages
- Provide flag alternatives for every prompt
Configuration Hierarchy
Apply configuration in this order: Flags → Environment → Project config → User config → Defaults.
Avoid hostile errors that leave users stranded:
- "Error: invalid input" → Instead: name the invalid input and suggest corrections
- Exit code 1 for everything → Instead: use distinct codes (1=user error, 2=system error, etc.)
- Stack traces as errors → Instead: catch exceptions and print human messages
Avoid breaking conventions that users expect:
-helpinstead of--help→ Use GNU-style double-dash for long flags- Requiring flag order → Let
cmd -v fileandcmd file -vwork the same - Secrets in flags → Read from stdin, files, or env vars instead
Avoid user-hostile defaults:
- Destructive operations without confirmation → Add
--forceto skip confirmation - Silent failures → Always indicate success or failure
- Mandatory prompts → Provide
--yesor flag alternatives
Avoid output crimes:
- Colors in non-TTY → Check
isatty()and respectNO_COLOR - Progress bars that break pipes → Detect when output isn't a terminal
- Mixing data and messages on stdout → Data to stdout, messages to stderr
Your CLI is well-designed when:
- First-time users succeed: Running
cmd --helpgives them enough to complete basic tasks - Errors guide recovery: Every error message answers "what happened?" and "what should I try?"
- Scripts work reliably: Exit codes are meaningful, output is parseable with
--json, no interactive prompts block automation - Power users stay efficient: Short flags exist for common options, shell completion works, config files reduce typing
- It composes well: Reads from stdin, writes to stdout, plays nicely in pipelines
A single-purpose tool needs minimal flags and maximum clarity—think cat, wc, head.
A multi-command suite needs consistent subcommand structure, shared flags, and shell completions—think git, docker, kubectl.
Don't add a plugin system to a grep replacement. Don't force a simple tool into a subcommand hierarchy it doesn't need.
The best CLIs feel like they were written by someone who uses the terminal 8 hours a day and has strong opinions about what makes tools pleasant to use. Channel that energy.
Converted and distributed by TomeVault — claim your Tome and manage your conversions.