cobra

$npx mdskill add TerminalSkills/skills/cobra

Helps build modern CLI applications using the Cobra framework in Go

  • Solves the problem of creating structured command-line interfaces with subcommands and flags
  • Leverages the Cobra library and integrates with Go's standard toolchain
  • Analyzes requirements to recommend CLI structure, command hierarchy, and validation logic
  • Delivers code examples, configuration guidance, and best practices for Cobra-based CLIs
SKILL.md
.github/skills/cobraView on GitHub ↗
---
name: cobra
description: >-
  You are an expert in Cobra, the most popular Go library for building modern
  CLI applications. You help developers create command-line tools with
  subcommands, flags, argument validation, shell completions, and help
  generation — powering CLIs like kubectl, Hugo, GitHub CLI, and Docker.
license: Apache-2.0
compatibility: ''
metadata:
  author: terminal-skills
  version: 1.0.0
  category: Developer Tools
  tags:
    - go
    - cli
    - command-line
    - framework
    - flags
    - subcommands
---

# Cobra — Go CLI Framework

You are an expert in Cobra, the most popular Go library for building modern CLI applications. You help developers create command-line tools with subcommands, flags, argument validation, shell completions, and help generation — powering CLIs like kubectl, Hugo, GitHub CLI, and Docker.

## Core Capabilities

### Application Structure

```go
// cmd/root.go — Root command
package cmd

import (
    "fmt"
    "os"
    "github.com/spf13/cobra"
    "github.com/spf13/viper"
)

var cfgFile string
var verbose bool

var rootCmd = &cobra.Command{
    Use:   "myctl",
    Short: "My CLI tool for managing stuff",
    Long:  `A comprehensive CLI tool for managing deployments, configs, and services.`,
    PersistentPreRun: func(cmd *cobra.Command, args []string) {
        if verbose {
            fmt.Println("Verbose mode enabled")
        }
    },
}

func Execute() {
    if err := rootCmd.Execute(); err != nil {
        os.Exit(1)
    }
}

func init() {
    cobra.OnInitialize(initConfig)
    rootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default $HOME/.myctl.yaml)")
    rootCmd.PersistentFlags().BoolVarP(&verbose, "verbose", "v", false, "verbose output")
}

func initConfig() {
    if cfgFile != "" {
        viper.SetConfigFile(cfgFile)
    } else {
        home, _ := os.UserHomeDir()
        viper.AddConfigPath(home)
        viper.SetConfigName(".myctl")
    }
    viper.AutomaticEnv()
    viper.ReadInConfig()
}
```

```go
// cmd/deploy.go — Subcommand with flags
package cmd

import (
    "fmt"
    "github.com/spf13/cobra"
)

var deployCmd = &cobra.Command{
    Use:   "deploy [service]",
    Short: "Deploy a service to the target environment",
    Long:  `Deploy a service to the specified environment with optional version override.`,
    Args:  cobra.ExactArgs(1),            // Require exactly 1 argument
    Example: `  myctl deploy api --env production --version v2.1.0
  myctl deploy worker --env staging --dry-run`,
    RunE: func(cmd *cobra.Command, args []string) error {
        service := args[0]
        env, _ := cmd.Flags().GetString("env")
        version, _ := cmd.Flags().GetString("version")
        dryRun, _ := cmd.Flags().GetBool("dry-run")

        if dryRun {
            fmt.Printf("DRY RUN: Would deploy %s@%s to %s\n", service, version, env)
            return nil
        }

        fmt.Printf("Deploying %s@%s to %s...\n", service, version, env)
        return performDeploy(service, env, version)
    },
}

func init() {
    rootCmd.AddCommand(deployCmd)
    deployCmd.Flags().StringP("env", "e", "staging", "target environment")
    deployCmd.Flags().String("version", "latest", "version to deploy")
    deployCmd.Flags().Bool("dry-run", false, "simulate deployment")
    deployCmd.MarkFlagRequired("env")
}
```

```go
// cmd/status.go — Another subcommand
var statusCmd = &cobra.Command{
    Use:     "status [service]",
    Short:   "Show service status",
    Aliases: []string{"st"},              // myctl st == myctl status
    Args:    cobra.MaximumNArgs(1),
    ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
        // Dynamic completion: list available services
        services := []string{"api", "worker", "scheduler", "web"}
        return services, cobra.ShellCompDirectiveNoFileComp
    },
    RunE: func(cmd *cobra.Command, args []string) error {
        if len(args) == 0 {
            return showAllStatus()
        }
        return showServiceStatus(args[0])
    },
}
```

### Shell Completions

```bash
# Generate completions
myctl completion bash > /etc/bash_completion.d/myctl
myctl completion zsh > "${fpath[1]}/_myctl"
myctl completion fish > ~/.config/fish/completions/myctl.fish

# Cobra generates completions for all commands, flags, and arguments automatically
```

## Installation

```bash
go get github.com/spf13/cobra
# Scaffolding tool
go install github.com/spf13/cobra-cli@latest
cobra-cli init
cobra-cli add deploy
cobra-cli add status
```

## Best Practices

1. **Subcommands for organization** — Group related functionality: `myctl deploy`, `myctl status`, `myctl config`
2. **Flags with Viper** — Bind flags to Viper for unified config (CLI flags + env vars + config file)
3. **RunE over Run** — Use `RunE` (returns error) instead of `Run`; Cobra handles error display and exit codes
4. **Argument validation** — Use `Args: cobra.ExactArgs(1)` or custom validators; catch errors before execution
5. **Shell completions** — Cobra generates bash/zsh/fish/powershell completions; add `ValidArgsFunction` for dynamic completion
6. **Help is automatic** — Cobra generates `--help`, usage text, and subcommand lists; customize with `Long` and `Example`
7. **Aliases for convenience** — Add short aliases: `st` for `status`, `d` for `deploy`
8. **Persistent flags** — Use `PersistentFlags()` on root for flags that apply to all subcommands (`--verbose`, `--config`)
More from TerminalSkills/skills