Golang CLI application development. Use when building, modifying, or reviewing a Go CLI tool — especially for command structure, flag handling, configuration layering, version embedding, exit codes, I/O patterns, signal handling, shell completion, argument validation, and CLI unit testing. Also triggers when code uses cobra, viper, or urfave/cli.
Persona: You are a Go CLI engineer. You build tools that feel native to the Unix shell — composable, scriptable, and predictable under automation.
Modes:
SilenceUsage/SilenceErrors, flag-to-Viper binding, exit codes, and stdout/stderr discipline.Use Cobra + Viper as the default stack for Go CLI applications. Cobra provides the command/subcommand/flag structure and Viper handles configuration from files, environment variables, and flags with automatic layering. This combination powers kubectl, docker, gh, hugo, and most production Go CLIs.
For trivial single-purpose tools with no subcommands and few flags, stdlib flag is sufficient.
| Concern | Package / Tool |
|---|---|
| Commands & flags | github.com/spf13/cobra |
| Configuration | github.com/spf13/viper |
| Flag parsing | github.com/spf13/pflag (via Cobra) |
| Colored output | github.com/fatih/color |
| Table output | github.com/olekukonko/tablewriter |
| Interactive prompts | github.com/charmbracelet/bubbletea |
| Version injection | go build -ldflags |
| Distribution | goreleaser |
Organize CLI commands in cmd/myapp/ with one file per command. Keep main.go minimal — it only calls Execute().
myapp/
├── cmd/
│ └── myapp/
│ ├── main.go # package main, only calls Execute()
│ ├── root.go # Root command + Viper init
│ ├── serve.go # "serve" subcommand
│ ├── migrate.go # "migrate" subcommand
│ └── version.go # "version" subcommand
├── go.mod
└── go.sum
main.go should be minimal — see assets/examples/main.go.
The root command initializes Viper configuration and sets up global behavior via PersistentPreRunE. See assets/examples/root.go.
Key points:
SilenceUsage: true MUST be set — prevents printing the full usage text on every errorSilenceErrors: true MUST be set — lets you control error output format yourselfPersistentPreRunE runs before every subcommand, so config is always initializedAdd subcommands by creating separate files in cmd/myapp/ and registering them in init(). See assets/examples/serve.go for a complete subcommand example including command groups.
See assets/examples/flags.go for all flag patterns:
--config)--port)Use MarkFlagRequired, MarkFlagsMutuallyExclusive, and MarkFlagsOneRequired for flag constraints.
Provide completion suggestions for flag values.
This ensures viper.GetInt("port") returns the flag value, env var MYAPP_PORT, or config file value — whichever has highest precedence.
Cobra provides built-in validators for positional arguments. See assets/examples/args.go for both built-in and custom validation examples.
| Validator | Description |
|---|---|
cobra.NoArgs | Fails if any args provided |
cobra.ExactArgs(n) | Requires exactly n args |
cobra.MinimumNArgs(n) | Requires at least n args |
cobra.MaximumNArgs(n) | Allows at most n args |
cobra.RangeArgs(min, max) | Requires between min and max |
cobra.ExactValidArgs(n) | Exactly n args, must be in ValidArgs |
Viper resolves configuration values in this order (highest to lowest precedence):
See assets/examples/config.go for complete Viper integration including struct unmarshaling and config file watching.