# 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](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](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.
