From charlesreid1

A guide from Heroku containing 12 principles for creating great CLI apps: https://medium.com/@jdxcode/12-factor-cli-apps-dd3c227a0e46

Rule 1: Great help is essential

show help with all of these:

# list all commands
$ mycli
$ mycli --help
$ mycli help
$ mycli -h

# get help for subcommand
$ mycli subcommand --help
$ mycli subcommand -h

Also consider shell completion!

Auto-documentation:

Autodoc.png

Rule 2: Prefer flags to arguments

Two ways for user to provide input: (positional) arguments, and flags.

Flags require a bit more typing, but make the CLI much clearer.

Example:

$ heroku fork --from FROMAPP --to TOAPP

Rule of thumb: 1 type of argument is fine, 2 types are very suspect, and 3 are never good.

If you pass off flags to another process, use -- argument to denote it should stop parsing arguments there and pass the rest of the arguments to the other process.

Rule 3: Make version number easy to find

Make all of these print the version:

$ mycli version # multi only
$ mycli --version
$ mycli -V

Rule 4: Mind stdout and stderr

Important to direct errors and messages to correct place

Example:

$ myapp > foo.txt
Warning: something went wrong

Don't want warning to get buried, or to have a problem with structured output.

In short: stdout is for output, stderr is for messaging.

If you wrap a subcommand, always display the stderr from that command to the user.

Rule 5: Handle things going wrong

Things go wrong a lot, especially with CLIs

Error messages should contain:

  • error code
  • error title
  • error description
  • how to fix
  • url for more info

Example:

$ myapp dump -o myfile.out
Error: EPERM - Invalid permissions on myfile.out
Cannot write to myfile.out, file does not have write permissions.
Fix with: chmod +w myfile.out
https://github.com/jdxcode/myapp

Rule 6: Be fancy, know when to be fancy

Colors and dimming highlight important info

Spinners and progress bars inform user that program is still working

But be able to fall back to basic behavior (and know when to)

If user's stdout or stderr are not connected to tty, probably piping to file, so no colors. Also no spinny things. (they use ansi codes, which you don't want to output to a file.)

Let the user turn off fancy stuff with:

  • TERM=dumb
  • NO_COLOR being set
  • --no-color flag being used
  • MYAPP_NOCOLOR=1 environment variable for your CLI application alone

Rule 7: Accept input from user

If the stdin is a tty, then you can accept input from the user. This should not be required, though, to ensure the tool can be automated/scripted.

A good practice is to require user input for confirmation dialogs, if the action being taken is dangerous.

Check boxes and radio buttons can give user menus and make things a lot easier to use

Rule 8: Use tables

Not the fancy tables with borders. Something you can parse with cut and grep and other command line utilities.

Tables require thinking about screen width.

By default, only show a few columns. Give the user a --columns flag to control that, where they pass a comma separated list of columns.

Cut off rows that will spill over, and provide a --no-truncate option.

Show column headers but provide a --no-headers option.

Implement a --filter command line option to filter specific columns

Allow sorting by column with --sort


Rule 9: Be speedy

Use the time utility to time your CLI

    <100ms: very fast (sadly, not feasible for scripting languages)
    100ms–500ms: fast enough, aim here
    500ms-2s: usable, but not going to impress anyone
    2s+: languid, users will prefer to avoid your CLI at this point

Rule 10: Encourage contributions

Open source, contributions file, license, code of conduct, etc.

Rule 11: Be clear about subcommands

CLIs can be single command (like cp or grep)

Multi commands are like git, which have a subcommand as the first arg and then trailing arguments after that.

One basic task => single command CLI

Most CLIs would benefit from subcommands

If user does not pass any arguments:

  • list subcommands for multi-command CLIs
  • display the help for single-CLIs
  • don't take a default action

If you need subcommands below your subcommands, those are called "topics".

Git uses spaces:

$ git submodule add git@github.com:rainbow-mind-machine/rainbow-mind-machine

Heroku uses colons:

$ heroku domains:add www.myapp.com

Rule 12: Use XDG

XDG-spec: https://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html

XDG is a spec for figuring out where to put files.

Environment variables like XDG_CONFIG_HOME allow you to specify a config or data file location

If not specified, use ~/.config/myapp for config files, and ~/.local/share/myapp for data files.

Use ~/.cache/myapp for cache files on Unix. Use ~/Library/Caches/myapp on Mac. Use %LOCALAPPDATA%\myapp on Windows.

Flags