Skip to content
OpenSmartRoute
Skillv1.0.0

cli-tool-design

Design command-line interfaces with clear argument parsing, subcommands, help text, output formatting, and exit codes. Covers Click, Typer, argparse, and shell completion. Triggers on CLI tool develop

by organvm-iv-taxis(0) 0 installs
Free
Sign in to install

Free account. Installing gives you the manifest plus copy-paste snippets.

See reviews

About

Imported from organvm-iv-taxis/a-i--skills (skills/development/cli-tool-design/SKILL.md). Install upstream with npx skills add organvm-iv-taxis/a-i--skills --skill cli-tool-design. Copyright stays with the author (MIT).

CLI Tool Design

Build command-line tools that are discoverable, composable, and pleasant to use.

Design Principles

The UNIX Philosophy Applied

  1. Do one thing well — Each command has a clear, singular purpose
  2. Compose through pipes — Support stdin/stdout for chaining
  3. Fail loudly — Non-zero exit codes and stderr for errors
  4. Be predictable — Consistent flags, consistent output format

Command Structure

program [global-options] command [command-options] [arguments]

Example:

organvm --verbose registry update --organ IV a-i--skills

Framework Selection

Framework Language Best For
Typer Python Modern CLIs with type hints, auto-completion
Click Python Complex CLIs, plugins, nested groups
argparse Python Zero-dependency, stdlib-only
clap Rust High-performance, compiled CLIs
cobra Go Go microservice CLIs

Building with Typer (Recommended for Python)

Basic Command

import typer

app = typer.Typer(help="ORGANVM system management CLI")

@app.command()
def status(
    organ: str = typer.Argument(help="Organ number (I-VII or META)"),
    verbose: bool = typer.Option(False, "--verbose", "-v", help="Show detailed output"),
):
    """Show the status of an organ's repositories."""
    # Implementation here

Subcommand Groups

app = typer.Typer()
registry_app = typer.Typer(help="Registry operations")
app.add_typer(registry_app, name="registry")

@registry_app.command("update")
def registry_update(
    organ: str = typer.Argument(help="Target organ"),
    dry_run: bool = typer.Option(False, "--dry-run", "-n"),
):
    """Update registry entries for an organ."""

Rich Output Integration

from rich.console import Console
from rich.table import Table

console = Console(stderr=True)  # Status to stderr

def show_repos(repos: list[dict]):
    table = Table(title="Repositories")
    table.add_column("Name", style="cyan")
    table.add_column("Status", style="green")
    table.add_column("Tier")
    for repo in repos:
        table.add_row(repo["name"], repo["status"], repo["tier"])
    console.print(table)

Argument Design

Positional vs Optional

Use Case Type Example
Required input Positional program FILE
Behavior modifier Flag --verbose, --dry-run
Configuration Option --output FORMAT
Multiple inputs Variadic program FILE...

Flag Conventions

-v, --verbose       Increase output verbosity
-q, --quiet         Suppress non-error output
-n, --dry-run       Show what would happen without doing it
-f, --force         Skip confirmation prompts
-o, --output FILE   Write output to FILE instead of stdout
    --json          Machine-readable JSON output
    --no-color      Disable colored output

Boolean Flags with Negation

@app.command()
def deploy(
    color: bool = typer.Option(True, "--color/--no-color"),
    interactive: bool = typer.Option(True, "--interactive/--no-interactive"),
):

Output Design

Human vs Machine Output

import json
import sys

def output_results(results: list[dict], json_mode: bool = False):
    if json_mode:
        # Machine output to stdout
        json.dump(results, sys.stdout, indent=2)
    else:
        # Human output with formatting
        for r in results:
            console.print(f"[cyan]{r['name']}[/] — {r['status']}")

Progress Indicators

from rich.progress import track

for item in track(items, description="Processing..."):
    process(item)

Stderr vs Stdout

  • stdout: Data output (pipeable)
  • stderr: Status messages, progress, errors

Exit Codes

Code Meaning
0 Success
1 General error
2 Usage error (bad arguments)
64-78 BSD sysexits conventions
130 Interrupted (Ctrl+C)
import sys

def main():
    try:
        result = run_command()
        if not result.success:
            console.print(f"[red]Error:[/] {result.error}", file=sys.stderr)
            raise SystemExit(1)
    except KeyboardInterrupt:
        raise SystemExit(130)

Configuration Loading

Priority order (highest to lowest):

  1. Command-line arguments
  2. Environment variables
  3. Project-level config file (.tool.yaml)
  4. User-level config (~/.config/tool/config.yaml)
  5. System defaults
def get_config(cli_value: str | None = None) -> str:
    return (
        cli_value
        or os.environ.get("TOOL_CONFIG")
        or load_project_config()
        or load_user_config()
        or DEFAULT_VALUE
    )

Shell Completion

Typer Auto-Completion

# Generate completion script
my-cli --install-completion

# Or manually
_MY_CLI_COMPLETE=bash_source my-cli > ~/.my-cli-complete.bash
source ~/.my-cli-complete.bash

Custom Completions

def complete_organ(incomplete: str) -> list[str]:
    organs = ["I", "II", "III", "IV", "V", "VI", "VII", "META"]
    return [o for o in organs if o.startswith(incomplete.upper())]

@app.command()
def status(organ: str = typer.Argument(autocompletion=complete_organ)):
    ...

Testing CLIs

from typer.testing import CliRunner

runner = CliRunner()

def test_status_command():
    result = runner.invoke(app, ["status", "IV"])
    assert result.exit_code == 0
    assert "a-i--skills" in result.stdout

def test_invalid_organ():
    result = runner.invoke(app, ["status", "INVALID"])
    assert result.exit_code == 2

Anti-Patterns

  • Requiring interactive input in scripts — Always support --yes / --no-interactive flags
  • Mixing data and status on stdout — Use stderr for progress and status messages
  • Inconsistent flag naming — Pick a convention and stick to it across all subcommands
  • No help text — Every command, argument, and option needs a help string
  • Swallowing errors — Always exit with appropriate non-zero codes on failure

Use it

Copy one of these into your project. Installing also returns the manifest and these snippets.

yaml
targets:
  - https://api.opensmartroute.ai/api/v1/registry/organvm-iv-taxis-a-i-skills-cli-tool-design/manifest   # or paste the manifest below

Manifest

An Open Capability Manifest: the router reads it to know what this does, what it costs and when to pick it.

organvm-iv-taxis-a-i-skills-cli-tool-design.ocm.jsonjson
{
  "ocm": "1",
  "id": "organvm-iv-taxis-a-i-skills-cli-tool-design",
  "kind": "skill",
  "name": "cli-tool-design",
  "description": "Design command-line interfaces with clear argument parsing, subcommands, help text, output formatting, and exit codes. Covers Click, Typer, argparse, and shell completion. Triggers on CLI tool development, argument parsing, or terminal UX design requests.",
  "publisher": "organvm-iv-taxis",
  "version": "1.0.0",
  "capabilities": {
    "domains": [
      "general"
    ],
    "tags": [
      "skill-md",
      "cli",
      "command-line",
      "argparse",
      "click",
      "typer",
      "terminal",
      "skills-sh"
    ],
    "languages": [
      "en"
    ]
  },
  "quality_prior": 0.6,
  "examples": [
    "Design command-line interfaces with clear argument parsing, subcommands, help text, output formatting, and exit codes. Covers Click, Typer, argparse, and shell completion. Triggers on CLI tool development, argument parsing, or terminal UX design requests."
  ],
  "primary": false,
  "metadata": {
    "source": {
      "provider": "skills.sh",
      "repository": "https://github.com/organvm-iv-taxis/a-i--skills",
      "path": "skills/development/cli-tool-design/SKILL.md",
      "ref": "HEAD",
      "url": "https://github.com/organvm-iv-taxis/a-i--skills/blob/HEAD/skills/development/cli-tool-design/SKILL.md",
      "key": "organvm-iv-taxis/a-i--skills/skills/development/cli-tool-design/SKILL.md"
    },
    "license": "MIT"
  },
  "instructions": "# CLI Tool Design\n\nBuild command-line tools that are discoverable, composable, and pleasant to use.\n\n## Design Principles\n\n### The UNIX Philosophy Applied\n\n1. **Do one thing well** — Each command has a clear, singular purpose\n2. **Compose through pipes** — Support stdin/stdout for chaining\n3. **Fail loudly** — Non-zero exit codes and stderr for errors\n4. **Be predictable** — Consistent flags, consistent output format\n\n### Command Structure\n\n```\nprogram [global-options] command [command-options] [arguments]\n```\n\nExample:\n```bash\norganvm --verbose registry update --organ IV a-i--skills\n```\n\n## F",
  "cost": {
    "context_tokens": 1521
  }
}

Fetch it by URL: GET /api/v1/registry/organvm-iv-taxis-a-i-skills-cli-tool-design/manifest?version=1.0.0

Reviews

Star ratings from people who tried it. One review per account; edit yours any time.

No reviews yet. Install it, try it, and be the first to rate it.