Skip to content

Building Command-Line Tools That People Actually Want to Use

November 22, 2024 · 2 min read

I've built a lot of command-line tools over the years, and I've learned that good CLI design is an art form. The best tools disappear into your workflow; the worst ones make you want to write a bash alias to avoid typing them.

Start with Good Help Text

Your --help output is your documentation. Make it count:

$ mycli --help
mycli - A tool that does something useful

USAGE:
    mycli [OPTIONS] <COMMAND>

COMMANDS:
    init        Initialize a new project
    build       Build the project
    deploy      Deploy to production

OPTIONS:
    -v, --verbose    Enable verbose output
    -q, --quiet      Suppress all output
    -h, --help       Print help information

Clear, organized, with examples. Don't make people guess what arguments do.

Provide Sensible Defaults

The tool should work with minimal configuration:

# Bad: requires everything
mycli --input file.txt --output result.txt --format json --indent 2

# Good: assumes sensible defaults
mycli file.txt  # outputs to file.json with pretty printing

Power users can override, but casual users shouldn't need to read the manual for basic operations.

Interactive Mode When It Makes Sense

For destructive operations, ask for confirmation:

fn delete_project(name: &str) -> Result<(), Error> {
    println!("This will permanently delete project '{}'", name);
    print!("Are you sure? (y/N): ");
    io::stdout().flush()?;

    let mut response = String::new();
    io::stdin().read_line(&mut response)?;

    if response.trim().to_lowercase() != "y" {
        println!("Cancelled.");
        return Ok(());
    }

    // Proceed with deletion
    fs::remove_dir_all(format!("./projects/{}", name))?;
    println!("Project '{}' deleted successfully.", name);
    Ok(())
}

But also provide --force for scripts and CI environments.

Progress Bars for Long Operations

Nothing is worse than staring at a blank terminal wondering if your command is frozen:

from tqdm import tqdm
import time

def process_files(files):
    for file in tqdm(files, desc="Processing"):
        # Do work
        time.sleep(0.1)

A simple progress bar tells users the tool is working and how long they'll wait.

Color and Formatting

Use color to draw attention to important information:

  • Green for success messages
  • Yellow for warnings
  • Red for errors
  • Bold for emphasis

But always provide a --no-color flag for CI environments and accessibility.

The Details Matter

Good CLI tools feel polished because the developers sweated the details. Tab completion, thoughtful error messages, consistent flag naming—these things add up to create tools that people reach for instead of dreading.

← Back to all posts