Mode d’emploi
- Copiez la commande et examinez le paquet avant de l’installer dans votre environnement agent.
- Consultez le document original pour les outils, identifiants et environnements requis.
- Décrivez les entrées et le livrable souhaité ; comparez la sortie aux sources.
npx skills add https://github.com/eduardo-sl/go-agent-skills --skill go-cliAvant de commencer
- L’installation n’inclut ni abonnement au modèle, ni quota API, ni accès aux fichiers.
- Étoiles et installations reflètent l’activité, pas un test indépendant de qualité ou de sécurité.
Rendu depuis le dépôt source en conservant titres, exemples, code, tableaux, liens et images.
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.NotifyContextmakes Ctrl+C cancel the context — every
long operation takes ctx and stops cleanly.
runreceives args and streams — tests call it directly with
strings.Reader/bytes.Buffer, no subprocess needed.
os.Exitonly inmain(it skips defers).
2. stdout vs stderr
- stdout: the program's output — data, results, the thing you pipe.
- stderr: logs, progress, warnings, usage errors.
--jsonor 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
| 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. 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/-helpoutput 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 (
psleaks 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
--jsonflag 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
run(ctx, args, stdin, stdout, stderr)pattern — logic testable without subprocesssignal.NotifyContextwired; long operations respect ctx cancellation- Data on stdout, diagnostics on stderr — verified by piping
- Exit codes: 0 success, 2 usage, documented codes otherwise;
os.Exitonly in main - Every flag has usage text;
-houtput reviewed -accepted for stdin/stdout where files are taken- Destructive actions require explicit flags
- No secrets via argv
- Cobra (if used): RunE everywhere, SilenceUsage, context propagated
- Colors/spinners disabled for non-TTY and NO_COLOR



