Production-ready Cobra CLI patterns including command structure, flags (local and persistent), nested commands, PreRun/PostRun hooks, argument validation, and initialization patterns used by kubectl and hugo. Use when building Go CLIs, implementing Cobra commands, creating nested command structures, managing flags, validating arguments, or when user mentions Cobra, CLI development, command-line tools, kubectl patterns, or Go CLI frameworks.
/plugin marketplace add vanman2024/cli-builder/plugin install cli-builder@cli-builderThis skill is limited to using the following tools:
examples/kubectl-style-cli.mdexamples/production-cli-complete.mdexamples/simple-cli-basic.mdscripts/add-command.shscripts/generate-completions.shscripts/setup-cobra-cli.shscripts/validate-cobra-cli.shtemplates/command.go.templatetemplates/completion-command.go.templatetemplates/main.go.templatetemplates/nested-command.go.templatetemplates/root.go.templateProduction-ready patterns for building powerful CLI applications with Cobra, following best practices from kubectl, hugo, and other production CLIs.
Select the appropriate CLI structure based on your use case:
Use the setup script to scaffold a new Cobra CLI:
cd /home/gotime2022/.claude/plugins/repos/cli-builder/skills/cobra-patterns
./scripts/setup-cobra-cli.sh <cli-name> <structure-type>
Structure types: simple, flat, nested, plugin, hybrid
Example:
./scripts/setup-cobra-cli.sh myctl nested
What This Creates:
var exampleCmd = &cobra.Command{
Use: "example [flags]",
Short: "Brief description",
Long: `Detailed description with examples`,
Args: cobra.ExactArgs(1),
Run: func(cmd *cobra.Command, args []string) {
// Command logic
},
}
var advancedCmd = &cobra.Command{
Use: "advanced",
Short: "Advanced command with hooks",
PersistentPreRun: func(cmd *cobra.Command, args []string) {
// Runs before command execution (inherited by children)
},
PreRun: func(cmd *cobra.Command, args []string) {
// Runs before command execution (local only)
},
Run: func(cmd *cobra.Command, args []string) {
// Main command logic
},
PostRun: func(cmd *cobra.Command, args []string) {
// Runs after command execution (local only)
},
PersistentPostRun: func(cmd *cobra.Command, args []string) {
// Runs after command execution (inherited by children)
},
}
var robustCmd = &cobra.Command{
Use: "robust",
Short: "Command with proper error handling",
RunE: func(cmd *cobra.Command, args []string) error {
// Return errors instead of os.Exit
if err := validateInput(args); err != nil {
return fmt.Errorf("validation failed: %w", err)
}
if err := executeOperation(); err != nil {
return fmt.Errorf("operation failed: %w", err)
}
return nil
},
}
func init() {
// Available to this command and all subcommands
rootCmd.PersistentFlags().StringVarP(&cfgFile, "config", "c", "", "config file")
rootCmd.PersistentFlags().BoolVarP(&verbose, "verbose", "v", false, "verbose output")
rootCmd.PersistentFlags().StringVar(&logLevel, "log-level", "info", "log level")
}
func init() {
// Only available to this specific command
createCmd.Flags().StringVarP(&name, "name", "n", "", "resource name")
createCmd.Flags().IntVar(&replicas, "replicas", 1, "number of replicas")
createCmd.Flags().BoolVar(&dryRun, "dry-run", false, "simulate operation")
// Mark required flags
createCmd.MarkFlagRequired("name")
}
func init() {
// Mutually exclusive flags (only one allowed)
createCmd.MarkFlagsMutuallyExclusive("json", "yaml", "text")
// Required together (all or none)
createCmd.MarkFlagsRequiredTogether("username", "password")
// At least one required
createCmd.MarkFlagsOneRequired("file", "stdin", "url")
// Custom flag completion
createCmd.RegisterFlagCompletionFunc("format", func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
return []string{"json", "yaml", "text"}, cobra.ShellCompDirectiveNoFileComp
})
}
// cmd/root.go
var rootCmd = &cobra.Command{
Use: "myctl",
Short: "A production-grade CLI tool",
Long: `A complete CLI application built with Cobra.
This application demonstrates production patterns including
nested commands, flag management, and proper error handling.`,
}
func Execute() error {
return rootCmd.Execute()
}
func init() {
cobra.OnInitialize(initConfig)
// Global flags
rootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file")
rootCmd.PersistentFlags().BoolVarP(&verbose, "verbose", "v", false, "verbose output")
// Add subcommands
rootCmd.AddCommand(getCmd)
rootCmd.AddCommand(createCmd)
rootCmd.AddCommand(deleteCmd)
}
func initConfig() {
// Initialize configuration, logging, etc.
}
// cmd/create/create.go
var createCmd = &cobra.Command{
Use: "create",
Short: "Create resources",
Long: `Create various types of resources`,
}
func init() {
// Add nested subcommands
createCmd.AddCommand(createDeploymentCmd)
createCmd.AddCommand(createServiceCmd)
createCmd.AddCommand(createConfigMapCmd)
}
// cmd/create/deployment.go
var createDeploymentCmd = &cobra.Command{
Use: "deployment [name]",
Short: "Create a deployment",
Args: cobra.ExactArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
return createDeployment(args[0])
},
}
func init() {
// Define command groups
rootCmd.AddGroup(&cobra.Group{
ID: "basic",
Title: "Basic Commands:",
})
rootCmd.AddGroup(&cobra.Group{
ID: "management",
Title: "Management Commands:",
})
// Assign commands to groups
getCmd.GroupID = "basic"
createCmd.GroupID = "management"
}
// No arguments allowed
var noArgsCmd = &cobra.Command{
Use: "list",
Args: cobra.NoArgs,
RunE: func(cmd *cobra.Command, args []string) error {
return listResources()
},
}
// Exactly n arguments
var exactArgsCmd = &cobra.Command{
Use: "get <name>",
Args: cobra.ExactArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
return getResource(args[0])
},
}
// Range of arguments
var rangeArgsCmd = &cobra.Command{
Use: "delete <name> [names...]",
Args: cobra.RangeArgs(1, 5),
RunE: func(cmd *cobra.Command, args []string) error {
return deleteResources(args)
},
}
// Custom validation
var customValidationCmd = &cobra.Command{
Use: "custom",
Args: func(cmd *cobra.Command, args []string) error {
if len(args) < 1 {
return fmt.Errorf("requires at least 1 argument")
}
for _, arg := range args {
if !isValid(arg) {
return fmt.Errorf("invalid argument: %s", arg)
}
}
return nil
},
RunE: func(cmd *cobra.Command, args []string) error {
return processArgs(args)
},
}
// Valid args with completion
var validArgsCmd = &cobra.Command{
Use: "select <resource>",
ValidArgs: []string{"pod", "service", "deployment", "configmap"},
Args: cobra.OnlyValidArgs,
RunE: func(cmd *cobra.Command, args []string) error {
return selectResource(args[0])
},
}
var (
cfgFile string
config Config
)
func init() {
// Register initialization functions
cobra.OnInitialize(initConfig, initLogging, initClient)
rootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file")
}
func initConfig() {
if cfgFile != "" {
viper.SetConfigFile(cfgFile)
} else {
home, err := os.UserHomeDir()
cobra.CheckErr(err)
viper.AddConfigPath(home)
viper.SetConfigType("yaml")
viper.SetConfigName(".myctl")
}
viper.AutomaticEnv()
if err := viper.ReadInConfig(); err == nil {
fmt.Fprintln(os.Stderr, "Using config file:", viper.ConfigFileUsed())
}
}
func initLogging() {
// Setup logging based on flags
}
func initClient() {
// Initialize API clients, connections, etc.
}
import (
"github.com/spf13/cobra"
"github.com/spf13/viper"
)
func init() {
// Bind flags to viper
rootCmd.PersistentFlags().String("output", "json", "output format")
viper.BindPFlag("output", rootCmd.PersistentFlags().Lookup("output"))
// Set defaults
viper.SetDefault("output", "json")
viper.SetDefault("timeout", 30)
}
func Execute() error {
// Access config via viper
output := viper.GetString("output")
timeout := viper.GetInt("timeout")
return rootCmd.Execute()
}
// Organize commands by resource type
// myctl get pods
// myctl create deployment
// myctl delete service
var getCmd = &cobra.Command{
Use: "get",
Short: "Display resources",
}
var createCmd = &cobra.Command{
Use: "create",
Short: "Create resources",
}
func init() {
// Resource-specific subcommands
getCmd.AddCommand(getPodsCmd)
getCmd.AddCommand(getServicesCmd)
createCmd.AddCommand(createDeploymentCmd)
createCmd.AddCommand(createServiceCmd)
}
// Support external commands (hugo server, hugo new, etc.)
func init() {
rootCmd.AddCommand(serverCmd)
rootCmd.AddCommand(newCmd)
// Auto-discover plugin commands
discoverPluginCommands(rootCmd)
}
func discoverPluginCommands(root *cobra.Command) {
// Look for executables like "myctl-plugin-*"
// Add them as dynamic commands
}
var longRunningCmd = &cobra.Command{
Use: "process",
Short: "Long-running operation",
RunE: func(cmd *cobra.Command, args []string) error {
ctx := cmd.Context()
// Respect context cancellation (Ctrl+C)
return processWithContext(ctx)
},
}
func processWithContext(ctx context.Context) error {
ticker := time.NewTicker(1 * time.Second)
defer ticker.Stop()
for {
select {
case <-ctx.Done():
return ctx.Err()
case <-ticker.C:
// Do work
}
}
}
Use validation scripts to ensure CLI compliance:
# Validate command structure
./scripts/validate-cobra-cli.sh <cli-directory>
# Test command execution
./scripts/test-cobra-commands.sh <cli-binary>
# Generate shell completions
./scripts/generate-completions.sh <cli-binary>
Validation Checks:
var completionCmd = &cobra.Command{
Use: "completion [bash|zsh|fish|powershell]",
Short: "Generate completion script",
Long: `Generate shell completion script.
Example usage:
# Bash
source <(myctl completion bash)
# Zsh
source <(myctl completion zsh)
# Fish
myctl completion fish | source
# PowerShell
myctl completion powershell | Out-String | Invoke-Expression
`,
DisableFlagsInUseLine: true,
ValidArgs: []string{"bash", "zsh", "fish", "powershell"},
Args: cobra.ExactArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
switch args[0] {
case "bash":
return cmd.Root().GenBashCompletion(os.Stdout)
case "zsh":
return cmd.Root().GenZshCompletion(os.Stdout)
case "fish":
return cmd.Root().GenFishCompletion(os.Stdout, true)
case "powershell":
return cmd.Root().GenPowerShellCompletionWithDesc(os.Stdout)
default:
return fmt.Errorf("unsupported shell: %s", args[0])
}
},
}
See examples/ directory for production patterns:
kubectl-style/: Kubectl command organization patternhugo-style/: Hugo plugin architecture patternsimple-cli/: Basic single-level CLInested-cli/: Multi-level command hierarchyproduction-cli/: Full production CLI with all featuresEach example includes:
# 1. Generate CLI structure
./scripts/setup-cobra-cli.sh myctl nested
# 2. Add commands
cd myctl
../scripts/add-command.sh get
../scripts/add-command.sh create --parent get
# 3. Validate structure
../scripts/validate-cobra-cli.sh .
# 4. Build and test
go build -o myctl
./myctl --help
# Use authentication template
cp templates/auth-command.go cmd/login.go
# Add persistent auth flags
cp templates/auth-flags.go cmd/root.go
# Implement token management
# Edit cmd/root.go to add initAuth() to cobra.OnInitialize
# Generate resource-based structure
./scripts/setup-cobra-cli.sh myctl nested
# Add resource commands (get, create, delete, update)
./scripts/add-command.sh get --style kubectl
./scripts/add-command.sh create --style kubectl
# Add resource types as subcommands
./scripts/add-command.sh pods --parent get
./scripts/add-command.sh services --parent get
Commands not showing in help: Ensure AddCommand() is called in init()
Flags not recognized: Check if flag is registered before command execution
PersistentFlags not inherited: Verify parent command has PersistentFlags defined
Completion not working: Run completion command and source output, check ValidArgs
Context cancellation ignored: Ensure you're checking ctx.Done() in long-running operations
This skill is used by:
Plugin: cli-builder Version: 1.0.0 Category: Go CLI Development Skill Type: Patterns & Templates
This skill should be used when the user asks to "create an agent", "add an agent", "write a subagent", "agent frontmatter", "when to use description", "agent examples", "agent tools", "agent colors", "autonomous agent", or needs guidance on agent structure, system prompts, triggering conditions, or agent development best practices for Claude Code plugins.
This skill should be used when the user asks to "create a slash command", "add a command", "write a custom command", "define command arguments", "use command frontmatter", "organize commands", "create command with file references", "interactive command", "use AskUserQuestion in command", or needs guidance on slash command structure, YAML frontmatter fields, dynamic arguments, bash execution in commands, user interaction patterns, or command development best practices for Claude Code.
This skill should be used when the user asks to "create a hook", "add a PreToolUse/PostToolUse/Stop hook", "validate tool use", "implement prompt-based hooks", "use ${CLAUDE_PLUGIN_ROOT}", "set up event-driven automation", "block dangerous commands", or mentions hook events (PreToolUse, PostToolUse, Stop, SubagentStop, SessionStart, SessionEnd, UserPromptSubmit, PreCompact, Notification). Provides comprehensive guidance for creating and implementing Claude Code plugin hooks with focus on advanced prompt-based hooks API.