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.
npx skills add eduardo-sl/go-agent-skills --skill go-cli -a claude-codeWhat 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-code2Manually: put the files in place
~/.claude/skills/go-cli/SKILL.mdCopy the whole skill folder; for one project use .claude/skills/go-cli/
1Skills CLI (Vercel)
npx skills add eduardo-sl/go-agent-skills --skill go-cli -a codex2Manually: put the files in place
.agents/skills/go-cli/SKILL.mdFor all projects use ~/.agents/skills/
1Skills CLI (Vercel)
npx skills add eduardo-sl/go-agent-skills --skill go-cli -a cursor2Manually: put the files in place
.cursor/skills/go-cli/SKILL.mdCursor also reads .agents/skills/ and .claude/skills/
1GitHub CLI
gh skill install eduardo-sl/go-agent-skills go-cli2Manually: put the files in place
.github/skills/go-cli/SKILL.md1Skills CLI (Vercel)
npx skills add eduardo-sl/go-agent-skills --skill go-cli -a gemini-cli2Platform CLI
gemini skills install https://github.com/eduardo-sl/go-agent-skills --path 'skills/(architecture)/go-cli'Manually: put the files in place
.devin/skills/go-cli/SKILL.mdThe legacy .windsurf/skills/ path still works
Skills CLI (Vercel)
npx skills add eduardo-sl/go-agent-skills --skill go-cli -a opencodeClaude.ai
Zip the folder and upload it in Settings → Capabilities → Skills
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