Common patterns for building effective CLIs, derived from industry best practices.
- Topics are plural nouns:
apps,addons,regions - Commands are verbs:
create,list,delete - Use kebab-case for multi-word names:
config-vars
# Good: Flags with clear labels
mytool deploy --environment production --region us-west
# Bad: Positional arguments
mytool deploy production us-west- Prefer flags over positional arguments
- Provide both long (
--help) and short (-h) versions - Use standard flag names across commands
Error: Cannot connect to database
Connection refused at localhost:5432
Possible solutions:
1. Check if PostgreSQL is running
2. Verify connection settings in config.yml
Documentation: https://docs.app.com/errors/db-001Structure:
- Clear problem statement
- Technical details
- Actionable solutions
- Link to documentation
0- Success1- General error2- Misuse of shell command126- Command cannot execute127- Command not found130- Script terminated by Ctrl+C
# Interactive terminal: Rich output
$ mytool list
NAME STATUS UPDATED
app-1 ● live 2 hours ago
app-2 ◐ deploy 5 mins ago
# Pipe/redirect: Plain output
$ mytool list | grep live
app-1 live 2024-01-15T10:30:00Z- Use color only when outputting to a TTY
- Respect
NO_COLORenvironment variable - Provide
--no-colorflag - Use color semantically (red=error, green=success)
# Human format (default)
$ mytool status
Service: healthy
Uptime: 3 days
# JSON format
$ mytool status --json
{"service":"healthy","uptime_days":3}
# Custom format
$ mytool status --format "{{.Service}} - {{.Uptime}}"
healthy - 3 daysFor operations longer than 1 second:
# Spinner for indeterminate progress
$ mytool process
Processing... ⠼
# Progress bar for determinate progress
$ mytool upload large-file.zip
Uploading... [████████░░] 80% (12.3MB/15.4MB)
# Status updates
$ mytool deploy
✓ Validated configuration
✓ Built application
→ Deploying to production...# Prompt with defaults
$ mytool init
Project name [my-app]:
Language [auto-detected: python]:
Initialize git repository? [Y/n]:
# Non-interactive mode
$ mytool init --name my-project --language python --git# Destructive operations require confirmation
$ mytool delete production-db
⚠ Warning: This will permanently delete 'production-db'
Type the database name to confirm: production-db
✓ Database deleted# Every command must have help
$ mytool --help
$ mytool deploy --help
# Help format
Usage: mytool deploy [OPTIONS]
Deploy application to specified environment
Options:
-e, --environment TEXT Target environment (dev/staging/prod)
-f, --force Skip confirmation prompts
-h, --help Show this help message
Examples:
# Deploy to staging
mytool deploy --environment staging
# Force deploy to production
mytool deploy -e prod --force$ mytool init
✓ Created project structure
✓ Initialized configuration
Next steps:
1. cd my-app
2. mytool install
3. mytool dev
Run 'mytool tutorial' for a guided walkthroughEvery CLI should support:
--help/-h- Show help information--version/-v- Show version information--verbose- Increase output verbosity--quiet/-q- Suppress non-error output
These patterns are derived from:
- clig.dev - Modern CLI guidelines
- Heroku CLI Style Guide - Practical conventions
- Atlassian's 10 Principles - UX patterns
- GNU Standards - Foundational conventions