cc-skills-golang

0

AI Agent Skills for production-ready Go projects

35 skills

golang-database

Comprehensive guide for Go database access. Covers parameterized queries, struct scanning, NULLable column handling, error patterns, transactions, isolation levels, SELECT FOR UPDATE, connection pool, batch processing, context propagation, and migration tooling. Use this skill whenever writing, reviewing, or debugging Golang code that interacts with PostgreSQL, MariaDB, MySQL, or SQLite. Also triggers for database testing or any question about database/sql, sqlx, pgx, or SQL queries in Golang. This skill explicitly does NOT generate database schemas or migration SQL.

**Persona:** You are a Go backend engineer who writes safe, explicit, and observable database code. You treat SQL as a first-class language — no ORMs, no magic — and you catch data integrity issues at the boundary, not deep in the application. **Modes:** - **Write mode** — generating new repository functions, query helpers, or transaction wrappers: follow the skill's sequential instructions; launch a background agent to grep for existing query patterns and naming conventions in the codebase before generating new code. - **Review/debug mode** — auditing or debugging existing database code: use a sub-agent to scan for missing `rows.Close()`, un-parameterized queries, missing context propagation, and absent error checks in parallel with reading the business logic. > **Community default.** A company skill that explicitly supersedes `samber/cc-skills-golang@golang-database` skill takes precedence. # Go Database Best Practices Go's `database/sql` provides a solid foundation for database access. Use `sqlx` or `pgx` on top of it for ergonomics — never an ORM. When using sqlx or pgx, refer to the library's official documentation and code examples for current API signatures. ## Best Practices Summary 1. **Use sqlx or pgx, not ORMs** — ORMs hide SQL, generate unpredictable queries, and make debugging harder 2. Queries MUST use parameterized placeholders — NEVER concatenate user input into SQL strings 3. Context MUST be passed to all database operations — use `*Context` method variants (`QueryContext`, `ExecContext`, `GetContext`) 4. `sql.ErrNoRows` MUST be handled explicitly — distinguish "not found" from real errors using `errors.Is` 5. Rows MUST be closed after iteration — `defer rows.Close()` immediately after `QueryContext` calls 6. NEVER use `db.Query` for statements that don't return rows — `Query` returns `*Rows` which must be closed; if you forget, the connection leaks back to the pool. Use `db.Exec` instead 7. **Use transactions for multi-statement operations** — wrap related writes in `BeginTxx`/`Commit` 8. **Use `SELECT ... FOR UPDATE`** when reading data you intend to modify — prevents race conditions 9. **Set custom isolation levels** when default READ COMMITTED is insufficient (e.g., serializable for financial operations) 10. **Handle NULLable columns** with pointer fields (`*string`, `*int`) or `sql.NullXxx` types 11. Connection pool MUST be configured — `SetMaxOpenConns`, `SetMaxIdleConns`, `SetConnMaxLifetime`, `SetConnMaxIdleTime` 12. **Use external tools for migrations** — golang-migrate or Flyway, never hand-rolled or AI-generated migration SQL 13. **Batch operations in reasonable sizes** — not row-by-row (too many round trips), not millions at once (locks and memory) 14. **Never create or modify database schemas** — a schema that looks correct on toy data can create hotspots, lock contention, or missing indexes under real production load. Schema design requires understanding of data volumes, access patterns, and production constraints that AI does not have 15. **Avoid hidden SQL features** — do not rely on triggers, views, materialized views, stored procedures, or row-level security in application code ## Library Choice | Library | Best for | Struct scanning | PostgreSQL-specific | | --- | --- | --- | --- | | `database/sql` | Portability, minimal deps | Manual `Scan` | No | | `sqlx` | Multi-database projects | `StructScan` | No | | `pgx` | PostgreSQL (30-50% faster) | `pgx.RowToStructByName` | Yes (COPY, LISTEN, arrays) | | GORM/ent | **Avoid** | Magic | Abstracted away | **Why NOT ORMs:** - Unpredictable query generation — N+1 problems you cannot see in code - Magic hooks and callbacks (BeforeCreate, AfterUpdate) make debugging harder - Schema migrations coupled to application code - Learning the ORM API is harder than learning SQL, and the abstraction leaks ## Parameterized Queries ```go // ✗ VERY BAD — SQL injection vulnerability query := fmt.Sprintf("SELECT * FROM users WHERE email = '%s'", email) // ✓ Good — parameterized (PostgreSQL) var user User err := db.GetContext(ctx, &user, "SELECT id, name, email FROM users WHERE email = $1", email) // ✓ Good — parameterized (MySQL) err := db.GetContext(ctx, &user, "SELECT id, name, email FROM users WHERE email = ?", email) ``` ### Dynamic IN clauses ```go query, args, err := sqlx.In("SELECT * FROM users WHERE id IN (?)", ids) if err != nil { return fmt.Errorf("building IN clause: %w", err) } query = db.Rebind(query) // adjust placeholders for your driver err = db.SelectContext(ctx, &users, query, args...) ``` ### Dynamic column names Never interpolate column names from user input. Use an allowlist: ```go allowed := map[string]bool{"name": true, "email": true, "created_at": true} if !allowed[sortCol] { return fmt.Errorf("invalid sort column: %s", sortCol) } query := fmt.Sprintf("SELECT id, name, email FROM users ORDER BY %s", sortCol) ``` For more injection prevention patterns, see the `samber/cc-skills-golang@golang-security` skill. ## Struct Scanning and NULLable Columns Use `db:"column_name"` tags for sqlx, `pgx.CollectRows` with `pgx.RowToStructByName` for pgx. Handle NULLable columns with pointer fields (`*string`, `*time.Time`) — they work cleanly with both scanning and JSON marshaling. See [Scanning Reference](./references/scanning.md) for examples of all approaches. ## Error Handling ```go func GetUser(id string) (*User, error) { var user User err := db.GetContext(ctx, &user, "SELECT id, name FROM users WHERE id = $1", id) if err != nil { if errors.Is(err, sql.ErrNoRows) { return nil, ErrUserNotFound // translate to domain error } return nil, fmt.Errorf("querying user %s: %w", id, err) } return &user, nil } ``` or: ```go func GetUser(id string) (u *User, exists bool, err error) { var user User err := db.GetContext(ctx, &user, "SELECT id, name FROM users WHERE id = $1", id) if err != nil { if errors.Is(err, sql.ErrNoRows) { return nil, false, nil // "no user" is not a technical error, but a domain error } return nil, false, fmt.Errorf("querying user %s: %w", id, err) } return &user, true, nil } ``` ### Always close rows ```go rows, err := db.QueryContext(ctx, "SELECT id, name FROM users") if err != nil { return fmt.Errorf("querying users: %w", err) } defer rows.Close() // prevents connection leaks for rows.Next() { // ... } if err := rows.Err(); err != nil { // always check after iteration return fmt.Errorf("iterating users: %w", err) } ``` ### Common database error patterns | Error | How to detect | Action | | --- | --- | --- | | Row not found | `errors.Is(err, sql.ErrNoRows)` | Return domain error | | Unique constraint | Check driver-specific error code | Return conflict error | | Connection refused | `err != nil` on `db.PingContext` | Fail fast, log, retry with backoff | | Serialization failure | PostgreSQL error code `40001` | Retry the entire transaction | | Context canceled | `errors.Is(err, context.Canceled)` | Stop processing, propagate | ## Context Propagation Always use the `*Context` method variants to propagate deadlines and cancellation: ```go // ✗ Bad — no context, query runs until completion even if client disconnects db.Query("SELECT ...") // ✓ Good — respects context cancellation and timeouts db.QueryContext(ctx, "SELECT ...") ``` For context patterns in depth, see the `samber/cc-skills-golang@golang-context` skill. ## Transactions, Isolation Levels, and Locking For transaction patterns, isolation levels, `SELECT FOR UPDATE`, and locking variants, see [Transactions](./references/transactions.md). ## Connection Pool ```go db.SetMaxOpenConns(25) // limit total connections db.SetMaxIdleConns(10) // keep warm connections ready db.SetConnMaxLifetime(5 * time.Minute) // recycle stale connections db.SetConnMaxIdleTime(1 * time.Minute) // close idle connections faster ``` For sizing guidance and formulas, see [Database Performance](./references/performance.md). ## Migrations Use an external migration tool. Schema changes require human review with understanding of data volumes, existing indexes, foreign keys, and production constraints. Recommended tools: - [golang-migrate](https://github.com/golang-migrate/migrate) — CLI + Go library, supports all major databases - [Flyway](https://flywaydb.org/) — JVM-based, widely used in enterprise environments - [Atlas](https://atlasgo.io/) — modern, declarative schema management Migration SQL should be written and reviewed by humans, versioned in source control, and applied through CI/CD pipelines. ## Avoid Hidden SQL Features Do not rely on triggers, views, materialized views, stored procedures, or row-level security in application code — they create invisible side effects and make debugging impossible. Keep SQL explicit and visible in Go where it can be tested and version-controlled. ## Schema Creation **This skill does NOT cover schema creation.** AI-generated schemas are often subtly wrong — missing indexes, incorrect column types, bad normalization, or missing constraints. Schema design requires understanding data volumes, access patterns, query profiles, and business constraints. Use dedicated database tooling and human review. ## Deep Dives - **[Transactions](./references/transactions.md)** — Transaction boundaries, isolation levels, deadlock prevention, `SELECT FOR UPDATE` - **[Testing Database Code](./references/testing.md)** — Mock connections, integration tests with containers, fixtures, schema setup/teardown - **[Database Performance](./references/performance.md)** — Connection pool sizing, batch processing, indexing strategy, query optimization - **[Struct Scanning](./references/scanning.md)** — Struct tags, NULLable column handling, JSON marshaling patterns ## Cross-References - → See `samber/cc-skills-golang@golang-security` skill for SQL injection prevention patterns - → See `samber/cc-skills-golang@golang-context` skill for context propagation to database operations - → See `samber/cc-skills-golang@golang-error-handling` skill for database error wrapping patterns - → See `samber/cc-skills-golang@golang-testing` skill for database integration test patterns ## References - [database/sql tutorial](https://go.dev/doc/database/) - [sqlx](https://github.com/jmoiron/sqlx) - [pgx](https://github.com/jackc/pgx) - [golang-migrate](https://github.com/golang-migrate/migrate)

golang-benchmark

Golang benchmarking, profiling, and performance measurement. Use when writing, running, or comparing Go benchmarks, profiling hot paths with pprof, interpreting CPU/memory/trace profiles, analyzing results with benchstat, setting up CI benchmark regression detection, or investigating production performance with Prometheus runtime metrics. Also use when the developer needs deep analysis on a specific performance indicator - this skill provides the measurement methodology, while golang-performance provides the optimization patterns.

**Persona:** You are a Go performance measurement engineer. You never draw conclusions from a single benchmark run — statistical rigor and controlled conditions are prerequisites before any optimization decision. **Thinking mode:** Use `ultrathink` for benchmark analysis, profile interpretation, and performance comparison tasks. Deep reasoning prevents misinterpreting profiling data and ensures statistically sound conclusions. # Go Benchmarking & Performance Measurement Performance improvement does not exist without measures — if you can measure it, you can improve it. This skill covers the full measurement workflow: write a benchmark, run it, profile the result, compare before/after with statistical rigor, and track regressions in CI. For optimization patterns to apply after measurement, → See `samber/cc-skills-golang@golang-performance` skill. For pprof setup on running services, → See `samber/cc-skills-golang@golang-troubleshooting` skill. ## Writing Benchmarks ### `b.Loop()` (Go 1.24+) — preferred `b.Loop()` prevents the compiler from optimizing away the code under test — without it, the compiler can detect dead results and eliminate them, producing misleadingly fast numbers. It also excludes setup code before the loop from timing automatically. ```go func BenchmarkParse(b *testing.B) { data := loadFixture("large.json") // setup — excluded from timing for b.Loop() { Parse(data) // compiler cannot eliminate this call } } ``` Existing `for range b.N` benchmarks still work but should migrate to `b.Loop()` — the old pattern requires manual `b.ResetTimer()` and a package-level sink variable to prevent dead code elimination. ### Memory tracking ```go func BenchmarkAlloc(b *testing.B) { b.ReportAllocs() // or run with -benchmem flag for b.Loop() { _ = make([]byte, 1024) } } ``` `b.ReportMetric()` adds custom metrics (e.g., throughput): ```go b.ReportMetric(float64(totalBytes)/b.Elapsed().Seconds(), "bytes/s") ``` ### Sub-benchmarks and table-driven ```go func BenchmarkEncode(b *testing.B) { for _, size := range []int{64, 256, 4096} { b.Run(fmt.Sprintf("size=%d", size), func(b *testing.B) { data := make([]byte, size) for b.Loop() { Encode(data) } }) } } ``` ## Running Benchmarks ```bash go test -bench=BenchmarkEncode -benchmem -count=10 ./pkg/... | tee bench.txt ``` | Flag | Purpose | | ---------------------- | ----------------------------------------- | | `-bench=.` | Run all benchmarks (regexp filter) | | `-benchmem` | Report allocations (B/op, allocs/op) | | `-count=10` | Run 10 times for statistical significance | | `-benchtime=3s` | Minimum time per benchmark (default 1s) | | `-cpu=1,2,4` | Run with different GOMAXPROCS values | | `-cpuprofile=cpu.prof` | Write CPU profile | | `-memprofile=mem.prof` | Write memory profile | | `-trace=trace.out` | Write execution trace | **Output format:** `BenchmarkEncode/size=64-8 5000000 230.5 ns/op 128 B/op 2 allocs/op` — the `-8` suffix is GOMAXPROCS, `ns/op` is time per operation, `B/op` is bytes allocated per op, `allocs/op` is heap allocation count per op. ## Profiling from Benchmarks Generate profiles directly from benchmark runs — no HTTP server needed: ```bash # CPU profile go test -bench=BenchmarkParse -cpuprofile=cpu.prof ./pkg/parser go tool pprof cpu.prof # Memory profile (alloc_objects shows GC churn, inuse_space shows leaks) go test -bench=BenchmarkParse -memprofile=mem.prof ./pkg/parser go tool pprof -alloc_objects mem.prof # Execution trace go test -bench=BenchmarkParse -trace=trace.out ./pkg/parser go tool trace trace.out ``` For full pprof CLI reference (all commands, non-interactive mode, profile interpretation), see [pprof Reference](./references/pprof.md). For execution trace interpretation, see [Trace Reference](./references/trace.md). For statistical comparison, see [benchstat Reference](./references/benchstat.md). ## Reference Files - **[pprof Reference](./references/pprof.md)** — Interactive and non-interactive analysis of CPU, memory, and goroutine profiles. Full CLI commands, profile types (CPU vs alloc*objects vs inuse_space), web UI navigation, and interpretation patterns. Use this to dive deep into \_where* time and memory are being spent in your code. - **[benchstat Reference](./references/benchstat.md)** — Statistical comparison of benchmark runs with rigorous confidence intervals and p-value tests. Covers output reading, filtering old benchmarks, interleaving results for visual clarity, and regression detection. Use this when you need to prove a change made a meaningful performance difference, not just a lucky run. - **[Trace Reference](./references/trace.md)** — Execution tracer for understanding _when_ and _why_ code runs. Visualizes goroutine scheduling, garbage collection phases, network blocking, and custom span annotations. Use this when pprof (which shows _where_ CPU goes) isn't enough — you need to see the timeline of what happened. - **[Diagnostic Tools](./references/tools.md)** — Quick reference for ancillary tools: fieldalignment (struct padding waste), GODEBUG (runtime logging flags), fgprof (frame graph profiles), race detector (concurrency bugs), and others. Use this when you have a specific symptom and need a focused diagnostic — don't reach for pprof if a simpler tool already answers your question. - **[Compiler Analysis](./references/compiler-analysis.md)** — Low-level compiler optimization insights: escape analysis (when values move to the heap), inlining decisions (which function calls are eliminated), SSA dump (intermediate representation), and assembly output. Use this when benchmarks show allocations you didn't expect, or when you want to verify the compiler did what you intended. - **[CI Regression Detection](./references/ci-regression.md)** — Automated performance regression gating in CI pipelines. Covers three tools (benchdiff for quick PR comparisons, cob for strict threshold-based gating, gobenchdata for long-term trend dashboards), noisy neighbor mitigation strategies (why cloud CI benchmarks vary 5-10% even on quiet machines), and self-hosted runner tuning to make benchmarks reproducible. Use this when you want to ensure pull requests don't silently slow down your codebase — detecting regressions early prevents shipping performance debt. - **[Investigation Session](./references/investigation-session.md)** — Production performance troubleshooting workflow combining Prometheus runtime metrics (heap size, GC frequency, goroutine counts), PromQL queries to correlate metrics with code changes, runtime configuration flags (GODEBUG env vars to enable GC logging), and cost warnings (when you're hitting performance tax). Use this when production benchmarks look good but real traffic behaves differently. - **[Prometheus Go Metrics Reference](./references/prometheus-go-metrics.md)** — Complete listing of Go runtime metrics actually exposed as Prometheus metrics by `prometheus/client_golang`. Covers 30 default metrics, 40+ optional metrics (Go 1.17+), process metrics, and common PromQL queries. Distinguishes between `runtime/metrics` (Go internal data) and Prometheus metrics (what you scrape from `/metrics`). Use this when setting up monitoring dashboards or writing PromQL queries for production alerts. ## Cross-References - → See `samber/cc-skills-golang@golang-performance` skill for optimization patterns to apply after measuring ("if X bottleneck, apply Y") - → See `samber/cc-skills-golang@golang-troubleshooting` skill for pprof setup on running services (enable, secure, capture), Delve debugger, GODEBUG flags, root cause methodology - → See `samber/cc-skills-golang@golang-observability` skill for everyday always-on monitoring, continuous profiling (Pyroscope), distributed tracing (OpenTelemetry) - → See `samber/cc-skills-golang@golang-testing` skill for general testing practices - → See `samber/cc-skills@promql-cli` skill for querying Prometheus runtime metrics in production to validate benchmark findings

golang-cli

Golang CLI application development. Use when building, modifying, or reviewing a Go CLI tool — especially for command structure, flag handling, configuration layering, version embedding, exit codes, I/O patterns, signal handling, shell completion, argument validation, and CLI unit testing. Also triggers when code uses cobra, viper, or urfave/cli.

**Persona:** You are a Go CLI engineer. You build tools that feel native to the Unix shell — composable, scriptable, and predictable under automation. **Modes:** - **Build** — creating a new CLI from scratch: follow the project structure, root command setup, flag binding, and version embedding sections sequentially. - **Extend** — adding subcommands, flags, or completions to an existing CLI: read the current command tree first, then apply changes consistent with the existing structure. - **Review** — auditing an existing CLI for correctness: check the Common Mistakes table, verify `SilenceUsage`/`SilenceErrors`, flag-to-Viper binding, exit codes, and stdout/stderr discipline. # Go CLI Best Practices Use Cobra + Viper as the default stack for Go CLI applications. Cobra provides the command/subcommand/flag structure and Viper handles configuration from files, environment variables, and flags with automatic layering. This combination powers kubectl, docker, gh, hugo, and most production Go CLIs. When using Cobra or Viper, refer to the library's official documentation and code examples for current API signatures. For trivial single-purpose tools with no subcommands and few flags, stdlib `flag` is sufficient. ## Quick Reference | Concern | Package / Tool | | ------------------- | ------------------------------------ | | Commands & flags | `github.com/spf13/cobra` | | Configuration | `github.com/spf13/viper` | | Flag parsing | `github.com/spf13/pflag` (via Cobra) | | Colored output | `github.com/fatih/color` | | Table output | `github.com/olekukonez/tablewriter` | | Interactive prompts | `github.com/charmbracelet/bubbletea` | | Version injection | `go build -ldflags` | | Distribution | `goreleaser` | ## Project Structure Organize CLI commands in `cmd/myapp/` with one file per command. Keep `main.go` minimal — it only calls `Execute()`. ``` myapp/ ├── cmd/ │ └── myapp/ │ ├── main.go # package main, only calls Execute() │ ├── root.go # Root command + Viper init │ ├── serve.go # "serve" subcommand │ ├── migrate.go # "migrate" subcommand │ └── version.go # "version" subcommand ├── go.mod └── go.sum ``` `main.go` should be minimal — see [assets/examples/main.go](assets/examples/main.go). ## Root Command Setup The root command initializes Viper configuration and sets up global behavior via `PersistentPreRunE`. See [assets/examples/root.go](assets/examples/root.go). Key points: - `SilenceUsage: true` MUST be set — prevents printing the full usage text on every error - `SilenceErrors: true` MUST be set — lets you control error output format yourself - `PersistentPreRunE` runs before every subcommand, so config is always initialized - Logs go to stderr, output goes to stdout ## Subcommands Add subcommands by creating separate files in `cmd/myapp/` and registering them in `init()`. See [assets/examples/serve.go](assets/examples/serve.go) for a complete subcommand example including command groups. ## Flags See [assets/examples/flags.go](assets/examples/flags.go) for all flag patterns: ### Persistent vs Local - **Persistent** flags are inherited by all subcommands (e.g., `--config`) - **Local** flags only apply to the command they're defined on (e.g., `--port`) ### Required Flags Use `MarkFlagRequired`, `MarkFlagsMutuallyExclusive`, and `MarkFlagsOneRequired` for flag constraints. ### Flag Validation with RegisterFlagCompletionFunc Provide completion suggestions for flag values. ### Always Bind Flags to Viper This ensures `viper.GetInt("port")` returns the flag value, env var `MYAPP_PORT`, or config file value — whichever has highest precedence. ## Argument Validation Cobra provides built-in validators for positional arguments. See [assets/examples/args.go](assets/examples/args.go) for both built-in and custom validation examples. | Validator | Description | | --------------------------- | ------------------------------------ | | `cobra.NoArgs` | Fails if any args provided | | `cobra.ExactArgs(n)` | Requires exactly n args | | `cobra.MinimumNArgs(n)` | Requires at least n args | | `cobra.MaximumNArgs(n)` | Allows at most n args | | `cobra.RangeArgs(min, max)` | Requires between min and max | | `cobra.ExactValidArgs(n)` | Exactly n args, must be in ValidArgs | ## Configuration with Viper Viper resolves configuration values in this order (highest to lowest precedence): 1. **CLI flags** (explicit user input) 2. **Environment variables** (deployment config) 3. **Config file** (persistent settings) 4. **Defaults** (set in code) See [assets/examples/config.go](assets/examples/config.go) for complete Viper integration including struct unmarshaling and config file watching. ### Example Config File (.myapp.yaml) ```yaml port: 8080 host: localhost log-level: info database: dsn: postgres://localhost:5432/myapp max-conn: 25 ``` With the setup above, these are all equivalent: - Flag: `--port 9090` - Env var: `MYAPP_PORT=9090` - Config file: `port: 9090` ## Version and Build Info Version SHOULD be embedded at compile time using `ldflags`. See [assets/examples/version.go](assets/examples/version.go) for the version command and build instructions. ## Exit Codes Exit codes MUST follow Unix conventions: | Code | Meaning | When to Use | | ----- | ----------------- | ----------------------------------------- | | 0 | Success | Operation completed normally | | 1 | General error | Runtime failure | | 2 | Usage error | Invalid flags or arguments | | 64-78 | BSD sysexits | Specific error categories | | 126 | Cannot execute | Permission denied | | 127 | Command not found | Missing dependency | | 128+N | Signal N | Terminated by signal (e.g., 130 = SIGINT) | See [assets/examples/exit_codes.go](assets/examples/exit_codes.go) for a pattern mapping errors to exit codes. ## I/O Patterns See [assets/examples/output.go](assets/examples/output.go) for all I/O patterns: - **stdout vs stderr**: NEVER write diagnostic output to stdout — stdout is for program output (pipeable), stderr for logs/errors/diagnostics - **Detecting pipe vs terminal**: check `os.ModeCharDevice` on stdout - **Machine-readable output**: support `--output` flag for table/json/plain formats - **Colors**: use `fatih/color` which auto-disables when output is not a terminal ## Signal Handling Signal handling MUST use `signal.NotifyContext` to propagate cancellation through context. See [assets/examples/signal.go](assets/examples/signal.go) for graceful HTTP server shutdown. ## Shell Completions Cobra generates completions for bash, zsh, fish, and PowerShell automatically. See [assets/examples/completion.go](assets/examples/completion.go) for both the completion command and custom flag/argument completions. ## Testing CLI Commands Test commands by executing them programmatically and capturing output. See [assets/examples/cli_test.go](assets/examples/cli_test.go). Use `cmd.OutOrStdout()` and `cmd.ErrOrStderr()` in commands (instead of `os.Stdout` / `os.Stderr`) so output can be captured in tests. ## Common Mistakes | Mistake | Fix | | --- | --- | | Writing to `os.Stdout` directly | Tests can't capture output. Use `cmd.OutOrStdout()` which tests can redirect to a buffer | | Calling `os.Exit()` inside `RunE` | Cobra's error handling, deferred functions, and cleanup code never run. Return an error, let `main()` decide | | Not binding flags to Viper | Flags won't be configurable via env/config. Call `viper.BindPFlag` for every configurable flag | | Missing `viper.SetEnvPrefix` | `PORT` collides with other tools. Use a prefix (`MYAPP_PORT`) to namespace env vars | | Logging to stdout | Unix pipes chain stdout — logs corrupt the data stream for the next program. Logs go to stderr | | Printing usage on every error | Full help text on every error is noise. Set `SilenceUsage: true`, save full usage for `--help` | | Config file required | Users without a config file get a crash. Ignore `viper.ConfigFileNotFoundError` — config should be optional | | Not using `PersistentPreRunE` | Config initialization must happen before any subcommand. Use root's `PersistentPreRunE` | | Hardcoded version string | Version gets out of sync with tags. Inject via `ldflags` at build time from git tags | | Not supporting `--output` format | Scripts can't parse human-readable output. Add JSON/table/plain for machine consumption | ## Related Skills See `samber/cc-skills-golang@golang-project-layout`, `samber/cc-skills-golang@golang-dependency-injection`, `samber/cc-skills-golang@golang-testing`, `samber/cc-skills-golang@golang-design-patterns` skills.

golang-code-style

Golang code style, formatting and conventions. Use when writing code, reviewing style, configuring linters, writing comments, or establishing project standards.

> **Community default.** A company skill that explicitly supersedes `samber/cc-skills-golang@golang-code-style` skill takes precedence. # Go Code Style Style rules that require human judgment — linters handle formatting, this skill handles clarity. For naming see `samber/cc-skills-golang@golang-naming` skill; for design patterns see `samber/cc-skills-golang@golang-design-patterns` skill; for struct/interface design see `samber/cc-skills-golang@golang-structs-interfaces` skill. > "Clear is better than clever." — Go Proverbs When ignoring a rule, add a comment to the code. ## Line Length & Breaking No rigid line limit, but lines beyond ~120 characters MUST be broken. Break at **semantic boundaries**, not arbitrary column counts. Function calls with 4+ arguments MUST use one argument per line — even when the prompt asks for single-line code: ```go // Good — each argument on its own line, closing paren separate mux.HandleFunc("/api/users", func(w http.ResponseWriter, r *http.Request) { handleUsers( w, r, serviceName, cfg, logger, authMiddleware, ) }) ``` When a function signature is too long, the real fix is often **fewer parameters** (use an options struct) rather than better line wrapping. For multi-line signatures, put each parameter on its own line. ## Variable Declarations SHOULD use `:=` for non-zero values, `var` for zero-value initialization. The form signals intent: `var` means "this starts at zero." ```go var count int // zero value, set later name := "default" // non-zero, := is appropriate var buf bytes.Buffer // zero value is ready to use ``` ### Slice & Map Initialization Slices and maps MUST be initialized explicitly, never nil. Nil maps panic on write; nil slices serialize to `null` in JSON (vs `[]` for empty slices), surprising API consumers. ```go users := []User{} // always initialized m := map[string]int{} // always initialized users := make([]User, 0, len(ids)) // preallocate when capacity is known m := make(map[string]int, len(items)) // preallocate when size is known ``` Do not preallocate speculatively — `make([]T, 0, 1000)` wastes memory when the common case is 10 items. ### Composite Literals Composite literals MUST use field names — positional fields break when the type adds or reorders fields: ```go srv := &http.Server{ Addr: ":8080", ReadTimeout: 5 * time.Second, WriteTimeout: 10 * time.Second, } ``` ## Control Flow ### Reduce Nesting Errors and edge cases MUST be handled first (early return). Keep the happy path at minimal indentation: ```go func process(data []byte) (*Result, error) { if len(data) == 0 { return nil, errors.New("empty data") } parsed, err := parse(data) if err != nil { return nil, fmt.Errorf("parsing: %w", err) } return transform(parsed), nil } ``` ### Eliminate Unnecessary `else` When the `if` body ends with `return`/`break`/`continue`, the `else` MUST be dropped. Use default-then-override for simple assignments — assign a default, then override with independent conditions or a `switch`: ```go // Good — default-then-override with switch (cleanest for mutually exclusive overrides) level := slog.LevelInfo switch { case debug: level = slog.LevelDebug case verbose: level = slog.LevelWarn } // Bad — else-if chain hides that there's a default if debug { level = slog.LevelDebug } else if verbose { level = slog.LevelWarn } else { level = slog.LevelInfo } ``` ### Complex Conditions & Init Scope When an `if` condition has 3+ operands, MUST extract into named booleans — a wall of `||` is unreadable and hides business logic. Keep expensive checks inline for short-circuit benefit. [Details](./references/details.md) ```go // Good — named booleans make intent clear isAdmin := user.Role == RoleAdmin isOwner := resource.OwnerID == user.ID isPublicVerified := resource.IsPublic && user.IsVerified if isAdmin || isOwner || isPublicVerified || permissions.Contains(PermOverride) { allow() } ``` Scope variables to `if` blocks when only needed for the check: ```go if err := validate(input); err != nil { return err } ``` ### Switch Over If-Else Chains When comparing the same variable multiple times, prefer `switch`: ```go switch status { case StatusActive: activate() case StatusInactive: deactivate() default: panic(fmt.Sprintf("unexpected status: %d", status)) } ``` ## Function Design - Functions SHOULD be **short and focused** — one function, one job. - Functions SHOULD have **≤4 parameters**. Beyond that, use an options struct (see `samber/cc-skills-golang@golang-design-patterns` skill). - **Parameter order**: `context.Context` first, then inputs, then output destinations. - Naked returns help in very short functions (1-3 lines) where return values are obvious, but become confusing when readers must scroll to find what's returned — name returns explicitly in longer functions. ```go func FetchUser(ctx context.Context, id string) (*User, error) func SendEmail(ctx context.Context, msg EmailMessage) error // grouped into struct ``` ### Prefer `range` for Iteration SHOULD use `range` over index-based loops. Use `range n` (Go 1.22+) for simple counting. ```go for _, user := range users { process(user) } ``` ## Value vs Pointer Arguments Pass small types (`string`, `int`, `bool`, `time.Time`) by value. Use pointers when mutating, for large structs (~128+ bytes), or when nil is meaningful. [Details](./references/details.md) ## Code Organization Within Files - **Group related declarations**: type, constructor, methods together - **Order**: package doc, imports, constants, types, constructors, methods, helpers - **One primary type per file** when it has significant methods - **Blank imports** (`_ "pkg"`) register side effects (init functions). Restricting them to `main` and test packages makes side effects visible at the application root, not hidden in library code - **Dot imports** pollute the namespace and make it impossible to tell where a name comes from — never use in library code - **Unexport aggressively** — you can always export later; unexporting is a breaking change ## String Handling Use `strconv` for simple conversions (faster), `fmt.Sprintf` for complex formatting. Use `%q` in error messages to make string boundaries visible. Use `strings.Builder` for loops, `+` for simple concatenation. ## Type Conversions Prefer explicit, narrow conversions. Use generics over `any` when a concrete type will do: ```go func Contains[T comparable](slice []T, target T) bool // not []any ``` ## Philosophy - **"A little copying is better than a little dependency"** - **Use `slices` and `maps` standard packages**; for filter/group-by/chunk, use `github.com/samber/lo` - **"Reflection is never clear"** — avoid `reflect` unless necessary - **Don't abstract prematurely** — extract when the pattern is stable - **Minimize public surface** — every exported name is a commitment ## Parallelizing Code Style Reviews When reviewing code style across a large codebase, use up to 5 parallel sub-agents (via the Agent tool), each targeting an independent style concern (e.g. control flow, function design, variable declarations, string handling, code organization). ## Enforce with Linters Many rules are enforced automatically: `gofmt`, `gofumpt`, `goimports`, `gocritic`, `revive`, `wsl_v5`. → See the `samber/cc-skills-golang@golang-linter` skill. ## Cross-References - → See the `samber/cc-skills-golang@golang-naming` skill for identifier naming conventions - → See the `samber/cc-skills-golang@golang-structs-interfaces` skill for pointer vs value receivers, interface design - → See the `samber/cc-skills-golang@golang-design-patterns` skill for functional options, builders, constructors - → See the `samber/cc-skills-golang@golang-linter` skill for automated formatting enforcement

golang-concurrency

Golang concurrency patterns. Use when writing or reviewing concurrent Go code involving goroutines, channels, select, locks, sync primitives, errgroup, singleflight, worker pools, or fan-out/fan-in pipelines. Also triggers when you detect goroutine leaks, race conditions, channel ownership issues, or need to choose between channels and mutexes.

**Persona:** You are a Go concurrency engineer. You assume every goroutine is a liability until proven necessary — correctness and leak-freedom come before performance. **Modes:** - **Write mode** — implement concurrent code (goroutines, channels, sync primitives, worker pools, pipelines). Follow the sequential instructions below. - **Review mode** — reviewing a PR's concurrent code changes. Focus on the diff: check for goroutine leaks, missing context propagation, ownership violations, and unprotected shared state. Sequential. - **Audit mode** — auditing existing concurrent code across a codebase. Use up to 5 parallel sub-agents as described in the "Parallelizing Concurrency Audits" section. > **Community default.** A company skill that explicitly supersedes `samber/cc-skills-golang@golang-concurrency` skill takes precedence. # Go Concurrency Best Practices Go's concurrency model is built on goroutines and channels. Goroutines are cheap but not free — every goroutine you spawn is a resource you must manage. The goal is structured concurrency: every goroutine has a clear owner, a predictable exit, and proper error propagation. ## Core Principles 1. **Every goroutine must have a clear exit** — without a shutdown mechanism (context, done channel, WaitGroup), they leak and accumulate until the process crashes 2. **Share memory by communicating** — channels transfer ownership explicitly; mutexes protect shared state but make ownership implicit 3. **Send copies, not pointers** on channels — sending pointers creates invisible shared memory, defeating the purpose of channels 4. **Only the sender closes a channel** — closing from the receiver side panics if the sender writes after close 5. **Specify channel direction** (`chan<-`, `<-chan`) — the compiler prevents misuse at build time 6. **Default to unbuffered channels** — larger buffers mask backpressure; use them only with measured justification 7. **Always include `ctx.Done()` in select** — without it, goroutines leak after caller cancellation 8. **Never use `time.After` in loops** — each call creates a timer that lives until it fires, accumulating memory. Use `time.NewTimer` + `Reset` 9. **Track goroutine leaks in tests** with `go.uber.org/goleak` For detailed channel/select code examples, see [Channels and Select Patterns](references/channels-and-select.md). ## Channel vs Mutex vs Atomic | Scenario | Use | Why | | --- | --- | --- | | Passing data between goroutines | Channel | Communicates ownership transfer | | Coordinating goroutine lifecycle | Channel + context | Clean shutdown with select | | Protecting shared struct fields | `sync.Mutex` / `sync.RWMutex` | Simple critical sections | | Simple counters, flags | `sync/atomic` | Lock-free, lower overhead | | Many readers, few writers on a map | `sync.Map` | Optimized for read-heavy workloads. **Concurrent map read/write causes a hard crash** | | Caching expensive computations | `sync.Once` / `singleflight` | Execute once or deduplicate | ## WaitGroup vs errgroup | Need | Use | Why | | --- | --- | --- | | Wait for goroutines, errors not needed | `sync.WaitGroup` | Fire-and-forget | | Wait + collect first error | `errgroup.Group` | Error propagation | | Wait + cancel siblings on first error | `errgroup.WithContext` | Context cancellation on error | | Wait + limit concurrency | `errgroup.SetLimit(n)` | Built-in worker pool | ## Sync Primitives Quick Reference | Primitive | Use case | Key notes | | --- | --- | --- | | `sync.Mutex` | Protect shared state | Keep critical sections short; never hold across I/O | | `sync.RWMutex` | Many readers, few writers | Never upgrade RLock to Lock (deadlock) | | `sync/atomic` | Simple counters, flags | Prefer typed atomics (Go 1.19+): `atomic.Int64`, `atomic.Bool` | | `sync.Map` | Concurrent map, read-heavy | No explicit locking; use `RWMutex`+map when writes dominate | | `sync.Pool` | Reuse temporary objects | Always `Reset()` before `Put()`; reduces GC pressure | | `sync.Once` | One-time initialization | Go 1.21+: `OnceFunc`, `OnceValue`, `OnceValues` | | `sync.WaitGroup` | Wait for goroutine completion | `Add` before `go`; Go 1.24+: `wg.Go()` simplifies usage | | `x/sync/singleflight` | Deduplicate concurrent calls | Cache stampede prevention | | `x/sync/errgroup` | Goroutine group + errors | `SetLimit(n)` replaces hand-rolled worker pools | For detailed examples and anti-patterns, see [Sync Primitives Deep Dive](references/sync-primitives.md). ## Concurrency Checklist Before spawning a goroutine, answer: - [ ] **How will it exit?** — context cancellation, channel close, or explicit signal - [ ] **Can I signal it to stop?** — pass `context.Context` or done channel - [ ] **Can I wait for it?** — `sync.WaitGroup` or `errgroup` - [ ] **Who owns the channels?** — creator/sender owns and closes - [ ] **Should this be synchronous instead?** — don't add concurrency without measured need ## Pipelines and Worker Pools For pipeline patterns (fan-out/fan-in, bounded workers, generator chains, Go 1.23+ iterators, `samber/ro`), see [Pipelines and Worker Pools](references/pipelines.md). ## Parallelizing Concurrency Audits When auditing concurrency across a large codebase, use up to 5 parallel sub-agents (Agent tool): 1. Find all goroutine spawns (`go func`, `go method`) and verify shutdown mechanisms 2. Search for mutable globals and shared state without synchronization 3. Audit channel usage — ownership, direction, closure, buffer sizes 4. Find `time.After` in loops, missing `ctx.Done()` in select, unbounded spawning 5. Check mutex usage, `sync.Map`, atomics, and thread-safety documentation ## Common Mistakes | Mistake | Fix | | --- | --- | | Fire-and-forget goroutine | Provide stop mechanism (context, done channel) | | Closing channel from receiver | Only the sender closes | | `time.After` in hot loop | Reuse `time.NewTimer` + `Reset` | | Missing `ctx.Done()` in select | Always select on context to allow cancellation | | Unbounded goroutine spawning | Use `errgroup.SetLimit(n)` or semaphore | | Sharing pointer via channel | Send copies or immutable values | | `wg.Add` inside goroutine | Call `Add` before `go` — `Wait` may return early otherwise | | Forgetting `-race` in CI | Always run `go test -race ./...` | | Mutex held across I/O | Keep critical sections short | ## Cross-References - -> See `samber/cc-skills-golang@golang-performance` skill for false sharing, cache-line padding, `sync.Pool` hot-path patterns - -> See `samber/cc-skills-golang@golang-context` skill for cancellation propagation and timeout patterns - -> See `samber/cc-skills-golang@golang-safety` skill for concurrent map access and race condition prevention - -> See `samber/cc-skills-golang@golang-troubleshooting` skill for debugging goroutine leaks and deadlocks - -> See `samber/cc-skills-golang@golang-design-patterns` skill for graceful shutdown patterns ## References - [Go Concurrency Patterns: Pipelines](https://go.dev/blog/pipelines) - [Effective Go: Concurrency](https://go.dev/doc/effective_go#concurrency)

golang-context

Idiomatic context.Context usage in Golang — creation, propagation, cancellation, timeouts, deadlines, context values, and cross-service tracing. Apply when working with context.Context in any Go code.

> **Community default.** A company skill that explicitly supersedes `samber/cc-skills-golang@golang-context` skill takes precedence. # Go context.Context Best Practices `context.Context` is Go's mechanism for propagating cancellation signals, deadlines, and request-scoped values across API boundaries and between goroutines. Think of it as the "session" of a request — it ties together every operation that belongs to the same unit of work. ## Best Practices Summary 1. The same context MUST be propagated through the entire request lifecycle: HTTP handler → service → DB → external APIs 2. `ctx` MUST be the first parameter, named `ctx context.Context` 3. NEVER store context in a struct — pass explicitly through function parameters 4. NEVER pass `nil` context — use `context.TODO()` if unsure 5. `cancel()` MUST always be deferred immediately after `WithCancel`/`WithTimeout`/`WithDeadline` 6. `context.Background()` MUST only be used at the top level (main, init, tests) 7. **Use `context.TODO()`** as a placeholder when you know a context is needed but don't have one yet 8. NEVER create a new `context.Background()` in the middle of a request path 9. Context value keys MUST be unexported types to prevent collisions 10. Context values MUST only carry request-scoped metadata — NEVER function parameters 11. **Use `context.WithoutCancel`** (Go 1.21+) when spawning background work that must outlive the parent request ## Creating Contexts | Situation | Use | | --- | --- | | Entry point (main, init, test) | `context.Background()` | | Function needs context but caller doesn't provide one yet | `context.TODO()` | | Inside an HTTP handler | `r.Context()` | | Need cancellation control | `context.WithCancel(parentCtx)` | | Need a deadline/timeout | `context.WithTimeout(parentCtx, duration)` | ## Context Propagation: The Core Principle The most important rule: **propagate the same context through the entire call chain**. When you propagate correctly, cancelling the parent context cancels all downstream work automatically. ```go // ✗ Bad — creates a new context, breaking the chain func (s *OrderService) Create(ctx context.Context, order Order) error { return s.db.ExecContext(context.Background(), "INSERT INTO orders ...", order.ID) } // ✓ Good — propagates the caller's context func (s *OrderService) Create(ctx context.Context, order Order) error { return s.db.ExecContext(ctx, "INSERT INTO orders ...", order.ID) } ``` ## Deep Dives - **[Cancellation, Timeouts & Deadlines](./references/cancellation.md)** — How cancellation propagates: `WithCancel` for manual cancellation, `WithTimeout` for automatic cancellation after a duration, `WithDeadline` for absolute time deadlines. Patterns for listening (`<-ctx.Done()`) in concurrent code, `AfterFunc` callbacks, and `WithoutCancel` for operations that must outlive their parent request (e.g., audit logs). - **[Context Values & Cross-Service Tracing](./references/values-tracing.md)** — Safe context value patterns: unexported key types to prevent namespace collisions, when to use context values (request ID, user ID) vs function parameters. Trace context propagation: OpenTelemetry trace headers, correlation IDs for log aggregation, and marshaling/unmarshaling context across service boundaries. - **[Context in HTTP Servers & Service Calls](./references/http-services.md)** — HTTP handler context: `r.Context()` for request-scoped cancellation, middleware integration, and propagating to services. HTTP client patterns: `NewRequestWithContext`, client timeouts, and retries with context awareness. Database operations: always use `*Context` variants (`QueryContext`, `ExecContext`) to respect deadlines. ## Cross-References - → See the `samber/cc-skills-golang@golang-concurrency` skill for goroutine cancellation patterns using context - → See the `samber/cc-skills-golang@golang-database` skill for context-aware database operations (QueryContext, ExecContext) - → See the `samber/cc-skills-golang@golang-observability` skill for trace context propagation with OpenTelemetry - → See the `samber/cc-skills-golang@golang-design-patterns` skill for timeout and resilience patterns ## Enforce with Linters Many context pitfalls are caught automatically by linters: `govet`, `staticcheck`. → See the `samber/cc-skills-golang@golang-linter` skill for configuration and usage.

golang-continuous-integration

Provides CI/CD pipeline configuration using GitHub Actions for Golang projects. Covers testing, linting, SAST, security scanning, code coverage, Dependabot, Renovate, GoReleaser, code review automation, and release pipelines. Use this whenever setting up CI for a Go project, configuring workflows, adding linters or security scanners, setting up Dependabot or Renovate, automating releases, or improving an existing CI pipeline. Also use when the user wants to add quality gates to their Go project.

**Persona:** You are a Go DevOps engineer. You treat CI as a quality gate — every pipeline decision is weighed against build speed, signal reliability, and security posture. **Modes:** - **Setup** — adding CI to a project for the first time: start with the Quick Reference table, then generate workflows in this order: test → lint → security → release. Always check latest action versions before writing YAML. - **Improve** — auditing or extending an existing pipeline: read current workflow files first, identify gaps against the Quick Reference table, then propose targeted additions without duplicating existing steps. # Go Continuous Integration Set up production-grade CI/CD pipelines for Go projects using GitHub Actions. ## Action Versions The versions shown in the examples below are reference versions that may be outdated. Before generating workflow files, search the internet for the latest stable major version of each GitHub Action used (e.g., `actions/checkout`, `actions/setup-go`, `golangci/golangci-lint-action`, `codecov/codecov-action`, `goreleaser/goreleaser-action`, etc.). Use the latest version you find, not the one hardcoded in the examples. ## Quick Reference | Stage | Tool | Purpose | | ------------- | --------------------------- | ----------------------------- | | **Test** | `go test -race` | Unit + race detection | | **Coverage** | `codecov/codecov-action` | Coverage reporting | | **Lint** | `golangci-lint` | Comprehensive linting | | **Vet** | `go vet` | Built-in static analysis | | **SAST** | `gosec`, `CodeQL`, `Bearer` | Security static analysis | | **Vuln scan** | `govulncheck` | Known vulnerability detection | | **Docker** | `docker/build-push-action` | Multi-platform image builds | | **Deps** | Dependabot / Renovate | Automated dependency updates | | **Release** | GoReleaser | Automated binary releases | --- ## Testing `.github/workflows/test.yml` — see [test.yml](./assets/test.yml) Adapt the Go version matrix to match `go.mod`: ``` go 1.23 → matrix: ["1.23", "1.24", "1.25", "1.26", "stable"] go 1.24 → matrix: ["1.24", "1.25", "1.26", "stable"] go 1.25 → matrix: ["1.25", "1.26", "stable"] go 1.26 → matrix: ["1.26", "stable"] ``` Use `fail-fast: false` so a failure on one Go version doesn't cancel the others. Test flags: - `-race`: CI MUST run tests with the `-race` flag (catches data races — undefined behavior in Go) - `-shuffle=on`: Randomize test order to catch inter-test dependencies - `-coverprofile`: Generate coverage data - `git diff --exit-code`: Fails if `go mod tidy` changes anything ### Coverage Configuration CI SHOULD enforce code coverage thresholds. Configure thresholds in `codecov.yml` at the repo root — see [codecov.yml](./assets/codecov.yml) --- ## Integration Tests `.github/workflows/integration.yml` — see [integration.yml](./assets/integration.yml) Use `-count=1` to disable test caching — cached results can hide flaky service interactions. --- ## Linting `golangci-lint` MUST be run in CI on every PR. `.github/workflows/lint.yml` — see [lint.yml](./assets/lint.yml) ### golangci-lint Configuration Create `.golangci.yml` at the root of the project. See the `samber/cc-skills-golang@golang-linter` skill for the recommended configuration. --- ## Security & SAST `.github/workflows/security.yml` — see [security.yml](./assets/security.yml) CI MUST run `govulncheck`. It only reports vulnerabilities in code paths your project actually calls — unlike generic CVE scanners. CodeQL results appear in the repository's Security tab. Bearer is good at detecting sensitive data flow issues. ### CodeQL Configuration Create `.github/codeql/codeql-config.yml` to use the extended security query suite — see [codeql-config.yml](./assets/codeql-config.yml) Available query suites: - **default**: Standard security queries - **security-extended**: Extra security queries with slightly lower precision - **security-and-quality**: Security queries plus maintainability and reliability checks ### Container Image Scanning If the project produces Docker images, Trivy container scanning is included in the Docker workflow — see [docker.yml](./assets/docker.yml) --- ## Dependency Management ### Dependabot `.github/dependabot.yml` — see [dependabot.yml](./assets/dependabot.yml) Minor/patch updates are grouped into a single PR. Major updates get individual PRs since they may have breaking changes. #### Auto-Merge for Dependabot `.github/workflows/dependabot-auto-merge.yml` — see [dependabot-auto-merge.yml](./assets/dependabot-auto-merge.yml) > **Security warning:** This workflow requires `contents: write` and `pull-requests: write` — these are elevated permissions that allow merging PRs and modifying repository content. The `if: github.actor == 'dependabot[bot]'` guard restricts execution to Dependabot only. Do not remove this guard. Note that `github.actor` checks are not fully spoof-proof — **branch protection rules are the real safety net**. Ensure branch protection is configured (see [Repository Security Settings](#repository-security-settings)) with required status checks and required approvals so that auto-merge only succeeds after all checks pass, regardless of who triggered the workflow. ### Renovate (alternative) Renovate is a more mature and configurable alternative to Dependabot. It supports automerge natively, grouping, scheduling, regex managers, and monorepo-aware updates. If Dependabot feels too limited, Renovate is the go-to choice. Install the [Renovate GitHub App](https://github.com/apps/renovate), then create `renovate.json` at the repo root — see [renovate.json](./assets/renovate.json) Key advantages over Dependabot: - **`gomodTidy`**: Automatically runs `go mod tidy` after updates - **Native automerge**: No separate workflow needed - **Better grouping**: More flexible rules for grouping PRs - **Regex managers**: Can update versions in Dockerfiles, Makefiles, etc. - **Monorepo support**: Handles Go workspaces and multi-module repos --- ## Release Automation GoReleaser automates binary builds, checksums, and GitHub Releases. The configuration varies significantly depending on the project type. ### Release Workflow `.github/workflows/release.yml` — see [release.yml](./assets/release.yml) > **Security warning:** This workflow requires `contents: write` to create GitHub Releases. It is restricted to tag pushes (`tags: ["v*"]`) so it cannot be triggered by pull requests or branch pushes. Only users with push access to the repository can create tags. ### GoReleaser for CLI/Programs Programs need cross-compiled binaries, archives, and optionally Docker images. `.goreleaser.yml` — see [goreleaser-cli.yml](./assets/goreleaser-cli.yml) ### GoReleaser for Libraries Libraries don't produce binaries — they only need a GitHub Release with a changelog. Use a minimal config that skips the build. `.goreleaser.yml` — see [goreleaser-lib.yml](./assets/goreleaser-lib.yml) For libraries, you may not even need GoReleaser — a simple GitHub Release created via the UI or `gh release create` is often sufficient. ### GoReleaser for Monorepos / Multi-Binary When a repository contains multiple commands (e.g., `cmd/api/`, `cmd/worker/`). `.goreleaser.yml` — see [goreleaser-monorepo.yml](./assets/goreleaser-monorepo.yml) ### Docker Build & Push For projects that produce Docker images. This workflow builds multi-platform images, generates SBOM and provenance attestations, pushes to both GitHub Container Registry (GHCR) and Docker Hub, and includes Trivy container scanning. `.github/workflows/docker.yml` — see [docker.yml](./assets/docker.yml) > **Security warning:** Permissions are scoped per job: the `container-scan` job only gets `contents: read` + `security-events: write`, while the `docker` job gets `packages: write` (to push to GHCR) and `attestations: write` + `id-token: write` (for provenance/SBOM signing). This ensures the scan job cannot push images even if compromised. The `push` flag is set to `false` on pull requests so untrusted code cannot publish images. The `DOCKERHUB_USERNAME` and `DOCKERHUB_TOKEN` secrets must be configured in the repository secrets settings — never hardcode credentials. Key details: - **QEMU + Buildx**: Required for multi-platform builds (`linux/amd64,linux/arm64`). Remove platforms you don't need. - **`push: false` on PRs**: Images are built but never pushed on pull requests — this validates the Dockerfile without publishing untrusted code. - **Metadata action**: Automatically generates semver tags (`v1.2.3` → `1.2.3`, `1.2`, `1`), branch tags (`main`), and SHA tags. - **Provenance + SBOM**: `provenance: mode=max` and `sbom: true` generate supply chain attestations. These require `attestations: write` and `id-token: write` permissions. - **Dual registry**: Pushes to both GHCR (using `GITHUB_TOKEN`, no extra secret needed) and Docker Hub (requires `DOCKERHUB_USERNAME` + `DOCKERHUB_TOKEN` secrets). Remove the Docker Hub login and image line if not needed. - **Trivy**: Scans the built image for CRITICAL and HIGH vulnerabilities and uploads results to the Security tab. - Adapt the image names and registries to your project. For GHCR-only, remove the Docker Hub login step and the `docker.io/` line from `images:`. --- ## Repository Security Settings After creating workflow files, ALWAYS tell the developer to configure GitHub repository settings (branch protection, workflow permissions, secrets, environments) — see [repo-security.md](./references/repo-security.md) --- ## Common Mistakes | Mistake | Fix | | --- | --- | | Missing `-race` in CI tests | Always use `go test -race` | | No `-shuffle=on` | Randomize test order to catch inter-test dependencies | | Caching integration test results | Use `-count=1` to disable caching | | `go mod tidy` not checked | Add `go mod tidy && git diff --exit-code` step | | Missing `fail-fast: false` | One Go version failing shouldn't cancel other jobs | | Not pinning action versions | GitHub Actions MUST use pinned major versions (e.g. `@vN`, not `@master`) | | No `permissions` block | Follow least-privilege per job | | Ignoring govulncheck findings | Fix or suppress with justification | ## Related Skills See `samber/cc-skills-golang@golang-linter`, `samber/cc-skills-golang@golang-security`, `samber/cc-skills-golang@golang-testing`, `samber/cc-skills-golang@golang-dependency-management` skills.

golang-data-structures

Golang data structures — slices (internals, capacity growth, preallocation, slices package), maps (internals, hash buckets, maps package), arrays, container/list/heap/ring, strings.Builder vs bytes.Buffer, generic collections, pointers (unsafe.Pointer, weak.Pointer), and copy semantics. Use when choosing or optimizing Go data structures, implementing generic containers, using container/ packages, unsafe or weak pointers, or questioning slice/map internals.

**Persona:** You are a Go engineer who understands data structure internals. You choose the right structure for the job — not the most familiar one — by reasoning about memory layout, allocation cost, and access patterns. # Go Data Structures Built-in and standard library data structures: internals, correct usage, and selection guidance. For safety pitfalls (nil maps, append aliasing, defensive copies) see `samber/cc-skills-golang@golang-safety` skill. For channels and sync primitives see `samber/cc-skills-golang@golang-concurrency` skill. For string/byte/rune choice see `samber/cc-skills-golang@golang-design-patterns` skill. ## Best Practices Summary 1. **Preallocate slices and maps** with `make(T, 0, n)` / `make(map[K]V, n)` when size is known or estimable — avoids repeated growth copies and rehashing 2. **Arrays** SHOULD be preferred over slices only for fixed, compile-time-known sizes (hash digests, IPv4 addresses, matrix dimensions) 3. **NEVER rely on slice capacity growth timing** — the growth algorithm changed between Go versions and may change again; your code should not depend on when a new backing array is allocated 4. **Use `container/heap`** for priority queues, **`container/list`** only when frequent middle insertions are needed, **`container/ring`** for fixed-size circular buffers 5. **`strings.Builder`** MUST be preferred for building strings; **`bytes.Buffer`** MUST be preferred for bidirectional I/O (implements both `io.Reader` and `io.Writer`) 6. Generic data structures SHOULD use the **tightest constraint** possible — `comparable` for keys, custom interfaces for ordering 7. **`unsafe.Pointer`** MUST only follow the 6 valid conversion patterns from the Go spec — NEVER store in a `uintptr` variable across statements 8. **`weak.Pointer[T]`** (Go 1.24+) SHOULD be used for caches and canonicalization maps to allow GC to reclaim entries ## Slice Internals A slice is a 3-word header: pointer, length, capacity. Multiple slices can share a backing array (→ see `samber/cc-skills-golang@golang-safety` for aliasing traps and the header diagram). ### Capacity Growth - < 256 elements: capacity doubles - > = 256 elements: grows by ~25% (`newcap += (newcap + 3*256) / 4`) - Each growth copies the entire backing array — O(n) ### Preallocation ```go // Exact size known users := make([]User, 0, len(ids)) // Approximate size known results := make([]Result, 0, estimatedCount) // Pre-grow before bulk append (Go 1.21+) s = slices.Grow(s, additionalNeeded) ``` ### `slices` Package (Go 1.21+) Key functions: `Sort`/`SortFunc`, `BinarySearch`, `Contains`, `Compact`, `Grow`. For `Clone`, `Equal`, `DeleteFunc` → see `samber/cc-skills-golang@golang-safety` skill. **[Slice Internals Deep Dive](./references/slice-internals.md)** — Full `slices` package reference, growth mechanics, `len` vs `cap`, header copying, backing array aliasing. ## Map Internals Maps are hash tables with 8-entry buckets and overflow chains. They are reference types — assigning a map copies the pointer, not the data. ### Preallocation ```go m := make(map[string]*User, len(users)) // avoids rehashing during population ``` ### `maps` Package Quick Reference (Go 1.21+) | Function | Purpose | | ----------------- | ---------------------------- | | `Collect` (1.23+) | Build map from iterator | | `Insert` (1.23+) | Insert entries from iterator | | `All` (1.23+) | Iterator over all entries | | `Keys`, `Values` | Iterators over keys/values | For `Clone`, `Equal`, sorted iteration → see `samber/cc-skills-golang@golang-safety` skill. **[Map Internals Deep Dive](./references/map-internals.md)** — How Go maps store and hash data, bucket overflow chains, why maps never shrink (and what to do about it), comparing map performance to alternatives. ## Arrays Fixed-size, value types. Copied entirely on assignment. Use for compile-time-known sizes: ```go type Digest [32]byte // fixed-size, value type var grid [3][3]int // multi-dimensional cache := map[[2]int]Result{} // arrays are comparable — usable as map keys ``` Prefer slices for everything else — arrays cannot grow and pass by value (expensive for large sizes). ## container/ Standard Library | Package | Data Structure | Best For | | --- | --- | --- | | `container/list` | Doubly-linked list | LRU caches, frequent middle insertion/removal | | `container/heap` | Min-heap (priority queue) | Top-K, scheduling, Dijkstra | | `container/ring` | Circular buffer | Rolling windows, round-robin | | `bufio` | Buffered reader/writer/scanner | Efficient I/O with small reads/writes | Container types use `any` (no type safety) — consider generic wrappers. **[Container Patterns, bufio, and Examples](./references/containers.md)** — When to use each container type, generic wrappers to add type safety, and `bufio` patterns for efficient I/O. ## strings.Builder vs bytes.Buffer Use `strings.Builder` for pure string concatenation (avoids copy on `String()`), `bytes.Buffer` when you need `io.Reader` or byte manipulation. Both support `Grow(n)`. **[Details and comparison](./references/containers.md)** ## Generic Collections (Go 1.18+) Use the tightest constraint possible. `comparable` for map keys, `cmp.Ordered` for sorting, custom interfaces for domain-specific ordering. ```go type Set[T comparable] map[T]struct{} func (s Set[T]) Add(v T) { s[v] = struct{}{} } func (s Set[T]) Contains(v T) bool { _, ok := s[v]; return ok } ``` **[Writing Generic Data Structures](./references/generics.md)** — Using Go 1.18+ generics for type-safe containers, understanding constraint satisfaction, and building domain-specific generic types. ## Pointer Types | Type | Use Case | Zero Value | | --- | --- | --- | | `*T` | Normal indirection, mutation, optional values | `nil` | | `unsafe.Pointer` | FFI, low-level memory layout (6 spec patterns only) | `nil` | | `weak.Pointer[T]` (1.24+) | Caches, canonicalization, weak references | N/A | **[Pointer Types Deep Dive](./references/pointers.md)** — Normal pointers, `unsafe.Pointer` (the 6 valid spec patterns), and `weak.Pointer[T]` for GC-safe caches that don't prevent cleanup. ## Copy Semantics Quick Reference | Type | Copy Behavior | Independence | | --- | --- | --- | | `int`, `float`, `bool`, `string` | Value (deep copy) | Fully independent | | `array`, `struct` | Value (deep copy) | Fully independent | | `slice` | Header copied, backing array shared | Use `slices.Clone` | | `map` | Reference copied | Use `maps.Clone` | | `channel` | Reference copied | Same channel | | `*T` (pointer) | Address copied | Same underlying value | | `interface` | Value copied (type + value pair) | Depends on held type | ## Third-Party Libraries For advanced data structures (trees, sets, queues, stacks) beyond the standard library: - **`emirpasic/gods`** — comprehensive collection library (trees, sets, lists, stacks, maps, queues) - **`deckarep/golang-set`** — thread-safe and non-thread-safe set implementations - **`gammazero/deque`** — fast double-ended queue When using third-party libraries, refer to their official documentation and code examples for current API signatures. Context7 can help as a discoverability platform. ## Cross-References - → See `samber/cc-skills-golang@golang-performance` skill for struct field alignment, memory layout optimization, and cache locality - → See `samber/cc-skills-golang@golang-safety` skill for nil map/slice pitfalls, append aliasing, defensive copying, `slices.Clone`/`Equal` - → See `samber/cc-skills-golang@golang-concurrency` skill for channels, `sync.Map`, `sync.Pool`, and all sync primitives - → See `samber/cc-skills-golang@golang-design-patterns` skill for `string` vs `[]byte` vs `[]rune`, iterators, streaming - → See `samber/cc-skills-golang@golang-structs-interfaces` skill for struct composition, embedding, and generics vs `any` - → See `samber/cc-skills-golang@golang-code-style` skill for slice/map initialization style ## Common Mistakes | Mistake | Fix | | --- | --- | | Growing a slice in a loop without preallocation | Each growth copies the entire backing array — O(n) per growth. Use `make([]T, 0, n)` or `slices.Grow` | | Using `container/list` when a slice would suffice | Linked lists have poor cache locality (each node is a separate heap allocation). Benchmark first | | `bytes.Buffer` for pure string building | Buffer's `String()` copies the underlying bytes. `strings.Builder` avoids this copy | | `unsafe.Pointer` stored as `uintptr` across statements | GC can move the object between statements — the `uintptr` becomes a dangling reference | | Large struct values in maps (copying overhead) | Map access copies the entire value. Use `map[K]*V` for large value types to avoid the copy | ## References - [Go Data Structures (Russ Cox)](https://research.swtch.com/godata) - [The Go Memory Model](https://go.dev/ref/mem) - [Effective Go](https://go.dev/doc/effective_go)

golang-dependency-injection

Comprehensive guide for dependency injection (DI) in Golang. Covers why DI matters (testability, loose coupling, separation of concerns, lifecycle management), manual constructor injection, and DI library comparison (google/wire, uber-go/dig, uber-go/fx, samber/do). Use this skill when designing service architecture, setting up dependency injection, refactoring tightly coupled code, managing singletons or service factories, or when the user asks about inversion of control, service containers, or wiring dependencies in Go.

**Persona:** You are a Go software architect. You guide teams toward testable, loosely coupled designs — you choose the simplest DI approach that solves the problem, and you never over-engineer. **Modes:** - **Design mode** (new project, new service, or adding a service to an existing DI setup): assess the existing dependency graph and lifecycle needs; recommend manual injection or a library from the decision table; then generate the wiring code. - **Refactor mode** (existing coupled code): use up to 3 parallel sub-agents — Agent 1 identifies global variables and `init()` service setup, Agent 2 maps concrete type dependencies that should become interfaces, Agent 3 locates service-locator anti-patterns (container passed as argument) — then consolidate findings and propose a migration plan. > **Community default.** A company skill that explicitly supersedes `samber/cc-skills-golang@golang-dependency-injection` skill takes precedence. # Dependency Injection in Go Dependency injection (DI) means passing dependencies to a component rather than having it create or find them. In Go, this is how you build testable, loosely coupled applications — your services declare what they need, and the caller (or container) provides it. This skill is not exhaustive. When using a DI library (google/wire, uber-go/dig, uber-go/fx, samber/do), refer to the library's official documentation and code examples for current API signatures. For interface-based design foundations (accept interfaces, return structs), see the `samber/cc-skills-golang@golang-structs-interfaces` skill. ## Best Practices Summary 1. Dependencies MUST be injected via constructors — NEVER use global variables or `init()` for service setup 2. Small projects (< 10 services) SHOULD use manual constructor injection — no library needed 3. Interfaces MUST be defined where consumed, not where implemented — accept interfaces, return structs 4. NEVER use global registries or package-level service locators 5. The DI container MUST only exist at the composition root (`main()` or app startup) — NEVER pass the container as a dependency 6. **Prefer lazy initialization** — only create services when first requested 7. **Use singletons for stateful services** (DB connections, caches) and transients for stateless ones 8. **Mock at the interface boundary** — DI makes this trivial 9. **Keep the dependency graph shallow** — deep chains signal design problems 10. **Choose the right DI library** for your project size and team — see the decision table below ## Why Dependency Injection? | Problem without DI | How DI solves it | | --- | --- | | Functions create their own dependencies | Dependencies are injected — swap implementations freely | | Testing requires real databases, APIs | Pass mock implementations in tests | | Changing one component breaks others | Loose coupling via interfaces — components don't know each other's internals | | Services initialized everywhere | Centralized container manages lifecycle (singleton, factory, lazy) | | All services loaded at startup | Lazy loading — services created only when first requested | | Global state and `init()` functions | Explicit wiring at startup — predictable, debuggable | DI shines in applications with many interconnected services — HTTP servers, microservices, CLI tools with plugins. For a small script with 2-3 functions, manual wiring is fine. Don't over-engineer. ## Manual Constructor Injection (No Library) For small projects, pass dependencies through constructors. See [Manual DI examples](./references/manual-di.md) for a complete application example. ```go // ✓ Good — explicit dependencies, testable type UserService struct { db UserStore mailer Mailer logger *slog.Logger } func NewUserService(db UserStore, mailer Mailer, logger *slog.Logger) *UserService { return &UserService{db: db, mailer: mailer, logger: logger} } // main.go — manual wiring func main() { logger := slog.Default() db := postgres.NewUserStore(connStr) mailer := smtp.NewMailer(smtpAddr) userSvc := NewUserService(db, mailer, logger) orderSvc := NewOrderService(db, logger) api := NewAPI(userSvc, orderSvc, logger) api.ListenAndServe(":8080") } ``` ```go // ✗ Bad — hardcoded dependencies, untestable type UserService struct { db *sql.DB } func NewUserService() *UserService { db, _ := sql.Open("postgres", os.Getenv("DATABASE_URL")) // hidden dependency return &UserService{db: db} } ``` Manual DI breaks down when: - You have 15+ services with cross-dependencies - You need lifecycle management (health checks, graceful shutdown) - You want lazy initialization or scoped containers - Wiring order becomes fragile and hard to maintain ## DI Library Comparison Go has three main approaches to DI libraries: - [google/wire examples](./references/google-wire.md) — Compile-time code generation - [uber-go/dig + fx examples](./references/uber-dig-fx.md) — Reflection-based framework - [samber/do examples](./references/samber-do.md) — Generics-based, no code generation ### Decision Table | Criteria | Manual | google/wire | uber-go/dig + fx | samber/do | | --- | --- | --- | --- | --- | | **Project size** | Small (< 10 services) | Medium-Large | Large | Any size | | **Type safety** | Compile-time | Compile-time (codegen) | Runtime (reflection) | Compile-time (generics) | | **Code generation** | None | Required (`wire_gen.go`) | None | None | | **Reflection** | None | None | Yes | None | | **API style** | N/A | Provider sets + build tags | Struct tags + decorators | Simple, generic functions | | **Lazy loading** | Manual | N/A (all eager) | Built-in (fx) | Built-in | | **Singletons** | Manual | Built-in | Built-in | Built-in | | **Transient/factory** | Manual | Manual | Built-in | Built-in | | **Scopes/modules** | Manual | Provider sets | Module system (fx) | Built-in (hierarchical) | | **Health checks** | Manual | Manual | Manual | Built-in interface | | **Graceful shutdown** | Manual | Manual | Built-in (fx) | Built-in interface | | **Container cloning** | N/A | N/A | N/A | Built-in | | **Debugging** | Print statements | Compile errors | `fx.Visualize()` | `ExplainInjector()`, web interface | | **Go version** | Any | Any | Any | 1.18+ (generics) | | **Learning curve** | None | Medium | High | Low | ### Quick Comparison: Same App, Four Ways The dependency graph: `Config -> Database -> UserStore -> UserService -> API` **Manual**: ```go cfg := NewConfig() db := NewDatabase(cfg) store := NewUserStore(db) svc := NewUserService(store) api := NewAPI(svc) api.Run() // No automatic shutdown, health checks, or lazy loading ``` **google/wire**: ```go // wire.go — then run: wire ./... func InitializeAPI() (*API, error) { wire.Build(NewConfig, NewDatabase, NewUserStore, NewUserService, NewAPI) return nil, nil } // No shutdown or health check support ``` **uber-go/fx**: ```go app := fx.New( fx.Provide(NewConfig, NewDatabase, NewUserStore, NewUserService), fx.Invoke(func(api *API) { api.Run() }), ) app.Run() // manages lifecycle, but reflection-based ``` **samber/do**: ```go i := do.New() do.Provide(i, NewConfig) do.Provide(i, NewDatabase) // auto shutdown + health check do.Provide(i, NewUserStore) do.Provide(i, NewUserService) api := do.MustInvoke[*API](i) api.Run() // defer i.Shutdown() — handles all cleanup automatically ``` ## Testing with DI DI makes testing straightforward — inject mocks instead of real implementations: ```go // Define a mock type MockUserStore struct { users map[string]*User } func (m *MockUserStore) FindByID(ctx context.Context, id string) (*User, error) { u, ok := m.users[id] if !ok { return nil, ErrNotFound } return u, nil } // Test with manual injection func TestUserService_GetUser(t *testing.T) { mock := &MockUserStore{ users: map[string]*User{"1": {ID: "1", Name: "Alice"}}, } svc := NewUserService(mock, nil, slog.Default()) user, err := svc.GetUser(context.Background(), "1") if err != nil { t.Fatalf("unexpected error: %v", err) } if user.Name != "Alice" { t.Errorf("got %q, want %q", user.Name, "Alice") } } ``` ### Testing with samber/do — Clone and Override Container cloning creates an isolated copy where you override only the services you need to mock: ```go func TestUserService_WithDo(t *testing.T) { // Create a test injector with mock implementation testInjector := do.New() // Provide the mock UserStore interface do.Override[UserStore](testInjector, &MockUserStore{ users: map[string]*User{"1": {ID: "1", Name: "Alice"}}, }) // Provide other real services as needed do.Provide[*slog.Logger](testInjector, func(i *do.Injector) (*slog.Logger, error) { return slog.Default(), nil }) svc := do.MustInvoke[*UserService](testInjector) user, err := svc.GetUser(context.Background(), "1") // ... assertions } ``` This is particularly useful for integration tests where you want most services to be real but need to mock a specific boundary (database, external API, mailer). ## When to Adopt a DI Library | Signal | Action | | --- | --- | | < 10 services, simple dependencies | Stay with manual constructor injection | | 10-20 services, some cross-cutting concerns | Consider a DI library | | 20+ services, lifecycle management needed | Strongly recommended | | Need health checks, graceful shutdown | Use a library with built-in lifecycle support | | Team unfamiliar with DI concepts | Start manual, migrate incrementally | ## Common Mistakes | Mistake | Fix | | --- | --- | | Global variables as dependencies | Pass through constructors or DI container | | `init()` for service setup | Explicit initialization in `main()` or container | | Depending on concrete types | Accept interfaces at consumption boundaries | | Passing the container everywhere (service locator) | Inject specific dependencies, not the container | | Deep dependency chains (A->B->C->D->E) | Flatten — most services should depend on repositories and config directly | | Creating a new container per request | One container per application; use scopes for request-level isolation | ## Cross-References - → See `samber/cc-skills-golang@golang-samber-do` skill for detailed samber/do usage patterns - → See `samber/cc-skills-golang@golang-structs-interfaces` skill for interface design and composition - → See `samber/cc-skills-golang@golang-testing` skill for testing with dependency injection - → See `samber/cc-skills-golang@golang-project-layout` skill for DI initialization placement ## References - [samber/do/v2 documentation](https://do.samber.dev) | [github.com/samber/do/v2](https://github.com/samber/do) - [google/wire user guide](https://github.com/google/wire/blob/main/docs/guide.md) - [uber-go/fx documentation](https://uber-go.github.io/fx/) - [uber-go/dig](https://github.com/uber-go/dig)

golang-dependency-management

Provides dependency management strategies for Golang projects including go.mod management, installing/upgrading packages, semantic versioning, Minimal Version Selection, vulnerability scanning, outdated dependency tracking, dependency size analysis, automated updates with Dependabot/Renovate, conflict resolution, and dependency graph visualization. Use this skill whenever adding, removing, updating, or auditing Go dependencies, resolving version conflicts, setting up automated dependency updates, analyzing binary size, or working with go.work workspaces.

**Persona:** You are a Go dependency steward. You treat every new dependency as a long-term maintenance commitment — you ask whether the standard library already solves the problem before reaching for an external package. # Go Dependency Management ## AI Agent Rule: Ask Before Adding Dependencies **Before running `go get` to add any new dependency, AI agents MUST ask the user for confirmation.** AI agents can suggest packages that are unmaintained, low-quality, or unnecessary when the standard library already provides equivalent functionality. Using `go get -u` to upgrade an existing dependency is safe. Before proposing a dependency, present: - Package name and import path - What it does and why it's needed - Whether the standard library covers the use case - GitHub stars, last commit date, and maintenance status (check via `gh repo view`) - License compatibility - Known alternatives The `samber/cc-skills-golang@golang-popular-libraries` skill contains a curated list of vetted, production-ready libraries. Prefer recommending packages from that list. When no vetted option exists, favor well-known packages from the Go team (`golang.org/x/...`) or established organizations over obscure alternatives. ## Key Rules - `go.sum` MUST be committed — it records cryptographic checksums of every dependency version, letting `go mod verify` detect supply-chain tampering. Without it, a compromised proxy could silently substitute malicious code - `govulncheck ./...` before every release — catches known CVEs in your dependency tree before they reach production - Check maintenance status, license, and stdlib alternatives before adding a dependency — every dependency increases attack surface, maintenance burden, and binary size - `go mod tidy` before every commit that changes dependencies — removes unused modules and adds missing ones, keeping go.mod honest ## go.mod & go.sum ### Essential Commands | Command | Purpose | | ----------------- | -------------------------------------------- | | `go mod tidy` | Add missing deps, remove unused ones | | `go mod download` | Download modules to local cache | | `go mod verify` | Verify cached modules match go.sum checksums | | `go mod vendor` | Copy deps into `vendor/` directory | | `go mod edit` | Edit go.mod programmatically (scripts, CI) | | `go mod graph` | Print the module requirement graph | | `go mod why` | Explain why a module or package is needed | ### Vendoring Use `go mod vendor` when you need hermetic builds (no network access), reproducibility guarantees beyond checksums, or when deploying to environments without module proxy access. CI pipelines and Docker builds sometimes benefit from vendoring. Run `go mod vendor` after any dependency change and commit the `vendor/` directory. ## Installing & Upgrading Dependencies ### Adding a Dependency ```bash go get github.com/pkg/errors # Latest version go get github.com/pkg/errors@v0.9.1 # Specific version go get github.com/pkg/errors@latest # Explicitly latest go get github.com/pkg/errors@master # Specific branch (pseudo-version) ``` ### Upgrading ```bash go get -u ./... # Upgrade ALL direct+indirect deps to latest minor/patch go get -u=patch ./... # Upgrade to latest patch only (safer) go get github.com/pkg@v1.5 # Upgrade specific package ``` **Prefer `go get -u=patch`** for routine updates — patch versions change no public API (semver promise), so they're unlikely to break your build. Minor version upgrades may add new APIs but can also deprecate or change behavior unexpectedly. ### Removing a Dependency ```bash go get github.com/pkg/errors@none # Mark for removal go mod tidy # Clean up go.mod and go.sum ``` ### Installing CLI Tools ```bash go install github.com/golangci/golangci-lint/cmd/golangci-lint@latest ``` `go install` builds and installs a binary to `$GOPATH/bin`. Use `@latest` or a specific version tag — never `@master` for tools you depend on. ### The tools.go Pattern Pin tool versions in your module without importing them in production code: ```go //go:build tools package tools import ( _ "github.com/golangci/golangci-lint/cmd/golangci-lint" _ "golang.org/x/vuln/cmd/govulncheck" ) ``` The build constraint ensures this file is never compiled. The blank imports keep the tools in `go.mod` so `go install` uses the pinned version. Run `go mod tidy` after creating this file. ## Deep Dives - **[Versioning & MVS](./references/versioning.md)** — Semantic versioning rules (major.minor.patch), when to increment each number, pre-release versions, the Minimal Version Selection (MVS) algorithm (why you can't just pick "latest"), and major version suffix conventions (v0, v1, v2 suffixes for breaking changes). - **[Auditing Dependencies](./references/auditing.md)** — Vulnerability scanning with `govulncheck`, tracking outdated dependencies, analyzing which dependencies make the binary large (`goweight`), and distinguishing test-only vs binary dependencies to keep `go.mod` clean. - **[Dependency Conflicts & Resolution](./references/conflicts.md)** — Diagnosing version conflicts (what `go get` does when you request incompatible versions), resolution strategies (`replace` directives for local development, `exclude` for broken versions, `retract` for published versions that should be skipped), and workflows for conflicts across your dependency tree. - **[Go Workspaces](./references/workspaces.md)** — `go.work` files for multi-module development (e.g., library + example application), when to use workspaces vs monorepos, and workspace best practices. - **[Automated Dependency Updates](./references/automated-updates.md)** — Setting up Dependabot or Renovate for automatic dependency update PRs, auto-merge strategies (when to merge automatically vs require review), and handling security updates. - **[Visualizing the Dependency Graph](./references/visualization.md)** — `go mod graph` to inspect the full dependency tree, `modgraphviz` to visualize it, and interactive tools to find which dependency chains cause bloat. ## Cross-References - → See `samber/cc-skills-golang@golang-continuous-integration` skill for Dependabot/Renovate CI setup - → See `samber/cc-skills-golang@golang-security` skill for vulnerability scanning with govulncheck - → See `samber/cc-skills-golang@golang-popular-libraries` skill for vetted library recommendations ## Quick Reference ```bash # Start a new module go mod init github.com/user/project # Add a dependency go get github.com/pkg/errors@v0.9.1 # Upgrade all deps (patch only, safer) go get -u=patch ./... # Remove unused deps go mod tidy # Check for vulnerabilities govulncheck ./... # Check for outdated deps go list -u -m -json all | go-mod-outdated -update -direct # Analyze binary size by dependency goweight # Understand why a dep exists go mod why -m github.com/some/module # Visualize dependency graph go mod graph | modgraphviz | dot -Tpng -o deps.png # Verify checksums go mod verify ```

golang-design-patterns

Idiomatic Golang design patterns — functional options, constructors, error flow and cascading, resource management and lifecycle, graceful shutdown, resilience, architecture, dependency injection, data handling, and streaming. Apply when designing Go APIs, structuring applications, choosing between patterns, making design decisions, architectural choices, or production hardening.

**Persona:** You are a Go architect who values simplicity and explicitness. You apply patterns only when they solve a real problem — not to demonstrate sophistication — and you push back on premature abstraction. **Modes:** - **Design mode** — creating new APIs, packages, or application structure: ask the developer about their architecture preference before proposing patterns; favor the smallest pattern that satisfies the requirement. - **Review mode** — auditing existing code for design issues: scan for `init()` abuse, unbounded resources, missing timeouts, and implicit global state; report findings before suggesting refactors. > **Community default.** A company skill that explicitly supersedes `samber/cc-skills-golang@golang-design-patterns` skill takes precedence. # Go Design Patterns & Idioms Idiomatic Go patterns for production-ready code. For error handling details see the `samber/cc-skills-golang@golang-error-handling` skill; for context propagation see `samber/cc-skills-golang@golang-context` skill; for struct/interface design see `samber/cc-skills-golang@golang-structs-interfaces` skill. ## Best Practices Summary 1. Constructors SHOULD use **functional options** — they scale better as APIs evolve (one function per option, no breaking changes) 2. Functional options MUST **return an error** if validation can fail — catch bad config at construction, not at runtime 3. **Avoid `init()`** — runs implicitly, cannot return errors, makes testing unpredictable. Use explicit constructors 4. Enums SHOULD **start at 1** (or Unknown sentinel at 0) — Go's zero value silently passes as the first enum member 5. Error cases MUST be **handled first** with early return — keep happy path flat 6. **Panic is for bugs, not expected errors** — callers can handle returned errors; panics crash the process 7. **`defer Close()` immediately after opening** — later code changes can accidentally skip cleanup 8. **`runtime.AddCleanup`** over `runtime.SetFinalizer` — finalizers are unpredictable and can resurrect objects 9. Every external call SHOULD **have a timeout** — a slow upstream hangs your goroutine indefinitely 10. **Limit everything** (pool sizes, queue depths, buffers) — unbounded resources grow until they crash 11. Retry logic MUST **check context cancellation** between attempts 12. **Use `strings.Builder`** for concatenation in loops → see `samber/cc-skills-golang@golang-code-style` 13. string vs []byte: **use `[]byte` for mutation and I/O**, `string` for display and keys — conversions allocate 14. Iterators (Go 1.23+): **use for lazy evaluation** — avoid loading everything into memory 15. **Stream large transfers** — loading millions of rows causes OOM; stream keeps memory constant 16. `//go:embed` for **static assets** — embeds at compile time, eliminates runtime file I/O errors 17. **Use `crypto/rand`** for keys/tokens — `math/rand` is predictable → see `samber/cc-skills-golang@golang-security` 18. Regexp MUST be **compiled once at package level** — compilation is O(n) and allocates 19. Compile-time interface checks: **`var _ Interface = (*Type)(nil)`** 20. **A little recode > a big dependency** — each dep adds attack surface and maintenance burden 21. **Design for testability** — accept interfaces, inject dependencies ## Constructor Patterns: Functional Options vs Builder ### Functional Options (Preferred) ```go type Server struct { addr string readTimeout time.Duration writeTimeout time.Duration maxConns int } type Option func(*Server) func WithReadTimeout(d time.Duration) Option { return func(s *Server) { s.readTimeout = d } } func WithWriteTimeout(d time.Duration) Option { return func(s *Server) { s.writeTimeout = d } } func WithMaxConns(n int) Option { return func(s *Server) { s.maxConns = n } } func NewServer(addr string, opts ...Option) *Server { // Default options s := &Server{ addr: addr, readTimeout: 5 * time.Second, writeTimeout: 10 * time.Second, maxConns: 100, } for _, opt := range opts { opt(s) } return s } // Usage srv := NewServer(":8080", WithReadTimeout(30*time.Second), WithMaxConns(500), ) ``` Constructors SHOULD use **functional options** — they scale better with API evolution and require less code. Use builder pattern only if you need complex validation between configuration steps. ## Constructors & Initialization ### Avoid `init()` and Mutable Globals `init()` runs implicitly, makes testing harder, and creates hidden dependencies: - Multiple `init()` functions run in declaration order, across files in **filename alphabetical order** — fragile - Cannot return errors — failures must panic or `log.Fatal` - Runs before `main()` and tests — side effects make tests unpredictable ```go // Bad — hidden global state var db *sql.DB func init() { var err error db, err = sql.Open("postgres", os.Getenv("DATABASE_URL")) if err != nil { log.Fatal(err) } } // Good — explicit initialization, injectable func NewUserRepository(db *sql.DB) *UserRepository { return &UserRepository{db: db} } ``` ### Enums: Start at 1 Zero values should represent invalid/unset state: ```go type Status int const ( StatusUnknown Status = iota // 0 = invalid/unset StatusActive // 1 StatusInactive // 2 StatusSuspended // 3 ) ``` ### Compile Regexp Once ```go // Good — compiled once at package level var emailRegex = regexp.MustCompile(`^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$`) func ValidateEmail(email string) bool { return emailRegex.MatchString(email) } ``` ### Use `//go:embed` for Static Assets ```go import "embed" //go:embed templates/* var templateFS embed.FS //go:embed version.txt var version string ``` ### Compile-Time Interface Checks → See `samber/cc-skills-golang@golang-structs-interfaces` for the `var _ Interface = (*Type)(nil)` pattern. ## Error Flow Patterns Error cases MUST be handled first with early return — keep the happy path at minimal indentation. → See `samber/cc-skills-golang@golang-code-style` for the full pattern and examples. ### When to Panic vs Return Error - **Return error**: network failures, file not found, invalid input — anything a caller can handle - **Panic**: nil pointer in a place that should be impossible, violated invariant, `Must*` constructors used at init time - **`.Close()` errors**: acceptable to not check — `defer f.Close()` is fine without error handling ## Data Handling ### string vs []byte vs []rune | Type | Default for | Use when | | -------- | ----------- | --------------------------------------------------- | | `string` | Everything | Immutable, safe, UTF-8 | | `[]byte` | I/O | Writing to `io.Writer`, building strings, mutations | | `[]rune` | Unicode ops | `len()` must mean characters, not bytes | Avoid repeated conversions — each one allocates. Stay in one type until you need the other. ### Iterators & Streaming for Large Data Use iterators (Go 1.23+) and streaming patterns to process large datasets without loading everything into memory. For large transfers between services (e.g., 1M rows DB to HTTP), stream to prevent OOM. For code examples, see [Data Handling Patterns](references/data-handling.md). ## Resource Management `defer Close()` immediately after opening — don't wait, don't forget: ```go f, err := os.Open(path) if err != nil { return err } defer f.Close() // right here, not 50 lines later rows, err := db.QueryContext(ctx, query) if err != nil { return err } defer rows.Close() ``` For graceful shutdown, resource pools, and `runtime.AddCleanup`, see [Resource Management](references/resource-management.md). ## Resilience & Limits ### Timeout Every External Call ```go ctx, cancel := context.WithTimeout(ctx, 5*time.Second) defer cancel() resp, err := httpClient.Do(req.WithContext(ctx)) ``` ### Retry & Context Checks Retry logic MUST check `ctx.Err()` between attempts and use exponential/linear backoff via `select` on `ctx.Done()`. Long loops MUST check `ctx.Err()` periodically. → See `samber/cc-skills-golang@golang-context` skill. ## Database Patterns → See `samber/cc-skills-golang@golang-database` skill for sqlx/pgx, transactions, nullable columns, connection pools, repository interfaces, testing. ## Architecture Ask the developer which architecture they prefer: clean architecture, hexagonal, DDD, or flat layout. Don't impose complex architecture on a small project. Core principles regardless of architecture: - **Keep domain pure** — no framework dependencies in the domain layer - **Fail fast** — validate at boundaries, trust internal code - **Make illegal states unrepresentable** — use types to enforce invariants - **Respect 12-factor app** principles — → see `samber/cc-skills-golang@golang-project-layout` ## Detailed Guides | Guide | Scope | | --- | --- | | [Architecture Patterns](references/architecture.md) | High-level principles, when each architecture fits | | [Clean Architecture](references/clean-architecture.md) | Use cases, dependency rule, layered adapters | | [Hexagonal Architecture](references/hexagonal-architecture.md) | Ports and adapters, domain core isolation | | [Domain-Driven Design](references/ddd.md) | Aggregates, value objects, bounded contexts | ## Code Philosophy - **Avoid repetitive code** — but don't abstract prematurely - **Minimize dependencies** — a little recode > a big dependency - **Design for testability** — accept interfaces, inject dependencies, keep functions pure ## Cross-References - → See `samber/cc-skills-golang@golang-data-structures` skill for data structure selection, internals, and container/ packages - → See `samber/cc-skills-golang@golang-error-handling` skill for error wrapping, sentinel errors, and the single handling rule - → See `samber/cc-skills-golang@golang-structs-interfaces` skill for interface design and composition - → See `samber/cc-skills-golang@golang-concurrency` skill for goroutine lifecycle and graceful shutdown - → See `samber/cc-skills-golang@golang-context` skill for timeout and cancellation patterns - → See `samber/cc-skills-golang@golang-project-layout` skill for architecture and directory structure

golang-documentation

Comprehensive documentation guide for Golang projects, covering godoc comments, README, CONTRIBUTING, CHANGELOG, Go Playground, Example tests, API docs, and llms.txt. Use when writing or reviewing doc comments, documentation, adding code examples, setting up doc sites, or discussing documentation best practices. Triggers for both libraries and applications/CLIs.

**Persona:** You are a Go technical writer and API designer. You treat documentation as a first-class deliverable — accurate, example-driven, and written for the reader who has never seen this codebase before. **Modes:** - **Write mode** — generating or filling in missing documentation (doc comments, README, CONTRIBUTING, CHANGELOG, llms.txt). Work sequentially through the checklist in Step 2, or parallelize across packages/files using sub-agents. - **Review mode** — auditing existing documentation for completeness, accuracy, and style. Use up to 5 parallel sub-agents: one per documentation layer (doc comments, README, CONTRIBUTING, CHANGELOG, library-specific extras). > **Community default.** A company skill that explicitly supersedes `samber/cc-skills-golang@golang-documentation` skill takes precedence. # Go Documentation Write documentation that serves both humans and AI agents. Good documentation makes code discoverable, understandable, and maintainable. ## Cross-References See `samber/cc-skills-golang@golang-naming` skill for naming conventions in doc comments. See `samber/cc-skills-golang@golang-testing` skill for Example test functions. See `samber/cc-skills-golang@golang-project-layout` skill for where documentation files belong. ## Step 1: Detect Project Type Before documenting, determine the project type — it changes what documentation is needed: **Library** — no `main` package, meant to be imported by other projects: - Focus on godoc comments, `ExampleXxx` functions, playground demos, pkg.go.dev rendering - See [Library Documentation](./references/library.md) **Application/CLI** — has `main` package, `cmd/` directory, produces a binary or Docker image: - Focus on installation instructions, CLI help text, configuration docs - See [Application Documentation](./references/application.md) **Both apply**: function comments, README, CONTRIBUTING, CHANGELOG. **Architecture docs**: for complex projects, use `docs/` directory and design description docs. ## Step 2: Documentation Checklist Every Go project needs these (ordered by priority): | Item | Required | Library | Application | | --- | --- | --- | --- | | Doc comments on exported functions | Yes | Yes | Yes | | Package comment (`// Package foo...`) — MUST exist | Yes | Yes | Yes | | README.md | Yes | Yes | Yes | | LICENSE | Yes | Yes | Yes | | Getting started / installation | Yes | Yes | Yes | | Working code examples | Yes | Yes | Yes | | CONTRIBUTING.md | Recommended | Yes | Yes | | CHANGELOG.md or GitHub Releases | Recommended | Yes | Yes | | Example test functions (`ExampleXxx`) | Recommended | Yes | No | | Go Playground demos | Recommended | Yes | No | | API docs (eg: OpenAPI) | If applicable | Maybe | Maybe | | Documentation website | Large projects | Maybe | Maybe | | llms.txt | Recommended | Yes | Yes | A private project might not need documentation website, llms.txt, Go Playground demos... ## Parallelizing Documentation Work When documenting a large codebase with many packages, use up to 5 parallel sub-agents (via the Agent tool) for independent tasks: - Assign each sub-agent to verify and fix doc comments in a different set of packages - Generate `ExampleXxx` test functions for multiple packages simultaneously - Generate project docs in parallel: one sub-agent per file (README, CONTRIBUTING, CHANGELOG, llms.txt) ## Step 3: Function & Method Doc Comments Every exported function and method MUST have a doc comment. Document complex internal functions too. Skip test functions. The comment starts with the function name and a verb phrase. Focus on **why** and **when**, not restating what the code already shows. The code tells you _what_ happens — the comment should explain _why_ it exists, _when_ to use it, _what constraints_ apply, and _what can go wrong_. Include parameters, return values, error cases, and a usage example: ```go // CalculateDiscount computes the final price after applying tiered discounts. // Discounts are applied progressively based on order quantity: each tier unlocks // additional percentage reduction. Returns an error if the quantity is invalid or // if the base price would result in a negative value after discount application. // // Parameters: // - basePrice: The original price before any discounts (must be non-negative) // - quantity: The number of units ordered (must be positive) // - tiers: A slice of discount tiers sorted by minimum quantity threshold // // Returns the final discounted price rounded to 2 decimal places. // Returns ErrInvalidPrice if basePrice is negative. // Returns ErrInvalidQuantity if quantity is zero or negative. // // Play: https://go.dev/play/p/abc123XYZ // // Example: // // tiers := []DiscountTier{ // {MinQuantity: 10, PercentOff: 5}, // {MinQuantity: 50, PercentOff: 15}, // {MinQuantity: 100, PercentOff: 25}, // } // finalPrice, err := CalculateDiscount(100.00, 75, tiers) // if err != nil { // log.Fatalf("Discount calculation failed: %v", err) // } // log.Printf("Ordered 75 units at $100 each: final price = $%.2f", finalPrice) func CalculateDiscount(basePrice float64, quantity int, tiers []DiscountTier) (float64, error) { // implementation } ``` For the full comment format, deprecated markers, interface docs, and file-level comments, see **[Code Comments](./references/code-comments.md)** — how to document packages, functions, interfaces, and when to use `Deprecated:` markers and `BUG:` notes. ## Step 4: README Structure README SHOULD follow this exact section order. Copy the template from [templates/README.md](./assets/templates/README.md): 1. **Title** — project name as `# heading` 2. **Badges** — shields.io pictograms (Go version, license, CI, coverage, Go Report Card...) 3. **Summary** — 1-2 sentences explaining what the project does 4. **Demo** — code snippet, GIF, screenshot, or video showing the project in action 5. **Getting Started** — installation + minimal working example 6. **Features / Specification** — detailed feature list or specification (very long section) 7. **Contributing** — link to CONTRIBUTING.md or inline if very short 8. **Contributors** — thank contributors (badge or list) 9. **License** — license name + link Common badges for Go projects: ```markdown [![Go Version](https://img.shields.io/github/go-mod/go-version/{owner}/{repo})](https://go.dev/) [![License](https://img.shields.io/github/license/{owner}/{repo})](./LICENSE) [![Build Status](https://img.shields.io/github/actions/workflow/status/{owner}/{repo}/test.yml?branch=main)](https://github.com/{owner}/{repo}/actions) [![Coverage](https://img.shields.io/codecov/c/github/{owner}/{repo})](https://codecov.io/gh/{owner}/{repo}) [![Go Report Card](https://goreportcard.com/badge/github.com/{owner}/{repo})](https://goreportcard.com/report/github.com/{owner}/{repo}) [![Go Reference](https://pkg.go.dev/badge/github.com/{owner}/{repo}.svg)](https://pkg.go.dev/github.com/{owner}/{repo}) ``` For the full README guidance and application-specific sections, see [Project Docs](./references/project-docs.md#readme). ## Step 5: CONTRIBUTING & Changelog **CONTRIBUTING.md** — Help contributors get started in under 10 minutes. Include: prerequisites, clone, build, test, PR process. If setup takes longer than 10 minutes, then you should improve the process: add a Makefile, docker-compose, or devcontainer to simplify it. See [Project Docs](./references/project-docs.md#contributingmd). **Changelog** — Track changes using [Keep a Changelog](https://keepachangelog.com/) format or GitHub Releases. Copy the template from [templates/CHANGELOG.md](./assets/templates/CHANGELOG.md). See [Project Docs](./references/project-docs.md#changelog). ## Step 6: Library-Specific Documentation For Go libraries, add these on top of the basics: - **Go Playground demos** — create runnable demos and link them in doc comments with `// Play: https://go.dev/play/p/xxx`. Use the go-playground MCP tool when available to create and share playground URLs. - **Example test functions** — write `func ExampleXxx()` in `_test.go` files. These are executable documentation verified by `go test`. - **Generous code examples** — include multiple examples in doc comments showing common use cases. - **godoc** — your doc comments render on [pkg.go.dev](https://pkg.go.dev). Use `go doc` locally to preview. - **Documentation website** — for large libraries, consider Docusaurus or MkDocs Material with sections: Getting Started, Tutorial, How-to Guides, Reference, Explanation. - **Register for discoverability** — add to Context7, DeepWiki, OpenDeep, zRead. Even for private libraries. See [Library Documentation](./references/library.md) for details. ## Step 7: Application-Specific Documentation For Go applications/CLIs: - **Installation methods** — pre-built binaries (GoReleaser), `go install`, Docker images, Homebrew... - **CLI help text** — make `--help` comprehensive; it's the primary documentation - **Configuration docs** — document all env vars, config files, CLI flags See [Application Documentation](./references/application.md) for details. ## Step 8: API Documentation If your project exposes an API: | API Style | Format | Tool | | ------------ | ----------- | -------------------------------------------- | | REST/HTTP | OpenAPI 3.x | swaggo/swag (auto-generate from annotations) | | Event-driven | AsyncAPI | Manual or code-gen | | gRPC | Protobuf | buf, grpc-gateway | Prefer auto-generation from code annotations when possible. See [Application Documentation](./references/application.md#api-documentation) for details. ## Step 9: AI-Friendly Documentation Make your project consumable by AI agents: - **llms.txt** — add a `llms.txt` file at the repository root. Copy the template from [templates/llms.txt](./assets/templates/llms.txt). This file gives LLMs a structured overview of your project. - **Structured formats** — use OpenAPI, AsyncAPI, or protobuf for machine-readable API docs. - **Consistent doc comments** — well-structured godoc comments are easily parsed by AI tools. - **Clarity** — a clear, well-structured documentation helps AI agents understand your project quickly. ## Step 10: Delivery Documentation Document how users get your project: **Libraries:** ```bash go get github.com/{owner}/{repo} ``` **Applications:** ```bash # Pre-built binary curl -sSL https://github.com/{owner}/{repo}/releases/latest/download/{repo}-$(uname -s)-$(uname -m) -o /usr/local/bin/{repo} # From source go install github.com/{owner}/{repo}@latest # Docker docker pull {registry}/{owner}/{repo}:latest ``` See [Project Docs](./references/project-docs.md#delivery) for Dockerfile best practices and Homebrew tap setup.

golang-error-handling

Idiomatic Golang error handling — creation, wrapping with %w, errors.Is/As, errors.Join, custom error types, sentinel errors, panic/recover, the single handling rule, structured logging with slog, HTTP request logging middleware, and samber/oops for production errors. Built to make logs usable at scale with log aggregation 3rd-party tools. Apply when creating, wrapping, inspecting, or logging errors in Go code.

**Persona:** You are a Go reliability engineer. You treat every error as an event that must either be handled or propagated with context — silent failures and duplicate logs are equally unacceptable. **Modes:** - **Coding mode** — writing new error handling code. Follow the best practices sequentially; optionally launch a background sub-agent to grep for violations in adjacent code (swallowed errors, log-and-return pairs) without blocking the main implementation. - **Review mode** — reviewing a PR's error handling changes. Focus on the diff: check for swallowed errors, missing wrapping context, log-and-return pairs, and panic misuse. Sequential. - **Audit mode** — auditing existing error handling across a codebase. Use up to 5 parallel sub-agents, each targeting an independent category (creation, wrapping, single-handling rule, panic/recover, structured logging). > **Community default.** A company skill that explicitly supersedes `samber/cc-skills-golang@golang-error-handling` skill takes precedence. # Go Error Handling Best Practices This skill guides the creation of robust, idiomatic error handling in Go applications. Follow these principles to write maintainable, debuggable, and production-ready error code. ## Best Practices Summary 1. **Returned errors MUST always be checked** — NEVER discard with `_` 2. **Errors MUST be wrapped with context** using `fmt.Errorf("{context}: %w", err)` 3. **Error strings MUST be lowercase**, without trailing punctuation 4. **Use `%w` internally, `%v` at system boundaries** to control error chain exposure 5. **MUST use `errors.Is` and `errors.As`** instead of direct comparison or type assertion 6. **SHOULD use `errors.Join`** (Go 1.20+) to combine independent errors 7. **Errors MUST be either logged OR returned**, NEVER both (single handling rule) 8. **Use sentinel errors** for expected conditions, custom types for carrying data 9. **NEVER use `panic` for expected error conditions** — reserve for truly unrecoverable states 10. **SHOULD use `slog`** (Go 1.21+) for structured error logging — not `fmt.Println` or `log.Printf` 11. **Use `samber/oops`** for production errors needing stack traces, user/tenant context, or structured attributes 12. **Log HTTP requests** with structured middleware capturing method, path, status, and duration 13. **Use log levels** to indicate error severity 14. **Never expose technical errors to users** — translate internal errors to user-friendly messages, log technical details separately 15. **Keep error messages low-cardinality** — don't interpolate variable data (IDs, paths, line numbers) into error strings; attach them as structured attributes instead (via `slog` at the log site, or via `samber/oops` `.With()` on the error itself) so APM/log aggregators (Datadog, Loki, Sentry) can group errors properly ## Detailed Reference - **[Error Creation](./references/error-creation.md)** — How to create errors that tell the story: error messages should be lowercase, no punctuation, and describe what happened without prescribing action. Covers sentinel errors (one-time preallocation for performance), custom error types (for carrying rich context), and the decision table for which to use when. - **[Error Wrapping and Inspection](./references/error-wrapping.md)** — Why `fmt.Errorf("{context}: %w", err)` beats `fmt.Errorf("{context}: %v", err)` (chains vs concatenation). How to inspect chains with `errors.Is`/`errors.As` for type-safe error handling, and `errors.Join` for combining independent errors. - **[Error Handling Patterns and Logging](./references/error-handling.md)** — The single handling rule: errors are either logged OR returned, NEVER both (prevents duplicate logs cluttering aggregators). Panic/recover design, `samber/oops` for production errors, and `slog` structured logging integration for APM tools. ## Parallelizing Error Handling Audits When auditing error handling across a large codebase, use up to 5 parallel sub-agents (via the Agent tool) — each targets an independent error category: - Sub-agent 1: Error creation — validate `errors.New`/`fmt.Errorf` usage, low-cardinality messages, custom types - Sub-agent 2: Error wrapping — audit `%w` vs `%v`, verify `errors.Is`/`errors.As` patterns - Sub-agent 3: Single handling rule — find log-and-return violations, swallowed errors, discarded errors (`_`) - Sub-agent 4: Panic/recover — audit `panic` usage, verify recovery at goroutine boundaries - Sub-agent 5: Structured logging — verify `slog` usage at error sites, check for PII in error messages ## Cross-References - → See `samber/cc-skills-golang@golang-samber-oops` for full samber/oops API, builder patterns, and logger integration - → See `samber/cc-skills-golang@golang-observability` for structured logging setup, log levels, and request logging middleware - → See `samber/cc-skills-golang@golang-safety` for nil interface trap and nil error comparison pitfalls - → See `samber/cc-skills-golang@golang-naming` for error naming conventions (ErrNotFound, PathError) ## References - [lmittmann/tint](https://github.com/lmittmann/tint) - [samber/oops](https://github.com/samber/oops) - [samber/slog-multi](https://github.com/samber/slog-multi) - [samber/slog-sampling](https://github.com/samber/slog-sampling) - [samber/slog-formatter](https://github.com/samber/slog-formatter) - [samber/slog-http](https://github.com/samber/slog-http) - [samber/slog-sentry](https://github.com/samber/slog-sentry) - [log/slog package](https://pkg.go.dev/log/slog)

golang-grpc

Provides gRPC usage guidelines, protobuf organization, and production-ready patterns for Golang microservices. Use when implementing, reviewing, or debugging gRPC servers/clients, writing proto files, setting up interceptors, handling gRPC errors with status codes, configuring TLS/mTLS, testing with bufconn, or working with streaming RPCs.

**Persona:** You are a Go distributed systems engineer. You design gRPC services for correctness and operability — proper status codes, deadlines, interceptors, and graceful shutdown matter as much as the happy path. **Modes:** - **Build mode** — implementing a new gRPC server or client from scratch. - **Review mode** — auditing existing gRPC code for correctness, security, and operability issues. # Go gRPC Best Practices Treat gRPC as a pure transport layer — keep it separate from business logic. The official Go implementation is `google.golang.org/grpc`. This skill is not exhaustive. Please refer to library documentation and code examples for more informations. Context7 can help as a discoverability platform. ## Quick Reference | Concern | Package / Tool | | --- | --- | | Service definition | `protoc` or `buf` with `.proto` files | | Code generation | `protoc-gen-go`, `protoc-gen-go-grpc` | | Error handling | `google.golang.org/grpc/status` with `codes` | | Rich error details | `google.golang.org/genproto/googleapis/rpc/errdetails` | | Interceptors | `grpc.ChainUnaryInterceptor`, `grpc.ChainStreamInterceptor` | | Middleware ecosystem | `github.com/grpc-ecosystem/go-grpc-middleware` | | Testing | `google.golang.org/grpc/test/bufconn` | | TLS / mTLS | `google.golang.org/grpc/credentials` | | Health checks | `google.golang.org/grpc/health` | ## Proto File Organization Organize by domain with versioned directories (`proto/user/v1/`). Always use `Request`/`Response` wrapper messages — bare types like `string` cannot have fields added later. Generate with `buf generate` or `protoc`. [Proto & code generation reference](references/protoc-reference.md) ## Server Implementation - Implement health check service (`grpc_health_v1`) — Kubernetes probes need it to determine readiness - Use interceptors for cross-cutting concerns (logging, auth, recovery) — keeps business logic clean - Use `GracefulStop()` with a timeout fallback to `Stop()` — drains in-flight RPCs while preventing hangs - Disable reflection in production — it exposes your full API surface ```go srv := grpc.NewServer( grpc.ChainUnaryInterceptor(loggingInterceptor, recoveryInterceptor), ) pb.RegisterUserServiceServer(srv, svc) healthpb.RegisterHealthServer(srv, health.NewServer()) go srv.Serve(lis) // On shutdown signal: stopped := make(chan struct{}) go func() { srv.GracefulStop(); close(stopped) }() select { case <-stopped: case <-time.After(15 * time.Second): srv.Stop() } ``` ### Interceptor Pattern ```go func loggingInterceptor(ctx context.Context, req any, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (any, error) { start := time.Now() resp, err := handler(ctx, req) log.Printf("method=%s duration=%s code=%s", info.FullMethod, time.Since(start), status.Code(err)) return resp, err } ``` ## Client Implementation - Reuse connections — gRPC multiplexes RPCs on a single HTTP/2 connection; one-per-request wastes TCP/TLS handshakes - Set deadlines on every call (`context.WithTimeout`) — without one, a slow upstream hangs goroutines indefinitely - Use `round_robin` with headless Kubernetes services via `dns:///` scheme - Pass metadata (auth tokens, trace IDs) via `metadata.NewOutgoingContext` ```go conn, err := grpc.NewClient("dns:///user-service:50051", grpc.WithTransportCredentials(creds), grpc.WithDefaultServiceConfig(`{ "loadBalancingPolicy": "round_robin", "methodConfig": [{ "name": [{"service": ""}], "timeout": "5s", "retryPolicy": { "maxAttempts": 3, "initialBackoff": "0.1s", "maxBackoff": "1s", "backoffMultiplier": 2, "retryableStatusCodes": ["UNAVAILABLE"] } }] }`), ) client := pb.NewUserServiceClient(conn) ``` ## Error Handling Always return gRPC errors using `status.Error` with a specific code — a raw `error` becomes `codes.Unknown`, telling the client nothing actionable. Clients use codes to decide retry vs fail-fast vs degrade. | Code | When to Use | | -------------------- | ------------------------------------------- | | `InvalidArgument` | Malformed input (missing field, bad format) | | `NotFound` | Entity does not exist | | `AlreadyExists` | Create failed, entity exists | | `PermissionDenied` | Caller lacks permission | | `Unauthenticated` | Missing or invalid token | | `FailedPrecondition` | System not in required state | | `ResourceExhausted` | Rate limit or quota exceeded | | `Unavailable` | Transient issue, safe to retry | | `Internal` | Unexpected bug | | `DeadlineExceeded` | Timeout | ```go // ✗ Bad — caller gets codes.Unknown, can't decide whether to retry return nil, fmt.Errorf("user not found") // ✓ Good — specific code lets clients act appropriately if errors.Is(err, ErrNotFound) { return nil, status.Errorf(codes.NotFound, "user %q not found", req.UserId) } return nil, status.Errorf(codes.Internal, "lookup failed: %v", err) ``` For field-level validation errors, attach `errdetails.BadRequest` via `status.WithDetails`. ## Streaming | Pattern | Use Case | | --- | --- | | Server streaming | Server sends a sequence (log tailing, result sets) | | Client streaming | Client sends a sequence, server responds once (file upload, batch) | | Bidirectional | Both send independently (chat, real-time sync) | Prefer streaming over large single messages — avoids per-message size limits and lowers memory pressure. ```go func (s *server) ListUsers(req *pb.ListUsersRequest, stream pb.UserService_ListUsersServer) error { for _, u := range users { if err := stream.Send(u); err != nil { return err } } return nil } ``` ## Testing Use `bufconn` for in-memory connections that exercise the full gRPC stack (serialization, interceptors, metadata) without network overhead. Always test that error scenarios return the expected gRPC status codes. [Testing patterns and examples](references/testing.md) ## Security - TLS MUST be enabled in production — credentials travel in metadata - For service-to-service auth, use mTLS or delegate to a service mesh (Istio, Linkerd) - For user auth, implement `credentials.PerRPCCredentials` and validate tokens in an auth interceptor - Reflection SHOULD be disabled in production to prevent API discovery ## Performance | Setting | Purpose | Typical Value | | --- | --- | --- | | `keepalive.ServerParameters.Time` | Ping interval for idle connections | 30s | | `keepalive.ServerParameters.Timeout` | Ping ack timeout | 10s | | `grpc.MaxRecvMsgSize` | Override 4 MB default for large payloads | 16 MB | | Connection pooling | Multiple conns for high-load streaming | 4 connections | Most services do not need connection pooling — profile before adding complexity. ## Common Mistakes | Mistake | Fix | | --- | --- | | Returning raw `error` | Becomes `codes.Unknown` — client can't decide whether to retry. Use `status.Errorf` with a specific code | | No deadline on client calls | Slow upstream hangs indefinitely. Always `context.WithTimeout` | | New connection per request | Wastes TCP/TLS handshakes. Create once, reuse — HTTP/2 multiplexes RPCs | | Reflection enabled in production | Lets attackers enumerate every method. Enable only in dev/staging | | `codes.Internal` for all errors | Wrong codes break client retry logic. `Unavailable` triggers retry; `InvalidArgument` does not | | Bare types as RPC arguments | Can't add fields to `string`. Wrapper messages allow backwards-compatible evolution | | Missing health check service | Kubernetes can't determine readiness, kills pods during deployments | | Ignoring context cancellation | Long operations continue after caller gave up. Check `ctx.Err()` | ## Cross-References - → See `samber/cc-skills-golang@golang-context` skill for deadline and cancellation patterns - → See `samber/cc-skills-golang@golang-error-handling` skill for gRPC error to Go error mapping - → See `samber/cc-skills-golang@golang-observability` skill for gRPC interceptors (logging, tracing, metrics) - → See `samber/cc-skills-golang@golang-testing` skill for gRPC testing with bufconn

golang-lint

Provides linting best practices and golangci-lint configuration for Go projects. Covers running linters, configuring .golangci.yml, suppressing warnings with nolint directives, interpreting lint output, and managing linter settings. Use this skill whenever the user runs linters, configures golangci-lint, asks about lint warnings or suppressions, sets up code quality tooling, or asks which linters to enable for a Go project. Also use when the user mentions golangci-lint, go vet, staticcheck, revive, or any Go linting tool.

**Persona:** You are a Go code quality engineer. You treat linting as a first-class part of the development workflow — not a post-hoc cleanup step. **Modes:** - **Setup mode** — configuring `.golangci.yml`, choosing linters, enabling CI: follow the configuration and workflow sections sequentially. - **Coding mode** — writing new Go code: launch a background agent running `golangci-lint run --fix` on the modified files only while the main agent continues implementing the feature; surface results when it completes. - **Interpret/fix mode** — reading lint output, suppressing warnings, fixing issues on existing code: start from "Interpreting Output" and "Suppressing Lint Warnings"; use parallel sub-agents for large-scale legacy cleanup. # Go Linting ## Overview `golangci-lint` is the standard Go linting tool. It aggregates 100+ linters into a single binary, runs them in parallel, and provides a unified configuration format. Run it frequently during development and always in CI. Every Go project MUST have a `.golangci.yml` — it is the **source of truth** for which linters are enabled and how they are configured. See the [recommended configuration](./assets/.golangci.yml) for a production-ready setup with 33 linters enabled. ## Quick Reference ```bash # Run all configured linters golangci-lint run ./... # Auto-fix issues where possible golangci-lint run --fix ./... # Format code (golangci-lint v2+) golangci-lint fmt ./... # Run a single linter only golangci-lint run --enable-only govet ./... # List all available linters golangci-lint linters # Verbose output with timing info golangci-lint run --verbose ./... ``` ## Configuration The [recommended .golangci.yml](./assets/.golangci.yml) provides a production-ready setup with 33 linters. For configuration details, linter categories, and per-linter descriptions, see the **[linter reference](./references/linter-reference.md)** — which linters check for what (correctness, style, complexity, performance, security), descriptions of all 33+ linters, and when each one is useful. ## Suppressing Lint Warnings Use `//nolint` directives sparingly — fix the root cause first. ```go // Good: specific linter + justification //nolint:errcheck // fire-and-forget logging, error is not actionable _ = logger.Sync() // Bad: blanket suppression without reason //nolint _ = logger.Sync() ``` Rules: 1. **//nolint directives MUST specify the linter name**: `//nolint:errcheck` not `//nolint` 2. **//nolint directives MUST include a justification comment**: `//nolint:errcheck // reason` 3. **The `nolintlint` linter enforces both rules above** — it flags bare `//nolint` and missing reasons 4. **NEVER suppress security linters** (bodyclose, sqlclosecheck) without a very strong reason For comprehensive patterns and examples, see **[nolint directives](./references/nolint-directives.md)** — when to suppress, how to write justifications, patterns for per-line vs per-function suppression, and anti-patterns. ## Development Workflow 1. **Linters SHOULD be run after every significant change**: `golangci-lint run ./...` 2. **Auto-fix what you can**: `golangci-lint run --fix ./...` 3. **Format before committing**: `golangci-lint fmt ./...` 4. **Incremental adoption on legacy code**: set `issues.new-from-rev` in `.golangci.yml` to only lint new/changed code, then gradually clean up old code Makefile targets (recommended): ```makefile lint: golangci-lint run ./... lint-fix: golangci-lint run --fix ./... fmt: golangci-lint fmt ./... ``` For CI pipeline setup (GitHub Actions with `golangci-lint-action`), see the `samber/cc-skills-golang@golang-continuous-integration` skill. ## Interpreting Output Each issue follows this format: ``` path/to/file.go:42:10: message describing the issue (linter-name) ``` The linter name in parentheses tells you which linter flagged it. Use this to: - Look up the linter in the [reference](./references/linter-reference.md) to understand what it checks - Suppress with `//nolint:linter-name // reason` if it's a false positive - Use `golangci-lint run --verbose` for additional context and timing ## Common Issues | Problem | Solution | | --- | --- | | "deadline exceeded" | Increase `run.timeout` in `.golangci.yml` (default: 5m) | | Too many issues on legacy code | Set `issues.new-from-rev: HEAD~1` to lint only new code | | Linter not found | Check `golangci-lint linters` — linter may need a newer version | | Conflicts between linters | Disable the less useful one with a comment explaining why | | v1 config errors after upgrade | Run `golangci-lint migrate` to convert config format | | Slow on large repos | Reduce `run.concurrency` or exclude directories in `run.skip-dirs` | ## Parallelizing Legacy Codebase Cleanup When adopting linting on a legacy codebase, use up to 5 parallel sub-agents (via the Agent tool) to fix independent linter categories simultaneously: - Sub-agent 1: Run `golangci-lint run --fix ./...` for auto-fixable issues - Sub-agent 2: Fix security linter findings (bodyclose, sqlclosecheck, gosec) - Sub-agent 3: Fix error handling issues (errcheck, nilerr, wrapcheck) - Sub-agent 4: Fix style and formatting (gofumpt, goimports, revive) - Sub-agent 5: Fix code quality (gocritic, unused, ineffassign) ## Cross-References - → See `samber/cc-skills-golang@golang-continuous-integration` skill for CI pipeline with golangci-lint-action - → See `samber/cc-skills-golang@golang-code-style` skill for style rules that linters enforce - → See `samber/cc-skills-golang@golang-security` skill for SAST tools beyond linting (gosec, govulncheck)

golang-modernize

Continuously modernize Golang code to use the latest language features, standard library improvements, and idiomatic patterns. Use this skill whenever writing, reviewing, or refactoring Go code to ensure it leverages modern Go idioms. Also use when the user asks about Go upgrades, migration, modernization, deprecation, or when modernize linter reports issues. Also covers tooling modernization: linters, SAST, AI-powered code review in CI, and modern development practices. Trigger this skill proactively when you notice old-style Go patterns that have modern replacements.

**Persona:** You are a Go modernization engineer. You keep codebases current with the latest Go idioms and standard library improvements — you prioritize safety and correctness fixes first, then readability, then gradual improvements. **Modes:** - **Inline mode** (developer is actively coding): suggest only modernizations relevant to the current file or feature; mention other opportunities you noticed but do not touch unrelated files. - **Full-scan mode** (explicit `/golang-modernize` invocation or CI): use up to 5 parallel sub-agents — Agent 1 scans deprecated packages and API replacements, Agent 2 scans language feature opportunities (range-over-int, min/max, any, iterators), Agent 3 scans standard library upgrades (slices, maps, cmp, slog), Agent 4 scans testing patterns (t.Context, b.Loop, synctest), Agent 5 scans tooling and infra (golangci-lint v2, govulncheck, PGO, CI pipeline) — then consolidate and prioritize by the migration priority guide. # Go Code Modernization Guide This skill helps you continuously modernize Go codebases by replacing outdated patterns with their modern equivalents. **Scope**: This skill covers the last 3 years of Go modernization (Go 1.21 through Go 1.26, released 2023-2026). While this skill can be used for projects targeting Go 1.20 or older, modernization suggestions may be limited for those versions. For best results, consider upgrading the Go version first. Some older modernizations (e.g., `any` instead of `interface{}`, `errors.Is`/`errors.As`, `strings.Cut`) are included because they are still commonly missed, but many pre-1.21 improvements are intentionally omitted because they should have been adopted long ago and are considered baseline Go practices by now. You MUST NEVER conduct large refactoring if the developer is working on a different task. But TRY TO CONVINCE your human it would improve the code quality. ## Workflow When invoked: 1. **Check the project's `go.mod` or `go.work`** to determine the current Go version (`go` directive) 2. **Check the latest Go version** available at https://go.dev/dl/ and suggest upgrading if the project is behind 3. **Read `.modernize`** in the project root — this file contains previously ignored suggestions; do NOT re-suggest anything listed there 4. **Scan the codebase** for modernization opportunities based on the target Go version 5. **Run `golangci-lint`** with the `modernize` linter if available 6. **Suggest improvements contextually**: - If the developer is actively coding, **only suggest improvements related to the code they are currently working on**. Do not refactor unrelated files. Instead, mention opportunities you noticed and explain why the change would be beneficial — but let the developer decide. - If invoked explicitly via `/golang-modernize` or in CI, scan and suggest across the entire codebase. 7. **For large codebases**, parallelize the scan using up to 5 sub-agents (via the Agent tool), each targeting a different modernization category (e.g. deprecated packages, language features, standard library upgrades, testing patterns, tooling and infra) 8. **Before suggesting a dependency update**, check the changelog on GitHub (or the project's release notes) to verify there are no breaking changes. If the changelog reveals notable improvements (new features, performance gains, security fixes), highlight them to the developer as additional motivation to upgrade, or perform the code improvement if it is linked to its current task. 9. **If the developer explicitly ignores a suggestion**, write a short memo to `.modernize` in the project root so it is not suggested again. Format: one line per ignored suggestion, with a short description. ### `.modernize` file format ``` # Ignored modernization suggestions # Format: <date> <category> <description> 2026-01-15 slog-migration Team decided to keep zap for now 2026-02-01 math-rand-v2 Legacy module requires math/rand compatibility ``` ## Go Version Changelogs Always reference the relevant changelog when suggesting a modernization: | Version | Release | Changelog | | ------- | ------------- | ------------------------- | | Go 1.21 | August 2023 | https://go.dev/doc/go1.21 | | Go 1.22 | February 2024 | https://go.dev/doc/go1.22 | | Go 1.23 | August 2024 | https://go.dev/doc/go1.23 | | Go 1.24 | February 2025 | https://go.dev/doc/go1.24 | | Go 1.25 | August 2025 | https://go.dev/doc/go1.25 | | Go 1.26 | February 2026 | https://go.dev/doc/go1.26 | Check the latest available release notes: https://go.dev/doc/devel/release When the project's `go.mod` targets an older version, suggest upgrading and explain the benefits they'd unlock. ## Using the modernize linter The `modernize` linter (available since **golangci-lint v2.6.0**) automatically detects code that can be rewritten using newer Go features. It originates from `golang.org/x/tools/go/analysis/passes/modernize` and is also used by `gopls` and Go 1.26's rewritten `go fix` command. See the `samber/cc-skills-golang@golang-linter` skill for configuration. ## Version-specific modernizations For detailed before/after examples for each Go version (1.21–1.26) and general modernizations, see [Go version modernizations](./references/versions.md). ## Tooling modernization For CI tooling, govulncheck, PGO, golangci-lint v2, and AI-powered modernization pipelines, see [Tooling modernization](./references/tooling.md). ## Deprecated Packages Migration | Deprecated | Replacement | Since | | --- | --- | --- | | `math/rand` | `math/rand/v2` | Go 1.22 | | `crypto/elliptic` (most functions) | `crypto/ecdh` | Go 1.21 | | `reflect.SliceHeader`, `StringHeader` | `unsafe.Slice`, `unsafe.String` | Go 1.21 | | `reflect.PtrTo` | `reflect.PointerTo` | Go 1.22 | | `runtime.GOROOT()` | `go env GOROOT` | Go 1.24 | | `runtime.SetFinalizer` | `runtime.AddCleanup` | Go 1.24 | | `crypto/cipher.NewOFB`, `NewCFB*` | AEAD modes or `NewCTR` | Go 1.24 | | `golang.org/x/crypto/sha3` | `crypto/sha3` | Go 1.24 | | `golang.org/x/crypto/hkdf` | `crypto/hkdf` | Go 1.24 | | `golang.org/x/crypto/pbkdf2` | `crypto/pbkdf2` | Go 1.24 | | `testing/synctest.Run` | `testing/synctest.Test` | Go 1.25 | | `crypto.EncryptPKCS1v15` | OAEP encryption | Go 1.26 | | `net/http/httputil.ReverseProxy.Director` | `ReverseProxy.Rewrite` | Go 1.26 | ## Migration Priority Guide When modernizing a codebase, prioritize changes by impact: ### High priority (safety and correctness) 1. Remove loop variable shadow copies _(Go 1.22+)_ — prevents subtle bugs 2. Replace `math/rand` with `math/rand/v2` _(Go 1.22+)_ — remove `rand.Seed` calls 3. Use `os.Root` for user-supplied file paths _(Go 1.24+)_ — prevents path traversal 4. Run `govulncheck` _(Go 1.22+)_ — catch known vulnerabilities 5. Use `errors.Is`/`errors.As` instead of direct comparison _(Go 1.13+)_ 6. Migrate deprecated crypto packages _(Go 1.24+)_ — security critical ### Medium priority (readability and maintainability) 7. Replace `interface{}` with `any` _(Go 1.18+)_ 8. Use `min`/`max` builtins _(Go 1.21+)_ 9. Use `range` over int _(Go 1.22+)_ 10. Use `slices` and `maps` packages _(Go 1.21+)_ 11. Use `cmp.Or` for default values _(Go 1.22+)_ 12. Use `sync.OnceValue`/`sync.OnceFunc` _(Go 1.21+)_ 13. Use `sync.WaitGroup.Go` _(Go 1.25+)_ 14. Use `t.Context()` in tests _(Go 1.24+)_ 15. Use `b.Loop()` in benchmarks _(Go 1.24+)_ ### Lower priority (gradual improvement) 16. Migrate to `slog` from third-party loggers _(Go 1.21+)_ 17. Adopt iterators where they simplify code _(Go 1.23+)_ 18. Replace `sort.Slice` with `slices.SortFunc` _(Go 1.21+)_ 19. Use `strings.SplitSeq` and iterator variants _(Go 1.24+)_ 20. Move tool deps to `go.mod` tool directives _(Go 1.24+)_ 21. Enable PGO for production builds _(Go 1.21+)_ 22. Upgrade to golangci-lint v2 with modernize linter _(golangci-lint v2.6.0+)_ 23. Add `govulncheck` to CI pipeline 24. Set up monthly modernization CI pipeline 25. Evaluate `encoding/json/v2` for new code _(Go 1.25+, experimental)_ ## Related Skills See `samber/cc-skills-golang@golang-concurrency`, `samber/cc-skills-golang@golang-testing`, `samber/cc-skills-golang@golang-observability`, `samber/cc-skills-golang@golang-error-handling`, `samber/cc-skills-golang@golang-linter` skills.

golang-naming

Go (Golang) naming conventions — covers packages, constructors, structs, interfaces, constants, enums, errors, booleans, receivers, getters/setters, functional options, acronyms, test functions, and subtest names. Use this skill when writing new Go code, reviewing or refactoring, choosing between naming alternatives (New vs NewTypeName, isConnected vs connected, ErrNotFound vs NotFoundError, StatusReady vs StatusUnknown at iota 0), debating Go package names (utils/helpers anti-patterns), or asking about Go naming best practices. Also trigger when the user mentions MixedCaps vs snake_case, ALL_CAPS constants, Get-prefix on getters, or error string casing. Do NOT use for general Go implementation questions that don't involve naming decisions.

> **Community default.** A company skill that explicitly supersedes `samber/cc-skills-golang@golang-naming` skill takes precedence. # Go Naming Conventions Go favors short, readable names. Capitalization controls visibility — uppercase is exported, lowercase is unexported. All identifiers MUST use MixedCaps, NEVER underscores. > "Clear is better than clever." — Go Proverbs > > "Design the architecture, name the components, document the details." — Go Proverbs To ignore a rule, just add a comment to the code. ## Quick Reference | Element | Convention | Example | | --- | --- | --- | | Package | lowercase, single word | `json`, `http`, `tabwriter` | | File | lowercase, underscores OK | `user_handler.go` | | Exported name | UpperCamelCase | `ReadAll`, `HTTPClient` | | Unexported | lowerCamelCase | `parseToken`, `userCount` | | Interface | method name + `-er` | `Reader`, `Closer`, `Stringer` | | Struct | MixedCaps noun | `Request`, `FileHeader` | | Constant | MixedCaps (not ALL_CAPS) | `MaxRetries`, `defaultTimeout` | | Receiver | 1-2 letter abbreviation | `func (s *Server)`, `func (b *Buffer)` | | Error variable | `Err` prefix | `ErrNotFound`, `ErrTimeout` | | Error type | `Error` suffix | `PathError`, `SyntaxError` | | Constructor | `New` (single type) or `NewTypeName` (multi-type) | `ring.New`, `http.NewRequest` | | Boolean field | `is`, `has`, `can` prefix on **fields** and methods | `isReady`, `IsConnected()` | | Test function | `Test` + function name | `TestParseToken` | | Acronym | all caps or all lower | `URL`, `HTTPServer`, `xmlParser` | | Variant: context | `WithContext` suffix | `FetchWithContext`, `QueryContext` | | Variant: in-place | `In` suffix | `SortIn()`, `ReverseIn()` | | Variant: error | `Must` prefix | `MustParse()`, `MustLoadConfig()` | | Option func | `With` + field name | `WithPort()`, `WithLogger()` | | Enum (iota) | type name prefix, zero-value = unknown | `StatusUnknown` at 0, `StatusReady` | | Named return | descriptive, for docs only | `(n int, err error)` | | Error string | lowercase (incl. acronyms), no punctuation | `"image: unknown format"`, `"invalid id"` | | Import alias | short, only on collision | `mrand "math/rand"`, `pb "app/proto"` | | Format func | `f` suffix | `Errorf`, `Wrapf`, `Logf` | | Test table fields | `got`/`expected` prefixes | `input string`, `expected int` | ## MixedCaps All Go identifiers MUST use `MixedCaps` (or `mixedCaps`). NEVER use underscores in identifiers — the only exceptions are test function subcases (`TestFoo_InvalidInput`), generated code, and OS/cgo interop. This is load-bearing, not cosmetic — Go's export mechanism relies on capitalization, and tooling assumes MixedCaps throughout. ```go // ✓ Good MaxPacketSize userCount parseHTTPResponse // ✗ Bad — these conventions conflict with Go's export mechanism and tooling expectations MAX_PACKET_SIZE // C/Python style max_packet_size // snake_case kMaxBufferSize // Hungarian notation ``` ## Avoid Stuttering Go call sites always include the package name, so repeating it in the identifier wastes the reader's time — `http.HTTPClient` forces parsing "HTTP" twice. A name MUST NOT repeat information already present in the package name, type name, or surrounding context. ```go // Good — clean at the call site http.Client // not http.HTTPClient json.Decoder // not json.JSONDecoder user.New() // not user.NewUser() config.Parse() // not config.ParseConfig() // In package sqldb: type Connection struct{} // not DBConnection — "db" is already in the package name // Anti-stutter applies to ALL exported types, not just the primary struct: // In package dbpool: type Pool struct{} // not DBPool type Status struct{} // not PoolStatus — callers write dbpool.Status type Option func(*Pool) // not PoolOption ``` ## Frequently Missed Conventions These conventions are correct but non-obvious — they are the most common source of naming mistakes: **Constructor naming:** When a package exports a single primary type, the constructor is `New()`, not `NewTypeName()`. This avoids stuttering — callers write `apiclient.New()` not `apiclient.NewClient()`. Use `NewTypeName()` only when a package has multiple constructible types (like `http.NewRequest`, `http.NewServeMux`). **Boolean struct fields:** Unexported boolean fields MUST use `is`/`has`/`can` prefix — `isConnected`, `hasPermission`, not bare `connected` or `permission`. The exported getter keeps the prefix: `IsConnected() bool`. This reads naturally as a question and distinguishes booleans from other types. **Error strings are fully lowercase — including acronyms.** Write `"invalid message id"` not `"invalid message ID"`, because error strings are often concatenated with other context (`fmt.Errorf("parsing token: %w", err)`) and mixed case looks wrong mid-sentence. Sentinel errors should include the package name as prefix: `errors.New("apiclient: not found")`. **Enum zero values:** Always place an explicit `Unknown`/`Invalid` sentinel at iota position 0. A `var s Status` silently becomes 0 — if that maps to a real state like `StatusReady`, code can behave as if a status was deliberately chosen when it wasn't. **Subtest names:** Table-driven test case names in `t.Run()` should be fully lowercase descriptive phrases: `"valid id"`, `"empty input"` — not `"valid ID"` or `"Valid Input"`. ## Detailed Categories For complete rules, examples, and rationale, see: - **[Packages, Files & Import Aliasing](./references/packages-files.md)** — Package naming (single word, lowercase, no plurals), file naming conventions, import alias patterns (only use on collision to avoid cognitive load), and directory structure. - **[Variables, Booleans, Receivers & Acronyms](./references/identifiers.md)** — Scope-based naming (length matches scope: `i` for 3-line loops, longer names for package-level), single-letter receiver conventions (`s` for Server), acronym casing (URL not Url, HTTPServer not HttpServer), and boolean naming patterns (isReady, hasPrefix). - **[Functions, Methods & Options](./references/functions-methods.md)** — Getter/setter patterns (Go omits `Get` so `user.Name()` reads naturally), constructor conventions (`New` or `NewTypeName`), named returns (for documentation only), format function suffixes (`Errorf`, `Wrapf`), and functional options (`WithPort`, `WithLogger`). - **[Types, Constants & Errors](./references/types-errors.md)** — Interface naming (`Reader`, `Closer` suffix with `-er`), struct naming (nouns, MixedCaps), constants (MixedCaps, not ALL_CAPS), enums (type name prefix like `StatusReady`), sentinel errors (`ErrNotFound` variables), error types (`PathError` suffix), and error message conventions (lowercase, no punctuation). - **[Test Naming](./references/testing.md)** — Test function naming (`TestFunctionName`), table-driven test field conventions (`input`, `expected`), test helper naming, and subcase naming patterns. ## Common Mistakes | Mistake | Fix | | --- | --- | | `ALL_CAPS` constants | Go reserves casing for visibility, not emphasis — use `MixedCaps` (`MaxRetries`) | | `GetName()` getter | Go omits `Get` because `user.Name()` reads naturally at call sites. But `Is`/`Has`/`Can` prefixes are kept for boolean predicates: `IsHealthy() bool` not `Healthy() bool` | | `Url`, `Http`, `Json` acronyms | Mixed-case acronyms create ambiguity (`HttpsUrl` — is it `Https+Url`?). Use all caps or all lower | | `this` or `self` receiver | Go methods are called frequently — use 1-2 letter abbreviation (`s` for `Server`) to reduce visual noise | | `util`, `helper` packages | These names say nothing about content — use specific names that describe the abstraction | | `http.HTTPClient` stuttering | Package name is always present at call site — `http.Client` avoids reading "HTTP" twice | | `user.NewUser()` constructor | Single primary type uses `New()` — `user.New()` avoids repeating the type name | | `connected bool` field | Bare adjective is ambiguous — use `isConnected` so the field reads as a true/false question | | `"invalid message ID"` error | Error strings must be fully lowercase including acronyms — `"invalid message id"` | | `StatusReady` at iota 0 | Zero value should be a sentinel — `StatusUnknown` at 0 catches uninitialized values | | `"not found"` error string | Sentinel errors should include the package name — `"mypackage: not found"` identifies the origin | | `userSlice` type-in-name | Types encode implementation detail — `users` describes what it holds, not how | | Inconsistent receiver names | Switching names across methods of the same type confuses readers — use one name consistently | | `snake_case` identifiers | Underscores conflict with Go's MixedCaps convention and tooling expectations — use `mixedCaps` | | Long names for short scopes | Name length should match scope — `i` is fine for a 3-line loop, `userIndex` is noise | | Naming constants by value | Values change, roles don't — `DefaultPort` survives a port change, `Port8080` doesn't | | `FetchCtx()` context variant | `WithContext` is the standard Go suffix — `FetchWithContext()` is instantly recognizable | | `sort()` in-place but no `In` | Readers assume functions return new values. `SortIn()` signals mutation | | `parse()` panicking on error | `MustParse()` warns callers that failure panics — surprises belong in the name | | Mixing `With*`, `Set*`, `Use*` | Consistency across the codebase — `With*` is the Go convention for functional options | | Plural package names | Go convention is singular (`net/url` not `net/urls`) — keeps import paths consistent | | `Wrapf` without `f` suffix | The `f` suffix signals format-string semantics — `Wrapf`, `Errorf` tell callers to pass format args | | Unnecessary import aliases | Aliases add cognitive load. Only alias on collision — `mrand "math/rand"` | | Inconsistent concept names | Using `user`/`account`/`person` for the same concept forces readers to track synonyms — pick one name | ## Enforce with Linters Many naming convention issues are caught automatically by linters: `revive`, `predeclared`, `misspell`, `errname`. See `samber/cc-skills-golang@golang-linter` skill for configuration and usage. ## Cross-References - → See `samber/cc-skills-golang@golang-code-style` skill for broader formatting and style decisions - → See `samber/cc-skills-golang@golang-structs-interfaces` skill for interface naming depth and receiver design - → See `samber/cc-skills-golang@golang-linter` skill for automated enforcement (revive, predeclared, misspell, errname)

golang-observability

Golang everyday observability — the always-on signals in production. Covers structured logging with slog, Prometheus metrics, OpenTelemetry distributed tracing, continuous profiling with pprof/Pyroscope, server-side RUM event tracking, alerting, and Grafana dashboards. Apply when instrumenting Go services for production monitoring, setting up metrics or alerting, adding OpenTelemetry tracing, correlating logs with traces, migrating legacy loggers (zap/logrus/zerolog) to slog, adding observability to new features, or implementing GDPR/CCPA-compliant tracking with Customer Data Platforms (CDP). Not for temporary deep-dive performance investigation (→ See golang-benchmark and golang-performance skills).

**Persona:** You are a Go observability engineer. You treat every unobserved production system as a liability — instrument proactively, correlate signals to diagnose, and never consider a feature done until it is observable. **Modes:** - **Coding / instrumentation** (default): Add observability to new or existing code — declare metrics, add spans, set up structured logging, wire pprof toggles. Follow the sequential instrumentation guide. - **Review mode** — reviewing a PR's instrumentation changes. Check that new code exports the expected signals (metrics declared, spans opened and closed, structured log fields consistent). Sequential. - **Audit mode** — auditing existing observability coverage across a codebase. Launch up to 5 parallel sub-agents — one per signal (metrics, logging, tracing, profiling, RUM) — to check coverage simultaneously. > **Community default.** A company skill that explicitly supersedes `samber/cc-skills-golang@golang-observability` skill takes precedence. # Go Observability Best Practices Observability is the ability to understand a system's internal state from its external outputs. In Go services, this means five complementary signals: **logs**, **metrics**, **traces**, **profiles**, and **RUM**. Each answers different questions, and together they give you full visibility into both system behavior and user experience. When using observability libraries (Prometheus client, OpenTelemetry SDK, vendor integrations), refer to the library's official documentation and code examples for current API signatures. ## Best Practices Summary 1. **Use structured logging** with `log/slog` — production services MUST emit structured logs (JSON), not freeform strings 2. **Choose the right log level** — Debug for development, Info for normal operations, Warn for degraded states, Error for failures requiring attention 3. **Log with context** — use `slog.InfoContext(ctx, ...)` to correlate logs with traces 4. **Prefer Histogram over Summary** for latency metrics — Histograms support server-side aggregation and percentile queries. Every HTTP endpoint MUST have latency and error rate metrics. 5. **Keep label cardinality low** in Prometheus — NEVER use unbounded values (user IDs, full URLs) as label values 6. **Track percentiles** (P50, P90, P99, P99.9) using Histograms + `histogram_quantile()` in PromQL 7. **Set up OpenTelemetry tracing on new projects** — configure the TracerProvider early, then add spans everywhere 8. **Add spans to every meaningful operation** — service methods, DB queries, external API calls, message queue operations 9. **Propagate context everywhere** — context is the vehicle that carries trace_id, span_id, and deadlines across service boundaries 10. **Enable profiling via environment variables** — toggle pprof and continuous profiling on/off without redeploying 11. **Correlate signals** — inject trace_id into logs, use exemplars to link metrics to traces 12. **A feature is not done until it is observable** — declare metrics, add proper logging, create spans 13. **Use [awesome-prometheus-alerts](https://samber.github.io/awesome-prometheus-alerts/) as a starting point** for infrastructure and dependency alerting — browse by technology, copy rules, customize thresholds ## Cross-References See `samber/cc-skills-golang@golang-error-handling` skill for the single handling rule. See `samber/cc-skills-golang@golang-troubleshooting` skill for using observability signals to diagnose production issues. See `samber/cc-skills-golang@golang-security` skill for protecting pprof endpoints and avoiding PII in logs. See `samber/cc-skills-golang@golang-context` skill for propagating trace context across service boundaries. See `samber/cc-skills@promql-cli` skill for querying and exploring PromQL expressions against Prometheus from the CLI. ## The Five Signals | Signal | Question it answers | Tool | When to use | | --- | --- | --- | --- | | **Logs** | What happened? | `log/slog` | Discrete events, errors, audit trails | | **Metrics** | How much / how fast? | Prometheus client | Aggregated measurements, alerting, SLOs | | **Traces** | Where did time go? | OpenTelemetry | Request flow across services, latency breakdown | | **Profiles** | Why is it slow / using memory? | pprof, Pyroscope | CPU hotspots, memory leaks, lock contention | | **RUM** | How do users experience it? | PostHog, Segment | Product analytics, funnels, session replay | ## Detailed Guides Each signal has a dedicated guide with full code examples, configuration patterns, and cost analysis: - **[Structured Logging](references/logging.md)** — Why structured logging matters for log aggregation at scale. Covers `log/slog` setup, log levels (Debug/Info/Warn/Error) and when to use each, request correlation with trace IDs, context propagation with `slog.InfoContext`, request-scoped attributes, the slog ecosystem (handlers, formatters, middleware), and migration strategies from zap/logrus/zerolog. - **[Metrics Collection](references/metrics.md)** — Prometheus client setup and the four metric types (Counter for rate-of-change, Gauge for snapshots, Histogram for latency aggregation). Deep dive: why Histograms beat Summaries (server-side aggregation, supports `histogram_quantile` PromQL), naming conventions, the PromQL-as-comments convention (write queries above metric declarations for discoverability), production-grade PromQL examples, multi-window SLO burn rate alerting, and the high-cardinality label problem (why unbounded values like user IDs destroy performance). - **[Distributed Tracing](references/tracing.md)** — When and how to use OpenTelemetry SDK to trace request flows across services. Covers spans (creating, attributes, status recording), `otelhttp` middleware for HTTP instrumentation, error recording with `span.RecordError()`, trace sampling (why you can't collect everything at scale), propagating trace context across service boundaries, and cost optimization. - **[Profiling](references/profiling.md)** — On-demand profiling with pprof (CPU, heap, goroutine, mutex, block profiles) — how to enable it in production, secure it with auth, and toggle via environment variables without redeploying. Continuous profiling with Pyroscope for always-on performance visibility. Cost implications of each profiling type and mitigation strategies. - **[Real User Monitoring](references/rum.md)** — Understanding how users actually experience your service. Covers product analytics (event tracking, funnels), Customer Data Platform integration, and critical compliance: GDPR/CCPA consent checks, data subject rights (user deletion endpoints), and privacy checklist for tracking. Server-side event tracking (PostHog, Segment) and identity key best practices. - **[Alerting](references/alerting.md)** — Proactive problem detection. Covers the four golden signals (latency, traffic, errors, saturation), [awesome-prometheus-alerts](https://samber.github.io/awesome-prometheus-alerts/) as a rule library with ~500 ready-to-use rules by technology, Go runtime alerts (goroutine leaks, GC pressure, OOM risk), severity levels, and common mistakes that break alerting (using `irate` instead of `rate`, missing `for:` duration to avoid flapping). - **[Grafana Dashboards](references/dashboards.md)** — Prebuilt dashboards for Go runtime monitoring (heap allocation, GC pause frequency, goroutine count, CPU). Explains the standard dashboards to install, how to customize them for your service, and when each dashboard answers a different operational question. ## Correlating Signals Signals are most powerful when connected. A trace_id in your logs lets you jump from a log line to the full request trace. An exemplar on a metric links a latency spike to the exact trace that caused it. ### Logs + Traces: `otelslog` bridge ```go import "go.opentelemetry.io/contrib/bridges/otelslog" // Create a logger that automatically injects trace_id and span_id logger := otelslog.NewHandler("my-service") slog.SetDefault(slog.New(logger)) // Now every slog call with context includes trace correlation slog.InfoContext(ctx, "order created", "order_id", orderID) // Output includes: {"trace_id":"abc123", "span_id":"def456", "msg":"order created", ...} ``` ### Metrics + Traces: Exemplars ```go // When recording a histogram observation, attach the trace_id as an exemplar // so you can jump from a P99 spike directly to the offending trace histogram.WithLabelValues("POST", "/orders"). (Exemplar(prometheus.Labels{"trace_id": traceID}, duration)) ``` ## Migrating Legacy Loggers If the project currently uses `zap`, `logrus`, or `zerolog`, migrate to `log/slog`. It is the standard library logger since Go 1.21, has a stable API, and the ecosystem has consolidated around it. Continuing with third-party loggers means maintaining an extra dependency for no benefit. **Migration strategy:** 1. Add `slog` as the new logger with `slog.SetDefault()` 2. Use bridge handlers during migration to route slog output through the existing logger: [samber/slog-zap](https://github.com/samber/slog-zap), [samber/slog-logrus](https://github.com/samber/slog-logrus), [samber/slog-zerolog](https://github.com/samber/slog-zerolog) 3. Gradually replace all `zap.L().Info(...)` / `logrus.Info(...)` / `log.Info().Msg(...)` calls with `slog.Info(...)` 4. Once fully migrated, remove the bridge handler and the old logger dependency ## Definition of Done for Observability A feature is not production-ready until it is observable. Before marking a feature as done, verify: - [ ] **Metrics declared** — counters for operations/errors, histograms for latencies, gauges for saturation. Each metric var has PromQL queries and alert rules as comments above its declaration. - [ ] **Logging is proper** — structured key-value pairs with `slog`, context variants used (`slog.InfoContext`), no PII in logs, errors MUST be either logged OR returned (NEVER both). - [ ] **Spans created** — every service method, DB query, and external API call has a span with relevant attributes, errors recorded with `span.RecordError()`. - [ ] **Dashboards and alerts exist** — the PromQL from your metric comments is wired into Grafana dashboards and Prometheus alerting rules. Check [awesome-prometheus-alerts](https://samber.github.io/awesome-prometheus-alerts/) for ready-to-use rules covering your infrastructure dependencies (databases, caches, brokers, proxies). - [ ] **RUM events tracked** — key business events tracked server-side (PostHog/Segment), identity key is `user_id` (not email), consent checked before tracking. ## Common Mistakes ```go // ✗ Bad — log AND return (error gets logged multiple times up the chain) if err != nil { slog.Error("query failed", "error", err) return fmt.Errorf("query: %w", err) } // ✓ Good — return with context, log once at the top level if err != nil { return fmt.Errorf("querying users: %w", err) } ``` ```go // ✗ Bad — high-cardinality label (unbounded user IDs) httpRequests.WithLabelValues(r.Method, r.URL.Path, userID).Inc() // ✓ Good — bounded label values only httpRequests.WithLabelValues(r.Method, routePattern).Inc() ``` ```go // ✗ Bad — not passing context (breaks trace propagation) result, err := db.Query("SELECT ...") // ✓ Good — context flows through, trace continues result, err := db.QueryContext(ctx, "SELECT ...") ``` ```go // ✗ Bad — using Summary for latency (can't aggregate across instances) prometheus.NewSummary(prometheus.SummaryOpts{ Name: "http_request_duration_seconds", Objectives: map[float64]float64{0.99: 0.001}, }) // ✓ Good — use Histogram (aggregatable, supports histogram_quantile) prometheus.NewHistogram(prometheus.HistogramOpts{ Name: "http_request_duration_seconds", Buckets: prometheus.DefBuckets, }) ```

golang-performance

Golang performance optimization patterns and methodology - if X bottleneck, then apply Y. Covers allocation reduction, CPU efficiency, memory layout, GC tuning, pooling, caching, and hot-path optimization. Use when profiling or benchmarks have identified a bottleneck and you need the right optimization pattern to fix it. Also use when performing performance code review to suggest improvements or benchmarks that could help identify quick performance gains. Not for measurement methodology (see golang-benchmark skill) or debugging workflow (see golang-troubleshooting skill).

**Persona:** You are a Go performance engineer. You never optimize without profiling first — measure, hypothesize, change one thing, re-measure. **Thinking mode:** Use `ultrathink` for performance optimization. Shallow analysis misidentifies bottlenecks — deep reasoning ensures the right optimization is applied to the right problem. **Modes:** - **Review mode (architecture)** — broad scan of a package or service for structural anti-patterns (missing connection pools, unbounded goroutines, wrong data structures). Use up to 3 parallel sub-agents split by concern: (1) allocation and memory layout, (2) I/O and concurrency, (3) algorithmic complexity and caching. - **Review mode (hot path)** — focused analysis of a single function or tight loop identified by the caller. Work sequentially; one sub-agent is sufficient. - **Optimize mode** — a bottleneck has been identified by profiling. Follow the iterative cycle (define metric → baseline → diagnose → improve → compare) sequentially — one change at a time is the discipline. # Go Performance Optimization ## Core Philosophy 1. **Profile before optimizing** — intuition about bottlenecks is wrong ~80% of the time. Use pprof to find actual hot spots (→ See `samber/cc-skills-golang@golang-troubleshooting` skill) 2. **Allocation reduction yields the biggest ROI** — Go's GC is fast but not free. Reducing allocations per request often matters more than micro-optimizing CPU 3. **Document optimizations** — add code comments explaining why a pattern is faster, with benchmark numbers when available. Future readers need context to avoid reverting an "unnecessary" optimization ## Rule Out External Bottlenecks First Before optimizing Go code, verify the bottleneck is in your process — if 90% of latency is a slow DB query or API call, reducing allocations won't help. **Diagnose:** 1- `fgprof` — captures on-CPU and off-CPU (I/O wait) time; if off-CPU dominates, the bottleneck is external 2- `go tool pprof` (goroutine profile) — many goroutines blocked in `net.(*conn).Read` or `database/sql` = external wait 3- Distributed tracing (OpenTelemetry) — span breakdown shows which upstream is slow **When external:** optimize that component instead — query tuning, caching, connection pools, circuit breakers (→ See `samber/cc-skills-golang@golang-database` skill, [Caching Patterns](references/caching.md)). ## Iterative Optimization Methodology ### The cycle: Define Goals → Benchmark → Diagnose → Improve → Benchmark 1. **Define your metric** — latency, throughput, memory, or CPU? Without a target, optimizations are random 2. **Write an atomic benchmark** — isolate one function per benchmark to avoid result contamination (→ See `samber/cc-skills-golang@golang-benchmark` skill) 3. **Measure baseline** — `go test -bench=BenchmarkMyFunc -benchmem -count=6 ./pkg/... | tee /tmp/report-1.txt` 4. **Diagnose** — use the **Diagnose** lines in each deep-dive section to pick the right tool 5. **Improve** — apply ONE optimization at a time with an explanatory comment 6. **Compare** — `benchstat /tmp/report-1.txt /tmp/report-2.txt` to confirm statistical significance 7. **Repeat** — increment report number, tackle next bottleneck Refer to library documentation for known patterns before inventing custom solutions. Keep all `/tmp/report-*.txt` files as an audit trail. ## Decision Tree: Where Is Time Spent? | Bottleneck | Signal (from pprof) | Action | | --- | --- | --- | | Too many allocations | `alloc_objects` high in heap profile | [Memory optimization](references/memory.md) | | CPU-bound hot loop | function dominates CPU profile | [CPU optimization](references/cpu.md) | | GC pauses / OOM | high GC%, container limits | [Runtime tuning](references/runtime.md) | | Network / I/O latency | goroutines blocked on I/O | [I/O & networking](references/io-networking.md) | | Repeated expensive work | same computation/fetch multiple times | [Caching patterns](references/caching.md) | | Wrong algorithm | O(n²) where O(n) exists | [Algorithmic complexity](references/caching.md#algorithmic-complexity) | | Lock contention | mutex/block profile hot | → See `samber/cc-skills-golang@golang-concurrency` skill | | Slow queries | DB time dominates traces | → See `samber/cc-skills-golang@golang-database` skill | ## Common Mistakes | Mistake | Fix | | --- | --- | | Optimizing without profiling | Profile with pprof first — intuition is wrong ~80% of the time | | Default `http.Client` without Transport | `MaxIdleConnsPerHost` defaults to 2; set to match your concurrency level | | Logging in hot loops | Log calls prevent inlining and allocate even when the level is disabled. Use `slog.LogAttrs` | | `panic`/`recover` as control flow | panic allocates a stack trace and unwinds the stack; use error returns | | `unsafe` without benchmark proof | Only justified when profiling shows >10% improvement in a verified hot path | | No GC tuning in containers | Set `GOMEMLIMIT` to 80-90% of container memory to prevent OOM kills | | `reflect.DeepEqual` in production | 50-200x slower than typed comparison; use `slices.Equal`, `maps.Equal`, `bytes.Equal` | ## Deep Dives - [Memory Optimization](references/memory.md) — allocation patterns, backing array leaks, sync.Pool, struct alignment - [CPU Optimization](references/cpu.md) — inlining, cache locality, false sharing, ILP, reflection avoidance - [I/O & Networking](references/io-networking.md) — HTTP transport config, streaming, JSON performance, cgo, batch operations - [Runtime Tuning](references/runtime.md) — GOGC, GOMEMLIMIT, GC diagnostics, GOMAXPROCS, PGO - [Caching Patterns](references/caching.md) — algorithmic complexity, compiled patterns, singleflight, work avoidance - [Production Observability](references/observability.md) — Prometheus metrics, PromQL queries, continuous profiling, alerting rules ## CI Regression Detection Automate benchmark comparison in CI to catch regressions before they reach production. → See `samber/cc-skills-golang@golang-benchmark` skill for `benchdiff` and `cob` setup. ## Cross-References - → See `samber/cc-skills-golang@golang-benchmark` skill for benchmarking methodology, `benchstat`, and `b.Loop()` (Go 1.24+) - → See `samber/cc-skills-golang@golang-troubleshooting` skill for pprof workflow, escape analysis diagnostics, and performance debugging - → See `samber/cc-skills-golang@golang-data-structures` skill for slice/map preallocation and `strings.Builder` - → See `samber/cc-skills-golang@golang-concurrency` skill for worker pools, `sync.Pool` API, goroutine lifecycle, and lock contention - → See `samber/cc-skills-golang@golang-safety` skill for defer in loops, slice backing array aliasing - → See `samber/cc-skills-golang@golang-database` skill for connection pool tuning and batch processing - → See `samber/cc-skills-golang@golang-observability` skill for continuous profiling in production

golang-popular-libraries

Recommends production-ready Golang libraries and frameworks. Apply when the user asks for library suggestions, wants to compare alternatives, or needs to choose a library for a specific task. Also apply when the AI agent is about to add a new dependency — ensures vetted, production-ready libraries are chosen.

**Persona:** You are a Go ecosystem expert. You know the library landscape well enough to recommend the simplest production-ready option — and to tell the developer when the standard library is already enough. # Go Libraries and Frameworks Recommendations ## Core Philosophy When recommending libraries, prioritize: 1. **Production-readiness** - Mature, well-maintained libraries with active communities 2. **Simplicity** - Go's philosophy favors simple, idiomatic solutions 3. **Performance** - Libraries that leverage Go's strengths (concurrency, compiled performance) 4. **Standard Library First** - SHOULD prefer stdlib when it covers the use case; only recommend external libs when they provide clear value ## Reference Catalogs - [Standard Library - New & Experimental](./references/stdlib.md) — v2 packages, promoted x/exp packages, golang.org/x extensions - [Libraries by Category](./references/libraries.md) — vetted third-party libraries for web, database, testing, logging, messaging, and more - [Development Tools](./references/tools.md) — debugging, linting, testing, and dependency management tools Find more libraries here: https://github.com/avelino/awesome-go This skill is not exhaustive. Please refer to library documentation and code examples for more informations. ## General Guidelines When recommending libraries: 1. **Assess requirements first** - Understand the use case, performance needs, and constraints 2. **Check standard library** - Always consider if stdlib can solve the problem 3. **Prioritize maturity** - MUST check maintenance status, license, and community adoption before recommending 4. **Consider complexity** - Simpler solutions are usually better in Go 5. **Think about dependencies** - More dependencies = more attack surface and maintenance burden Remember: The best library is often no library at all. Go's standard library is excellent and sufficient for many use cases. ## Anti-Patterns to Avoid - Over-engineering simple problems with complex libraries - Using libraries that wrap standard library functionality without adding value - Abandoned or unmaintained libraries: ask the developer before recommending these - Suggesting libraries with large dependency footprints for simple needs - Ignoring standard library alternatives ## Cross-References - → See `samber/cc-skills-golang@golang-dependency-management` skill for adding, auditing, and managing dependencies - → See `samber/cc-skills-golang@golang-samber-do` skill for samber/do dependency injection details - → See `samber/cc-skills-golang@golang-samber-oops` skill for samber/oops error handling details - → See `samber/cc-skills-golang@golang-stretchr-testify` skill for testify testing details - → See `samber/cc-skills-golang@golang-grpc` skill for gRPC implementation details

golang-project-layout

Provides a guide for setting up Golang project layouts and workspaces. Use this whenever starting a new Go project, organizing an existing codebase, setting up a monorepo with multiple packages, creating CLI tools with multiple main packages, or deciding on directory structure. Apply this for any Go project initialization or restructuring work.

**Persona:** You are a Go project architect. You right-size structure to the problem — a script stays flat, a service gets layers only when justified by actual complexity. # Go Project Layout ## Architecture Decision: Ask First When starting a new project, **ask the developer** what software architecture they prefer (clean architecture, hexagonal, DDD, flat structure, etc.). NEVER over-structure small projects — a 100-line CLI tool does not need layers of abstractions or dependency injection. -> See `samber/cc-skills-golang@golang-design-patterns` skill for detailed architecture guides with file trees and code examples. ## Dependency Injection: Ask Next After settling on the architecture, **ask the developer** which dependency injection approach they want: manual constructor injection, or a DI library (samber/do, google/wire, uber-go/dig+fx), or none at all. The choice affects how services are wired, how lifecycle (health checks, graceful shutdown) is managed, and how the project is structured. See the `samber/cc-skills-golang@golang-dependency-injection` skill for a full comparison and decision table. ## 12-Factor App For applications (services, APIs, workers), follow [12-Factor App](https://12factor.net/) conventions: config via environment variables, logs to stdout, stateless processes, graceful shutdown, backing services as attached resources, and admin tasks as one-off commands (e.g., `cmd/migrate/`). ## Quick Start: Choose Your Project Type | Project Type | Use When | Key Directories | | --- | --- | --- | | **CLI Tool** | Building a command-line application | `cmd/{name}/`, `internal/`, optional `pkg/` | | **Library** | Creating reusable code for others | `pkg/{name}/`, `internal/` for private code | | **Service** | HTTP API, microservice, or web app | `cmd/{service}/`, `internal/`, `api/`, `web/` | | **Monorepo** | Multiple related packages/modules | `go.work`, separate modules per package | | **Workspace** | Developing multiple local modules | `go.work`, replace directives | ## Module Naming Conventions ### Module Name (go.mod) Your module path in `go.mod` should: - **MUST match your repository URL**: `github.com/username/project-name` - **Use lowercase only**: `github.com/you/my-app` (not `MyApp`) - **Use hyphens for multi-word**: `user-auth` not `user_auth` or `userAuth` - **Be semantic**: Name should clearly express purpose **Examples:** ```go // ✅ Good module github.com/jdoe/payment-processor module github.com/company/cli-tool // ❌ Bad module myproject module github.com/jdoe/MyProject module utils ``` ### Package Naming Packages MUST be lowercase, singular, and match their directory name. -> See `samber/cc-skills-golang@golang-naming` skill for complete package naming conventions and examples. ## Directory Layout All `main` packages must reside in `cmd/` with minimal logic — parse flags, wire dependencies, call `Run()`. Business logic belongs in `internal/` or `pkg/`. Use `internal/` for non-exported packages, `pkg/` only when code is useful to external consumers. See [directory layout examples](references/directory-layouts.md) for universal, small project, and library layouts, plus common mistakes. ## Essential Configuration Files Every Go project should include at the root: - **Makefile** — build automation. See [Makefile template](assets/Makefile) - **.gitignore** — git ignore patterns. See [.gitignore template](assets/.gitignore) - **.golangci.yml** — linter config. See the `samber/cc-skills-golang@golang-linter` skill for the recommended configuration For application configuration with Cobra + Viper, see [config reference](references/config.md). ## Tests, Benchmarks, and Examples Co-locate `_test.go` files with the code they test. Use `testdata/` for fixtures. See [testing layout](references/testing-layout.md) for file naming, placement, and organization details. ## Go Workspaces Use `go.work` when developing multiple related modules in a monorepo. See [workspaces](references/workspaces.md) for setup, structure, and commands. ## Initialization Checklist When starting a new Go project: - [ ] **Ask the developer** their preferred software architecture (clean, hexagonal, DDD, flat, etc.) - [ ] **Ask the developer** their preferred DI approach — see `samber/cc-skills-golang@golang-dependency-injection` skill - [ ] Decide project type (CLI, library, service, monorepo) - [ ] Right-size the structure to the project scope - [ ] Choose module name (matches repo URL, lowercase, hyphens) - [ ] Run `go version` to detect the current go version - [ ] Run `go mod init github.com/user/project-name` - [ ] Create `cmd/{name}/main.go` for entry point - [ ] Create `internal/` for private code - [ ] Create `pkg/` only if you have public libraries - [ ] For monorepos: Initialize `go work` and add modules - [ ] Run `gofmt -s -w .` to ensure formatting - [ ] Add `.gitignore` with `/vendor/` and binary patterns ## Related Skills -> See `samber/cc-skills-golang@golang-cli` skill for CLI tool structure and Cobra/Viper patterns. -> See `samber/cc-skills-golang@golang-dependency-injection` skill for DI approach comparison and wiring. -> See `samber/cc-skills-golang@golang-linter` skill for golangci-lint configuration. -> See `samber/cc-skills-golang@golang-continuous-integration` skill for CI/CD pipeline setup. -> See `samber/cc-skills-golang@golang-design-patterns` skill for architectural patterns.

golang-safety

Defensive Golang coding to prevent panics, silent data corruption, and subtle runtime bugs. Use whenever writing or reviewing Go code that involves nil-prone types (pointers, interfaces, maps, slices, channels), numeric conversions, resource lifecycle (defer in loops), or defensive copying. Also triggers on questions about nil panics, append aliasing, map concurrent access, float comparison, or zero-value design.

**Persona:** You are a defensive Go engineer. You treat every untested assumption about nil, capacity, and numeric range as a latent crash waiting to happen. # Go Safety: Correctness & Defensive Coding Prevents programmer mistakes — bugs, panics, and silent data corruption in normal (non-adversarial) code. Security handles attackers; safety handles ourselves. ## Best Practices Summary 1. **Prefer generics over `any`** when the type set is known — compiler catches mismatches instead of runtime panics 2. **Always use comma-ok for type assertions** — bare assertions panic on mismatch 3. **Typed nil pointer in an interface is not `== nil`** — the type descriptor makes it non-nil 4. **Writing to a nil map panics** — always initialize before use 5. **`append` may reuse the backing array** — both slices share memory if capacity allows, silently corrupting each other 6. **Return defensive copies** from exported functions — otherwise callers mutate your internals 7. **`defer` runs at function exit, not loop iteration** — extract loop body to a function 8. **Integer conversions truncate silently** — `int64` to `int32` wraps without error 9. **Float arithmetic is not exact** — use epsilon comparison or `math/big` 10. **Design useful zero values** — nil map fields panic on first write; use lazy init 11. **Use `sync.Once` for lazy init** — guarantees exactly-once even under concurrency ## Nil Safety Nil-related panics are the most common crash in Go. ### The nil interface trap Interfaces store (type, value). An interface is `nil` only when both are nil. Returning a typed nil pointer sets the type descriptor, making it non-nil: ```go // ✗ Dangerous — interface{type: *MyHandler, value: nil} is not == nil func getHandler() http.Handler { var h *MyHandler // nil pointer if !enabled { return h // interface{type: *MyHandler, value: nil} != nil } return h } // ✓ Good — return nil explicitly func getHandler() http.Handler { if !enabled { return nil // interface{type: nil, value: nil} == nil } return &MyHandler{} } ``` ### Nil map, slice, and channel behavior | Type | Read from nil | Write to nil | Len/Cap of nil | Range over nil | | --- | --- | --- | --- | --- | | Map | Zero value | **panic** | 0 | 0 iterations | | Slice | **panic** (index) | **panic** (index) | 0 | 0 iterations | | Channel | Blocks forever | Blocks forever | 0 | Blocks forever | ```go // ✗ Bad — nil map panics on write var m map[string]int m["key"] = 1 // ✓ Good — initialize or lazy-init in methods m := make(map[string]int) func (r *Registry) Add(name string, val int) { if r.items == nil { r.items = make(map[string]int) } r.items[name] = val } ``` See **[Nil Safety Deep Dive](./references/nil-safety.md)** for nil receivers, nil in generics, and nil interface performance. ## Slice & Map Safety ### Slice aliasing — the append trap `append` reuses the backing array if capacity allows. Both slices then share memory: ```go // ✗ Dangerous — a and b share backing array a := make([]int, 3, 5) b := append(a, 4) b[0] = 99 // also modifies a[0] // ✓ Good — full slice expression forces new allocation b := append(a[:len(a):len(a)], 4) ``` ### Map concurrent access Maps MUST NOT be accessed concurrently — → see `samber/cc-skills-golang@golang-concurrency` for sync primitives. See **[Slice and Map Deep Dive](./references/slice-map-safety.md)** for range pitfalls, subslice memory retention, and `slices.Clone`/`maps.Clone`. ## Numeric Safety ### Implicit type conversions truncate silently ```go // ✗ Bad — silently wraps around if val > math.MaxInt32 (3B becomes -1.29B) var val int64 = 3_000_000_000 i32 := int32(val) // -1294967296 (silent wraparound) // ✓ Good — check before converting if val > math.MaxInt32 || val < math.MinInt32 { return fmt.Errorf("value %d overflows int32", val) } i32 := int32(val) ``` ### Float comparison ```go // ✗ Bad — floating point arithmetic is not exact 0.1+0.2 == 0.3 // false // ✓ Good — use epsilon comparison const epsilon = 1e-9 math.Abs((0.1+0.2)-0.3) < epsilon // true ``` ### Division by zero Integer division by zero panics. Float division by zero produces `+Inf`, `-Inf`, or `NaN`. ```go func avg(total, count int) (int, error) { if count == 0 { return 0, errors.New("division by zero") } return total / count, nil } ``` For integer overflow as a security vulnerability, see the `samber/cc-skills-golang@golang-security` skill section. ## Resource Safety ### defer in loops — resource accumulation `defer` runs at _function_ exit, not loop iteration. Resources accumulate until the function returns: ```go // ✗ Bad — all files stay open until function returns for _, path := range paths { f, _ := os.Open(path) defer f.Close() // deferred until function exits process(f) } // ✓ Good — extract to function so defer runs per iteration for _, path := range paths { if err := processOne(path); err != nil { return err } } func processOne(path string) error { f, err := os.Open(path) if err != nil { return err } defer f.Close() return process(f) } ``` ### Goroutine leaks → See `samber/cc-skills-golang@golang-concurrency` for goroutine lifecycle and leak prevention. ## Immutability & Defensive Copying Exported functions returning slices/maps SHOULD return defensive copies. ### Protecting struct internals ```go // ✗ Bad — exported slice field, anyone can mutate type Config struct { Hosts []string } // ✓ Good — unexported field with accessor returning a copy type Config struct { hosts []string } func (c *Config) Hosts() []string { return slices.Clone(c.hosts) } ``` ## Initialization Safety ### Zero-value design Design types so `var x MyType` is safe — prevents "forgot to initialize" bugs: ```go var mu sync.Mutex // ✓ usable at zero value var buf bytes.Buffer // ✓ usable at zero value // ✗ Bad — nil map panics on write type Cache struct { data map[string]any } ``` ### sync.Once for lazy initialization ```go type DB struct { once sync.Once conn *sql.DB } func (db *DB) connection() *sql.DB { db.once.Do(func() { db.conn, _ = sql.Open("postgres", connStr) }) return db.conn } ``` ### init() function pitfalls → See `samber/cc-skills-golang@golang-design-patterns` for why init() should be avoided in favor of explicit constructors. ## Enforce with Linters Many safety pitfalls are caught automatically by linters: `errcheck`, `forcetypeassert`, `nilerr`, `govet`, `staticcheck`. See the `samber/cc-skills-golang@golang-linter` skill for configuration and usage. ## Cross-References - → See `samber/cc-skills-golang@golang-concurrency` skill for concurrent access patterns and sync primitives - → See `samber/cc-skills-golang@golang-data-structures` skill for slice/map internals, capacity growth, and container/ packages - → See `samber/cc-skills-golang@golang-error-handling` skill for nil error interface trap - → See `samber/cc-skills-golang@golang-security` skill for security-relevant safety issues (memory safety, integer overflow) - → See `samber/cc-skills-golang@golang-troubleshooting` skill for debugging panics and race conditions ## Common Mistakes | Mistake | Fix | | --- | --- | | Bare type assertion `v := x.(T)` | Panics on type mismatch, crashing the program. Use `v, ok := x.(T)` to handle gracefully | | Returning typed nil in interface function | Interface holds (type, nil) which is != nil. Return untyped `nil` for the nil case | | Writing to a nil map | Nil maps have no backing storage — write panics. Initialize with `make(map[K]V)` or lazy-init | | Assuming `append` always copies | If capacity allows, both slices share the backing array. Use `s[:len(s):len(s)]` to force a copy | | `defer` in a loop | `defer` runs at function exit, not loop iteration — resources accumulate. Extract body to a separate function | | `int64` to `int32` without bounds check | Values wrap silently (3B → -1.29B). Check against `math.MaxInt32`/`math.MinInt32` first | | Comparing floats with `==` | IEEE 754 representation is not exact (`0.1+0.2 != 0.3`). Use `math.Abs(a-b) < epsilon` | | Integer division without zero check | Integer division by zero panics. Guard with `if divisor == 0` before dividing | | Returning internal slice/map reference | Callers can mutate your struct's internals through the shared backing array. Return a defensive copy | | Multiple `init()` with ordering assumptions | `init()` execution order across files is unspecified. → See `samber/cc-skills-golang@golang-design-patterns` — use explicit constructors | | Blocking forever on nil channel | Nil channels block on both send and receive. Always initialize before use |

golang-samber-do

Implements dependency injection in Golang using samber/do. Apply this skill when working with dependency injection, setting up service containers, managing service lifecycles, or when you see code using github.com/samber/do/v2. Also use when refactoring manual dependency injection, implementing health checks, graceful shutdown, or organizing services into scopes/modules.

**Persona:** You are a Go architect setting up dependency injection. You keep the container at the composition root, depend on interfaces not concrete types, and treat provider errors as first-class failures. # Using samber/do for Dependency Injection in Go Type-safe dependency injection toolkit for Go based on Go 1.18+ generics. **Official Resources:** - [pkg.go.dev/github.com/samber/do/v2](https://pkg.go.dev/github.com/samber/do/v2) - [do.samber.dev](https://do.samber.dev) - [github.com/samber/do](https://github.com/samber/do) This skill is not exhaustive. Please refer to library documentation and code examples for more informations. Context7 can help as a discoverability platform. DO NOT USE v1 OF THIS LIBRARY. INSTALL v2 INSTEAD: ```bash go get -u github.com/samber/do/v2 ``` ## Core Concepts ### The Injector (Container) ```go import "github.com/samber/do/v2" injector := do.New() ``` ### Service Types - **Lazy** (default): Created when first requested - **Eager**: Created immediately when the container starts - **Transient**: New instance created on every request - **Value**: Pre-created value, no instantiation ### Provider Functions Services MUST be registered via provider functions: ```go type Provider[T any] func(i Injector) (T, error) ``` ## Basic Usage ### 1. Define and Register Services Follow "Accept Interfaces, Return Structs": ```go // Register a service (lazy by default) do.Provide(injector, func(i do.Injector) (Database, error) { return &PostgreSQLDatabase{connString: "postgres://..."}, nil }) // Register a pre-created value do.ProvideValue(injector, &Config{Port: 8080}) // Register a transient service (new instance each time) do.ProvideTransient(injector, func(i do.Injector) (*Logger, error) { return &Logger{}, nil }) // Register an eager service (created immediately) do.Provide(injector, do.Eager(&Config{Port: 8080})) ``` ### 2. Invoke Services The container MUST only be accessed at the composition root: ```go // Invoke with error handling db, err := do.Invoke[Database](injector) // MustInvoke panics on error (use when confident service exists) db := do.MustInvoke[Database](injector) ``` ### 3. Service Dependencies ```go func NewUserService(i do.Injector) (UserService, error) { db := do.MustInvoke[Database](i) cache := do.MustInvoke[Cache](i) return &userService{db: db, cache: cache}, nil } do.Provide(injector, NewUserService) ``` ### 4. Implicit Aliasing (Preferred) Register a concrete type and invoke as an interface without explicit aliasing: ```go // Register concrete type do.Provide(injector, func(i do.Injector) (*PostgreSQLDatabase, error) { return &PostgreSQLDatabase{}, nil }) // Invoke directly as interface (implicit aliasing) db := do.MustInvokeAs[Database](injector) ``` ### 5. Named Services Register multiple services of the same type: ```go do.ProvideNamed(injector, "primary-db", func(i do.Injector) (*Database, error) { return &Database{URL: "postgres://primary..."}, nil }) mainDB := do.MustInvokeNamed[*Database](injector, "primary-db") ``` ## Package Organization Use `do.Package()` to organize service registration by module: ```go // infrastructure/package.go var Package = do.Package( do.Lazy(func(i do.Injector) (*postgres.DB, error) { cfg := do.MustInvoke[*Config](i) return postgres.Connect(cfg.DatabaseURL) }), do.Lazy(func(i do.Injector) (*redis.Client, error) { cfg := do.MustInvoke[*Config](i) return redis.NewClient(cfg.RedisURL), nil }), ) // main.go injector := do.New(infrastructure.Package, service.Package) ``` ## Full Application Setup ```go func main() { injector := do.New( infrastructure.Package, repository.Package, service.Package, transport.Package, ) server := do.MustInvoke[*http.Server](injector) go server.ListenAndServe() _ = injector.ShutdownOnSignalsWithContext(context.Background(), os.Interrupt) } ``` ## Best Practices 1. Depend on interfaces, not concrete types — lets you swap implementations in tests without touching production code 2. Each service should have one job — services with multiple responsibilities are harder to test and harder to replace 3. Keep dependency trees shallow — chains beyond 3-4 levels make initialization order fragile and errors harder to trace 4. Handle errors in provider functions — a silently failing provider creates a broken service that crashes later in unexpected places 5. Use scopes to organize services by lifecycle — request-scoped services prevent leaks, global services prevent redundant initialization For scopes, lifecycle management, struct injection, and debugging, see [Advanced Usage](./references/advanced.md). For testing patterns (cloning, overrides, mocks), see [Testing](./references/testing.md). ## Quick Reference ### Registration | Function | Purpose | | ------------------------------- | -------------------------------- | | `do.Provide[T]()` | Register lazy service (default) | | `do.ProvideNamed[T]()` | Register named lazy service | | `do.ProvideValue[T]()` | Register pre-created value | | `do.ProvideNamedValue[T]()` | Register named value | | `do.ProvideTransient[T]()` | Register new instance each time | | `do.ProvideNamedTransient[T]()` | Register named transient service | | `do.Package()` | Group service registrations | ### Invocation | Function | Purpose | | -------------------------- | ----------------------------------------- | | `do.Invoke[T]()` | Get service (with error) | | `do.InvokeNamed[T]()` | Get named service | | `do.InvokeAs[T]()` | Get first service matching interface | | `do.InvokeStruct[T]()` | Inject into struct fields using tags | | `do.MustInvoke[T]()` | Get service (panic on error) | | `do.MustInvokeNamed[T]()` | Get named service (panic on error) | | `do.MustInvokeAs[T]()` | Get service by interface (panic on error) | | `do.MustInvokeStruct[T]()` | Inject into struct (panic on error) | ## Cross-References - -> See `samber/cc-skills-golang@golang-dependency-injection` skill for DI concepts, comparison, and when to adopt a DI library - -> See `samber/cc-skills-golang@golang-structs-interfaces` skill for interface design patterns - -> See `samber/cc-skills-golang@golang-testing` skill for general testing patterns

golang-samber-hot

In-memory caching in Golang using samber/hot — eviction algorithms (LRU, LFU, TinyLFU, W-TinyLFU, S3FIFO, ARC, TwoQueue, SIEVE, FIFO), TTL, cache loaders, sharding, stale-while-revalidate, missing key caching, and Prometheus metrics. Apply when using or adopting samber/hot, when the codebase imports github.com/samber/hot, or when the project repeatedly loads the same medium-to-low cardinality resources at high frequency and needs to reduce latency or backend pressure.

**Persona:** You are a Go engineer who treats caching as a system design decision. You choose eviction algorithms based on measured access patterns, size caches from working-set data, and always plan for expiration, loader failures, and monitoring. # Using samber/hot for In-Memory Caching in Go Generic, type-safe in-memory caching library for Go 1.22+ with 9 eviction algorithms, TTL, loader chains with singleflight deduplication, sharding, stale-while-revalidate, and Prometheus metrics. **Official Resources:** - [pkg.go.dev/github.com/samber/hot](https://pkg.go.dev/github.com/samber/hot) - [github.com/samber/hot](https://github.com/samber/hot) This skill is not exhaustive. Please refer to library documentation and code examples for more informations. Context7 can help as a discoverability platform. ```bash go get -u github.com/samber/hot ``` ## Algorithm Selection Pick based on your access pattern — the wrong algorithm wastes memory or tanks hit rate. | Algorithm | Constant | Best for | Avoid when | | --- | --- | --- | --- | | **W-TinyLFU** | `hot.WTinyLFU` | General-purpose, mixed workloads (default) | You need simplicity for debugging | | **LRU** | `hot.LRU` | Recency-dominated (sessions, recent queries) | Frequency matters (scan pollution evicts hot items) | | **LFU** | `hot.LFU` | Frequency-dominated (popular products, DNS) | Access patterns shift (stale popular items never evict) | | **TinyLFU** | `hot.TinyLFU` | Read-heavy with frequency bias | Write-heavy (admission filter overhead) | | **S3FIFO** | `hot.S3FIFO` | High throughput, scan-resistant | Small caches (<1000 items) | | **ARC** | `hot.ARC` | Self-tuning, unknown patterns | Memory-constrained (2x tracking overhead) | | **TwoQueue** | `hot.TwoQueue` | Mixed with hot/cold split | Tuning complexity is unacceptable | | **SIEVE** | `hot.SIEVE` | Simple scan-resistant LRU alternative | Highly skewed access patterns | | **FIFO** | `hot.FIFO` | Simple, predictable eviction order | Hit rate matters (no frequency/recency awareness) | **Decision shortcut:** Start with `hot.WTinyLFU`. Switch only when profiling shows the miss rate is too high for your SLO. For detailed algorithm comparison, benchmarks, and a decision tree, see [Algorithm Guide](./references/algorithm-guide.md). ## Core Usage ### Basic Cache with TTL ```go import "github.com/samber/hot" cache := hot.NewHotCache[string, *User](hot.WTinyLFU, 10_000). WithTTL(5 * time.Minute). WithJanitor(). Build() defer cache.StopJanitor() cache.Set("user:123", user) cache.SetWithTTL("session:abc", session, 30*time.Minute) value, found, err := cache.Get("user:123") ``` ### Loader Pattern (Read-Through) Loaders fetch missing keys automatically with singleflight deduplication — concurrent `Get()` calls for the same missing key share one loader invocation: ```go cache := hot.NewHotCache[int, *User](hot.WTinyLFU, 10_000). WithTTL(5 * time.Minute). WithLoaders(func(ids []int) (map[int]*User, error) { return db.GetUsersByIDs(ctx, ids) // batch query }). WithJanitor(). Build() defer cache.StopJanitor() user, found, err := cache.Get(123) // triggers loader on miss ``` ## Capacity Sizing Before setting the cache capacity, estimate how many items fit in the memory budget: 1. **Estimate single-item size** — estimate size of the struct, add the size of heap-allocated fields (slices, maps, strings). Include the key size. A rough per-entry overhead of ~100 bytes covers internal bookkeeping (pointers, expiry timestamps, algorithm metadata). 2. **Ask the developer** how much memory is dedicated to this cache in production (e.g., 256 MB, 1 GB). This depends on the service's total memory and what else shares the process. 3. **Compute capacity** — `capacity = memoryBudget / estimatedItemSize`. Round down to leave headroom. ``` Example: *User struct ~500 bytes + string key ~50 bytes + overhead ~100 bytes = ~650 bytes/entry 256 MB budget → 256_000_000 / 650 ≈ 393,000 items ``` If the item size is unknown, ask the developer to measure it with a unit test that allocates N items and checks `runtime.ReadMemStats`. Guessing capacity without measuring leads to OOM or wasted memory. ## Common Mistakes 1. **Forgetting `WithJanitor()`** — without it, expired entries stay in memory until the algorithm evicts them. Always chain `.WithJanitor()` in the builder and `defer cache.StopJanitor()`. 2. **Calling `SetMissing()` without missing cache config** — panics at runtime. Enable `WithMissingCache(algorithm, capacity)` or `WithMissingSharedCache()` in the builder first. 3. **`WithoutLocking()` + `WithJanitor()`** — mutually exclusive, panics. `WithoutLocking()` is only safe for single-goroutine access without background cleanup. 4. **Oversized cache** — a cache holding everything is a map with overhead. Size to your working set (typically 10-20% of total data). Monitor hit rate to validate. 5. **Ignoring loader errors** — `Get()` returns `(zero, false, err)` on loader failure. Always check `err`, not just `found`. ## Best Practices 1. Always set TTL — unbounded caches serve stale data indefinitely because there is no signal to refresh 2. Use `WithJitter(lambda, upperBound)` to spread expirations — without jitter, items created together expire together, causing thundering herd on the loader 3. Monitor with `WithPrometheusMetrics(cacheName)` — hit rate below 80% usually means the cache is undersized or the algorithm is wrong for the workload 4. Use `WithCopyOnRead(fn)` / `WithCopyOnWrite(fn)` for mutable values — without copies, callers mutate cached objects and corrupt shared state For advanced patterns (revalidation, sharding, missing cache, monitoring setup), see [Production Patterns](./references/production-patterns.md). For the complete API surface, see [API Reference](./references/api-reference.md). If you encounter a bug or unexpected behavior in samber/hot, open an issue at https://github.com/samber/hot/issues. ## Cross-References - -> See `samber/cc-skills-golang@golang-performance` skill for general caching strategy and when to use in-memory cache vs Redis vs CDN - -> See `samber/cc-skills-golang@golang-observability` skill for Prometheus metrics integration and monitoring - -> See `samber/cc-skills-golang@golang-database` skill for database query patterns that pair with cache loaders - -> See `samber/cc-skills@promql-cli` skill for querying Prometheus cache metrics via CLI

golang-samber-lo

Functional programming helpers for Golang using samber/lo — 500+ type-safe generic functions for slices, maps, channels, strings, math, tuples, and concurrency (Map, Filter, Reduce, GroupBy, Chunk, Flatten, Find, Uniq, etc.). Core immutable package (lo), concurrent variants (lo/parallel aka lop), in-place mutations (lo/mutable aka lom), lazy iterators (lo/it aka loi for Go 1.23+), and experimental SIMD (lo/exp/simd). Apply when using or adopting samber/lo, when the codebase imports github.com/samber/lo, or when implementing functional-style data transformations in Go. Not for streaming pipelines (→ See golang-samber-ro skill).

**Persona:** You are a Go engineer who prefers declarative collection transforms over manual loops. You reach for `lo` to eliminate boilerplate, but you know when the stdlib is enough and when to upgrade to `lop`, `lom`, or `loi`. # samber/lo — Functional Utilities for Go Lodash-inspired, generics-first utility library with 500+ type-safe helpers for slices, maps, strings, math, channels, tuples, and concurrency. Zero external dependencies. Immutable by default. **Official Resources:** - [github.com/samber/lo](https://github.com/samber/lo) - [lo.samber.dev](https://lo.samber.dev) - [pkg.go.dev/github.com/samber/lo](https://pkg.go.dev/github.com/samber/lo) This skill is not exhaustive. Please refer to library documentation and code examples for more informations. Context7 can help as a discoverability platform. ## Why samber/lo Go's stdlib `slices` and `maps` packages cover ~10 basic helpers (sort, contains, keys). Everything else — Map, Filter, Reduce, GroupBy, Chunk, Flatten, Zip — requires manual for-loops. `lo` fills this gap: - **Type-safe generics** — no `interface{}` casts, no reflection, compile-time checking, no interface boxing overhead - **Immutable by default** — returns new collections, safe for concurrent reads, easier to reason about - **Composable** — functions take and return slices/maps, so they chain without wrapper types - **Zero dependencies** — only Go stdlib, no transitive dependency risk - **Progressive complexity** — start with `lo`, upgrade to `lop`/`lom`/`loi` only when profiling demands it - **Error variants** — most functions have `Err` suffixes (`MapErr`, `FilterErr`, `ReduceErr`) that stop on first error ## Installation ```bash go get github.com/samber/lo ``` | Package | Import | Alias | Go version | | --- | --- | --- | --- | | Core (immutable) | `github.com/samber/lo` | `lo` | 1.18+ | | Parallel | `github.com/samber/lo/parallel` | `lop` | 1.18+ | | Mutable | `github.com/samber/lo/mutable` | `lom` | 1.18+ | | Iterator | `github.com/samber/lo/it` | `loi` | 1.23+ | | SIMD (experimental) | `github.com/samber/lo/exp/simd` | — | 1.25+ (amd64 only) | ## Choose the Right Package Start with `lo`. Move to other packages only when profiling shows a bottleneck or when lazy evaluation is explicitly needed. | Package | Use when | Trade-off | | --- | --- | --- | | `lo` | Default for all transforms | Allocates new collections (safe, predictable) | | `lop` | CPU-bound work on large datasets (1000+ items) | Goroutine overhead; not for I/O or small slices | | `lom` | Hot path confirmed by `pprof -alloc_objects` | Mutates input — caller must understand side effects | | `loi` | Large datasets with chained transforms (Go 1.23+) | Lazy evaluation saves memory but adds iterator complexity | | `simd` | Numeric bulk ops after benchmarking (experimental) | Unstable API, may break between versions | **Key rules:** - `lop` is for CPU parallelism, not I/O concurrency — for I/O fan-out, use `errgroup` instead - `lom` breaks immutability — only use when allocation pressure is measured, never assumed - `loi` eliminates intermediate allocations in chains like `Map → Filter → Take` by evaluating lazily - For reactive/streaming pipelines over infinite event streams, → see `samber/cc-skills-golang@golang-samber-ro` skill + `samber/ro` package For detailed package comparison and decision flowchart, see [Package Guide](./references/package-guide.md). ## Core Patterns ### Transform a slice ```go // ✓ lo — declarative, type-safe names := lo.Map(users, func(u User, _ int) string { return u.Name }) // ✗ Manual — boilerplate, error-prone names := make([]string, 0, len(users)) for _, u := range users { names = append(names, u.Name) } ``` ### Filter + Reduce ```go total := lo.Reduce( lo.Filter(orders, func(o Order, _ int) bool { return o.Status == "paid" }), func(sum float64, o Order, _ int) float64 { return sum + o.Amount }, 0, ) ``` ### GroupBy ```go byStatus := lo.GroupBy(tasks, func(t Task, _ int) string { return t.Status }) // map[string][]Task{"open": [...], "closed": [...]} ``` ### Error variant — stop on first error ```go results, err := lo.MapErr(urls, func(url string, _ int) (Response, error) { return http.Get(url) }) ``` ## Common Mistakes | Mistake | Why it fails | Fix | | --- | --- | --- | | Using `lo.Contains` when `slices.Contains` exists | Unnecessary dependency for a stdlib-covered op | Prefer `slices.Contains`, `slices.Sort`, `maps.Keys` since Go 1.21+ | | Using `lop.Map` on 10 items | Goroutine creation overhead exceeds transform cost | Use `lo.Map` — `lop` benefits start at ~1000+ items for CPU-bound work | | Assuming `lo.Filter` modifies the input | `lo` is immutable by default — it returns a new slice | Use `lom.Filter` if you explicitly need in-place mutation | | Using `lo.Must` in production code paths | `Must` panics on error — fine in tests and init, dangerous in request handlers | Use the non-Must variant and handle the error | | Chaining many eager transforms on large data | Each step allocates an intermediate slice | Use `loi` (lazy iterators) to avoid intermediate allocations | ## Best Practices 1. **Prefer stdlib when available** — `slices.Contains`, `slices.Sort`, `maps.Keys` carry no dependency. Use `lo` for transforms the stdlib doesn't offer (Map, Filter, Reduce, GroupBy, Chunk, Flatten) 2. **Compose lo functions** — chain `lo.Filter` → `lo.Map` → `lo.GroupBy` instead of writing nested loops. Each function is a building block 3. **Profile before optimizing** — switch from `lo` to `lom`/`lop` only after `go tool pprof` confirms allocation or CPU as the bottleneck 4. **Use error variants** — prefer `lo.MapErr` over `lo.Map` + manual error collection. Error variants stop early and propagate cleanly 5. **Use `lo.Must` only in tests and init** — in production, handle errors explicitly ## Quick Reference | Function | What it does | | --- | --- | | `lo.Map` | Transform each element | | `lo.Filter` / `lo.Reject` | Keep / remove elements matching predicate | | `lo.Reduce` | Fold elements into a single value | | `lo.ForEach` | Side-effect iteration | | `lo.GroupBy` | Group elements by key | | `lo.Chunk` | Split into fixed-size batches | | `lo.Flatten` | Flatten nested slices one level | | `lo.Uniq` / `lo.UniqBy` | Remove duplicates | | `lo.Find` / `lo.FindOrElse` | First match or default | | `lo.Contains` / `lo.Every` / `lo.Some` | Membership tests | | `lo.Keys` / `lo.Values` | Extract map keys or values | | `lo.PickBy` / `lo.OmitBy` | Filter map entries | | `lo.Zip2` / `lo.Unzip2` | Pair/unpair two slices | | `lo.Range` / `lo.RangeFrom` | Generate number sequences | | `lo.Ternary` / `lo.If` | Inline conditionals | | `lo.ToPtr` / `lo.FromPtr` | Pointer helpers | | `lo.Must` / `lo.Try` | Panic-on-error / recover-as-bool | | `lo.Async` / `lo.Attempt` | Async execution / retry with backoff | | `lo.Debounce` / `lo.Throttle` | Rate limiting | | `lo.ChannelDispatcher` | Fan-out to multiple channels | For the complete function catalog (300+ functions), see [API Reference](./references/api-reference.md). For composition patterns, stdlib interop, and iterator pipelines, see [Advanced Patterns](./references/advanced-patterns.md). If you encounter a bug or unexpected behavior in samber/lo, open an issue at [github.com/samber/lo/issues](https://github.com/samber/lo/issues). ## Cross-References - → See `samber/cc-skills-golang@golang-samber-ro` skill for reactive/streaming pipelines over infinite event streams (`samber/ro` package) - → See `samber/cc-skills-golang@golang-samber-mo` skill for monadic types (Option, Result, Either) that compose with lo transforms - → See `samber/cc-skills-golang@golang-data-structures` skill for choosing the right underlying data structure - → See `samber/cc-skills-golang@golang-performance` skill for profiling methodology before switching to `lom`/`lop`

golang-samber-mo

Monadic types for Golang using samber/mo — Option, Result, Either, Future, IO, Task, and State types for type-safe nullable values, error handling, and functional composition with pipeline sub-packages. Apply when using or adopting samber/mo, when the codebase imports `github.com/samber/mo`, or when considering functional programming patterns as a safety design for Golang.

**Persona:** You are a Go engineer bringing functional programming safety to Go. You use monads to make impossible states unrepresentable — nil checks become type constraints, error handling becomes composable pipelines. **Thinking mode:** Use `ultrathink` when designing multi-step Option/Result/Either pipelines. Wrong type choice creates unnecessary wrapping/unwrapping that defeats the purpose of monads. # samber/mo — Monads and Functional Abstractions for Go Go 1.18+ library providing type-safe monadic types with zero dependencies. Inspired by Scala, Rust, and fp-ts. **Official Resources:** - [pkg.go.dev/github.com/samber/mo](https://pkg.go.dev/github.com/samber/mo) - [github.com/samber/mo](https://github.com/samber/mo) This skill is not exhaustive. Please refer to library documentation and code examples for more information. Context7 can help as a discoverability platform. ```bash go get github.com/samber/mo ``` For an introduction to functional programming concepts and why monads are valuable in Go, see [Monads Guide](./references/monads-guide.md). ## Core Types at a Glance | Type | Purpose | Think of it as... | | --- | --- | --- | | `Option[T]` | Value that may be absent | Rust's `Option`, Java's `Optional` | | `Result[T]` | Operation that may fail | Rust's `Result<T, E>`, replaces `(T, error)` | | `Either[L, R]` | Value of one of two types | Scala's `Either`, TypeScript discriminated union | | `EitherX[L, R]` | Value of one of X types | Scala's `Either`, TypeScript discriminated union | | `Future[T]` | Async value not yet available | JavaScript `Promise` | | `IO[T]` | Lazy synchronous side effect | Haskell's `IO` | | `Task[T]` | Lazy async computation | fp-ts `Task` | | `State[S, A]` | Stateful computation | Haskell's `State` monad | ## Option[T] — Nullable Values Without nil Represents a value that is either present (`Some`) or absent (`None`). Eliminates nil pointer risks at the type level. ```go import "github.com/samber/mo" name := mo.Some("Alice") // Option[string] with value empty := mo.None[string]() // Option[string] without value fromPtr := mo.PointerToOption(ptr) // nil pointer -> None // Safe extraction name.OrElse("Anonymous") // "Alice" empty.OrElse("Anonymous") // "Anonymous" // Transform if present, skip if absent upper := name.Map(func(s string) (string, bool) { return strings.ToUpper(s), true }) ``` **Key methods:** `Some`, `None`, `Get`, `MustGet`, `OrElse`, `OrEmpty`, `Map`, `FlatMap`, `Match`, `ForEach`, `ToPointer`, `IsPresent`, `IsAbsent`. Option implements `json.Marshaler/Unmarshaler`, `sql.Scanner`, `driver.Valuer` — use it directly in JSON structs and database models. For full API reference, see [Option Reference](./references/option.md). ## Result[T] — Error Handling as Values Represents success (`Ok`) or failure (`Err`). Equivalent to `Either[error, T]` but specialized for Go's error pattern. ```go // Wrap Go's (value, error) pattern result := mo.TupleToResult(os.ReadFile("config.yaml")) // Same-type transform — errors short-circuit automatically upper := mo.Ok("hello").Map(func(s string) (string, error) { return strings.ToUpper(s), nil }) // Ok("HELLO") // Extract with fallback val := upper.OrElse("default") ``` **Go limitation:** Direct methods (`.Map`, `.FlatMap`) cannot change the type parameter — `Result[T].Map` returns `Result[T]`, not `Result[U]`. Go methods cannot introduce new type parameters. For type-changing transforms (e.g. `Result[[]byte]` to `Result[Config]`), use sub-package functions or `mo.Do`: ```go import "github.com/samber/mo/result" // Type-changing pipeline: []byte -> Config -> ValidConfig parsed := result.Pipe2( mo.TupleToResult(os.ReadFile("config.yaml")), result.Map(func(data []byte) Config { return parseConfig(data) }), result.FlatMap(func(cfg Config) mo.Result[ValidConfig] { return validate(cfg) }), ) ``` **Key methods:** `Ok`, `Err`, `Errf`, `TupleToResult`, `Try`, `Get`, `MustGet`, `OrElse`, `Map`, `FlatMap`, `MapErr`, `Match`, `ForEach`, `ToEither`, `IsOk`, `IsError`. For full API reference, see [Result Reference](./references/result.md). ## Either[L, R] — Discriminated Union of Two Types Represents a value that is one of two possible types. Unlike Result, neither side implies success or failure — both are valid alternatives. ```go // API that returns either cached data or fresh data func fetchUser(id string) mo.Either[CachedUser, FreshUser] { if cached, ok := cache.Get(id); ok { return mo.Left[CachedUser, FreshUser](cached) } return mo.Right[CachedUser, FreshUser](db.Fetch(id)) } // Pattern match result.Match( func(cached CachedUser) mo.Either[CachedUser, FreshUser] { /* use cached */ }, func(fresh FreshUser) mo.Either[CachedUser, FreshUser] { /* use fresh */ }, ) ``` **When to use Either vs Result:** Use `Result[T]` when one path is an error. Use `Either[L, R]` when both paths are valid alternatives (cached vs fresh, left vs right, strategy A vs B). `Either3[T1, T2, T3]`, `Either4`, and `Either5` extend this to 3-5 type variants. For full API reference, see [Either Reference](./references/either.md). ## Do Notation — Imperative Style with Monadic Safety `mo.Do` wraps imperative code in a `Result`, catching panics from `MustGet()` calls: ```go result := mo.Do(func() int { // MustGet panics on None/Err — Do catches it as Result error a := mo.Some(21).MustGet() b := mo.Ok(2).MustGet() return a * b // 42 }) // result is Ok(42) result := mo.Do(func() int { val := mo.None[int]().MustGet() // panics return val }) // result is Err("no such element") ``` Do notation bridges imperative Go style with monadic safety — write straight-line code, get automatic error propagation. ## Pipeline Sub-Packages vs Direct Chaining samber/mo provides two ways to compose operations: **Direct methods** (`.Map`, `.FlatMap`) — work when the output type equals the input type: ```go opt := mo.Some(42) doubled := opt.Map(func(v int) (int, bool) { return v * 2, true }) // Option[int] ``` **Sub-package functions** (`option.Map`, `result.Map`) — required when the output type differs from input: ```go import "github.com/samber/mo/option" // int -> string type change: use sub-package Map strOpt := option.Map(func(v int) string { return fmt.Sprintf("value: %d", v) })(mo.Some(42)) // Option[string] ``` **Pipe functions** (`option.Pipe3`, `result.Pipe3`) — chain multiple type-changing transformations readably: ```go import "github.com/samber/mo/option" result := option.Pipe3( mo.Some(42), option.Map(func(v int) string { return strconv.Itoa(v) }), option.Map(func(s string) []byte { return []byte(s) }), option.FlatMap(func(b []byte) mo.Option[string] { if len(b) > 0 { return mo.Some(string(b)) } return mo.None[string]() }), ) ``` **Rule of thumb:** Use direct methods for same-type transforms. Use sub-package functions + pipes when types change across steps. For detailed pipeline API reference, see [Pipelines Reference](./references/pipelines.md). ## Common Patterns ### JSON API responses with Option ```go type UserResponse struct { Name string `json:"name"` Nickname mo.Option[string] `json:"nickname"` // omits null gracefully Bio mo.Option[string] `json:"bio"` } ``` ### Database nullable columns ```go type User struct { ID int Email string Phone mo.Option[string] // implements sql.Scanner + driver.Valuer } err := row.Scan(&u.ID, &u.Email, &u.Phone) ``` ### Wrapping existing Go APIs ```go // Convert map lookup to Option func MapGet[K comparable, V any](m map[K]V, key K) mo.Option[V] { return mo.TupleToOption(m[key]) // m[key] returns (V, bool) } ``` ### Uniform extraction with Fold `mo.Fold` works uniformly across Option, Result, and Either via the `Foldable` interface: ```go str := mo.Fold[error, int, string]( mo.Ok(42), // works with Option, Result, or Either func(v int) string { return fmt.Sprintf("got %d", v) }, func(err error) string { return "failed" }, ) // "got 42" ``` ## Best Practices 1. **Prefer `OrElse` over `MustGet`** — `MustGet` panics on absent/error values; use it only inside `mo.Do` blocks where panics are caught, or when you are certain the value exists 2. **Use `TupleToResult` at API boundaries** — convert Go's `(T, error)` to `Result[T]` at the boundary, then chain with `Map`/`FlatMap` inside your domain logic 3. **Use `Result[T]` for errors, `Either[L, R]` for alternatives** — Result is specialized for success/failure; Either is for two valid types 4. **Option for nullable fields, not zero values** — `Option[string]` distinguishes "absent" from "empty string"; use plain `string` when empty string is a valid value 5. **Chain, don't nest** — `result.Map(...).FlatMap(...).OrElse(default)` reads left-to-right; avoid nested if/else patterns when monadic chaining is cleaner 6. **Use sub-package pipes for multi-step type transformations** — when 3+ steps each change the type, `option.Pipe3(...)` is more readable than nested function calls For advanced types (Future, IO, Task, State), see [Advanced Types Reference](./references/advanced-types.md). If you encounter a bug or unexpected behavior in samber/mo, open an issue at https://github.com/samber/mo/issues. ## Cross-References - -> See `samber/cc-skills-golang@golang-samber-lo` skill for functional collection transforms (Map, Filter, Reduce on slices) that compose with mo types - -> See `samber/cc-skills-golang@golang-error-handling` skill for idiomatic Go error handling patterns - -> See `samber/cc-skills-golang@golang-safety` skill for nil-safety and defensive Go coding - -> See `samber/cc-skills-golang@golang-database` skill for database access patterns - -> See `samber/cc-skills-golang@golang-design-patterns` skill for functional options and other Go patterns

golang-samber-oops

Structured error handling in Golang with samber/oops — error builders, stack traces, error codes, error context, error wrapping, error attributes, user-facing vs developer messages, panic recovery, and logger integration. Apply when using or adopting samber/oops, or when the codebase already imports github.com/samber/oops.

**Persona:** You are a Go engineer who treats errors as structured data. Every error carries enough context — domain, attributes, trace — for an on-call engineer to diagnose the problem without asking the developer. # samber/oops Structured Error Handling **samber/oops** is a drop-in replacement for Go's standard error handling that adds structured context, stack traces, error codes, public messages, and panic recovery. Variable data goes in `.With()` attributes (not the message string), so APM tools (Datadog, Loki, Sentry) can group errors properly. Unlike the stdlib approach (adding `slog` attributes at the log site), oops attributes travel with the error through the call stack. ## Why use samber/oops Standard Go errors lack context — you see `connection failed` but not which user triggered it, what query was running, or the full call stack. `samber/oops` provides: - **Structured context** — key-value attributes on any error - **Stack traces** — automatic call stack capture - **Error codes** — machine-readable identifiers - **Public messages** — user-safe messages separate from technical details - **Low-cardinality messages** — variable data in `.With()` attributes, not the message string, so APM tools group errors properly This skill is not exhaustive. Please refer to library documentation and code examples for more informations. Context7 can help as a discoverability platform. ## Core pattern: Error builder chain All `oops` errors use a fluent builder pattern: ```go err := oops. In("user-service"). // domain/feature Tags("database", "postgres"). // categorization Code("network_failure"). // machine-readable identifier User("user-123", "email", "foo@bar.com"). // user context With("query", query). // custom attributes Errorf("failed to fetch user: %s", "timeout") ``` Terminal methods: - `.Errorf(format, args...)` — create a new error - `.Wrap(err)` — wrap an existing error - `.Wrapf(err, format, args...)` — wrap with a message - `.Join(err1, err2, ...)` — combine multiple errors - `.Recover(fn)` / `.Recoverf(fn, format, args...)` — convert panic to error ### Error builder methods | Methods | Use case | | --- | --- | | `.With("key", value)` | Add custom key-value attribute (lazy `func() any` values supported) | | `.WithContext(ctx, "key1", "key2")` | Extract values from Go context into attributes (lazy values supported) | | `.In("domain")` | Set the feature/service/domain | | `.Tags("auth", "sql")` | Add categorization tags (query with `err.HasTag("tag")`) | | `.Code("iam_authz_missing_permission")` | Set machine-readable error identifier/slug | | `.Public("Could not fetch user.")` | Set user-safe message (separate from technical details) | | `.Hint("Runbook: https://doc.acme.org/doc/abcd.md")` | Add debugging hint for developers | | `.Owner("team/slack")` | Identify responsible team/owner | | `.User(id, "k", "v")` | Add user identifier and attributes | | `.Tenant(id, "k", "v")` | Add tenant/organization context and attributes | | `.Trace(id)` | Add trace / correlation ID (default: ULID) | | `.Span(id)` | Add span ID representing a unit of work/operation (default: ULID) | | `.Time(t)` | Override error timestamp (default: `time.Now()`) | | `.Since(t)` | Set duration based on time since `t` (exposed via `err.Duration()`) | | `.Duration(d)` | Set explicit error duration | | `.Request(req, includeBody)` | Attach `*http.Request` (optionally including body) | | `.Response(res, includeBody)` | Attach `*http.Response` (optionally including body) | | `oops.FromContext(ctx)` | Start from an `OopsErrorBuilder` stored in a Go context | ## Common scenarios ### Database/repository layer ```go func (r *UserRepository) FetchUser(id string) (*User, error) { query := "SELECT * FROM users WHERE id = $1" row, err := r.db.Query(query, id) if err != nil { return nil, oops. In("user-repository"). Tags("database", "postgres"). With("query", query). With("user_id", id). Wrapf(err, "failed to fetch user from database") } // ... } ``` ### HTTP handler layer ```go func (h *Handler) CreateUser(w http.ResponseWriter, r *http.Request) { userID := getUserID(r) err := h.service.CreateUser(r.Context(), userID) if err != nil { return oops. In("http-handler"). Tags("endpoint", "/users"). Request(r, false). User(userID). Wrapf(err, "create user failed") } w.WriteHeader(http.StatusCreated) } ``` ### Service layer with reusable builder ```go func (s *UserService) CreateOrder(ctx context.Context, req CreateOrderRequest) error { builder := oops. In("order-service"). Tags("orders", "checkout"). Tenant(req.TenantID, "plan", req.Plan). User(req.UserID, "email", req.UserEmail) product, err := s.catalog.GetProduct(ctx, req.ProductID) if err != nil { return builder. With("product_id", req.ProductID). Wrapf(err, "product lookup failed") } if product.Stock < req.Quantity { return builder. Code("insufficient_stock"). Public("Not enough items in stock."). With("requested", req.Quantity). With("available", product.Stock). Errorf("insufficient stock for product %s", req.ProductID) } return nil } ``` ## Error wrapping best practices ### DO: Wrap directly, no nil check needed ```go // ✓ Good — Wrap returns nil if err is nil return oops.Wrapf(err, "operation failed") // ✗ Bad — unnecessary nil check if err != nil { return oops.Wrapf(err, "operation failed") } return nil ``` ### DO: Add context at each layer Each architectural layer SHOULD add context via Wrap/Wrapf — at least once per package boundary (not necessarily at every function call). ```go // ✓ Good — each layer adds relevant context func Controller() error { return oops.In("controller").Trace(traceID).Wrapf(Service(), "user request failed") } func Service() error { return oops.In("service").With("op", "create_user").Wrapf(Repository(), "db operation failed") } func Repository() error { return oops.In("repository").Tags("database", "postgres").Errorf("connection timeout") } ``` ### DO: Keep error messages low-cardinality Error messages MUST be low-cardinality for APM aggregation. Interpolating variable data into the message breaks grouping in Datadog, Loki, Sentry. ```go // ✗ Bad — high-cardinality, breaks APM grouping oops.Errorf("failed to process user %s in tenant %s", userID, tenantID) // ✓ Good — static message + structured attributes oops.With("user_id", userID).With("tenant_id", tenantID).Errorf("failed to process user") ``` ## Panic recovery `oops.Recover()` MUST be used in goroutine boundaries. Convert panics to structured errors: ```go func ProcessData(data string) (err error) { return oops. In("data-processor"). Code("panic_recovered"). Hint("Check input data format and dependencies"). With("panic_value", r). Recover(func() { riskyOperation(data) }) } ``` ## Accessing error information `samber/oops` errors implement the standard `error` interface. Access additional info: ```go if oopsErr, ok := err.(oops.OopsError); ok { fmt.Println("Code:", oopsErr.Code()) fmt.Println("Domain:", oopsErr.Domain()) fmt.Println("Tags:", oopsErr.Tags()) fmt.Println("Context:", oopsErr.Context()) fmt.Println("Stacktrace:", oopsErr.Stacktrace()) } // Get public-facing message with fallback publicMsg := oops.GetPublic(err, "Something went wrong") ``` ### Output formats ```go fmt.Printf("%+v\n", err) // verbose with stack trace bytes, _ := json.Marshal(err) // JSON for logging slog.Error(err.Error(), slog.Any("error", err)) // slog integration ``` ## Context propagation Carry error context through Go contexts: ```go func middleware(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { builder := oops. In("http"). Request(r, false). Trace(r.Header.Get("X-Trace-ID")) ctx := oops.WithBuilder(r.Context(), builder) next.ServeHTTP(w, r.WithContext(ctx)) }) } func handler(ctx context.Context) error { return oops.FromContext(ctx).Tags("handler", "users").Errorf("something failed") } ``` For assertions, configuration, and additional logger examples, see [Advanced patterns](./references/advanced.md). ## References - [github.com/samber/oops](https://github.com/samber/oops) - [pkg.go.dev/github.com/samber/oops](https://pkg.go.dev/github.com/samber/oops) ## Cross-References - → See `samber/cc-skills-golang@golang-error-handling` skill for general error handling patterns - → See `samber/cc-skills-golang@golang-observability` skill for logger integration and structured logging

golang-samber-ro

Reactive streams and event-driven programming in Golang using samber/ro — ReactiveX implementation with 150+ type-safe operators, cold/hot observables, 5 subject types (Publish, Behavior, Replay, Async, Unicast), declarative pipelines via Pipe, 40+ plugins (HTTP, cron, fsnotify, JSON, logging), automatic backpressure, error propagation, and Go context integration. Apply when using or adopting samber/ro, when the codebase imports github.com/samber/ro, or when building asynchronous event-driven pipelines, real-time data processing, streams, or reactive architectures in Go. Not for finite slice transforms (-> See golang-samber-lo skill).

**Persona:** You are a Go engineer who reaches for reactive streams when data flows asynchronously or infinitely. You use samber/ro to build declarative pipelines instead of manual goroutine/channel wiring, but you know when a simple slice + samber/lo is enough. **Thinking mode:** Use `ultrathink` when designing advanced reactive pipelines or choosing between cold/hot observables, subjects, and combining operators. Wrong architecture leads to resource leaks or missed events. # samber/ro — Reactive Streams for Go Go implementation of [ReactiveX](https://reactivex.io/). Generics-first, type-safe, composable pipelines for asynchronous data streams with automatic backpressure, error propagation, context integration, and resource cleanup. 150+ operators, 5 subject types, 40+ plugins. **Official Resources:** - [github.com/samber/ro](https://github.com/samber/ro) - [ro.samber.dev](https://ro.samber.dev) - [pkg.go.dev/github.com/samber/ro](https://pkg.go.dev/github.com/samber/ro) This skill is not exhaustive. Please refer to library documentation and code examples for more informations. Context7 can help as a discoverability platform. ## Why samber/ro (Streams vs Slices) Go channels + goroutines become unwieldy for complex async pipelines: manual channel closures, verbose goroutine lifecycle, error propagation across nested selects, and no composable operators. `samber/ro` solves this with declarative, chainable stream operators. **When to use which tool:** | Scenario | Tool | Why | | --- | --- | --- | | Transform a slice (map, filter, reduce) | `samber/lo` | Finite, synchronous, eager — no stream overhead needed | | Simple goroutine fan-out with error handling | `errgroup` | Standard lib, lightweight, sufficient for bounded concurrency | | Infinite event stream (WebSocket, tickers, file watcher) | `samber/ro` | Declarative pipeline with backpressure, retry, timeout, combine | | Real-time data enrichment from multiple async sources | `samber/ro` | CombineLatest/Zip compose dependent streams without manual select | | Pub/sub with multiple consumers sharing one source | `samber/ro` | Hot observables (Share/Subjects) handle multicast natively | **Key differences: lo vs ro** | Aspect | `samber/lo` | `samber/ro` | | --- | --- | --- | | Data | Finite slices | Infinite streams | | Execution | Synchronous, blocking | Asynchronous, non-blocking | | Evaluation | Eager (allocates intermediate slices) | Lazy (processes items as they arrive) | | Timing | Immediate | Time-aware (delay, throttle, interval, timeout) | | Error model | Return `(T, error)` per call | Error channel propagates through pipeline | | Use case | Collection transforms | Event-driven, real-time, async pipelines | ## Installation ```bash go get github.com/samber/ro ``` ## Core Concepts Four building blocks: 1. **Observable** — a data source that emits values over time. Cold by default: each subscriber triggers independent execution from scratch 2. **Observer** — a consumer with three callbacks: `onNext(T)`, `onError(error)`, `onComplete()` 3. **Operator** — a function that transforms an observable into another observable, chained via `Pipe` 4. **Subscription** — the connection between observable and observer. Call `.Wait()` to block or `.Unsubscribe()` to cancel ```go observable := ro.Pipe2( ro.RangeWithInterval(0, 5, 1*time.Second), ro.Filter(func(x int) bool { return x%2 == 0 }), ro.Map(func(x int) string { return fmt.Sprintf("even-%d", x) }), ) observable.Subscribe(ro.NewObserver( func(s string) { fmt.Println(s) }, // onNext func(err error) { log.Println(err) }, // onError func() { fmt.Println("Done!") }, // onComplete )) // Output: "even-0", "even-2", "even-4", "Done!" // Or collect synchronously: values, err := ro.Collect(observable) ``` ## Cold vs Hot Observables **Cold** (default): each `.Subscribe()` starts a new independent execution. Safe and predictable — use by default. **Hot**: multiple subscribers share a single execution. Use when the source is expensive (WebSocket, DB poll) or subscribers must see the same events. | Convert with | Behavior | | --- | --- | | `Share()` | Cold → hot with reference counting. Last unsubscribe tears down | | `ShareReplay(n)` | Same as Share + buffers last N values for late subscribers | | `Connectable()` | Cold → hot, but waits for explicit `.Connect()` call | | Subjects | Natively hot — call `.Send()`, `.Error()`, `.Complete()` directly | | Subject | Constructor | Replay behavior | | --- | --- | --- | | `PublishSubject` | `NewPublishSubject[T]()` | None — late subscribers miss past events | | `BehaviorSubject` | `NewBehaviorSubject[T](initial)` | Replays last value to new subscribers | | `ReplaySubject` | `NewReplaySubject[T](bufferSize)` | Replays last N values | | `AsyncSubject` | `NewAsyncSubject[T]()` | Emits only last value, only on complete | | `UnicastSubject` | `NewUnicastSubject[T](bufferSize)` | Single subscriber only | For subject details and hot observable patterns, see [Subjects Guide](./references/subjects-guide.md). ## Operator Quick Reference | Category | Key operators | Purpose | | --- | --- | --- | | Creation | `Just`, `FromSlice`, `FromChannel`, `Range`, `Interval`, `Defer`, `Future` | Create observables from various sources | | Transform | `Map`, `MapErr`, `FlatMap`, `Scan`, `Reduce`, `GroupBy` | Transform or accumulate stream values | | Filter | `Filter`, `Take`, `TakeLast`, `Skip`, `Distinct`, `Find`, `First`, `Last` | Selectively emit values | | Combine | `Merge`, `Concat`, `Zip2`–`Zip6`, `CombineLatest2`–`CombineLatest5`, `Race` | Merge multiple observables | | Error | `Catch`, `OnErrorReturn`, `OnErrorResumeNextWith`, `Retry`, `RetryWithConfig` | Recover from errors | | Timing | `Delay`, `DelayEach`, `Timeout`, `ThrottleTime`, `SampleTime`, `BufferWithTime` | Control emission timing | | Side effect | `Tap`/`Do`, `TapOnNext`, `TapOnError`, `TapOnComplete` | Observe without altering stream | | Terminal | `Collect`, `ToSlice`, `ToChannel`, `ToMap` | Consume stream into Go types | Use typed `Pipe2`, `Pipe3` ... `Pipe25` for compile-time type safety across operator chains. The untyped `Pipe` uses `any` and loses type checking. For the complete operator catalog (150+ operators with signatures), see [Operators Guide](./references/operators-guide.md). ## Common Mistakes | Mistake | Why it fails | Fix | | --- | --- | --- | | Using `ro.OnNext()` without error handler | Errors are silently dropped — bugs hide in production | Use `ro.NewObserver(onNext, onError, onComplete)` with all 3 callbacks | | Using untyped `Pipe()` instead of `Pipe2`/`Pipe3` | Loses compile-time type safety, errors surface at runtime | Use `Pipe2`, `Pipe3`...`Pipe25` for typed operator chains | | Forgetting `.Unsubscribe()` on infinite streams | Goroutine leak — the observable runs forever | Use `TakeUntil(signal)`, context cancellation, or explicit `Unsubscribe()` | | Using `Share()` when cold is sufficient | Unnecessary complexity, harder to reason about lifecycle | Use hot observables only when multiple consumers need the same stream | | Using `samber/ro` for finite slice transforms | Stream overhead (goroutines, subscriptions) for a synchronous operation | Use `samber/lo` — it's simpler, faster, and purpose-built for slices | | Not propagating context for cancellation | Streams ignore shutdown signals, causing resource leaks on termination | Chain `ContextWithTimeout` or `ThrowOnContextCancel` in the pipeline | ## Best Practices 1. **Always handle all three events** — use `NewObserver(onNext, onError, onComplete)`, not just `OnNext`. Unhandled errors cause silent data loss 2. **Use `Collect()` for synchronous consumption** — when the stream is finite and you need `[]T`, `Collect` blocks until complete and returns the slice + error 3. **Prefer typed Pipe functions** — `Pipe2`, `Pipe3`...`Pipe25` catch type mismatches at compile time. Reserve untyped `Pipe` for dynamic operator chains 4. **Bound infinite streams** — use `Take(n)`, `TakeUntil(signal)`, `Timeout(d)`, or context cancellation. Unbounded streams leak goroutines 5. **Use `Tap`/`Do` for observability** — log, trace, or meter emissions without altering the stream. Chain `TapOnError` for error monitoring 6. **Prefer `samber/lo` for simple transforms** — if the data is a finite slice and you need Map/Filter/Reduce, use `lo`. Reach for `ro` when data arrives over time, from multiple sources, or needs retry/timeout/backpressure ## Plugin Ecosystem 40+ plugins extend ro with domain-specific operators: | Category | Plugins | Import path prefix | | --- | --- | --- | | Encoding | JSON, CSV, Base64, Gob | `plugins/encoding/...` | | Network | HTTP, I/O, FSNotify | `plugins/http`, `plugins/io`, `plugins/fsnotify` | | Scheduling | Cron, ICS | `plugins/cron`, `plugins/ics` | | Observability | Zap, Slog, Zerolog, Logrus, Sentry, Oops | `plugins/observability/...`, `plugins/samber/oops` | | Rate limiting | Native, Ulule | `plugins/ratelimit/...` | | Data | Bytes, Strings, Sort, Strconv, Regexp, Template | `plugins/bytes`, `plugins/strings`, etc. | | System | Process, Signal | `plugins/proc`, `plugins/signal` | For the full plugin catalog with import paths and usage examples, see [Plugin Ecosystem](./references/plugin-ecosystem.md). For real-world reactive patterns (retry+timeout, WebSocket fan-out, graceful shutdown, stream combination), see [Patterns](./references/patterns.md). If you encounter a bug or unexpected behavior in samber/ro, open an issue at [github.com/samber/ro/issues](https://github.com/samber/ro/issues). ## Cross-References - → See `samber/cc-skills-golang@golang-samber-lo` skill for finite slice transforms (Map, Filter, Reduce, GroupBy) — use lo when data is already in a slice - → See `samber/cc-skills-golang@golang-samber-mo` skill for monadic types (Option, Result, Either) that compose with ro pipelines - → See `samber/cc-skills-golang@golang-samber-hot` skill for in-memory caching (also available as an ro plugin) - → See `samber/cc-skills-golang@golang-concurrency` skill for goroutine/channel patterns when reactive streams are overkill - → See `samber/cc-skills-golang@golang-observability` skill for monitoring reactive pipelines in production

golang-samber-slog

Structured logging extensions for Golang using samber/slog-**** packages — multi-handler pipelines (slog-multi), log sampling (slog-sampling), attribute formatting (slog-formatter), HTTP middleware (slog-fiber, slog-gin, slog-chi, slog-echo), and backend routing (slog-datadog, slog-sentry, slog-loki, slog-syslog, slog-logstash, slog-graylog...). Apply when using or adopting slog, or when the codebase already imports any github.com/samber/slog-* package.

**Persona:** You are a Go logging architect. You design log pipelines where every record flows through the right handlers — sampling drops noise early, formatters strip PII before records leave the process, and routers send errors to Sentry while info goes to Loki. # samber/slog-\*\*\*\* — Structured Logging Pipeline for Go 20+ composable `slog.Handler` packages for Go 1.21+. Three core pipeline libraries plus HTTP middlewares and backend sinks that all implement the standard `slog.Handler` interface. **Official resources:** - [github.com/samber/slog-multi](https://github.com/samber/slog-multi) — handler composition - [github.com/samber/slog-sampling](https://github.com/samber/slog-sampling) — throughput control - [github.com/samber/slog-formatter](https://github.com/samber/slog-formatter) — attribute transformation This skill is not exhaustive. Please refer to library documentation and code examples for more informations. Context7 can help as a discoverability platform. ## The Pipeline Model Every samber/slog pipeline follows a canonical ordering. Records flow left to right — place sampling first to drop early and avoid wasting CPU on records that never reach a sink. ``` record → [Sampling] → [Pipe: trace/PII] → [Router] → [Sinks] ``` Order matters: sampling before formatting saves CPU. Formatting before routing ensures all sinks receive clean attributes. Reversing this wastes work on records that get dropped. ## Core Libraries | Library | Purpose | Key constructors | | --- | --- | --- | | `slog-multi` | Handler composition | `Fanout`, `Router`, `FirstMatch`, `Failover`, `Pool`, `Pipe` | | `slog-sampling` | Throughput control | `UniformSamplingOption`, `ThresholdSamplingOption`, `AbsoluteSamplingOption`, `CustomSamplingOption` | | `slog-formatter` | Attribute transforms | `PIIFormatter`, `ErrorFormatter`, `FormatByType[T]`, `FormatByKey`, `FlattenFormatterMiddleware` | ## slog-multi — Handler Composition Six composition patterns, each for a different routing need: | Pattern | Behavior | Latency impact | | --- | --- | --- | | `Fanout(handlers...)` | Broadcast to all handlers sequentially | Sum of all handler latencies | | `Router().Add(h, predicate).Handler()` | Route to ALL matching handlers | Sum of matching handlers | | `Router().Add(...).FirstMatch().Handler()` | Route to FIRST match only | Single handler latency | | `Failover()(handlers...)` | Try sequentially until one succeeds | Primary handler latency (happy path) | | `Pool()(handlers...)` | Concurrent broadcast to all handlers | Max of all handler latencies | | `Pipe(middlewares...).Handler(sink)` | Middleware chain before sink | Middleware overhead + sink | ```go // Route errors to Sentry, all logs to stdout logger := slog.New( slogmulti.Router(). Add(sentryHandler, slogmulti.LevelIs(slog.LevelError)). Add(slog.NewJSONHandler(os.Stdout, nil)). Handler(), ) ``` Built-in predicates: `LevelIs`, `LevelIsNot`, `MessageIs`, `MessageIsNot`, `MessageContains`, `MessageNotContains`, `AttrValueIs`, `AttrKindIs`. For full code examples of every pattern, see [Pipeline Patterns](references/pipeline-patterns.md). ## slog-sampling — Throughput Control | Strategy | Behavior | Best for | | --- | --- | --- | | Uniform | Drop fixed % of all records | Dev/staging noise reduction | | Threshold | Log first N per interval, then sample at rate R | Production — preserves initial visibility | | Absolute | Cap at N records per interval globally | Hard cost control | | Custom | User function returns sample rate per record | Level-aware or time-aware rules | Sampling MUST be the outermost handler in the pipeline — placing it after formatting wastes CPU on records that get dropped. ```go // Threshold: log first 10 per 5s, then 10% — errors always pass through via Router logger := slog.New( slogmulti. Pipe(slogsampling.ThresholdSamplingOption{ Tick: 5 * time.Second, Threshold: 10, Rate: 0.1, }.NewMiddleware()). Handler(innerHandler), ) ``` Matchers group similar records for deduplication: `MatchByLevel()`, `MatchByMessage()`, `MatchByLevelAndMessage()` (default), `MatchBySource()`, `MatchByAttribute(groups, key)`. For strategy comparison and configuration details, see [Sampling Strategies](references/sampling-strategies.md). ## slog-formatter — Attribute Transformation Apply as a `Pipe` middleware so all downstream handlers receive clean attributes. ```go logger := slog.New( slogmulti.Pipe(slogformatter.NewFormatterMiddleware( slogformatter.PIIFormatter("user"), // mask PII fields slogformatter.ErrorFormatter("error"), // structured error info slogformatter.IPAddressFormatter("client"), // mask IP addresses )).Handler(slog.NewJSONHandler(os.Stdout, nil)), ) ``` Key formatters: `PIIFormatter`, `ErrorFormatter`, `TimeFormatter`, `UnixTimestampFormatter`, `IPAddressFormatter`, `HTTPRequestFormatter`, `HTTPResponseFormatter`. Generic formatters: `FormatByType[T]`, `FormatByKey`, `FormatByKind`, `FormatByGroup`, `FormatByGroupKey`. Flatten nested attributes with `FlattenFormatterMiddleware`. ## HTTP Middlewares Consistent pattern across frameworks: `router.Use(slogXXX.New(logger))`. Available: `slog-gin`, `slog-echo`, `slog-fiber`, `slog-chi`, `slog-http` (net/http). All share a `Config` struct with: `DefaultLevel`, `ClientErrorLevel`, `ServerErrorLevel`, `WithRequestBody`, `WithResponseBody`, `WithUserAgent`, `WithRequestID`, `WithTraceID`, `WithSpanID`, `Filters`. ```go // Gin with filters — skip health checks router.Use(sloggin.NewWithConfig(logger, sloggin.Config{ DefaultLevel: slog.LevelInfo, ClientErrorLevel: slog.LevelWarn, ServerErrorLevel: slog.LevelError, WithRequestBody: true, Filters: []sloggin.Filter{ sloggin.IgnorePath("/health", "/metrics"), }, })) ``` For framework-specific setup, see [HTTP Middlewares](references/http-middlewares.md). ## Backend Sinks All follow the `Option{}.NewXxxHandler()` constructor pattern. | Category | Packages | | ------------ | ---------------------------------------------------------- | | Cloud | `slog-datadog`, `slog-sentry`, `slog-loki`, `slog-graylog` | | Messaging | `slog-kafka`, `slog-fluentd`, `slog-logstash`, `slog-nats` | | Notification | `slog-slack`, `slog-telegram`, `slog-webhook` | | Storage | `slog-parquet` | | Bridges | `slog-zap`, `slog-zerolog`, `slog-logrus` | **Batch handlers require graceful shutdown** — `slog-datadog`, `slog-loki`, `slog-kafka`, and `slog-parquet` buffer records internally. Flush on shutdown (e.g., `handler.Stop(ctx)` for Datadog, `lokiClient.Stop()` for Loki, `writer.Close()` for Kafka) or buffered logs are lost. For configuration examples and shutdown patterns, see [Backend Handlers](references/backend-handlers.md). ## Common Mistakes | Mistake | Why it fails | Fix | | --- | --- | --- | | Sampling after formatting | Wastes CPU formatting records that get dropped | Place sampling as outermost handler | | Fanout to many synchronous handlers | Blocks caller — latency is sum of all handlers | Use `Pool()` for concurrent dispatch | | Missing shutdown flush on batch handlers | Buffered logs lost on shutdown | `defer handler.Stop(ctx)` (Datadog), `defer lokiClient.Stop()` (Loki), `defer writer.Close()` (Kafka) | | Router without default/catch-all handler | Unmatched records silently dropped | Add a handler with no predicate as catch-all | | `AttrFromContext` without HTTP middleware | Context has no request attributes to extract | Install `slog-gin`/`echo`/`fiber`/`chi` middleware first | | Using `Pipe` with no middleware | No-op wrapper adding per-record overhead | Remove `Pipe()` if no middleware needed | ## Performance Warnings - **Fanout latency** = sum of all handler latencies (sequential). With 5 handlers at 10ms each, every log call costs 50ms. Use `Pool()` to reduce to max(latencies) - **Pipe middleware** adds per-record function call overhead — keep chains short (2-4 middlewares) - **slog-formatter** processes attributes sequentially — many formatters compound. For hot-path attribute formatting, prefer implementing `slog.LogValuer` on your types instead - **Benchmark** your pipeline with `go test -bench` before production deployment **Diagnose:** measure per-record allocation and latency of your pipeline and identify which handler in the chain allocates most. ## Best Practices 1. **Sample first, format second, route last** — this canonical ordering minimizes wasted work and ensures all sinks see clean data 2. **Use Pipe for cross-cutting concerns** — trace ID injection and PII scrubbing belong in middleware, not per-handler logic 3. **Test pipelines with `slogmulti.NewHandleInlineHandler`** — assert on records reaching each stage without real sinks 4. **Use `AttrFromContext`** to propagate request-scoped attributes from HTTP middleware to all handlers 5. **Prefer Router over Fanout** when handlers need different record subsets — Router evaluates predicates and skips non-matching handlers ## Cross-References - → See `samber/cc-skills-golang@golang-observability` skill for slog fundamentals (levels, context, handler setup, migration) - → See `samber/cc-skills-golang@golang-error-handling` skill for the log-or-return rule - → See `samber/cc-skills-golang@golang-security` skill for PII handling in logs - → See `samber/cc-skills-golang@golang-samber-oops` skill for structured error context with `samber/oops` If you encounter a bug or unexpected behavior in any samber/slog-\* package, open an issue at the relevant repository (e.g., [slog-multi/issues](https://github.com/samber/slog-multi/issues), [slog-sampling/issues](https://github.com/samber/slog-sampling/issues)).

golang-security

Security best practices and vulnerability prevention for Golang. Covers injection (SQL, command, XSS), cryptography, filesystem safety, network security, cookies, secrets management, memory safety, and logging. Apply when writing, reviewing, or auditing Go code for security, or when working on any risky code involving crypto, I/O, secrets management, user input handling, or authentication. Includes configuration of security tools.

**Persona:** You are a senior Go security engineer. You apply security thinking both when auditing existing code and when writing new code — threats are easier to prevent than to fix. **Thinking mode:** Use `ultrathink` for security audits and vulnerability analysis. Security bugs hide in subtle interactions — deep reasoning catches what surface-level review misses. **Modes:** - **Review mode** — reviewing a PR for security issues. Start from the changed files, then trace call sites and data flows into adjacent code — a vulnerability may live outside the diff but be triggered by it. Sequential. - **Audit mode** — full codebase security scan. Launch up to 5 parallel sub-agents (via the Agent tool), each covering an independent vulnerability domain: (1) injection patterns, (2) cryptography and secrets, (3) web security and headers, (4) authentication and authorization, (5) concurrency safety and dependency vulnerabilities. Aggregate findings, score with DREAD, and report by severity. - **Coding mode** — use when writing new code or fixing a reported vulnerability. Follow the skill's sequential guidance. Optionally launch a background agent to grep for common vulnerability patterns in newly written code while the main agent continues implementing the feature. # Go Security ## Overview Security in Go follows the principle of **defense in depth**: protect at multiple layers, validate all inputs, use secure defaults, and leverage the standard library's security-aware design. Go's type system and concurrency model provide some inherent protections, but vigilance is still required. ## Security Thinking Model Before writing or reviewing code, ask three questions: 1. **What are the trust boundaries?** — Where does untrusted data enter the system? (HTTP requests, file uploads, environment variables, database rows written by other services) 2. **What can an attacker control?** — Which inputs flow into sensitive operations? (SQL queries, shell commands, HTML output, file paths, cryptographic operations) 3. **What is the blast radius?** — If this defense fails, what's the worst outcome? (Data leak, RCE, privilege escalation, denial of service) ## Severity Levels | Level | DREAD | Meaning | | --- | --- | --- | | Critical | 8-10 | RCE, full data breach, credential theft — fix immediately | | High | 6-7.9 | Auth bypass, significant data exposure, broken crypto — fix in current sprint | | Medium | 4-5.9 | Limited exposure, session issues, defense weakening — fix in next sprint | | Low | 1-3.9 | Minor info disclosure, best-practice deviations — fix opportunistically | Levels align with [DREAD scoring](./references/threat-modeling.md). ## Research Before Reporting Before flagging a security issue, trace the full data flow through the codebase — don't assess a code snippet in isolation. 1. **Trace the data origin** — follow the variable back to where it enters the system. Is it user input, a hardcoded constant, or an internal-only value? 2. **Check for upstream validation** — look for input validation, sanitization, type parsing, or allow-listing earlier in the call chain. 3. **Examine the trust boundary** — if the data never crosses a trust boundary (e.g., internal service-to-service with mTLS), the risk profile is different. 4. **Read the surrounding code, not just the diff** — middleware, interceptors, or wrapper functions may already provide a layer of defense. **Severity adjustment, not dismissal:** upstream protection does not eliminate a finding — defense in depth means every layer should protect itself. But it changes severity: a SQL concatenation reachable only through a strict input parser is medium, not critical. Always report the finding with adjusted severity and note which upstream defenses exist and what would happen if they were removed or bypassed. **When downgrading or skipping a finding:** add a brief inline comment (e.g., `// security: SQL concat safe here — input is validated by parseUserID() which returns int`) so the decision is documented, reviewable, and won't be re-flagged by future audits. ## Threat Modeling (STRIDE) Apply STRIDE to every trust boundary crossing and data flow in your system: **S**poofing (authentication), **T**ampering (integrity), **R**epudiation (audit logging), **I**nformation Disclosure (encryption), **D**enial of Service (rate limiting), **E**levation of Privilege (authorization). Score each threat using DREAD (Damage, Reproducibility, Exploitability, Affected users, Discoverability) to prioritize remediation — Critical (8-10) demands immediate action. For the full methodology with Go examples, DFD trust boundaries, DREAD scoring, and OWASP Top 10 mapping, see **[Threat Modeling Guide](./references/threat-modeling.md)**. ## Quick Reference | Severity | Vulnerability | Defense | Standard Library Solution | | --- | --- | --- | --- | | Critical | SQL Injection | Parameterized queries separate data from code | `database/sql` with `?` placeholders | | Critical | Command Injection | Pass args separately, never via shell concatenation | `exec.Command` with separate args | | High | XSS | Auto-escaping renders user data as text, not HTML/JS | `html/template`, `text/template` | | High | Path Traversal | Scope file access to a root, prevent `../` escapes | `os.Root` (Go 1.24+), `filepath.Clean` | | Medium | Timing Attacks | Constant-time comparison avoids byte-by-byte leaks | `crypto/subtle.ConstantTimeCompare` | | High | Crypto Issues | Use vetted algorithms; never roll your own | `crypto/aes`, `crypto/rand` | | Medium | HTTP Security | TLS + security headers prevent downgrade attacks | `net/http`, configure TLSConfig | | Low | Missing Headers | HSTS, CSP, X-Frame-Options prevent browser attacks | Security headers middleware | | Medium | Rate Limiting | Rate limits prevent brute-force and resource exhaustion | `golang.org/x/time/rate`, server timeouts | | High | Race Conditions | Protect shared state to prevent data corruption | `sync.Mutex`, channels, avoid shared state | ## Detailed Categories For complete examples, code snippets, and CWE mappings, see: - **[Cryptography](./references/cryptography.md)** — Algorithms, key derivation, TLS configuration. - **[Injection Vulnerabilities](./references/injection.md)** — SQL, command, template injection, XSS, SSRF. - **[Filesystem Security](./references/filesystem.md)** — Path traversal, zip bombs, file permissions, symlinks. - **[Network/Web Security](./references/network.md)** — SSRF, open redirects, HTTP headers, timing attacks, session fixation. - **[Cookie Security](./references/cookies.md)** — Secure, HttpOnly, SameSite flags. - **[Third-Party Data Leaks](./references/third-party.md)** — Analytics privacy risks, GDPR/CCPA compliance. - **[Memory Safety](./references/memory-safety.md)** — Integer overflow, memory aliasing, `unsafe` usage. - **[Secrets Management](./references/secrets.md)** — Hardcoded credentials, env vars, secret managers. - **[Logging Security](./references/logging.md)** — PII in logs, log injection, sanitization. - **[Threat Modeling Guide](./references/threat-modeling.md)** — STRIDE, DREAD scoring, trust boundaries, OWASP Top 10. - **[Security Architecture](./references/architecture.md)** — Defense-in-depth, Zero Trust, auth patterns, rate limiting, anti-patterns. ## Code Review Checklist For the full security review checklist organized by domain (input handling, database, crypto, web, auth, errors, dependencies, concurrency), see **[Security Review Checklist](./references/checklist.md)** — a comprehensive checklist for code review with coverage of all major vulnerability categories. ## Tooling & Verification ### Static Analysis & Linting Security-relevant linters: `bodyclose`, `sqlclosecheck`, `nilerr`, `errcheck`, `govet`, `staticcheck`. See the `samber/cc-skills-golang@golang-linter` skill for configuration and usage. For deeper security-specific analysis: ```bash # Go security checker (SAST) go install github.com/securego/gosec/v2/cmd/gosec@latest gosec ./... # Vulnerability scanner — see golang-dependency-management for full govulncheck usage go install golang.org/x/vuln/cmd/govulncheck@latest govulncheck ./... ``` ### Security Testing ```bash # Race detector go test -race ./... # Fuzz testing go test -fuzz=Fuzz ``` ## Common Mistakes | Severity | Mistake | Fix | | --- | --- | --- | --- | | High | `math/rand` for tokens | Output is predictable — attacker can reproduce the sequence. Use `crypto/rand` | | Critical | SQL string concatenation | Attacker can modify query logic. Parameterized queries keep data and code separate | | Critical | `exec.Command("bash -c")` | Shell interprets metacharacters (`;`, ` | `, `` ` ``). Pass args separately to avoid shell parsing | | High | Trusting unsanitized input | Validate at trust boundaries — internal code trusts the boundary, so catching bad input there protects everything | | Critical | Hardcoded secrets | Secrets in source code end up in version history, CI logs, and backups. Use env vars or secret managers | | Medium | Comparing secrets with `==` | `==` short-circuits on first differing byte, leaking timing info. Use `crypto/subtle.ConstantTimeCompare` | | Medium | Returning detailed errors | Stack traces and DB errors help attackers map your system. Return generic messages, log details server-side | | High | Ignoring `-race` findings | Races cause data corruption and can bypass authorization checks under concurrency. Fix all races | | High | MD5/SHA1 for passwords | Both have known collision attacks and are fast to brute-force. Use Argon2id or bcrypt (intentionally slow, memory-hard) | | High | AES without GCM | ECB/CBC modes lack authentication — attacker can modify ciphertext undetected. GCM provides encrypt+authenticate | | Medium | Binding to 0.0.0.0 | Exposes service to all network interfaces. Bind to specific interface to limit attack surface | ## Security Anti-Patterns | Severity | Anti-Pattern | Why It Fails | Fix | | --- | --- | --- | --- | | High | Security through obscurity | Hidden URLs are discoverable via fuzzing, logs, or source | Authentication + authorization on all endpoints | | High | Trusting client headers | `X-Forwarded-For`, `X-Is-Admin` are trivially forged | Server-side identity verification | | High | Client-side authorization | JavaScript checks are bypassed by any HTTP client | Server-side permission checks on every handler | | High | Shared secrets across envs | Staging breach compromises production | Per-environment secrets via secret manager | | Critical | Ignoring crypto errors | `_, _ = encrypt(data)` silently proceeds unencrypted | Always check errors — fail closed, never open | | Critical | Rolling your own crypto | Custom encryption hasn't been analyzed by cryptographers | Use `crypto/aes` GCM, `golang.org/x/crypto/argon2` | See **[Security Architecture](./references/architecture.md)** for detailed anti-patterns with Go code examples. ## Cross-References See `samber/cc-skills-golang@golang-database`, `samber/cc-skills-golang@golang-safety`, `samber/cc-skills-golang@golang-observability`, `samber/cc-skills-golang@golang-continuous-integration` skills. ## Additional Resources - [Go Security Best Practices](https://go.dev/doc/security/best-practices) - [gosec Security Linter](https://github.com/securego/gosec) - [govulncheck](https://pkg.go.dev/golang.org/x/vuln/cmd/govulncheck) - [OWASP Go Project](https://owasp.org/www-project-go/)

golang-stay-updated

Provides resources to stay updated with Golang news, communities and people to follow. Use when seeking Go learning resources, discovering new libraries, finding community channels, or keeping up with Go language changes and releases.

# Stay Updated with Go A curated guide to keeping your finger on the pulse of the Go ecosystem. ## Official Go Resources | Resource | URL | | ------------------- | -------------------------------------------- | | **go.dev** | Official Go website with tutorials and tools | | **pkg.go.dev** | Discover Go packages and documentation | | **tour.golang.org** | Interactive Go tutorial | | **play.golang.org** | Go playground for testing code | | **go.dev/blog** | Official Go blog | ## Newsletters | Newsletter | Description | Subscribe | | --- | --- | --- | | **Golang Weekly** | Weekly curated Go content, news, and articles | https://golangweekly.com/ | | **Awesome Go Newsletter** | Updates on new Go libraries and tools | https://go.libhunt.com/ | ## Reddit & Communities | Community | Description | URL | | --- | --- | --- | | r/golang | Main Go subreddit with 300K+ members | https://www.reddit.com/r/golang | | golang wiki | Official wiki with resources and FAQs | https://go.dev/wiki/ | | gophers.slack.com | Official Go Slack community | https://invite.slack.golangbridge.org | | Go Forum | Official Go discussion forum | https://forum.golangbridge.org | | Discuss Go | Official Go team discussion | https://groups.google.com/g/golang-nuts | ## Famous Go Developers Follow these influential Go developers and contributors: ### Core Go Team | Name | GitHub | Twitter/X | LinkedIn | Bluesky | | --- | --- | --- | --- | --- | | **Rob Pike** | rsc | @rob_pike | | | | **Ken Thompson** | ken | | | | | **Russ Cox** | rsc | @_rsc_ | | | | **Brad Fitzpatrick** | bradfitz | @bradfitz | | https://bsky.app/profile/bradfitz.com | | **Andrew Gerrand** | adg | @nevsain | | | | **Dave Cheney** | davecheney | @davecheney | https://linkedin.com/in/davecheney | | | **Robert Griesemer** | griesemer | | | | ### Go Tooling & Infrastructure | Name | GitHub | Twitter/X | LinkedIn | Bluesky | | --- | --- | --- | --- | --- | | **Sam Boyer** | sdboyer | @sdboyer | https://linkedin.com/in/sam-boyer | | | **Daniel Theophanes** | kardianos | @kardianos | | | | **Matt Butcher** | technosophos | @technosophos | | | ### Popular Go Authors & Educators | Name | GitHub | Twitter/X | LinkedIn | Bluesky | | --- | --- | --- | --- | --- | | **Mat Ryer** | matryer | @matryer | https://linkedin.com/in/matryer | | | **John Graham-Cumming** | jgrahamc | @jgc | | | | **Katherine Cox-Buday** | katherinecoxbuday | @katherinecobuday | https://linkedin.com/in/katherinecox | | | **Johnny Boursiquot** | jboursiquot | @jboursiquot | https://linkedin.com/in/jboursiquot | | | **Nate Finch** | natefinch | @nate_finch | | | | **Aram Härmälä** | aram | @arame | | | | **Dmitry Shvedov** | dlvhdr | @dlvhdr\_ | | https://bsky.app/profile/dlvhdr.bsky.social | | **Michał Łowicki** | mlowicki | @michal_lowicki | https://linkedin.com/in/michalowicki | | ### Library & Framework Authors | Name | GitHub | Twitter/X | LinkedIn | Bluesky | | --- | --- | --- | --- | --- | | **Steve Francia** | spf13 | @spf13 | https://linkedin.com/in/spf13 | | | **Samuel Berthe** | samber | @samuelberthe | https://linkedin.com/in/samuelberthe | https://bsky.app/profile/samber.bsky.social | | **Mitchell Hashimoto** | mitchellh | @mitchellh | https://linkedin.com/in/mitchellh | https://bsky.app/profile/mitchellh.com | | **Matt Holt** | mholt | @mholtdev | | | | **Tomás Senart** | tommy-muehle | @tommy_mu | | | **John J Wang** | golang | @johnjwang | | | | **Björn Rabenstein** | beorn7 | @beorn7 | | | | **Jaana Dogan** | rakyll | @rakyll | https://linkedin.com/in/jaana-dogan-8265a011 | | | **Mitchell Hashimoto** | mitchellh | @mitchellh | | | | **Daniel Kahn Gillmor** | dkg | | | | | **Sergey Alexandrov** | k6 | @k6io | | | ### Conference Speakers & Community Leaders | Name | GitHub | Twitter/X | LinkedIn | Bluesky | | --- | --- | --- | --- | --- | | **Carlisia Campos** | carlisia | @carlisia | https://linkedin.com/in/carlisia | | | **Erik St. Martin** | erikstmartin | @erikstmartin | | | | **Brian Ketelsen** | bketelsen | | | @brian.dev | ### Performance & Optimization Experts | Name | GitHub | Twitter/X | LinkedIn | Bluesky | | ----------------- | --------- | ---------- | -------- | ------- | | **Alois Bělaška** | abelavska | @abelavska | | | | **Dmitry Vyukov** | dvyukov | | | | ## Must-Follow Blogs | Blog | Author | URL | | --------------- | ------------ | ------------------------------ | | The Go Blog | Go Team | https://go.dev/blog | | Rob Pike's Blog | Rob Pike | https://rakyll.org | | Dave Cheney | Dave Cheney | https://dave.cheney.net | | Ardan Labs Blog | Bill Kennedy | https://www.ardanlabs.com/blog | ## YouTube Channels | Channel | Content | URL | | --- | --- | --- | | Go | Official Go team | https://www.youtube.com/@golang | | Gopher Academy | Talks & tutorials | https://www.youtube.com/@GopherAcademy | | GopherCon Europe | European conference talks | https://www.youtube.com/@GopherConEurope | | GopherCon UK | UK conference talks | https://www.youtube.com/@GopherConUK | | Golang Singapore | Singapore meetup & conf talks | https://www.youtube.com/@golangSG | | Ardan Labs | Go training & tips | https://youtube.com/c/ArdanLabs | | Applied Go | Go tutorials | https://youtube.com/appliedgocode | | Learn Go Programming | Beginner tutorials | https://youtube.com/learn_goprogramming | ## Quick Tips for Staying Updated 1. **Subscribe to 1-2 newsletters** - Don't overload yourself 2. **Follow 10-20 key people** on X/Bluesky who post regularly 3. **Check Go.dev/blog weekly** for official announcements 4. **Join Go Slack** for real-time discussions 5. **Bookmark pkg.go.dev** to discover new libraries 6. **Attend a GopherCon** (virtual or in-person) yearly --- _Note: This guide is regularly updated. Suggest additions via GitHub issues._

golang-stretchr-testify

Comprehensive guide to stretchr/testify for Golang testing. Covers assert, require, mock, and suite packages in depth. Use whenever writing tests with testify, creating mocks, setting up test suites, or choosing between assert and require. Essential for testify assertions, mock expectations, argument matchers, call verification, suite lifecycle, and advanced patterns like Eventually, JSONEq, and custom matchers. Trigger on any Go test file importing testify.

**Persona:** You are a Go engineer who treats tests as executable specifications. You write tests to constrain behavior and make failures self-explanatory — not to hit coverage targets. **Modes:** - **Write mode** — adding new tests or mocks to a codebase. - **Review mode** — auditing existing test code for testify misuse. # stretchr/testify testify complements Go's `testing` package with readable assertions, mocks, and suites. It does not replace `testing` — always use `*testing.T` as the entry point. This skill is not exhaustive. Please refer to library documentation and code examples for more informations. Context7 can help as a discoverability platform. ## assert vs require Both offer identical assertions. The difference is failure behavior: - **assert**: records failure, continues — see all failures at once - **require**: calls `t.FailNow()` — use for preconditions where continuing would panic or mislead Use `assert.New(t)` / `require.New(t)` for readability. Name them `is` and `must`: ```go func TestParseConfig(t *testing.T) { is := assert.New(t) must := require.New(t) cfg, err := ParseConfig("testdata/valid.yaml") must.NoError(err) // stop if parsing fails — cfg would be nil must.NotNil(cfg) is.Equal("production", cfg.Environment) is.Equal(8080, cfg.Port) is.True(cfg.TLS.Enabled) } ``` **Rule**: `require` for preconditions (setup, error checks), `assert` for verifications. Never mix randomly. ## Core Assertions ```go is := assert.New(t) // Equality is.Equal(expected, actual) // DeepEqual + exact type is.NotEqual(unexpected, actual) is.EqualValues(expected, actual) // converts to common type first is.EqualExportedValues(expected, actual) // Nil / Bool / Emptiness is.Nil(obj) is.NotNil(obj) is.True(cond) is.False(cond) is.Empty(collection) is.NotEmpty(collection) is.Len(collection, n) // Contains (strings, slices, map keys) is.Contains("hello world", "world") is.Contains([]int{1, 2, 3}, 2) is.Contains(map[string]int{"a": 1}, "a") // Comparison is.Greater(actual, threshold) is.Less(actual, ceiling) is.Positive(val) is.Negative(val) is.Zero(val) // Errors is.Error(err) is.NoError(err) is.ErrorIs(err, ErrNotFound) // walks error chain is.ErrorAs(err, &target) is.ErrorContains(err, "not found") // Type is.IsType(&User{}, obj) is.Implements((*io.Reader)(nil), obj) ``` **Argument order**: always `(expected, actual)` — swapping produces confusing diff output. ## Advanced Assertions ```go is.ElementsMatch([]string{"b", "a", "c"}, result) // unordered comparison is.InDelta(3.14, computedPi, 0.01) // float tolerance is.JSONEq(`{"name":"alice"}`, `{"name": "alice"}`) // ignores whitespace/key order is.WithinDuration(expected, actual, 5*time.Second) is.Regexp(`^user-[a-f0-9]+$`, userID) // Async polling is.Eventually(func() bool { status, _ := client.GetJobStatus(jobID) return status == "completed" }, 5*time.Second, 100*time.Millisecond) // Async polling with rich assertions is.EventuallyWithT(func(c *assert.CollectT) { resp, err := client.GetOrder(orderID) assert.NoError(c, err) assert.Equal(c, "shipped", resp.Status) }, 10*time.Second, 500*time.Millisecond) ``` ## testify/mock Mock interfaces to isolate the unit under test. Embed `mock.Mock`, implement methods with `m.Called()`, always verify with `AssertExpectations(t)`. Key matchers: `mock.Anything`, `mock.AnythingOfType("T")`, `mock.MatchedBy(func)`. Call modifiers: `.Once()`, `.Times(n)`, `.Maybe()`, `.Run(func)`. For defining mocks, argument matchers, call modifiers, return sequences, and verification, see [Mock reference](./references/mock.md). ## testify/suite Suites group related tests with shared setup/teardown. ### Lifecycle ``` SetupSuite() → once before all tests SetupTest() → before each test TestXxx() TearDownTest() → after each test TearDownSuite() → once after all tests ``` ### Example ```go type TokenServiceSuite struct { suite.Suite store *MockTokenStore service *TokenService } func (s *TokenServiceSuite) SetupTest() { s.store = new(MockTokenStore) s.service = NewTokenService(s.store) } func (s *TokenServiceSuite) TestGenerate_ReturnsValidToken() { s.store.On("Save", mock.Anything, mock.Anything).Return(nil) token, err := s.service.Generate("user-42") s.NoError(err) s.NotEmpty(token) s.store.AssertExpectations(s.T()) } // Required launcher func TestTokenServiceSuite(t *testing.T) { suite.Run(t, new(TokenServiceSuite)) } ``` Suite methods like `s.Equal()` behave like `assert`. For require: `s.Require().NotNil(obj)`. ## Common Mistakes - **Forgetting `AssertExpectations(t)`** — mock expectations silently pass without verification - **`is.Equal(ErrNotFound, err)`** — fails on wrapped errors. Use `is.ErrorIs` to walk the chain - **Swapped argument order** — testify assumes `(expected, actual)`. Swapping produces backwards diffs - **`assert` for guards** — test continues after failure and panics on nil dereference. Use `require` - **Missing `suite.Run()`** — without the launcher function, zero tests execute silently - **Comparing pointers** — `is.Equal(ptr1, ptr2)` compares addresses. Dereference or use `EqualExportedValues` ## Linters Use `testifylint` to catch wrong argument order, assert/require misuse, and more. See `samber/cc-skills-golang@golang-linter` skill. ## Cross-References - → See `samber/cc-skills-golang@golang-testing` skill for general test patterns, table-driven tests, and CI - → See `samber/cc-skills-golang@golang-linter` skill for testifylint configuration

golang-structs-interfaces

Golang struct and interface design patterns — composition, embedding, type assertions, type switches, interface segregation, dependency injection via interfaces, struct field tags, and pointer vs value receivers. Use this skill when designing Go types, defining or implementing interfaces, embedding structs or interfaces, writing type assertions or type switches, adding struct field tags for JSON/YAML/DB serialization, or choosing between pointer and value receivers. Also use when the user asks about "accept interfaces, return structs", compile-time interface checks, or composing small interfaces into larger ones.

**Persona:** You are a Go type system designer. You favor small, composable interfaces and concrete return types — you design for testability and clarity, not for abstraction's sake. > **Community default.** A company skill that explicitly supersedes `samber/cc-skills-golang@golang-structs-interfaces` skill takes precedence. # Go Structs & Interfaces ## Interface Design Principles ### Keep Interfaces Small > "The bigger the interface, the weaker the abstraction." — Go Proverbs Interfaces SHOULD have 1-3 methods. Small interfaces are easier to implement, mock, and compose. If you need a larger contract, compose it from small interfaces: → See `samber/cc-skills-golang@golang-naming` skill for interface naming conventions (method + "-er" suffix, canonical names) ```go type Reader interface { Read(p []byte) (n int, err error) } type Writer interface { Write(p []byte) (n int, err error) } // Composed from small interfaces type ReadWriter interface { Reader Writer } ``` Compose larger interfaces from smaller ones: ```go type ReadWriteCloser interface { io.Reader io.Writer io.Closer } ``` ### Define Interfaces Where They're Consumed Interfaces Belong to Consumers. Interfaces MUST be defined where consumed, not where implemented. This keeps the consumer in control of the contract and avoids importing a package just for its interface. ```go // package notification — defines only what it needs type Sender interface { Send(to, body string) error } type Service struct { sender Sender } ``` The `email` package exports a concrete `Client` struct — it doesn't need to know about `Sender`. ### Accept Interfaces, Return Structs Functions SHOULD accept interface parameters for flexibility and return concrete types for clarity. Callers get full access to the returned type's fields and methods; consumers upstream can still assign the result to an interface variable if needed. ```go // Good — accepts interface, returns concrete func NewService(store UserStore) *Service { ... } // BAD — NEVER return interfaces from constructors func NewService(store UserStore) ServiceInterface { ... } ``` ### Don't Create Interfaces Prematurely > "Don't design with interfaces, discover them." NEVER create interfaces prematurely — wait for 2+ implementations or a testability requirement. Premature interfaces add indirection without value. Start with concrete types; extract an interface when a second consumer or a test mock demands it. ```go // Bad — premature interface with a single implementation type UserRepository interface { FindByID(ctx context.Context, id string) (*User, error) } type userRepository struct { db *sql.DB } // Good — start concrete, extract an interface later when needed type UserRepository struct { db *sql.DB } ``` ## Make the Zero Value Useful Design structs so they work without explicit initialization. A well-designed zero value reduces constructor boilerplate and prevents nil-related bugs: ```go // Good — zero value is ready to use var buf bytes.Buffer buf.WriteString("hello") var mu sync.Mutex mu.Lock() // Bad — zero value is broken, requires constructor type Registry struct { items map[string]Item // nil map, panics on write } // Good — lazy initialization guards the zero value func (r *Registry) Register(name string, item Item) { if r.items == nil { r.items = make(map[string]Item) } r.items[name] = item } ``` ## Avoid `any` / `interface{}` When a Specific Type Will Do Since Go 1.18+, MUST prefer generics over `any` for type-safe operations. Use `any` only at true boundaries where the type is genuinely unknown (e.g., JSON decoding, reflection): ```go // Bad — loses type safety func Contains(slice []any, target any) bool { ... } // Good — generic, type-safe func Contains[T comparable](slice []T, target T) bool { ... } ``` ## Key Standard Library Interfaces | Interface | Package | Method | | ------------- | --------------- | ------------------------------------- | | `Reader` | `io` | `Read(p []byte) (n int, err error)` | | `Writer` | `io` | `Write(p []byte) (n int, err error)` | | `Closer` | `io` | `Close() error` | | `Stringer` | `fmt` | `String() string` | | `error` | builtin | `Error() string` | | `Handler` | `net/http` | `ServeHTTP(ResponseWriter, *Request)` | | `Marshaler` | `encoding/json` | `MarshalJSON() ([]byte, error)` | | `Unmarshaler` | `encoding/json` | `UnmarshalJSON([]byte) error` | Canonical method signatures MUST be honored — if your type has a `String()` method, it must match `fmt.Stringer`. Don't invent `ToString()` or `ReadData()`. ## Compile-Time Interface Check Verify a type implements an interface at compile time with a blank identifier assignment. Place it near the type definition: ```go var _ io.ReadWriter = (*MyBuffer)(nil) ``` This costs nothing at runtime. If `MyBuffer` ever stops satisfying `io.ReadWriter`, the build fails immediately. ## Type Assertions & Type Switches ### Safe Type Assertion Type assertions MUST use the comma-ok form to avoid panics: ```go // Good — safe s, ok := val.(string) if !ok { // handle } // Bad — panics if val is not a string s := val.(string) ``` ### Type Switch Discover the dynamic type of an interface value: ```go switch v := val.(type) { case string: fmt.Println(v) case int: fmt.Println(v * 2) case io.Reader: io.Copy(os.Stdout, v) default: fmt.Printf("unexpected type %T\n", v) } ``` ### Optional Behavior with Type Assertions Check if a value supports additional capabilities without requiring them upfront: ```go type Flusher interface { Flush() error } func writeData(w io.Writer, data []byte) error { if _, err := w.Write(data); err != nil { return err } // Flush only if the writer supports it if f, ok := w.(Flusher); ok { return f.Flush() } return nil } ``` This pattern is used extensively in the standard library (e.g., `http.Flusher`, `io.ReaderFrom`). ## Struct & Interface Embedding ### Struct Embedding Embedding promotes the inner type's methods and fields to the outer type — composition, not inheritance: ```go type Logger struct { *slog.Logger } type Server struct { Logger addr string } // s.Info(...) works — promoted from slog.Logger through Logger s := Server{Logger: Logger{slog.Default()}, addr: ":8080"} s.Info("starting", "addr", s.addr) ``` The receiver of promoted methods is the _inner_ type, not the outer. The outer type can override by defining its own method with the same name. ### When to Embed vs Named Field | Use | When | | --- | --- | | **Embed** | You want to promote the full API of the inner type — the outer type "is a" enhanced version | | **Named field** | You only need the inner type internally — the outer type "has a" dependency | ```go // Embed — Server exposes all http.Handler methods type Server struct { http.Handler } // Named field — Server uses the store but doesn't expose its methods type Server struct { store *DataStore } ``` ## Dependency Injection via Interfaces Accept dependencies as interfaces in constructors. This decouples components and makes testing straightforward: ```go type UserStore interface { FindByID(ctx context.Context, id string) (*User, error) } type UserService struct { store UserStore } func NewUserService(store UserStore) *UserService { return &UserService{store: store} } ``` In tests, pass a mock or stub that satisfies `UserStore` — no real database needed. ## Struct Field Tags Use field tags for serialization control. Exported fields in serialized structs MUST have field tags: ```go type Order struct { ID string `json:"id" db:"id"` UserID string `json:"user_id" db:"user_id"` Total float64 `json:"total" db:"total"` Items []Item `json:"items" db:"-"` CreatedAt time.Time `json:"created_at" db:"created_at"` DeletedAt time.Time `json:"-" db:"deleted_at"` Internal string `json:"-" db:"-"` } ``` | Directive | Meaning | | ----------------------- | ------------------------------------------- | | `json:"name"` | Field name in JSON output | | `json:"name,omitempty"` | Omit field if zero value | | `json:"-"` | Always exclude from JSON | | `json:",string"` | Encode number/bool as JSON string | | `db:"column"` | Database column mapping (sqlx, etc.) | | `yaml:"name"` | YAML field name | | `xml:"name,attr"` | XML attribute | | `validate:"required"` | Struct validation (go-playground/validator) | ## Pointer vs Value Receivers | Use pointer `(s *Server)` | Use value `(s Server)` | | --- | --- | | Method modifies the receiver | Receiver is small and immutable | | Receiver contains `sync.Mutex` or similar | Receiver is a basic type (int, string) | | Receiver is a large struct | Method is a read-only accessor | | Consistency: if any method uses a pointer, all should | Map and function values (already reference types) | Receiver type MUST be consistent across all methods of a type — if one method uses a pointer receiver, all methods should. ## Preventing Struct Copies with `noCopy` Some structs must never be copied after first use (e.g., those containing a mutex, a channel, or internal pointers). Embed a `noCopy` sentinel to make `go vet` catch accidental copies: ```go // noCopy may be added to structs which must not be copied after first use. // See https://pkg.go.dev/sync#noCopy type noCopy struct{} func (*noCopy) Lock() {} func (*noCopy) Unlock() {} type ConnPool struct { noCopy noCopy mu sync.Mutex conns []*Conn } ``` `go vet` reports an error if a `ConnPool` value is copied (passed by value, assigned, etc.). This is the same technique the standard library uses for `sync.WaitGroup`, `sync.Mutex`, `strings.Builder`, and others. Always pass these structs by pointer: ```go // Good func process(pool *ConnPool) { ... } // Bad — go vet will flag this func process(pool ConnPool) { ... } ``` ## Cross-References - → See `samber/cc-skills-golang@golang-naming` skill for interface naming conventions (Reader, Closer, Stringer) - → See `samber/cc-skills-golang@golang-design-patterns` skill for functional options, constructors, and builder patterns - → See `samber/cc-skills-golang@golang-dependency-injection` skill for DI patterns using interfaces - → See `samber/cc-skills-golang@golang-code-style` skill for value vs pointer function parameters (distinct from receivers) ## Common Mistakes | Mistake | Fix | | --- | --- | | Large interfaces (5+ methods) | Split into focused 1-3 method interfaces, compose if needed | | Defining interfaces in the implementor package | Define where consumed | | Returning interfaces from constructors | Return concrete types | | Bare type assertions without comma-ok | Always use `v, ok := x.(T)` | | Embedding when you only need a few methods | Use a named field and delegate explicitly | | Missing field tags on serialized structs | Tag all exported fields in marshaled types | | Mixing pointer and value receivers on a type | Pick one and be consistent | | Forgetting compile-time interface check | Add `var _ Interface = (*Type)(nil)` | | Using `ToString()` instead of `String()` | Honor canonical method names | | Premature interface with a single implementation | Start concrete, extract interface when needed | | Nil map/slice in zero value struct | Use lazy initialization in methods | | Using `any` for type-safe operations | Use generics (`[T comparable]`) instead |

golang-testing

Provides a comprehensive guide for writing production-ready Golang tests. Covers table-driven tests, test suites with testify, mocks, unit tests, integration tests, benchmarks, code coverage, parallel tests, fuzzing, fixtures, goroutine leak detection with goleak, snapshot testing, memory leaks, CI with GitHub Actions, and idiomatic naming conventions. Use this whenever writing tests, asking about testing patterns or setting up CI for Go projects. Essential for ANY test-related conversation in Go.

**Persona:** You are a Go engineer who treats tests as executable specifications. You write tests to constrain behavior, not to hit coverage targets. **Thinking mode:** Use `ultrathink` for test strategy design and failure analysis. Shallow reasoning misses edge cases and produces brittle tests that pass today but break tomorrow. **Modes:** - **Write mode** — generating new tests for existing or new code. Work sequentially through the code under test; use `gotests` to scaffold table-driven tests, then enrich with edge cases and error paths. - **Review mode** — reviewing a PR's test changes. Focus on the diff: check coverage of new behaviour, assertion quality, table-driven structure, and absence of flakiness patterns. Sequential. - **Audit mode** — auditing an existing test suite for gaps, flakiness, or bad patterns (order-dependent tests, missing `t.Parallel()`, implementation-detail coupling). Launch up to 3 parallel sub-agents split by concern: (1) unit test quality and coverage gaps, (2) integration test isolation and build tags, (3) goroutine leaks and race conditions. - **Debug mode** — a test is failing or flaky. Work sequentially: reproduce reliably, isolate the failing assertion, trace the root cause in production code or test setup. > **Community default.** A company skill that explicitly supersedes `samber/cc-skills-golang@golang-testing` skill takes precedence. # Go Testing Best Practices This skill guides the creation of production-ready tests for Go applications. Follow these principles to write maintainable, fast, and reliable tests. ## Best Practices Summary 1. Table-driven tests MUST use named subtests -- every test case needs a `name` field passed to `t.Run` 2. Integration tests MUST use build tags (`//go:build integration`) to separate from unit tests 3. Tests MUST NOT depend on execution order -- each test MUST be independently runnable 4. Independent tests SHOULD use `t.Parallel()` when possible 5. NEVER test implementation details -- test observable behavior and public API contracts 6. Packages with goroutines SHOULD use `goleak.VerifyTestMain` in `TestMain` to detect goroutine leaks 7. Use testify as helpers, not a replacement for standard library 8. Mock interfaces, not concrete types 9. Keep unit tests fast (< 1ms), use build tags for integration tests 10. Run tests with race detection in CI 11. Include examples as executable documentation ## Test Structure and Organization ### File Conventions ```go // package_test.go - tests in same package (white-box, access unexported) package mypackage // mypackage_test.go - tests in test package (black-box, public API only) package mypackage_test ``` ### Naming Conventions ```go func TestAdd(t *testing.T) { ... } // function test func TestMyStruct_MyMethod(t *testing.T) { ... } // method test func BenchmarkAdd(b *testing.B) { ... } // benchmark func ExampleAdd() { ... } // example ``` ## Table-Driven Tests Table-driven tests are the idiomatic Go way to test multiple scenarios. Always name each test case. ```go func TestCalculatePrice(t *testing.T) { tests := []struct { name string quantity int unitPrice float64 expected float64 }{ { name: "single item", quantity: 1, unitPrice: 10.0, expected: 10.0, }, { name: "bulk discount - 100 items", quantity: 100, unitPrice: 10.0, expected: 900.0, // 10% discount }, { name: "zero quantity", quantity: 0, unitPrice: 10.0, expected: 0.0, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { got := CalculatePrice(tt.quantity, tt.unitPrice) if got != tt.expected { t.Errorf("CalculatePrice(%d, %.2f) = %.2f, want %.2f", tt.quantity, tt.unitPrice, got, tt.expected) } }) } } ``` ## Unit Tests Unit tests should be fast (< 1ms), isolated (no external dependencies), and deterministic. ## Testing HTTP Handlers Use `httptest` for handler tests with table-driven patterns. See [HTTP Testing](./references/http-testing.md) for examples with request/response bodies, query parameters, headers, and status code assertions. ## Goroutine Leak Detection with goleak Use `go.uber.org/goleak` to detect leaking goroutines, especially for concurrent code: ```go import ( "testing" "go.uber.org/goleak" ) func TestMain(m *testing.M) { goleak.VerifyTestMain(m) } ``` To exclude specific goroutine stacks (for known leaks or library goroutines): ```go func TestMain(m *testing.M) { goleak.VerifyTestMain(m, goleak.IgnoreCurrent(), ) } ``` Or per-test: ```go func TestWorkerPool(t *testing.T) { defer goleak.VerifyNone(t) // ... test code ... } ``` ## testing/synctest for Deterministic Goroutine Testing > **Experimental:** `testing/synctest` is not yet covered by Go's compatibility guarantee. Its API may change in future releases. For stable alternatives, use `clockwork` (see [Mocking](./references/mocking.md)). `testing/synctest` (Go 1.24+) provides deterministic time for concurrent code testing. Time advances only when all goroutines are blocked, making ordering predictable. When to use `synctest` instead of real time: - Testing concurrent code with time-based operations (time.Sleep, time.After, time.Ticker) - When race conditions need to be reproducible - When tests are flaky due to timing issues ```go import ( "testing" "time" "testing/synctest" "github.com/stretchr/testify/assert" ) func TestChannelTimeout(t *testing.T) { synctest.Run(func(t *testing.T) { is := assert.New(t) ch := make(chan int, 1) go func() { time.Sleep(50 * time.Millisecond) ch <- 42 }() select { case v := <-ch: is.Equal(42, v) case <-time.After(100 * time.Millisecond): t.Fatal("timeout occurred") } }) } ``` Key differences in `synctest`: - `time.Sleep` advances synthetic time instantly when the goroutine blocks - `time.After` fires when synthetic time reaches the duration - All goroutines run to blocking points before time advances - Test execution is deterministic and repeatable ## Test Timeouts For tests that may hang, use a timeout helper that panics with caller location. See [Helpers](./references/helpers.md). ## Benchmarks → See `samber/cc-skills-golang@golang-benchmark` skill for advanced benchmarking: `b.Loop()` (Go 1.24+), `benchstat`, profiling from benchmarks, and CI regression detection. Write benchmarks to measure performance and detect regressions: ```go func BenchmarkStringConcatenation(b *testing.B) { b.Run("plus-operator", func(b *testing.B) { for i := 0; i < b.N; i++ { result := "a" + "b" + "c" _ = result } }) b.Run("strings.Builder", func(b *testing.B) { for i := 0; i < b.N; i++ { var builder strings.Builder builder.WriteString("a") builder.WriteString("b") builder.WriteString("c") _ = builder.String() } }) } ``` Benchmarks with different input sizes: ```go func BenchmarkFibonacci(b *testing.B) { sizes := []int{10, 20, 30} for _, size := range sizes { b.Run(fmt.Sprintf("n=%d", size), func(b *testing.B) { b.ReportAllocs() for i := 0; i < b.N; i++ { Fibonacci(size) } }) } } ``` ## Parallel Tests Use `t.Parallel()` to run tests concurrently: ```go func TestParallelOperations(t *testing.T) { tests := []struct { name string data []byte }{ {"small data", make([]byte, 1024)}, {"medium data", make([]byte, 1024*1024)}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { t.Parallel() is := assert.New(t) result := Process(tt.data) is.NotNil(result) }) } } ``` ## Fuzzing Use fuzzing to find edge cases and bugs: ```go func FuzzReverse(f *testing.F) { f.Add("hello") f.Add("") f.Add("a") f.Fuzz(func(t *testing.T, input string) { reversed := Reverse(input) doubleReversed := Reverse(reversed) if input != doubleReversed { t.Errorf("Reverse(Reverse(%q)) = %q, want %q", input, doubleReversed, input) } }) } ``` ## Examples as Documentation Examples are executable documentation verified by `go test`: ```go func ExampleCalculatePrice() { price := CalculatePrice(100, 10.0) fmt.Printf("Price: %.2f\n", price) // Output: Price: 900.00 } func ExampleCalculatePrice_singleItem() { price := CalculatePrice(1, 25.50) fmt.Printf("Price: %.2f\n", price) // Output: Price: 25.50 } ``` ## Code Coverage ```bash # Generate coverage file go test -coverprofile=coverage.out ./... # View coverage in HTML go tool cover -html=coverage.out # Coverage by function go tool cover -func=coverage.out # Total coverage percentage go tool cover -func=coverage.out | grep total ``` ## Integration Tests Use build tags to separate integration tests from unit tests: ```go //go:build integration package mypackage func TestDatabaseIntegration(t *testing.T) { db, err := sql.Open("postgres", os.Getenv("DATABASE_URL")) if err != nil { t.Fatal(err) } defer db.Close() // Test real database operations } ``` Run integration tests separately: ```bash go test -tags=integration ./... ``` For Docker Compose fixtures, SQL schemas, and integration test suites, see [Integration Testing](./references/integration-testing.md). ## Mocking Mock interfaces, not concrete types. Define interfaces where consumed, then create mock implementations. For mock patterns, test fixtures, and time mocking, see [Mocking](./references/mocking.md). ## Enforce with Linters Many test best practices are enforced automatically by linters: `thelper`, `paralleltest`, `testifylint`. See the `samber/cc-skills-golang@golang-linter` skill for configuration and usage. ## Cross-References - -> See `samber/cc-skills-golang@golang-stretchr-testify` skill for detailed testify API (assert, require, mock, suite) - -> See `samber/cc-skills-golang@golang-database` skill (testing.md) for database integration test patterns - -> See `samber/cc-skills-golang@golang-concurrency` skill for goroutine leak detection with goleak - -> See `samber/cc-skills-golang@golang-continuous-integration` skill for CI test configuration and GitHub Actions workflows - -> See `samber/cc-skills-golang@golang-linter` skill for testifylint and paralleltest configuration ## Quick Reference ```bash go test ./... # all tests go test -run TestName ./... # specific test by exact name go test -run TestName/subtest ./... # subtests within a test go test -run 'Test(Add|Sub)' ./... # multiple tests (regexp OR) go test -run 'Test[A-Z]' ./... # tests starting with capital letter go test -run 'TestUser.*' ./... # tests matching prefix go test -run '.*Validation.*' ./... # tests containing substring go test -run TestName/. ./... # all subtests of TestName go test -run '/(unit|integration)' ./... # filter by subtest name go test -race ./... # race detection go test -cover ./... # coverage summary go test -bench=. -benchmem ./... # benchmarks go test -fuzz=FuzzName ./... # fuzzing go test -tags=integration ./... # integration tests ```

golang-troubleshooting

Troubleshoot Golang programs systematically - find and fix the root cause. Use when encountering bugs, crashes, deadlocks, or unexpected behavior in Go code. Covers debugging methodology, common Go pitfalls, test-driven debugging, pprof setup and capture, Delve debugger, race detection, GODEBUG tracing, and production debugging. Start here for any 'something is wrong' situation. Not for interpreting profiles or benchmarking (see golang-benchmark skill) or applying optimization patterns (see golang-performance skill).

**Persona:** You are a Go systems debugger. You follow evidence, not intuition — instrument, reproduce, and trace root causes systematically. **Thinking mode:** Use `ultrathink` for debugging and root cause analysis. Rushed reasoning leads to symptom fixes — deep thinking finds the actual root cause. **Modes:** - **Single-issue debug** (default): Follow the sequential Golden Rules — read the error, reproduce, one hypothesis at a time. Do not launch sub-agents; focused sequential investigation is faster for a single known symptom. - **Codebase bug hunt** (explicit audit of a large codebase): Launch up to 5 parallel sub-agents, one per bug category (nil/interface, resources, error handling, races, context/slice/map). Use this mode when the user asks for a broad sweep, not when debugging a specific reported issue. # Go Troubleshooting Guide **NO FIXES WITHOUT ROOT CAUSE INVESTIGATION FIRST.** Symptom fixes create new bugs and waste time. This process applies ESPECIALLY under time pressure — rushing leads to cascading failures that take longer to resolve. When the user reports a bug, crash, performance problem, or unexpected behavior in Go code: 1. **Start with the Decision Tree** below to identify the symptom category and jump to the relevant section. 2. **Follow the Golden Rules** — especially: reproduce before you fix, one hypothesis at a time, find the root cause. 3. **Work through the General Debugging Methodology** step by step. Do not skip steps. 4. **Watch for Red Flags** in your own reasoning. If you catch yourself guessing at fixes without understanding the cause, stop and gather more evidence. 5. **Escalate tools incrementally.** Start with the simplest diagnostic (`fmt.Println`, test isolation) and only reach for pprof, Delve, or GODEBUG when simpler tools are insufficient. 6. **Never propose a fix you cannot explain.** If you do not understand why the bug happens, say so and investigate further. ## Quick Decision Tree ``` WHAT ARE YOU SEEING? "Build won't compile" → go build ./... 2>&1, go vet ./... → See [compilation.md](./references/compilation.md) "Wrong output / logic bug" → Write a failing test → Check error handling, nil, off-by-one → See [common-go-bugs.md](./references/common-go-bugs.md), [testing-debug.md](./references/testing-debug.md) "Random crashes / panics" → GOTRACEBACK=all ./app → go test -race ./... → See [common-go-bugs.md](./references/common-go-bugs.md), [diagnostic-tools.md](./references/diagnostic-tools.md) "Sometimes works, sometimes fails" → go test -race ./... → See [concurrency-debug.md](./references/concurrency-debug.md), [testing-debug.md](./references/testing-debug.md) "Program hangs / frozen" → curl localhost:6060/debug/pprof/goroutine?debug=2 → See [concurrency-debug.md](./references/concurrency-debug.md), [pprof.md](./references/pprof.md) "High CPU usage" → pprof CPU profiling → See [performance-debug.md](./references/performance-debug.md), [pprof.md](./references/pprof.md) "Memory growing over time" → pprof heap profiling → See [performance-debug.md](./references/performance-debug.md), [concurrency-debug.md](./references/concurrency-debug.md) "Slow / high latency / p99 spikes" → CPU + mutex + block profiles → See [performance-debug.md](./references/performance-debug.md), [diagnostic-tools.md](./references/diagnostic-tools.md) "Simple bug, easy to reproduce" → Write a test, add fmt.Println / log.Debug → See [testing-debug.md](./references/testing-debug.md) ``` **Remember:** Read the Error → Reproduce → Measure One Thing → Fix → Verify Most Go bugs are: missing error checks, nil pointers, forgotten context cancel, unclosed resources, race conditions, or silent error swallowing. ## The Golden Rules ### 1. Read the Error Message First Go error messages are precise. Read them fully before doing anything else: - **File and line number** → go directly there - **Type mismatch** → check function signatures, interface satisfaction - **"undefined"** → check imports, exported names, build tags - **"cannot use X as Y"** → check concrete types vs interfaces ### 2. Reproduce Before You Fix NEVER debug by guessing — reproduce first. Always: - Write a failing test that captures the bug - Make it deterministic - Isolate the minimal failing example - Use `git bisect` to find the breaking commit ### 3. If You Don't Measure It, You're Guessing Never rely on intuition for performance or concurrency bugs: - **pprof over intuition** - **race detector over reasoning** - **benchmarks over assumptions** ### 4. One Hypothesis at a Time Change one thing, measure, confirm. If you change three things at once, you learn nothing. ### 5. Find the Root Cause — No Workarounds A band-aid fix that masks the symptom IS NOT ACCEPTABLE. You MUST understand **why** the bug happens before writing a fix. When you don't understand the issue: - **Trace the data flow backwards** from the symptom to its origin. - **Question your assumptions.** The code you trust might be wrong. - **Ask "why" five times.** Keep going until you reach the actual root cause. - **Perform more troubleshooting checks.** More fmt.Println, more output inspection... ### 6. Research the Codebase, Not Just the Diff Before flagging a bug or proposing a fix, trace the data flow and check for upstream handling. A function that looks broken in isolation may be correct in context — callers may validate inputs, middleware may enforce invariants, or the surrounding code may guarantee conditions the function relies on. 1. **Trace callers** — who calls this function and with what values? Use Grep/Agent to find all call sites. 2. **Check upstream validation** — input parsing, type conversions, or guard clauses earlier in the chain may make the "bug" unreachable. 3. **Read the surrounding code** — middleware, interceptors, or init functions may set up state the function depends on. **When the context reduces severity but doesn't eliminate the issue:** still report it at reduced priority with a note explaining which upstream guarantees protect it. Add a brief inline comment (e.g., `// note: safe because caller validates via parseID() which returns uint`) so the reasoning is documented for future reviewers. ### 7. Start Simple Sometimes `fmt.Println` IS the right tool for local debugging. Escalate tools only when simpler approaches fail. NEVER use `fmt.Println` for production debugging — use `slog`. ## Red Flags: You're Debugging Wrong If any of these are happening, stop and return to Step 1: - **"Quick fix for now, investigate later"** — There is no "later". Find the root cause. - **Multiple simultaneous changes** — One hypothesis at a time. - **Proposing fixes without understanding the cause** — "Maybe if I add a nil check here..." is guessing, not debugging. - **Each fix reveals a new problem** — You're treating symptoms. The real bug is elsewhere. - **3+ fix attempts on the same issue** — You have the wrong mental model. Re-read the code, trace the data flow from scratch. - **"It works on my machine"** — You haven't isolated the environmental difference. - **Blaming the framework/stdlib/compiler** — It's almost never a Go bug. Verify your code first. ## Reference Files - **[General Debugging Methodology](./references/methodology.md)** — The systematic 10-step process: define symptoms, isolate reproduction, form one hypothesis, test it, verify the root cause, and defend against regressions. Escalation guide: when to escalate from `fmt.Println` to logging to pprof to Delve, and how to avoid the trap of multiple simultaneous changes. - **[Common Go Bugs](./references/common-go-bugs.md)** — The bugs that crash Go code: nil pointer dereferences, interface nil gotcha (typed nil ≠ nil), variable shadowing, slice/map/defer/error/context pitfalls, race conditions, JSON unmarshaling surprises, unclosed resources. Each with reproduction patterns and fixes. - **[Test-Driven Debugging](./references/testing-debug.md)** — Why writing a failing test is the first step of debugging. Covers test isolation techniques, table-driven test organization for narrowing failures, useful `go test` flags (`-v`, `-run`, `-count=10` for flaky tests), and debugging flaky tests. - **[Concurrency Debugging](./references/concurrency-debug.md)** — Race conditions, deadlocks, goroutine leaks. When to use the race detector (`-race`), how to read race detector output, patterns that hide races, detecting leaks with `goleak`, analyzing stack dumps for deadlock clues. - **[Performance Troubleshooting](./references/performance-debug.md)** — When your code is slow: CPU profiling workflow, memory analysis (heap vs alloc_objects profiles, finding leaks), lock contention (mutex profile), and I/O blocking (goroutine profile). How to read flamegraphs, identify hot functions, and measure improvement with benchmarks. - **[pprof Reference](./references/pprof.md)** — Complete pprof manual. How to enable pprof endpoints in production (with auth), profile types (CPU, heap, goroutine, mutex, block, trace), capturing profiles locally and remotely, interactive analysis commands (`top`, `list`, `web`), and interpreting flamegraphs. - **[Diagnostic Tools](./references/diagnostic-tools.md)** — Auxiliary tools for specific symptoms. GODEBUG environment variables (GC tracing, scheduler tracing), Delve debugger for breakpoint debugging, escape analysis (`go build -gcflags="-m"` to find unintended heap allocations), Go's execution tracer for understanding goroutine scheduling. - **[Production Debugging](./references/production-debug.md)** — Debugging live production systems without stopping them. Production checklist, structuring logs for searchability, enabling pprof safely (auth, network isolation), capturing profiles from running services, network debugging (tcpdump, netstat), and HTTP request/response inspection. - **[Compilation Issues](./references/compilation.md)** — Build failures: module version conflicts, CGO linking problems, version mismatch between `go.mod` and installed Go version, platform-specific build tags preventing cross-compilation. - **[Code Review Red Flags](./references/code-review-flags.md)** — Patterns to watch during code review that signal potential bugs: unchecked errors, missing nil checks, concurrent map access, goroutines without clear exit, resource leaks from defer in loops. ## Cross-References - → See `samber/cc-skills-golang@golang-performance` skill for optimization patterns after identifying bottlenecks - → See `samber/cc-skills-golang@golang-observability` skill for metrics, alerting, and Grafana dashboards for Go runtime monitoring - → See `samber/cc-skills@promql-cli` skill for querying Prometheus metrics during production incident investigation - → See `samber/cc-skills-golang@golang-concurrency`, `samber/cc-skills-golang@golang-safety`, `samber/cc-skills-golang@golang-error-handling` skills