After building Folder Intelligence — a Python CLI that reads file contents to organize them — I've refined a set of patterns I now use in every project. These aren't fancy abstractions. They're practical building blocks that make CLIs feel professional and maintainable.
Here are the 5 patterns, with real code from my projects.
1. Rich Progress Bars Instead of print()
The first thing users notice about your CLI is feedback. Bare print() calls feel amateurish. The rich library makes it trivial to add beautiful progress output.
from rich.progress import Progress, SpinnerColumn, TextColumn
from rich.console import Console
console = Console()
def process_files(files):
with Progress(
SpinnerColumn(),
TextColumn("[progress.description]{task.description}"),
transient=True,
) as progress:
task = progress.add_task("Processing files...", total=len(files))
for f in files:
do_something(f)
progress.advance(task)
console.print("[bold green]Done![/bold green]")
This pattern shows real-time progress without flooding the terminal. The transient=True clears the bar when done, leaving a clean output.
2. --dry-run Mode From Day One
Every CLI that modifies files, databases, or APIs should have a dry-run mode. It builds trust with users and makes testing 10x easier.
import click
@click.command()
@click.option('--dry-run', is_flag=True, help='Preview changes without applying them')
def organize(dry_run):
for file in get_files():
new_name = generate_name(file)
if dry_run:
click.echo(f"Would rename: {file} -> {new_name}")
else:
file.rename(new_name)
click.echo(f"Renamed: {file} -> {new_name}")
This is the single most-requested feature after releasing Folder Intelligence. Ship it on day one.
3. JSON Audit Logs for Every Destructive Operation
If your CLI moves, renames, or deletes anything, write an audit log. Users need a way to review (and potentially undo) what happened.
import json
from datetime import datetime
from pathlib import Path
def write_audit_log(operations: list[dict], output_dir: Path):
timestamp = datetime.now().strftime("%Y-%m-%d_%H-%M-%S")
log_file = output_dir / f"audit_{timestamp}.json"
with open(log_file, 'w') as f:
json.dump({
"timestamp": timestamp,
"operations": operations,
"total": len(operations)
}, f, indent=2)
return log_file
# Usage
ops = []
for old, new in renames:
ops.append({"action": "rename", "from": str(old), "to": str(new)})
old.rename(new)
log = write_audit_log(ops, output_dir)
print(f"Audit log written: {log}")
This pattern has saved me multiple times during testing. JSON is readable, diffable, and easy to parse for an undo script later.
4. Graceful Error Handling with Context
Nothing is more frustrating than a CLI that throws a raw traceback at you. Catch errors where they happen and give context about what failed.
from rich.console import Console
console = Console()
def process_file(filepath):
try:
content = extract_text(filepath)
new_name = generate_name(content)
return new_name
except PermissionError:
console.print(f"[yellow]Skipped {filepath.name}: no read permission[/yellow]")
return None
except Exception as e:
console.print(f"[red]Error processing {filepath.name}: {e}[/red]")
return None
The key is: never crash the whole pipeline because one file failed. Log it, skip it, continue.
5. Configuration via Both CLI Args and a Config File
Power users want to set defaults without typing flags every time. The pattern I use: CLI args override config file, which overrides built-in defaults.
import click
import json
from pathlib import Path
def load_config() -> dict:
config_path = Path.home() / '.folder-intelligence' / 'config.json'
if config_path.exists():
return json.loads(config_path.read_text())
return {}
@click.command()
@click.option('--output-dir', default=None, help='Output directory')
@click.pass_context
def run(ctx, output_dir):
config = load_config()
# CLI arg > config file > default
final_output = output_dir or config.get('output_dir') or './organized'
process(final_output)
This makes your CLI usable for both quick one-offs and automated pipelines.
Putting It All Together
These patterns are all used in Folder Intelligence — a CLI that reads PDFs, Word docs, and images (via OCR) and organizes them based on their actual content, not just filenames.
If you've found a CLI pattern that you use everywhere, drop it in the comments — I'm always looking to improve the toolbox.
Top comments (0)