CLI Guidelines - Designing Great Command-Line Interfaces

CLI Guidelines

Comprehensive guide for creating user-friendly command-line tools:

Core Design Principles:

Human-First Design:

  • Helpful by Default: Show useful information without being asked
  • Fail Gracefully: Clear error messages with actionable suggestions
  • Consistent Behavior: Follow established conventions
  • Progressive Disclosure: Start simple, allow complexity when needed

Error Handling Best Practices:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
# Bad error message
error: invalid input

# Good error message  
error: expected a number, got "hello"
Try: mycommand --count 5

# Even better with suggestions
error: unknown flag '--hep'
Did you mean '--help'?

# Excellent with context
error: cannot connect to database
  database: postgresql://localhost:5432/myapp
  reason: connection refused
  help: is PostgreSQL running? try 'brew services start postgresql'

Guidelines by Category:

Arguments and Flags:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
# Prefer flags over positional arguments for clarity
# Good
deploy --environment staging --version 1.2.3

# Less clear
deploy staging 1.2.3

# Support both short and long forms
grep -r --recursive      # Both work
grep -R --recursive      # Consistent

# Use consistent flag naming
--verbose / -v           # Standard conventions
--quiet / -q
--help / -h
--version / -V (capital for version)

Output and Feedback:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
# Show progress for long operations
Downloading... [โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆ] 100% (15.2 MB/s)

# Provide machine-readable output options
mycommand --format json
mycommand --format csv
mycommand --format table  # Human-readable default

# Color coding (but respect NO_COLOR)
โœ“ Success: Database backup completed
โš  Warning: Low disk space  
โœ— Error: Connection failed

# Quiet modes for scripts
mycommand --quiet         # No output on success
mycommand --silent        # Minimal output

Configuration and Environment:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
# Configuration hierarchy (most to least specific)
1. Command-line flags
2. Environment variables  
3. Configuration files
4. Defaults

# Environment variable naming
MYAPP_DATABASE_URL
MYAPP_LOG_LEVEL
MYAPP_CONFIG_PATH

# Config file locations (XDG spec)
~/.config/myapp/config.yaml    # Primary
~/.myapp.yaml                  # Fallback
/etc/myapp/config.yaml         # System-wide

Advanced Features:

Interactive Elements:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
# Example: Interactive confirmation
import click

@click.command()
@click.option('--force', is_flag=True, help='Skip confirmation')
def delete_database(force):
    if not force:
        click.confirm('This will delete all data. Continue?', abort=True)
    
    with click.progressbar(tables, label='Dropping tables') as bar:
        for table in bar:
            drop_table(table)
    
    click.secho('โœ“ Database deleted', fg='green')

# Tab completion support
@click.command()
@click.argument('environment', type=click.Choice(['dev', 'staging', 'prod']))
def deploy(environment):
    """Deploy to specified environment."""
    pass

Documentation Integration:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
# Multi-level help
mycommand --help              # Overview
mycommand deploy --help       # Subcommand help
mycommand --help-advanced     # Advanced options

# Examples in help text
Usage: git-deploy [OPTIONS] ENVIRONMENT

  Deploy application to specified environment.

  Examples:
    git-deploy staging
    git-deploy prod --version 1.2.3
    git-deploy dev --force --no-backup

Options:
  --version TEXT    Specific version to deploy
  --force          Skip safety checks
  --no-backup      Skip database backup
  --help           Show this message and exit.

Parinfer - Revolutionary Lisp Editing

Parinfer - simpler Lisp editing

Innovative approach to editing Lisp code that infers parentheses from indentation:

The Parentheses Problem:

Traditional Lisp Editing Challenges:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
;; Traditional Lisp - parentheses can be overwhelming
(defn factorial [n]
  (if (<= n 1)
    1
    (* n (factorial (- n 1)))))

;; Easy to have mismatched parens
(defn broken [x]
  (if (> x 0)
    (inc x)
    (dec x))  ; Missing closing paren somewhere?

Parinfer Modes:

Indent Mode:

  • Indentation drives structure: Parentheses inferred from indentation
  • Writing-focused: Natural for entering new code
  • Familiar: Works like Python or other indentation-based languages
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
;; Type this (without worrying about parens):
defn factorial [n]
  if (<= n 1)
    1
    * n (factorial (- n 1))

;; Parinfer automatically adds parens:
(defn factorial [n]
  (if (<= n 1)
    1
    (* n (factorial (- n 1)))))

Paren Mode:

  • Parentheses drive structure: Indentation adjusted to match parens
  • Editing-focused: Good for modifying existing code
  • Traditional: Familiar to experienced Lisp programmers
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
;; Move a closing paren:
(defn example [x]
  (if (> x 0)
    (inc x))
    (dec x))

;; Parinfer adjusts indentation:
(defn example [x]
  (if (> x 0)
    (inc x)
    (dec x)))

Smart Features:

Cursor-Based Inference:

1
2
3
4
5
6
7
8
;; Cursor position affects paren inference
;; Cursor at end of line:
(map inc [1 2 3|])
;; Result: (map inc [1 2 3])

;; Cursor in middle:
(map inc [1 2| 3])  
;; Different grouping possible based on context

Tab Stops:

1
2
3
4
5
6
7
8
9
;; Smart tab stops for alignment
(let [x    1
      y    2    ; Aligned automatically
      long 3])

;; Function arguments align naturally  
(function arg1
          arg2     ; Aligned with first arg
          arg3)

Editor Integration:

Available Implementations:

  • Atom: Lisp editing with Parinfer integration
  • VS Code: Parinfer extension for modern editor
  • Vim/Neovim: Multiple Parinfer plugins available
  • Emacs: Parinfer packages for the classic Lisp editor
  • Sublime Text: Community-maintained Parinfer support

Configuration Example (VS Code):

1
2
3
4
5
6
{
  "parinfer.defaultMode": "indent",
  "parinfer.forceBalance": true,
  "parinfer.previewCursorScope": true,
  "parinfer.dimParens": true
}

Benefits for Lisp Learning:

Reduced Cognitive Load:

  • Focus on Logic: Less mental energy spent on parentheses
  • Visual Structure: Indentation makes nesting obvious
  • Error Prevention: Automatic balancing prevents common mistakes
  • Gentle Learning Curve: Familiar indentation-based editing

Before/After Comparison:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
;; Without Parinfer - manual paren management
(defn process-items [items]
  (map (fn [item]
         (if (valid? item)
           (transform item)
           (default-value))) items))

;; With Parinfer - focus on structure
defn process-items [items]
  map (fn [item]
        if (valid? item)
          transform item
          default-value) items

Mosh - Mobile Shell

Mosh: the mobile shell

Robust, responsive terminal application that handles intermittent connectivity:

Problems with Traditional SSH:

Common SSH Issues:

  • Connection Drops: WiFi disconnections kill sessions
  • Lag: Every keystroke waits for round-trip
  • IP Changes: Moving between networks breaks connections
  • Firewall Issues: NAT and firewall complications

Mosh Solutions:

Key Technologies:

S - - - P - - - t r a C O W e S U R t l n o d h n e e i l r i o d d e y k c w e u S n s t s r c y t s i l e n e v t i s c a n v e y n h n d e p e p r d s r E e s e o c d r n s d U h p c i e i D o c r e z r f P : h e i a v f a d v t e e f r i e i r r o a c d o e r c t n m n t i l a c b e o a P i e e r n t r n s t s s e o t , t n t a e i u c o i n r m n y c n o m t o t h e i d l s a d l r y f n i a ( n u d a c m S c l l t o a S h l i e n t P r n l f i ) o s g y i c : n c r a i r o m l z e f e l e e d y d n p a b t u c y e p k r d e s m a t e i t r n e l v a s o e l s r s s t a t e

Roaming Support:

1
2
3
4
5
6
7
# Traditional SSH breaks when IP changes
ssh user@server
# WiFi โ†’ 4G transition = broken connection

# Mosh maintains connection across IP changes
mosh user@server  
# WiFi โ†’ 4G โ†’ different WiFi = seamless transition

Technical Architecture:

Connection Process:

1
2
3
4
5
6
7
8
# 1. Mosh client connects via SSH
mosh user@server

# 2. SSH launches mosh-server on remote host
# 3. mosh-server chooses UDP port and prints connection info
# 4. SSH connection terminates
# 5. Client connects directly via UDP
# 6. State synchronization begins

State Synchronization:

C S U C S N S l e s l e e e i r e i r t r e v r e v w v n e n e o e t r t t r r r y k S S p S S S t t e t t p t a a s a a a a t t : t t c t e e e e k e : : : : e : t " " " " " a " h h h h h r h e e e e e r e l l l l l i l l l l l l v l o o o o o e o s w w w w w : w o o o o o o r r r r r r l l l l l l d d d d d d " " ! ! " ! " " " ( ( ( i u s m n y m t n e i c d l h i r a n o t e n e t i l w z y o e r d s k ) h o p w a n c ) k e t a r r i v e s )

Advanced Features:

Predictive Text Display:

# $ # $ # $ U g O g I g s i n i f i e t c t t r e s c c e c t o s o r o y m e m v m p m r m e m e i v i r i s t e t t r d q - - i - u m c m f m i o f c " n " e " k f f f r f l i i i s i y x r x : x : m b s b b u ( : u ( u g u g n g " n " o " d r ( e m s r a e l l r i v n d e e i r d s p h = l a a d p y r d e = i d f i c f c o e t n r e f e d i n ) r t m e r d e ) s p o n s e )

Firewall and NAT Traversal:

1
2
3
4
5
6
7
8
# Mosh uses UDP port range (default 60000-61000)
# Configure firewall to allow:
iptables -A INPUT -p udp --dport 60000:61000 -j ACCEPT

# Or specify port range:
mosh --server="mosh-server new -p 2222" user@server

# Works through NAT (unlike SSH X11 forwarding)

Installation and Usage:

Installation:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
# Ubuntu/Debian (both client and server needed)
sudo apt install mosh

# macOS
brew install mosh

# CentOS/RHEL
sudo yum install mosh

# Client connects to server (server auto-installed via SSH)
mosh user@hostname

Advanced Options:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
# Specify SSH port
mosh --ssh="ssh -p 2222" user@server

# Set prediction mode
mosh --predict=always user@server    # Always predict
mosh --predict=never user@server     # Never predict  
mosh --predict=adaptive user@server  # Default

# Specify colors (for 256-color support)
mosh --colors=256 user@server

ripgrep-all (rga) - Search Inside Documents

rga: ripgrep, but also search in PDFs, E-Books, Office documents, zip, tar.gz, etc.

Extended version of ripgrep that searches inside various file formats:

Supported File Types:

Archive Formats:

1
2
3
4
5
6
7
# Search inside compressed archives
rga "search term" archive.zip
rga "function name" backup.tar.gz
rga "config setting" bundle.tar.xz

# Nested archives supported
rga "password" archive.zip/nested.tar.gz/document.pdf

Document Formats:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
# Office documents
rga "quarterly report" presentation.pptx
rga "budget analysis" spreadsheet.xlsx  
rga "project timeline" document.docx

# PDF documents  
rga "machine learning" research_paper.pdf
rga "installation guide" manual.pdf

# E-books
rga "character development" novel.epub
rga "design patterns" programming_book.mobi

Media and Other Formats:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
# Image text extraction (OCR)
rga "street sign" photo.jpg
rga "license plate" security_footage.png

# Subtitle files
rga "dramatic scene" movie.mkv  # Searches embedded subtitles
rga "dialogue" subtitles.srt

# Database files
rga "user_table" database.sqlite

Advanced Usage:

Adapter Configuration:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
# List available adapters
rga --rga-list-adapters

# Use specific adapter
rga --rga-adapters=zip,tar "search term" 

# Disable slow adapters (like OCR)
rga --rga-adapters=-tesseract "search term"

# Cache results for faster repeated searches
rga --rga-cache-max-blob-len=10M "search term"

Integration with ripgrep Options:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
# Case-insensitive search
rga -i "Search Term" documents/

# Show context lines
rga -C 3 "important phrase" reports/

# Search specific file types only
rga -t pdf "research data" papers/

# JSON output for processing
rga --json "api_key" config_files/

# Parallel processing
rga -j 8 "performance" large_archive.zip

Performance Considerations:

Caching Strategy:

1
2
3
4
5
6
# Enable caching for large files
export RGA_CACHE_DIR=~/.cache/rga
rga --rga-cache-max-blob-len=100M "search term"

# Preprocess large archives
rga --rga-cache-compression-level=1 "index term" huge_backup.tar.gz

Resource Management:

1
2
3
4
5
6
7
8
# Limit memory usage for OCR
rga --rga-adapters=-tesseract "text" images/

# Parallel processing limits
rga -j 4 "search term" documents/  # Use 4 threads max

# Skip large files
rga --max-filesize=50M "config" archive.zip

Practical Applications:

Log Analysis:

1
2
3
4
5
6
# Search compressed log archives
rga "ERROR" logs.tar.gz
rga -A 5 -B 5 "database timeout" application_logs.zip

# Find configuration in backups
rga "database.*password" system_backup.tar.gz

Research and Documentation:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
# Academic research
rga -i "neural network" papers/*.pdf
rga "methodology" thesis_sources.zip

# Code archaeology  
rga "deprecated function" legacy_code.tar.gz
rga "TODO.*security" project_archive.zip

# Compliance and auditing
rga "personal.*data" document_archive.tar.gz
rga "license.*agreement" contracts.zip

Troubleshooting Script:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
#!/bin/bash
# search-everywhere.sh - comprehensive search tool

search_term="$1"
directory="${2:-.}"

echo "Searching for '$search_term' in $directory"
echo "======================================="

echo "Regular files:"
rg "$search_term" "$directory"

echo -e "\nDocuments and archives:"  
rga "$search_term" "$directory"

echo -e "\nCase-insensitive search:"
rga -i "$search_term" "$directory"

echo -e "\nWith context:"
rga -C 2 "$search_term" "$directory"

These tools represent modern approaches to common development and system administration tasks - creating user-friendly CLIs, making complex code editing more accessible, handling unreliable network connections, and searching through diverse file formats efficiently.