click
Composable command line interface creation toolkit for Python — creates CLI tools with decorators, handles argument parsing, generates help text, and supports complex CLI hierarchies. click features: @click.command(), @click.group() for multi-command CLIs, @click.option() and @click.argument() decorators, types (INT, FLOAT, STRING, BOOL, UUID, Path, File, DateTime), multiple=True for multi-value options, required=True, default=, envvar= for env var fallback, prompt=True for interactive input, password=True for hidden input, confirmation prompts, custom callbacks, lazy loading, click.echo() for output, click.style()/click.secho() for colored output, testing via CliRunner, and progressbar.
Score Breakdown
⚙ Agent Friendliness
🔒 Security
CLI framework. password=True hides input from terminal echo. envvar= for secrets reads from environment (better than CLI args visible in ps). hide_input=True equivalent. Do not log CLI argument values that may contain secrets.
⚡ Reliability
Best When
Production CLI tools needing robust argument handling, nested subcommands, and extensive testing — click is the standard for Python CLI tools with excellent documentation and testing support.
Avoid When
Quick scripts (use fire), type-hint-first CLIs (use typer), or when argparse's stdlib advantage matters.
Use Cases
- • Agent CLI tool — import click; @click.command(); @click.option('--count', default=10, help='Number of items'); @click.option('--output', type=click.Path(), required=True, help='Output file'); @click.argument('input_file'); def process(count, output, input_file): data = load(input_file); results = compute(data, count); save(output, results); if __name__ == '__main__': process() — CLI; agent creates CLI with typed options
- • Agent multi-command — @click.group(); def cli(): pass; @cli.command(); @click.option('--verbose', is_flag=True); def fetch(verbose): do_fetch(verbose); @cli.command(); def process(): do_process(); if __name__ == '__main__': cli() — group; agent creates multi-subcommand CLI (like git); cli fetch --verbose; cli process
- • Agent interactive input — @click.command(); @click.option('--name', prompt='Your name', help='The person to greet'); @click.option('--count', prompt=True, type=int, default=1); def greet(name, count): for _ in range(count): click.echo(f'Hello, {name}!') — prompt; agent interactively collects missing options from user
- • Agent env var options — @click.command(); @click.option('--api-key', envvar='API_KEY', required=True, hide_input=True); @click.option('--endpoint', envvar='API_ENDPOINT', default='https://api.example.com'); def run(api_key, endpoint): call_api(api_key, endpoint) — env vars; agent reads config from environment variables with CLI override
- • Agent file processing — @click.command(); @click.argument('input', type=click.File('r')); @click.argument('output', type=click.File('w')); def transform(input, output): for line in input: output.write(process(line)) — file streams; agent reads/writes files with automatic stream handling; use '-' for stdin/stdout
Not For
- • Zero-config CLI — fire is simpler for wrapping existing functions with minimal code
- • Type-hint-first CLI — typer generates CLI from type annotations; click uses decorators
- • Complex validation pipelines — click handles basic types; for complex validation combine with pydantic
Interface
Authentication
No auth — CLI framework.
Pricing
click is BSD 3-Clause licensed. Free for all use.
Agent Metadata
Known Gotchas
- ⚠ pass_context=True for accessing Context object — @click.command(); @click.pass_context; def cmd(ctx, ...): ctx.obj; stores shared data between commands; @click.group(); @click.pass_context; def cli(ctx): ctx.ensure_object(dict) — group pattern; agent multi-command CLIs pass shared state via context object; ctx.obj is the shared data dict
- ⚠ invoke_without_command=True for group with default action — @click.group(invoke_without_command=True) allows group to run code when no subcommand given; @click.pass_context; def group(ctx): if ctx.invoked_subcommand is None: do_default(); agent code: add default behavior when user runs just the group name without subcommand
- ⚠ standalone_mode=False to prevent sys.exit() — click calls sys.exit(0) on success by default (standalone_mode=True); standalone_mode=False returns return value instead; for embedding in tests or other code: runner.invoke(cli, catch_exceptions=False) or cli(standalone_mode=False); agent testing: use CliRunner.invoke()
- ⚠ option names with dashes become underscores — @click.option('--my-option') passes as my_option parameter (dashes to underscores); @click.option('--my-option', 'my_option_name') overrides parameter name; agent code: use dashes in CLI option names for POSIX style (--my-option); Python parameter receives underscore version automatically
- ⚠ is_flag=True creates boolean toggle — @click.option('--verbose/--no-verbose', default=False) — pair; @click.option('--verbose', is_flag=True) — single flag; agent code: --verbose sets True, not present = False; count=True for --verbose -v -vvv to count occurrences; is_eager=True for options that should be processed before others (--version)
- ⚠ CliRunner for testing does not write to terminal — from click.testing import CliRunner; runner = CliRunner(); result = runner.invoke(cli, ['--option', 'value']); result.exit_code; result.output; result.exception; agent code testing CLIs: use CliRunner — catches sys.exit, captures output, handles input; result.exit_code == 0 for success; check result.output for output
Alternatives
Full Evaluation Report
Detailed scoring breakdown, competitive positioning, security analysis, and improvement recommendations for click.
Scores are editorial opinions as of 2026-03-06.