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.tomlwhenXDG_CONFIG_HOMEis 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.