go-cobra
Original:🇺🇸 English
Translated
Write, scaffold, and debug Go CLI applications with `github.com/spf13/cobra`. Use this skill whenever the user mentions Cobra, `cobra.Command`, a Go command-line app, subcommands, persistent or local flags, required flags, argument validation, shell completions, generated docs, or wants to build or refactor a cobra-based CLI.
5installs
Sourceaaronflorey/agent-skills
Added on
NPX Install
npx skill4agent add aaronflorey/agent-skills go-cobraTags
Translated version includes tags in frontmatterSKILL.md Content
View Translation Comparison →Cobra CLI Framework Skill
Write, scaffold, and debug Go CLI applications using the spf13/cobra library. Use this skill whenever the user wants to build a command-line interface in Go, add commands/subcommands to a CLI, work with flags (persistent, local, required), implement shell completions, generate documentation, or asks anything about cobra-based CLI development -- even if they just say "I want to build a CLI tool" or "how do I add commands to my Go app".
Quick Start
Installation
bash
go get -u github.com/spf13/cobra@latestFor the CLI generator (optional but recommended for scaffolding):
bash
go install github.com/spf13/cobra-cli@latestProject Structure
myapp/
cmd/
root.go # Root command and Execute()
version.go # Additional commands
serve.go
main.go # Just calls cmd.Execute()Minimal main.go
go
package main
import "myapp/cmd"
func main() {
cmd.Execute()
}Minimal root.go
go
package cmd
import (
"fmt"
"os"
"github.com/spf13/cobra"
)
var rootCmd = &cobra.Command{
Use: "myapp",
Short: "A brief description of your application",
Long: `A longer description that spans multiple lines.`,
Run: func(cmd *cobra.Command, args []string) {
fmt.Println("Hello from myapp!")
},
}
func Execute() {
if err := rootCmd.Execute(); err != nil {
fmt.Fprintln(os.Stderr, err)
os.Exit(1)
}
}Core Concepts
Commands represent actions. Args are things. Flags modify behavior.
Pattern:
APPNAME COMMAND ARG --FLAGExamples:
- — "server" is command, "port" is flag
hugo server --port=1313 - — "clone" is command, "URL" is arg, "bare" is flag
git clone URL --bare
Command Structure
Creating Commands
go
var serveCmd = &cobra.Command{
Use: "serve", // How to call it
Short: "Start the server", // One-line help
Long: `Detailed description here...`, // Full help text
Example: ` myapp serve --port 8080`, // Usage examples
Run: func(cmd *cobra.Command, args []string) {
// Command logic here
},
}
func init() {
rootCmd.AddCommand(serveCmd)
}Key Command Fields
| Field | Purpose |
|---|---|
| Usage pattern: |
| Alternative names: |
| Brief description for help listings |
| Full description for |
| Usage examples (indent with 2 spaces) |
| The actual command logic |
| Same as Run but returns error |
| Positional argument validation |
| Static list for shell completion |
| Dynamic completion function |
| Hide from help output |
| Mark as deprecated with message |
| Version string (enables --version) |
Run vs RunE
Use when you need to return errors to the caller:
RunEgo
var tryCmd = &cobra.Command{
Use: "try",
Short: "Try something",
RunE: func(cmd *cobra.Command, args []string) error {
if err := doSomething(); err != nil {
return err // Error handled by Cobra
}
return nil
},
}Flags
Flag Types
Persistent Flags — Available to this command AND all subcommands:
go
rootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file path")
rootCmd.PersistentFlags().BoolVarP(&verbose, "verbose", "v", false, "verbose output")Local Flags — Only for this specific command:
go
serveCmd.Flags().IntVarP(&port, "port", "p", 8080, "port to listen on")
serveCmd.Flags().StringVar(&host, "host", "localhost", "host address")Flag Methods
| Method | Example |
|---|---|
| |
| |
| |
| |
| |
| |
| |
Required Flags
go
cmd.Flags().StringVarP(®ion, "region", "r", "", "AWS region")
cmd.MarkFlagRequired("region")
// For persistent flags
cmd.MarkPersistentFlagRequired("config")Flag Groups
go
// Must be used together
cmd.MarkFlagsRequiredTogether("username", "password")
// Cannot be used together
cmd.MarkFlagsMutuallyExclusive("json", "yaml")
// At least one required
cmd.MarkFlagsOneRequired("json", "yaml")
// Exactly one required (combine both)
cmd.MarkFlagsOneRequired("json", "yaml")
cmd.MarkFlagsMutuallyExclusive("json", "yaml")Count Flags (Verbosity Pattern)
go
var verbose int
func init() {
rootCmd.PersistentFlags().CountVarP(&verbose, "verbose", "v", "verbosity (-v, -vv, -vvv)")
}
// Usage:
// myapp -v → verbose = 1
// myapp -vv → verbose = 2
// myapp -vvv → verbose = 3Positional Arguments
Built-in Validators
go
cmd.Args = cobra.NoArgs // No args allowed
cmd.Args = cobra.ArbitraryArgs // Any args (default)
cmd.Args = cobra.MinimumNArgs(1) // At least N
cmd.Args = cobra.MaximumNArgs(3) // At most N
cmd.Args = cobra.ExactArgs(2) // Exactly N
cmd.Args = cobra.RangeArgs(1, 3) // Between min and max
cmd.Args = cobra.OnlyValidArgs // Only from ValidArgs listCombining Validators
go
cmd.Args = cobra.MatchAll(cobra.ExactArgs(2), cobra.OnlyValidArgs)Custom Validator
go
cmd.Args = func(cmd *cobra.Command, args []string) error {
if len(args) < 1 {
return fmt.Errorf("requires at least 1 arg")
}
if !isValidInput(args[0]) {
return fmt.Errorf("invalid argument: %s", args[0])
}
return nil
}Lifecycle Hooks
Hooks execute in this order:
- (inherited by children)
PersistentPreRun PreRunRunPostRun- (inherited by children)
PersistentPostRun
go
var rootCmd = &cobra.Command{
Use: "app",
PersistentPreRun: func(cmd *cobra.Command, args []string) {
// Runs before every command (including subcommands)
initLogging()
},
PersistentPostRun: func(cmd *cobra.Command, args []string) {
// Runs after every command
cleanup()
},
}
var subCmd = &cobra.Command{
Use: "sub",
PreRun: func(cmd *cobra.Command, args []string) {
// Only for this command, before Run
},
Run: func(cmd *cobra.Command, args []string) {
// Main logic
},
}Use variants to return errors:
*RunEgo
PersistentPreRunE: func(cmd *cobra.Command, args []string) error {
return initConfig()
}Viper Integration
Cobra integrates seamlessly with Viper for configuration management. See references/viper-integration.md for complete documentation.
go
import "github.com/spf13/viper"
func init() {
cobra.OnInitialize(initConfig)
rootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file")
rootCmd.PersistentFlags().String("author", "Me", "author name")
// Bind flag to viper - priority: flag > env > config > default
viper.BindPFlag("author", rootCmd.PersistentFlags().Lookup("author"))
}
func initConfig() {
if cfgFile != "" {
viper.SetConfigFile(cfgFile)
} else {
home, _ := os.UserHomeDir()
viper.AddConfigPath(home)
viper.SetConfigType("yaml")
viper.SetConfigName(".myapp")
}
viper.AutomaticEnv()
viper.ReadInConfig()
}
// IMPORTANT: Use viper.GetString("author"), not the flag variable
// Flag variables are NOT updated from config file valuesHelp & Usage
Automatic Features
- /
--helpflag added automatically-h - subcommand added when you have subcommands
help - Typo suggestions: → "Did you mean 'server'?"
myapp srever
Customization
go
// Custom help template
cmd.SetHelpTemplate(`Custom help: {{.Use}}`)
// Custom usage template
cmd.SetUsageTemplate(`Usage: {{.UseLine}}`)
// Custom help function
cmd.SetHelpFunc(func(cmd *cobra.Command, args []string) {
fmt.Println("Custom help!")
})
// Disable suggestions
cmd.DisableSuggestions = true
// Adjust suggestion distance
cmd.SuggestionsMinimumDistance = 1Version Flag
go
var rootCmd = &cobra.Command{
Use: "myapp",
Version: "1.0.0", // Enables --version flag
}
// Custom version template
cmd.SetVersionTemplate(`Version: {{.Version}}`)Grouping Commands
go
rootCmd.AddGroup(&cobra.Group{ID: "core", Title: "Core Commands:"})
rootCmd.AddGroup(&cobra.Group{ID: "util", Title: "Utility Commands:"})
serveCmd.GroupID = "core"
versionCmd.GroupID = "util"Shell Completions
Cobra automatically provides a command. For detailed shell completion implementation, see .
completionreferences/completions.mdQuick usage:
bash
# Bash
source <(myapp completion bash)
# Zsh
myapp completion zsh > "${fpath[1]}/_myapp"
# Fish
myapp completion fish > ~/.config/fish/completions/myapp.fish
# PowerShell
myapp completion powershell | Out-String | Invoke-ExpressionDynamic Completions
go
cmd.ValidArgsFunction = func(cmd *cobra.Command, args []string, toComplete string) ([]cobra.Completion, cobra.ShellCompDirective) {
if len(args) != 0 {
return nil, cobra.ShellCompDirectiveNoFileComp
}
return []cobra.Completion{"option1", "option2"}, cobra.ShellCompDirectiveNoFileComp
}Documentation Generation
Cobra can generate man pages, markdown, and more. See for details.
references/docgen.mdQuick example:
go
import "github.com/spf13/cobra/doc"
// Markdown
doc.GenMarkdownTree(rootCmd, "./docs")
// Man pages
header := &doc.GenManHeader{Title: "MYAPP", Section: "1"}
doc.GenManTree(rootCmd, header, "./man")Creating Plugins
For tools like kubectl that use plugins ( called as ):
kubectl-mypluginkubectl myplugingo
rootCmd := &cobra.Command{
Use: "kubectl-myplugin",
Annotations: map[string]string{
cobra.CommandDisplayNameAnnotation: "kubectl myplugin",
},
}Global Settings
go
// Enable case-insensitive command matching
cobra.EnableCaseInsensitive = true
// Enable prefix matching (dangerous for production)
cobra.EnablePrefixMatching = true
// Execute all parent hooks (not just first found)
cobra.EnableTraverseRunHooks = true
// Disable command sorting in help
cobra.EnableCommandSorting = falseTesting Commands
go
func TestServeCommand(t *testing.T) {
cmd := rootCmd
// Capture output
buf := new(bytes.Buffer)
cmd.SetOut(buf)
cmd.SetErr(buf)
// Set args
cmd.SetArgs([]string{"serve", "--port", "9000"})
// Execute
err := cmd.Execute()
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
// Check output
if !strings.Contains(buf.String(), "expected") {
t.Errorf("unexpected output: %s", buf.String())
}
}Context Support
go
var rootCmd = &cobra.Command{
Use: "myapp",
Run: func(cmd *cobra.Command, args []string) {
ctx := cmd.Context()
// Use context for cancellation, timeouts, etc.
},
}
// Execute with context
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()
rootCmd.ExecuteContext(ctx)Common Patterns
Subcommand Organization
For large apps, organize subcommands in separate packages:
cmd/
root.go
config/
config.go # Defines configCmd
get.go # config get
set.go # config setgo
// cmd/config/config.go
var ConfigCmd = &cobra.Command{Use: "config", Short: "Manage configuration"}
func init() {
ConfigCmd.AddCommand(getCmd)
ConfigCmd.AddCommand(setCmd)
}
// cmd/root.go
import "myapp/cmd/config"
func init() {
rootCmd.AddCommand(config.ConfigCmd)
}Error Handling
go
func Execute() {
if err := rootCmd.Execute(); err != nil {
// Error already printed by Cobra
os.Exit(1)
}
}
// To silence automatic error printing:
rootCmd.SilenceErrors = true
rootCmd.SilenceUsage = trueSilent/Quiet Mode
go
var quiet bool
func init() {
rootCmd.PersistentFlags().BoolVarP(&quiet, "quiet", "q", false, "suppress output")
}
func output(msg string) {
if !quiet {
fmt.Println(msg)
}
}Reference Files
For more detailed information on specific topics:
- — Shell completion implementation details
references/completions.md - — Documentation generation (man, markdown, yaml, rst)
references/docgen.md - — Advanced patterns and edge cases
references/advanced.md