cli.md

CLIs

Choose the smallest CLI shape that will still feel good to use. Prefer boring, explicit command structure over clever frameworks, generated wrappers, or hidden magic.

Shape choices

  • One or two flags, server-style binary: the ecosystem's standard flag parser is usually enough.
  • User-facing command with help/version/completions/subcommands: use a mature command framework plus a polished help/error layer when the ecosystem has one.
  • Interactive prompts: add a prompt library only when prompts are central, not for a single confirmation.
  • Full-screen interaction: this is a TUI; read tui.md.

Config and version policy

  • Read config at the boundary, validate early, and store it in typed domain structures.
  • Prefer explicit config discovery. Avoid magical precedence unless the project truly needs layering.
  • Default precedence is flag, then environment variable, then config file.
  • Default config path is $XDG_CONFIG_HOME/<app-name>/config.toml, falling back to ~/.config/<app-name>/config.toml when XDG_CONFIG_HOME is unset.
  • Do not add exact version plumbing just for its own sake. Add project-owned version resolution when the version appears in release artifacts, package metadata, MCP metadata, tests, or multiple user-visible surfaces.

UX rules

  • Human text goes to stderr when stdout may be piped.
  • Machine output needs an explicit --json, --jsonl, or equivalent.
  • Destructive commands need names and help text that make the effect obvious.
  • Interactive commands need a non-interactive path for scripts and CI.

Go path

For Go CLIs, read golang/index.md first and follow its CLI chain. Do not jump straight to golang/cli.md; the index intentionally forces the Go baseline, mise, and library context before CLI specifics.