SKILL·F42446

go-cli

eduardo-sl
Updated Yesterday
63
9
63
View on GitHub
Metaapidesign

About

This Claude Skill provides guidance for building robust command-line tools in Go, covering flag parsing, subcommands, proper I/O handling, and signal management. It helps developers decide when to use the standard library versus frameworks like Cobra/Viper. Use it specifically for CLI construction tasks, not for API design or project scaffolding.

Quick Install

Claude Code

Recommended
Primary
npx skills add eduardo-sl/go-agent-skills -a claude-code
Plugin CommandAlternative
/plugin add https://github.com/eduardo-sl/go-agent-skills
Git CloneAlternative
git clone https://github.com/eduardo-sl/go-agent-skills.git ~/.claude/skills/go-cli

Copy and paste this command in Claude Code to install this skill

Documentation

Go CLI Design

A good CLI is a well-behaved Unix citizen: flags before magic, stdout for data, stderr for diagnostics, exit codes that scripts can trust, and Ctrl+C that actually stops it.

1. Structure: Testable main

func main() {
    ctx, stop := signal.NotifyContext(context.Background(),
        os.Interrupt, syscall.SIGTERM)
    defer stop()

    if err := run(ctx, os.Args[1:], os.Stdin, os.Stdout, os.Stderr); err != nil {
        fmt.Fprintln(os.Stderr, "error:", err)
        os.Exit(1)
    }
}

func run(ctx context.Context, args []string, stdin io.Reader, stdout, stderr io.Writer) error {
    fs := flag.NewFlagSet("mytool", flag.ContinueOnError)
    fs.SetOutput(stderr)
    verbose := fs.Bool("v", false, "verbose output")
    out := fs.String("o", "-", "output file (- for stdout)")
    if err := fs.Parse(args); err != nil {
        return err
    }
    // ...
    _ = verbose
    _ = out
    return nil
}
  • signal.NotifyContext makes Ctrl+C cancel the context — every long operation takes ctx and stops cleanly.
  • run receives args and streams — tests call it directly with strings.Reader/bytes.Buffer, no subprocess needed.
  • os.Exit only in main (it skips defers).

2. stdout vs stderr

  • stdout: the program's output — data, results, the thing you pipe.
  • stderr: logs, progress, warnings, usage errors.
  • --json or detecting a pipe (!term.IsTerminal(int(os.Stdout.Fd()))) should silence decorations, never change the data.
// ✅ Good — result to stdout, progress to stderr
fmt.Fprintf(stderr, "processed %d files\n", n)
fmt.Fprintln(stdout, result)

// ❌ Bad — mixing both into stdout breaks every pipe
fmt.Printf("processing...\ndone: %s\n", result)

3. Exit Codes

CodeMeaning
0Success
1Generic runtime failure
2Usage error (bad flags/arguments) — flag package's convention
>2Tool-specific, documented meanings (e.g. grep's 1 = no match)

Map errors to codes in one place (main), not scattered os.Exit calls. If scripts will branch on distinct failures, define sentinel errors and translate: errors.Is(err, ErrNoMatch) → 1.

4. Flags and Arguments

  • Flags for options, positional args for the primary operands: mytool -v convert input.yaml, not mytool --input=input.yaml.
  • Every flag has a usage string; -h/-help output is your primary UX.
  • Accept - as "stdin/stdout" for file arguments.
  • Defaults must be safe: destructive behavior behind explicit flags (--force), never default-on.
  • Read secrets from env or files, never from flags (ps leaks argv).

5. Subcommands

Standard library, fine up to a handful of commands:

switch fs.Arg(0) {
case "serve":
    return runServe(ctx, fs.Args()[1:], stdout, stderr)
case "migrate":
    return runMigrate(ctx, fs.Args()[1:], stdout, stderr)
default:
    fmt.Fprintln(stderr, usage)
    return fmt.Errorf("unknown command %q", fs.Arg(0))
}

Adopt Cobra when you need nested commands, generated help/completions, and many flags — the structure pays for the dependency:

var rootCmd = &cobra.Command{Use: "mytool", SilenceUsage: true}

var serveCmd = &cobra.Command{
    Use:   "serve",
    Short: "Start the server",
    RunE: func(cmd *cobra.Command, args []string) error {
        return serve(cmd.Context(), addr) // RunE returns errors; no os.Exit
    },
}

func init() {
    serveCmd.Flags().StringVar(&addr, "addr", ":8080", "listen address")
    rootCmd.AddCommand(serveCmd)
}

Cobra rules: always RunE (never Run + os.Exit), set SilenceUsage: true so runtime errors don't dump help, pass cmd.Context() down. Add Viper only when layered config (flags > env > file) is a real requirement — for most tools flag + os.Getenv is enough.

6. Output for Humans and Machines

  • --json flag for machine consumption; table/text default for humans.
  • Never emit ANSI colors when stdout is not a terminal or NO_COLOR is set.
  • Progress bars/spinners go to stderr and only when it's a terminal.

Verification Checklist

  1. run(ctx, args, stdin, stdout, stderr) pattern — logic testable without subprocess
  2. signal.NotifyContext wired; long operations respect ctx cancellation
  3. Data on stdout, diagnostics on stderr — verified by piping
  4. Exit codes: 0 success, 2 usage, documented codes otherwise; os.Exit only in main
  5. Every flag has usage text; -h output reviewed
  6. - accepted for stdin/stdout where files are taken
  7. Destructive actions require explicit flags
  8. No secrets via argv
  9. Cobra (if used): RunE everywhere, SilenceUsage, context propagated
  10. Colors/spinners disabled for non-TTY and NO_COLOR

GitHub Repository

eduardo-sl/go-agent-skills
Path: skills/(architecture)/go-cli
0
FAQ

Frequently asked questions

What is the go-cli skill?

go-cli is a Claude Skill by eduardo-sl. Skills package instructions and resources that Claude loads on demand, so Claude can perform go-cli-related tasks without extra prompting.

How do I install go-cli?

Use the install commands on this page: add go-cli to Claude Code as a plugin, or clone its repository into your skills directory, then restart Claude so it picks up the skill.

What category does go-cli belong to?

go-cli is in the Meta category, tagged api and design.

Is go-cli free to use?

Yes. go-cli is listed on AIMCP and free to install.

Related Skills

content-collections
Meta

This skill provides a production-tested setup for Content Collections, a TypeScript-first tool that transforms Markdown/MDX files into type-safe data collections with Zod validation. Use it when building blogs, documentation sites, or content-heavy Vite + React applications to ensure type safety and automatic content validation. It covers everything from Vite plugin configuration and MDX compilation to deployment optimization and schema validation.

View skill
polymarket
Meta

This skill enables developers to build applications with the Polymarket prediction markets platform, including API integration for trading and market data. It also provides real-time data streaming via WebSocket to monitor live trades and market activity. Use it for implementing trading strategies or creating tools that process live market updates.

View skill
creating-opencode-plugins
Meta

This skill helps developers create OpenCode plugins that hook into 25+ event types like commands, files, and LSP operations. It provides the plugin structure, event API specifications, and implementation patterns for JavaScript/TypeScript modules. Use it when you need to intercept, monitor, or extend the OpenCode AI assistant's lifecycle with custom event-driven logic.

View skill
sglang
Meta

SGLang is a high-performance LLM serving framework that specializes in fast, structured generation for JSON, regex, and agentic workflows using its RadixAttention prefix caching. It delivers significantly faster inference, especially for tasks with repeated prefixes, making it ideal for complex, structured outputs and multi-turn conversations. Choose SGLang over alternatives like vLLM when you need constrained decoding or are building applications with extensive prefix sharing.

View skill