CLI Tools Highlights Summary
Every highlight bullet from the 10 pages in this section, gathered on one page and grouped by the page it came from.
- stdout, stderr, and exit codes are the real API of a CLI - everything else is convenience on top
- argparse, Click, and Typer are three implementations of the same POSIX/GNU argument grammar, not three different grammars
- TTY detection is why the same command looks different piped into a file than printed to a terminal
- Config precedence (flags over env over file over defaults) is a convention every well-behaved tool follows for the same reason
- A CLI that only works interactively isn't a complete CLI - scriptability is part of the contract, not an extra
- Use argparse instead of sys.argv for real command-line tools
- Exit code 0 signals success, non-zero signals failure to shell
- stdout carries data for piping, stderr carries visible logs
- argparse auto-generates help and validates argument types
- Environment variables configure 12-factor apps, flags override
- add_subparsers groups subcommands, each with separate arguments
- Use action=count for -v, -vv verbosity levels
- Pass argv to parse_args to test CLI without subprocess
- Require subparsers with required=True to enforce commands
- Load secrets from env at runtime, never in argparse defaults
- Raise SystemExit to return proper CLI exit codes
- Organize multi-command patterns with subparsers like deploy staging
- Use @click.group() to organize related commands into subcommands
- Decorators like click.Path and click.Choice validate input types and values
- Always use click.echo instead of print to avoid encoding issues on Windows
- Use @click.pass_context to access parent options through ctx.obj in subcommands
- Register CLI commands in [project.scripts] so users can install globally
- Test Click commands with CliRunner.invoke() instead of direct CLI invocation
- Type hints generate CLI arguments—str/int/bool/Enum/Path map automatically with validation
- Annotate every parameter or Typer cannot infer arguments correctly
- Use typer.Option for flags instead of bool positional arguments
- Install typer[all] for shell completion support or use uv add typer[all]
- Complex validation requires Pydantic models or callback validators, not just hints
- Pin Typer version in pyproject.toml due to breaking changes between releases
- Rich renders styled output readably without breaking script pipelines
- Output JSON via --json flag so scripts can parse your CLI results
- Use Console force_terminal False to strip ANSI codes in piped output
- Send progress bars and spinners to stderr, not stdout
- Use rich.logging.RichHandler instead of print for structured logs
- Honor NO_COLOR environment variable or provide a --plain output flag
- CLI flags override env vars, which override config file, overriding code defaults
- Never commit secrets in config files, always use env vars with .env in .gitignore
- Validate all config values at load time with Pydantic types, not at runtime
- Use env_prefix to namespace variables consistently, like INVOICE_API_KEY
- Limit CLI flags to common overrides, keep most settings in config files
- Filter secrets from debug output to prevent leaking credentials in logs
- Interactive prompts hang in CI without CI=true or --yes flag detection
- Default=False required on confirm() for destructive operations
- questionary.password() or click.prompt(hide_input=True) hides password input
- Every prompt needs CLI flag equivalent for non-interactive scripting
- questionary returns None on cancel - check result and exit gracefully
- Use Rich Console or UTF-8 terminal to fix Unicode display on Windows
- Use [project.scripts] entry points to map command names to callables for CLI distribution
- pipx creates isolated venv per tool to eliminate dependency conflicts between CLIs
- Set requires-python in pyproject.toml to block installation on unsupported Python versions
- Minimize dependencies and use lazy imports to speed up pipx install times
- Document shell completion in README and help epilog so users discover it
- Use semver and deprecation warnings to avoid breaking CLI scripts on version bumps
- Use subcommands for verbs, not flags like --deploy
- Make exit codes meaningful: 0 for success, distinct failures
- Direct data to stdout, logs to stderr for piping
- Flags override env vars which override config files
- Never store secrets in config files, use environment only
- Confirm destructive actions with default No to prevent accidents
Y29kZWd1aWRlcy5pb3xjZ2lvNjI5fDIwMjYwNw
Revisado por Chris St. John·Última actualización: 31 jul 2026