Unix Philosophy
Do one thing and do it well.
Accept input from stdin where applicable; write output to stdout; errors to stderr.
Silent on success unless -v / --verbose is passed.
Exit 0 on success; non-zero on failure. Use distinct exit codes for distinct failure modes.
Interface
--help and --version are mandatory.
Support --dry-run for any destructive or irreversible operation.
No interactive prompts in non-TTY environments (detect with isatty).
Prefer long flags (--output) with short aliases (-o).
Use a proper CLI framework: cobra (Go), CLI11 (C++), picocli (Java).
Output
Support --output json (or similar) for machine-readable output; human-readable is the default.
Never mix diagnostic or progress output with data output on stdout.
Error Reporting
Errors go to stderr with enough context to diagnose without consulting logs.
Refer users to --debug or --verbose for more detail.
Build the stderr text and any --output json error payload from a structured error's fields
(code, context) at the CLI boundary — don't let one pre-formatted string be the only source for
both the human-readable and the machine-readable representation (see error_handling.md).
Directives
--help and --version are mandatory; use cobra (Go), CLI11 (C++), or picocli (Java)
Silent on success; errors to stderr; exit 0 on success, non-zero on failure with distinct codes
Build stderr and --output json error output from a structured error's fields at the boundary,
not from one pre-formatted string
No interactive prompts in non-TTY environments (detect with isatty)
--dry-run for destructive or irreversible operations
--output json for machine-readable output; never mix diagnostic output with data on stdout
Back to top