Receber por email
← Voltar para o catálogo

cli-tool-architect

Cross-language CLI standards — subcommand structure, flag/env/config/default precedence, TOML in XDG, stdout-data/stderr-logs split, --output json|yaml, exit codes, NO_COLOR, completions. Go (cobra+pflag+viper) and Python (typer) recipes. Use when designing or reviewing a CLI.

2estrelas
Atualizado há 4 meses

Ver no GitHub ↗ Licença: GPL-3.0

Como adicionar

/plugin marketplace add ralvarezdev/ralvaskills

O comando exato pode variar conforme o repositório. Confira o README no GitHub.

Para o autor da skill

Cole no README do seu repo

Mostra que sua skill está catalogada na Skillteca, gera backlink e tráfego rastreável.

[![Skillteca](https://www.skillteca.com.br/api/badge/cli-tool-architect/svg)](https://www.skillteca.com.br/skills/cli-tool-architect)

Skills relacionadas

Ver todas de Dados e Análise →

Alerta por categoria

Receba novas skills de Dados e Análise toda segunda

1 email curto, só com as skills novas de Dados e Análise. 4 minutos de leitura, sem spam, cancela com 1 clique.

Você confirma o email no primeiro envio. Sem spam. Cancela com 1 clique.

Ler descrição completa

CLI Tool Architecture

Language-agnostic conventions for command-line tools. Go-specific recipes use spf13/cobra + spf13/pflag + spf13/viper; Python-specific recipes use typer. Per-language stacks are canonical in [go-architect](../../languages/go-architect/SKILL.md) and [python-architect](../../languages/python-architect/SKILL.md). See [STACK.md](STACK.md) for additional CLI-specific libraries (output styling, alternative loggers).

1. Command structure

  • Root + subcommands. tool <subcommand> [args] [flags]. Mirrors git, kubectl, docker, rsk. Top-level flags are global; subcommand flags are scoped to that subcommand.
  • One verb per subcommand. tool create user is fine. tool create-user-now is not.
  • Hierarchy when it reads naturally: tool resource action (e.g. kubectl get pods, aws s3 ls). Skip if your tool has fewer than ~5 commands — flatten.
  • tool alone (no subcommand) prints help. Never run "the default action" — implicit behavior is the source of surprise commits and accidental deploys.
  • Names: short, lowercase, single-word where possible. get, list, apply, delete. Two words if they're a phrase: get-config.

2. Arguments vs flags

  • Positional arguments for the required noun of the verb: tool delete <user-id>. Use sparingly — every extra positional reduces clarity.
  • Flags for everything else. Required flags exist; mark them with Required: true (cobra) / Option(...) (typer) and document explicitly.
  • No more than 2 positional args in most cases. Beyond that, switch to flags.
  • Short flags only for the top 5 most-used. -v, -h, -f, -o. Don't shortify every flag — tool deploy -e prod -r us-east-1 -p high -d becomes unreadable; long form is self-documenting.
  • Boolean flags are pure switches: --dry-run, not --dry-run=true. Negate with --no-foo if both states need an explicit form.
  • Plural for repeatable flags: --tag debug --tag perf becomes --tags debug,perf or --tag repeatable. Pick one and document.

3. Flag / env / config-file / defaults precedence

Configuration values can come from four places. The order is fixed and inviolable:

flag > env var > config file > built-in default
  • A --log-level=debug flag wins over TOOL_LOG_LEVEL=info env wins over log_level = "warn" in the config wins over the compiled-in default (info).
  • Env-var prefix is the tool name in upper-snake: TOOL_LOG_LEVEL, TOOL_API_URL. Document the prefix in --help.
  • Show effective config: every CLI should have a tool config show (or tool config --show) that prints the resolved values and where each came from (flag / env / file / default). This is the difference between "user can diagnose" and "user files a bug ticket".

4. Configuration file — TOML in XDG location

  • Default format: TOML — readable, supports comments, modern default (Rust/Cargo, Python pyproject.toml, uv.lock).
  • Default location: XDG Base Directory spec.
  • Config: $XDG_CONFIG_HOME/<tool>/config.toml, falling back to ~/.config/<tool>/config.toml
  • Cache: $XDG_CACHE_HOME/<tool>/, falling back to ~/.cache/<tool>/
  • Data: $XDG_DATA_HOME/<tool>/, falling back to ~/.local/share/<tool>/
  • Windows: %APPDATA%\<tool>\config.toml (per XDG-on-Windows convention translated to platform).
  • Discovery order for the config file:
  • --config <path> flag (explicit override)
  • TOOL_CONFIG env var
  • ./<tool>.toml (project-local; useful for tools that have per-repo config)
  • $XDG_CONFIG_HOME/<tool>/config.toml (user-global)
  • One canonical filename per tool. Don't accept .tool.toml, tool.config.toml, config.toml, .toolrc all at once. Pick one and stick to it.
  • tool init writes a sane default config to the canonical location; refuse to overwrite without --force.
Note: rsk itself uses ~/.config/rsk/config.json (JSON) for legacy / parsing reasons; TOML is the recommended default for new CLIs.

5. Help text discipline

Every command, subcommand, and flag has documented help. Help is the API surface.

  • tool --help lists subcommands with a one-line description each.
  • tool <subcommand> --help has: short description, usage line, flags grouped (Required, Common, Global), and at least one example at the bottom.
  • Examples drive understanding — newcomers read examples before they read flag tables. Include 2–3 realistic invocations per subcommand.
  • Line length 80 chars in help text — terminals are still ~80 cols by default.
  • No marketing copy. Short, factual, actionable.

6. Output discipline — stdout for data, stderr for logs

Strict separation. Always.

  • Data → stdout. The thing the user wants — JSON, the filename created, the resource ID, the table.
  • Logs, progress, errors → stderr. Anything the user doesn't want piped into the next command.
  • Errors that prevent producing data must exit non-zero (see §8). Don't print an error to stdout and exit 0.

Non-negotiable. Tools that mix the streams break every shell pipeline. Concrete pipe examples in [RECIPES § Output discipline](RECIPES.md#output-discipline--stdoutstderr-separation).

7. Output formats — --output json|yaml mandatory on list/get

Human-readable text is the default. Every command returning structured data must also support --output json and --output yaml.

  • -o short form is standard (kubectl, gh, oc).
  • JSON output is stable and documented — clients depend on it. Schema changes are breaking.
  • JSONL for list operations — one line per record, so tool list -o json | grep works.
  • YAML for human eyeballing of nested data; rarely useful for pipes.

Invocation examples in [RECIPES § Output format flag examples](RECIPES.md#output-format-flag-examples).

8. Exit codes

Standard semantics across the ecosystem — full table in [RECIPES § Exit-code reference](RECIPES.md#exit-code-reference). Key rules:

  • 0 success, 1 generic failure, 2 misuse, 130 SIGINT. Anything custom is domain-specific and documented.
  • Document every non-standard exit code in --help or tool help exit-codes.
  • Don't reuse codes across categories within one tool.
  • Misuse vs failure: parsing errors are 2; tool worked but operation failed is 1 or a custom non-zero.

9. Color & TTY behavior

  • Auto-detect TTY: color on when stdout is a terminal, off when piped (tool list | less should not contain ANSI escapes).
  • Respect NO_COLOR environment variable (no-color.org). Set → no color, regardless of TTY detection.
  • Respect --no-color flag as an explicit override.
  • Respect FORCE_COLOR when set (CI logs in tools like GitHub Actions render ANSI).
  • --color=auto|always|never for full control (matches git, grep, ls).
  • Don't go wild with color. A status column (green: OK, red: FAILED, yellow: WARN) is great. Rainbow output is not.

10. Logging — structured to stderr

CLI logging is for the user's terminal, not log aggregation. Different style from server logging.

  • Default log level: info. -v → debug, -vv → trace. --quiet / -q → warn.
  • Log to stderr always. No exceptions.
  • Structured output even for human reading — key=value pairs are scannable. Use log/slog (Go) or structlog (Python). charmbracelet/log (Go) and rich (Python) add pretty-printing while preserving structure.
  • Errors include the operation that failed, the inputs that mattered, and any correlation id if cross-service. Format example in [RECIPES § Error message format](RECIPES.md#error-message-format).
  • No stack traces in user-facing errors (see §15).

11. Progress feedback

For long-running operations only — anything that takes more than ~2 seconds.

  • Spinner for indeterminate work ("connecting to API...
Compartilhar X LinkedIn