Skip to main content
skill CX Codex

go-cli — Claude Code skill: what it does, how to install

Guides coding agents in building well-behaved Go CLI tools with clean signal handling, flag parsing, and Unix I/O discipline.

Install into Claude Code · Skills CLI (Vercel) All methods and platforms ↓
npx skills add eduardo-sl/go-agent-skills --skill go-cli -a claude-code
Open on GitHub

What go-cli does

The skill structures Go command-line tools around a testable run(ctx, args, stdin, stdout, stderr) function. This pattern allows unit tests to execute via in-memory buffers instead of spinning up subprocesses. Graceful shutdown relies on signal.NotifyContext tied directly to Ctrl+C, keeping os.Exit restricted strictly to main so defer statements still execute.

Output rules enforce strict Unix conventions. Data streams go to stdout, while diagnostic logs and progress indicators route to stderr. The skill outlines when the standard flag library suffices and when adding Cobra makes sense, requiring RunE and SilenceUsage: true to prevent messy help dumps on runtime failures. Integration tests use testscript (.txtar) and golden files.

Running this skill requires the local Go toolchain. It focuses exclusively on command-line ergonomics, leaving API design and project scaffolding to other domain skills.

What it helps with

  • isolate data streams on stdout from diagnostics on stderr
  • handle Ctrl+C cancellations via context without leaking defers
  • test CLI arguments and streams without running subprocesses
  • choose appropriately between standard flags and Cobra subcommands

Example prompts for the agent

  • Build a Go CLI tool that reads from stdin and outputs JSON using only the standard library
  • Add a Cobra subcommand structure with proper signal handling and RunE
  • Set up golden file tests for this command-line tool

How to install go-cli

1Skills CLI (Vercel)

npx skills add eduardo-sl/go-agent-skills --skill go-cli -a claude-code

2Manually: put the files in place

~/.claude/skills/go-cli/SKILL.md

Copy the whole skill folder; for one project use .claude/skills/go-cli/

Step by step, with commands for each platform: How to install skills in Claude Code: five ways

Questions about go-cli

How to install go-cli in Claude Code?

Run npx skills add eduardo-sl/go-agent-skills --skill go-cli -a claude-code.

What does the go-cli skill do?

It instructs coding agents on Go CLI best practices, covering flag parsing, exit code conventions, testable entry points, and Cobra integration.

What dependencies are needed for go-cli?

You must have the Go toolchain installed. The skill also relies on standard file tools and go/gofmt execution permissions.

Source text

SKILL.md · MIT
---
name: go-cli
description: >
  Build command-line tools in Go: flag handling, subcommands, stdin/stdout
  discipline, exit codes, signal handling, and when Cobra/Viper earn their
  weight over the standard library. Use when: "build a CLI", "add a
  subcommand", "parse flags", "exit codes", "handle Ctrl+C", "cobra
  command", "read from stdin", "CLI UX".
  Not for: HTTP APIs (go-api-design), scaffolding (go-project-layout),
  service configuration (go-architecture-review).
user-invocable: true
license: MIT
compatibility: Designed for Claude Code or similar AI coding agents working on Go projects. Requires the Go toolchain.
allowed-tools: Read Edit Write Glob Grep Bash(go:*) Bash(gofmt:*)
metadata:
  author: eduardo-sl
  version: "1.2.0"
---

# 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.

Detailed reference material, loaded on demand:

- `references/testing-and-versioning.md` — exit-code mapping in `main`,
  golden-file and testscript tests, version from build info, completions.

Read a reference file only when the summary below is not enough.

## 1. Structure: Testable main

```go
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. Call `stop()` once the
  context is done so a second Ctrl+C kills a stuck program immediately.
- `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.

```go
// ✅ 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

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

Map errors to codes in one place (`main`), not scattered `os.Exit`
calls. With `flag.ContinueOnError`, `-h` returns `flag.ErrHelp` — exit 0
for it, and wrap parse errors in a usage error type so `main` can exit 2.
Exit 130 after Ctrl+C. 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:

```go
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:

```go
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.

## 7. Testing

Test `run` directly with buffers, comparing stdout against golden files
regenerated with `-update`. For end-to-end behavior — real binary, exit
codes, stdin — use `testscript` (`.txtar` scripts), the format the Go
command tests itself with.

## 8. Version Information

`mytool version` reads `debug.ReadBuildInfo()`: since Go 1.24 the main
module's version comes from the VCS tag, and `vcs.revision` from the
build settings. Fall back to `-ldflags "-X main.version=..."` only when
building without VCS metadata.

## 9. Shell Completions

Cobra generates `completion bash|zsh|fish|powershell`; add
`ValidArgsFunction` for dynamic values. Without Cobra, ship a static
completion script with the release.

Examples for sections 3 and 7-9: `references/testing-and-versioning.md`.

## 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
11. `-h` exits 0, usage errors exit 2, Ctrl+C exits 130
12. `version` output comes from build info; golden or testscript tests cover the CLI surface

© eduardo-sl · MIT · eduardo-sl/go-agent-skills

Similar skills

All skills for Programming languages →

From the same set34

go-openapi Enforces spec-first REST development in Go by generating servers and clients via oapi-codegen, validating requests, and detecting breaking API changes. CX Codex +1 ★ 83repo stars go-interface-design This skill guides Go interface design, package decoupling, and compile-time contract checks. Use it when shaping dependencies or refactoring code for testability. CX Codex +1 ★ 83repo stars go-grpc A skill that steers your coding agent through gRPC work in Go: proto contracts, error codes, deadlines, interceptors and streaming. CX Codex +1 ★ 83repo stars go-graphql A skill for building Go GraphQL servers with gqlgen. It guides schema-first generation, fixes N+1 query fan-outs via dataloaders, and enforces query limits. CX Codex +1 ★ 83repo stars go-design-patterns This skill helps an agent choose Go patterns for constructors, runtime behavior and dependency failures. Use it when deciding how to structure a Go project. CX Codex +1 ★ 83repo stars go-dependency-injection A skill that steers your agent toward constructor injection and a single composition root in main. Useful once globals creep in or tests get hard to write. CX Codex +1 ★ 83repo stars go-architecture-review This skill reviews Go package structure, dependency direction, and module boundaries. Use it to assess an existing codebase or plan a refactor. CX Codex +1 ★ 83repo stars go-api-design A skill that steers the agent through Go HTTP handler design: routing, middleware, validation, pagination, graceful shutdown. Useful when you start a REST service or rework one. CX Codex +1 ★ 83repo stars

Project sponsors

Companies that keep this analytics open
Gold sponsor

Impressions, clicks and code copies — open statistics. We keep the numbers public for the same reason NeBlask itself is public. Become a sponsor