Skip to main content

cli

CLI application design: argument conventions, output streams, exit codes, configuration hierarchy, interactive modes, and terminal UX. Invoke whenever task involves any interaction with command-line tools or terminal applications — building, reviewing, debugging, or designing CLI interfaces.

Source facts

Repository
xobotyi/cc-foundry
Last source activity
August 23, 2026 at 23:46
Detected SKILL.md language
English
Stars
22
Forks
0

Install options

The review-first prompt is selected by default. You can switch to a direct command or download a local copy.

Review the source files

Read SKILL.md and any companion files shown by SkillsMP before deciding whether to install.

File Explorer
8 files

Showing SKILL.md

SKILL.md
Source instructions · Read-only preview
name
cli
description
CLI application design: argument conventions, output streams, exit codes, configuration hierarchy, interactive modes, and terminal UX. Invoke whenever task involves any interaction with command-line tools or terminal applications — building, reviewing, debugging, or designing CLI interfaces.
# CLI Design **Programs are composable by default.** stdout carries data, stderr carries diagnostics, exit codes carry status, and signals carry intent. Get the boundaries right and everything else follows. ## References - **Arguments** [`${CLAUDE_SKILL_DIR}/references/arguments.md`] — Full POSIX guidelines, GNU long option table, subcommand patterns, flag design - **Output** [`${CLAUDE_SKILL_DIR}/references/output.md`] — Stream separation details, color codes, ANSI escapes, NO_COLOR spec, pager setup - **Exit codes** [`${CLAUDE_SKILL_DIR}/references/exit-codes.md`] — Standard/extended code tables, signal exit codes, partial success patterns - **Interaction** [`${CLAUDE_SKILL_DIR}/references/interaction.md`] — TTY detection, prompting patterns, confirmation levels, progress display, error format - **Configuration** [`${CLAUDE_SKILL_DIR}/references/configuration.md`] — Full hierarchy, XDG spec, env var catalog, config file formats, secret handling - **Signals** [`${CLAUDE_SKILL_DIR}/references/signals.md`] — Full signal table, SIGPIPE handling, crash-only design, child process signals ## Output Streams This is the single most important convention. Mixing data and diagnostics in stdout is the #1 way to break composability. - **stdout is data.** Primary output goes to stdout -- query results, computed values, formatted data. This is what gets piped to the next command or redirected to a file. - **stderr is diagnostics.** Progress indicators, status messages, warnings, errors, and debug output go to stderr. Users see stderr in the terminal even when stdout is redirected. - **Check each stream independently.** stdout may be piped while stderr is still a TTY. Adapt output format per-stream: human-readable when TTY, machine-parseable when piped. - **No animations when not a TTY.** Disable spinners, progress bars, and color when the target stream is not an interactive terminal. This prevents CI logs from becoming escape-code garbage. - **Print something within 100ms.** Before any network request or long operation, print a status line to stderr. Silence looks like a hang. - **Tell the user what changed.** When a command modifies state, describe what happened and suggest what to do next. ## Arguments - **POSIX short flags, GNU long flags.** Single-letter options use `-x`, multi-letter use `--long-name`. Every short flag must have a long equivalent. Reserve one-letter flags for frequently-used options. - **`--` terminates options.** Everything after `--` is an operand, even if it starts with `-`. This is POSIX Guideline 10 and is non-negotiable. - **Prefer flags over positional arguments.** Flags are self-documenting. Exception: primary action on a single target (`rm file.txt`, `cat file.txt`). Two or more positional args for different things is a design smell. - **`-` means stdin/stdout.** When a command accepts file arguments, `-` means read from stdin (or write to stdout when context is clear). - **Use standard flag names.** `-h`/`--help`, `--version`, `-v`/`--verbose`, `-q`/`--quiet`, `-f`/`--force`, `-n`/`--dry-run`, `-o`/`--output`, `--json`, `--no-color`, `--no-input`. Don't reinvent these. - **Make flags order-independent.** Users add flags by pressing up-arrow and appending. `mycmd --flag subcmd` and `mycmd subcmd --flag` should both work where possible. ## Subcommands - **`noun verb` or `verb noun`, pick one and be consistent.** Don't mix ordering styles. `docker container create` and `docker image pull` follow `noun verb`. - **Support help at every level.** `mycmd --help`, `mycmd subcmd --help`, and `mycmd help subcmd` should all work. - **No catch-all subcommand.** Don't interpret unknown first arguments as an implicit default subcommand. This prevents you from ever adding new subcommands. - **No arbitrary abbreviations.** If `mycmd i` aliases `mycmd install`, you can never add `mycmd init`. Aliases must be explicit and stable. ## Exit Codes - **0 = success, 1 = error, 2 = usage error.** This covers most programs. Only define additional codes when callers need to distinguish specific failure modes. - **Signal exit codes use 128+N.** SIGINT (Ctrl-C) exits 130, SIGTERM exits 143. Preserve this convention so calling scripts can distinguish "user cancelled" from "error." - **Never return 0 on failure.** Scripts depend on exit codes via `$?` and `set -e`. A false success silently breaks pipelines. ## Configuration - **Flags > env vars > project config > user config > system config > defaults.** This is the universal precedence hierarchy. A flag always wins over an env var, which always wins over a config file. - **Follow XDG for user-level files.** Use `$XDG_CONFIG_HOME/myapp/` (default `~/.config/myapp/`), not `~/.myapp`. Respect `XDG_DATA_HOME`, `XDG_STATE_HOME`, `XDG_CACHE_HOME`. - **Respect well-known environment variables.** `NO_COLOR`, `FORCE_COLOR`, `DEBUG`, `EDITOR`, `PAGER`, `HTTP_PROXY`/`HTTPS_PROXY`, `TMPDIR`, `HOME`, `TERM`, `LINES`, `COLUMNS`. Check these before inventing app-specific alternatives. - **Never read secrets from environment variables.** They leak through `ps`, Docker inspect, systemd, and process listings. Accept secrets via `--password-file`, stdin, or a credential helper. - **Never read secrets from flags.** `--password=secret` leaks into `ps` output and shell history. Use `--password-file` or stdin. ## Color and Terminal Output - **Disable color when:** stdout/stderr is not a TTY (check each independently), `NO_COLOR` is set and non-empty, `TERM=dumb`, or `--no-color` is passed. - **Support `FORCE_COLOR` or `--color`** to override detection and force color output when the user explicitly wants it. - **Use color intentionally.** Red for errors, green for success, yellow for warnings. Don't paint everything -- if everything is colored, nothing stands out. - **Use a color library.** Don't hand-code ANSI escape sequences. Libraries handle NO_COLOR, TERM detection, and cross-platform differences. ## Interactive Behavior - **Only prompt when stdin is a TTY.** If stdin is not interactive, fail with an error telling the user which flag to pass. Never hang waiting for input that will never come. - **Provide `--no-input`.** An explicit flag to disable all prompts. Required for CI/CD, cron, and automation. - **Confirm before destructive actions.** Prompt for `y/N` interactively, require `--force` non-interactively. For severe operations (deleting infrastructure), require typing the resource name. - **Provide `--dry-run`.** For any state-modifying command, let users preview what would happen without executing it. - **Don't echo passwords.** Disable terminal echo when accepting secret input. Provide `--password-file` as a non-interactive alternative. ## Signal Handling - **Respond to SIGINT immediately.** Print "Shutting down..." before starting cleanup. Add a timeout so cleanup can't hang forever. - **Second Ctrl-C skips cleanup.** Tell the user: "press Ctrl+C again to force." Then exit immediately. - **Handle SIGTERM like SIGINT.** Process managers (systemd, Docker, K8s) send SIGTERM before SIGKILL. Complete cleanup within the grace period. - **Handle SIGPIPE silently.** When the user pipes your output to `head`, don't print an error when the pipe closes. Exit quietly with code 141 or 0. - **Design for crash recovery.** Use atomic file operations (write to temp, rename). Check for incomplete state on startup. Don't require cleanup to complete for correctness. ## Help Text - **Support `-h` and `--help`.** Both must show help. Don't overload `-h` for anything else. - **Show concise help with no arguments.** When a command requires arguments and gets none, show a brief description, one or two examples, and a pointer to `--help` for the full listing. - **Lead with examples.** Users read examples first. Show common invocations before the flag catalog. - **Suggest corrections.** When the user types a close misspelling, suggest the correct command. Don't auto-execute the suggestion. - **Support `--version`.** Print the version and exit. Format: program name and version, optionally with build metadata. ## Error Messages - **Structure errors consistently.** Use a format like: `error: <what went wrong>` followed by `hint: <how to fix it>`. - **Be actionable.** Don't say "permission denied" -- say "permission denied; run with sudo or use --config-dir for a writable location." - **Put important information last.** The eye lands at the bottom of output. Put the error summary and fix there, not the stack trace. - **No stack traces by default.** Put them behind `--verbose` or write to a debug log file. Signal-to-noise ratio matters. - **Make bug reporting easy.** For unexpected errors, provide a URL or command to file a bug, pre-populated with diagnostic information. ## Structured Output - **Support `--json` for machine-readable output.** Output well-formed JSON to stdout. Use consistent field names across commands. - **Support `--plain` for scriptable tabular output.** One record per line, no color, no decorations. Useful for `grep` and `awk` pipelines. - **Use a pager for large output.** Pipe through `less -FIRX` when stdout is a TTY. Respect the `PAGER` environment variable. Don't page when output fits one screen. ## Robustness - **Validate input early.** Check arguments and flags before starting work. Report all validation errors at once, not one at a time. - **Make operations idempotent where possible.** Running the same command twice should produce the same result, not an error or doubled state. - **Make operations recoverable.** If the program fails partway through, the user can hit up-arrow and enter to retry from where it left off. - **Set network timeouts.** Allow timeout configuration and have a reasonable default. Never hang indefinitely on a network call. ## Naming - **Lowercase, short, memorable.** `curl` not `DownloadURL`. Use only lowercase letters and hyphens. Keep it easy to type. - **Avoid ambiguous subcommand names.** Don't have both "update" and "upgrade". Use distinct verbs or disambiguate with extra words. ## Future-Proofing - **Keep changes additive.** Add new flags rather than changing existing behavior. If you must break compatibility, warn in advance. - **Warn before deprecation.** When a user invokes a deprecated flag, tell them what to use instead and when the old form will be removed. - **Changing human-readable output is OK.** Encourage `--json` or `--plain` for scripts. Human-readable output is not a stable interface. ## Application When **writing** CLI code: - Apply all conventions silently. Don't narrate each rule. - Use an argument parsing library (clap, cobra, argparse, commander). - Wire up stdout/stderr correctly from the start. Retrofitting is painful. - Handle SIGINT/SIGTERM from day one. Don't defer signal handling. When **reviewing** CLI code: - Check stdout vs stderr usage first. This is the most common mistake. - Verify exit codes match actual success/failure. - Confirm `--help`, `--version`, and `--no-color` are supported. - Look for secret leaks in flags and env vars. ## Integration This skill covers CLI platform concerns -- the interface between a program and the terminal/shell/pipeline. Language-specific implementation details (argument parsing libraries, terminal I/O APIs) come from language skills (golang, javascript, etc.). The coding discipline skill governs general workflow. **Programs are composable when they respect boundaries.**
View on GitHub