Loading...
Loading...
Golang CLI command tree library using spf13/cobra — cobra.Command, RunE vs Run, PersistentPreRunE hook chain, Args validators (NoArgs, ExactArgs, MatchAll, custom), persistent vs local flags, command groups, ValidArgsFunction, RegisterFlagCompletionFunc, ShellCompDirective, usage/help template customization, man-page and markdown doc generation, and testing with SetArgs/SetOut/SetErr. Apply when using or adopting spf13/cobra, or when the codebase imports `github.com/spf13/cobra`. For configuration layering alongside cobra, see the `samber/cc-skills-golang@golang-spf13-viper` skill. For general CLI architecture (project layout, exit codes, signal handling, I/O patterns), see `samber/cc-skills-golang@golang-cli`.
npx skill4agent add samber/cc-skills-golang golang-spf13-cobraRunEOutOrStdout()pflaggo get github.com/spf13/cobra@latest| Concern | cobra | viper |
|---|---|---|
| Owns | Command tree, flags, arg validation, completions | Configuration value resolution |
| User-facing? | Yes — subcommands, flags, help text | No — purely a key-value resolver |
| Without the other? | Yes — a CLI with flags only needs cobra | Yes — a daemon reading YAML + env needs only viper |
| Integration seam | Hands | Treats the cobra flag as the highest-precedence layer |
PersistentPreRunEsamber/cc-skills-golang@golang-spf13-viperAddCommandvar rootCmd = &cobra.Command{
Use: "myapp",
Short: "One-line summary",
SilenceUsage: true, // ✓ prevents usage wall on every error
SilenceErrors: true, // ✓ lets you control error output format
}AddGroupAddCommandPersistentPreRunE → PreRunE → RunE → PostRunE → PersistentPostRunE*EEPersistentPreRunEPersistentPreRunEPostRunERunERunElen(args)RunENoArgsExactArgs(n)MinimumNArgs(n)MaximumNArgs(n)RangeArgs(min,max)OnlyValidArgsExactValidArgs(n)MatchAll(v1, v2)func(cmd *cobra.Command, args []string) errorMatchAllpflagPersistentFlags()Flags()rootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file path") // inherited by all subcommands
serveCmd.Flags().IntVar(&port, "port", 8080, "listen port") // local to serveCmd only
serveCmd.MarkFlagRequired("port")
serveCmd.MarkFlagsMutuallyExclusive("json", "yaml")ValidArgs []stringValidArgsFunctionfunc(cmd, args, toComplete string) ([]string, ShellCompDirective)ShellCompDirectiveNoFileCompRegisterFlagCompletionFunc(name, fn)ShellCompDirectiveos.Stdoutos.Stderrcmd.OutOrStdout()cmd.ErrOrStderr()func TestServeCmd(t *testing.T) {
buf := new(bytes.Buffer)
rootCmd.SetOut(buf)
rootCmd.SetArgs([]string{"serve", "--port", "9090"})
require.NoError(t, rootCmd.Execute())
assert.Contains(t, buf.String(), "listening on :9090")
}Execute()RunERunRunos.ExitPersistentPreRunEArgsRunEArgsMatchAllcmd.OutOrStdout()cmd.ErrOrStderr()os.StdoutExecute()| Mistake | Why it fails | Fix |
|---|---|---|
Using | Cannot return an error — only escape is | Use |
Writing | Bypasses cobra's standard error messages ("accepts 1 arg, received 2") | Declare |
Writing to | Tests cannot capture output — os-level file handles can't be redirected | Use |
Child | Cobra does not chain — the child replaces the parent's hook entirely | Call |
| Reusing a root command across tests | Cobra accumulates flag state; second | Build a fresh command tree per test |
cobra-clisamber/cc-skills-golang@golang-clisamber/cc-skills-golang@golang-spf13-vipersamber/cc-skills-golang@golang-testing