Go Development
Session Init
At the start of any Go session, detect the project's Go version:
- Read
go.mod and extract the go directive (e.g., go 1.26)
- This version controls which language features and stdlib APIs are available
- If you are about to suggest a feature gated behind a newer version, stop and note the incompatibility
Version Feature Table
| Version |
Key additions |
| 1.21 |
log/slog, slices, maps, min/max/clear builtins, context.AfterFunc, context.WithoutCancel, sync.OnceFunc/OnceValue, PGO auto |
| 1.22 |
for i := range n, math/rand/v2, enhanced http.ServeMux routing (method+pattern), loopvar semantic change |
| 1.23 |
iter.Seq/iter.Seq2, range-over-func, unique.Handle, structs.HostLayout |
| 1.24 |
testing.T.Context, testing.T.Chdir, os.Root, generic type aliases, go tool runs module tools, testing/synctest, omitzero JSON tag |
| 1.25 |
sync.WaitGroup.Go, testing.T.Attr, testing.T.Output, sync.Map range-over-func, os.OpenRoot |
| 1.26 |
errors.AsType[T], testing.T.ArtifactDir, go test -artifacts, go fix command (21 fixers), new vet analyzers (waitgroup, hostport), new(expr) shorthand |
Toolchain-First Workflow
This is the core of this skill. Go ships a powerful toolchain - use it instead of guessing.
Before Writing Code
When about to use a stdlib or third-party API you are not certain about, verify the signature first:
go doc <package>.<Symbol> # exact function/type/method
go doc -all <package>.<Type> # full type with all methods
go doc -src <package>.<Symbol> # source code when implementation matters
Token efficiency matters: go doc fmt.Fprintf returns 5 lines. go doc fmt returns hundreds. Always use the most specific query that answers your question.
For third-party packages, they must be importable (in go.mod) before go doc works. For stdlib, it always works.
After Writing or Modifying Code
Pick the verification level that matches the scope of the change:
Full - new files, unfamiliar APIs, concurrency code, public interface changes:
gofmt -d . # format check (should produce no output)
go vet ./... # static analysis
go build ./... # compilation check
go test -race -count=1 ./... # tests with race detector, cache bypassed
Or use the bundled script: ${CLAUDE_SKILL_DIR}/scripts/go-quality-check.sh ./...
Standard - modifying existing code in patterns the project already uses:
go vet ./...
go test -count=1 -run TestRelevant ./path/to/pkg/...
Light - formatting, comments, documentation, renaming:
gofmt -d <changed-file>
When Modernizing Code
Go 1.26 introduced go fix, which applies automated improvements:
go fix -diff ./... # preview changes as unified diff
go fix ./... # apply all fixes
This replaces patterns like interface{} with any, sort.Slice with slices.Sort, manual wg.Add/Done with wg.Go, and many more. Always preview with -diff first.
When Debugging Test Failures
go test -v -run TestName -count=1 ./pkg/... # verbose, cache-bypassed
go test -race -count=1 ./... # if concurrency is involved
go test -coverprofile=c.out ./... && go tool cover -func=c.out # coverage gaps
When Adding Dependencies
- Prefer stdlib when the stdlib solution is adequate
- Run
go doc on the candidate package to verify its API before committing to it
go get <module>@latest && go mod tidy
go mod why <module> to verify it is actually used
Tool Command Reference
go doc
| Pattern |
What it returns |
go doc fmt |
Package synopsis |
go doc fmt.Fprintf |
Specific function signature and doc |
go doc -all fmt.Stringer |
Full type including all methods |
go doc -src fmt.Fprintf |
Source code of the function |
go doc -short fmt |
One-line per symbol |
go doc -u net/http.Transport |
Include unexported fields |
go doc cmd/go |
Go command documentation |
go vet analyzers (37 total)
| Analyzer |
What it catches |
appends |
Missing values after append |
assign |
Useless assignments |
atomic |
Common sync/atomic mistakes |
bools |
Boolean operator mistakes |
buildtag |
Invalid //go:build directives |
composites |
Unkeyed composite literals |
copylocks |
Locks passed by value |
defers |
Common defer mistakes |
errorsas |
Wrong types passed to errors.As |
hostport |
Bad address format for net.Dial |
httpresponse |
HTTP response handling mistakes |
loopclosure |
Loop variable capture in nested functions |
lostcancel |
Context cancel function not called |
printf |
Printf format string mismatches |
shadow |
Variable shadowing (via -vettool) |
slog |
Invalid structured logging calls |
stdversion |
Uses of too-new stdlib symbols |
structtag |
Malformed struct tags |
tests |
Mistaken test/example/benchmark signatures |
unmarshal |
Non-pointer passed to unmarshal |
unusedresult |
Unused results from certain calls |
waitgroup |
Misuses of sync.WaitGroup |
(Run go tool vet help for the full list of all 37.)
go fix fixers (21 total, Go 1.26+)
| Fixer |
What it modernizes |
any |
interface{} -> any |
fmtappendf |
[]byte(fmt.Sprintf(...)) -> fmt.Appendf |
forvar |
Remove redundant loop variable re-declarations |
mapsloop |
Explicit map loops -> maps package calls |
minmax |
if/else chains -> min/max builtins |
newexpr |
Simplify with new(expr) (1.26) |
omitzero |
omitempty -> omitzero for struct fields |
rangeint |
3-clause for -> for i := range n |
slicescontains |
Loop searches -> slices.Contains |
slicessort |
sort.Slice -> slices.Sort |
stringsbuilder |
String concatenation += -> strings.Builder |
stringscut |
strings.Index patterns -> strings.Cut |
stringscutprefix |
HasPrefix/TrimPrefix -> CutPrefix |
stringsseq |
Split/Fields ranges -> SplitSeq/FieldsSeq iterators |
testingcontext |
context.WithCancel in tests -> t.Context() |
waitgroup |
wg.Add(1); go func() { defer wg.Done()... } -> wg.Go(f) |
(Run go tool fix help for the full list.)
go test key flags
| Flag |
Purpose |
-race |
Enable race detector |
-count=1 |
Bypass test cache |
-run <regex> |
Run only matching tests |
-v |
Verbose output |
-short |
Skip long-running tests (tests check testing.Short()) |
-shuffle=on |
Randomize test order |
-failfast |
Stop on first failure |
-cover |
Enable coverage analysis |
-coverprofile=f |
Write coverage profile to file |
-coverpkg=pattern |
Apply coverage to matching packages |
-bench=<regex> |
Run matching benchmarks |
-benchmem |
Report allocations in benchmarks |
-benchtime=5s |
Benchmark duration |
-fuzz=<regex> |
Run matching fuzz tests |
-timeout=10m |
Test timeout (default 10m) |
-cpuprofile=f |
Write CPU profile |
-memprofile=f |
Write memory profile |
-artifacts |
Store test artifacts in output directory (1.26+) |
go build key flags
| Flag |
Purpose |
-race |
Enable race detector |
-pgo=auto |
Profile-guided optimization (auto uses default.pgo) |
-gcflags='-m' |
Show escape analysis |
-gcflags='-S' |
Show assembly output |
-ldflags='-s -w' |
Strip debug info (smaller binary) |
-ldflags='-X main.version=v1.0' |
Embed build-time values |
-trimpath |
Remove filesystem paths from binary |
-tags=<list> |
Build constraint tags |
-o <file> |
Output file path |
go mod subcommands
| Command |
Purpose |
go mod tidy |
Sync go.mod/go.sum with imports |
go mod download |
Download modules to cache |
go mod graph |
Print module dependency graph |
go mod vendor |
Create vendored copy |
go mod verify |
Verify dependencies match go.sum |
go mod why <mod> |
Explain why a module is needed |
go mod edit -go=1.26 |
Update go directive |
gofmt flags
| Flag |
Purpose |
-d |
Print diff (do not modify files) |
-l |
List files with formatting differences |
-s |
Simplify code |
-w |
Write changes to files |
External tools
Check availability before use. These are not part of the Go toolchain:
| Tool |
Check |
Purpose |
staticcheck |
which staticcheck |
Extended static analysis beyond go vet |
golangci-lint |
which golangci-lint |
Meta-linter running 100+ linters |
govulncheck |
which govulncheck |
Scan dependencies for known vulnerabilities |
If unavailable, go vet covers the most critical checks. Do not block on missing external tools.
Common Diagnostics
| Diagnostic |
Cause |
Fix |
Reference |
declared and not used |
Unused variable |
Remove it or use it |
- |
imported and not used |
Unused import |
Remove import; use _ alias only during active development |
- |
cannot use X as type Y |
Type mismatch |
Run go doc on both types; check interface satisfaction |
references/interfaces-and-design.md |
data race detected |
Concurrent unsynchronized access |
Use mutex, channel, or atomic; see concurrency patterns |
references/concurrency.md |
err is shadowed during return |
:= in inner scope shadows outer err |
Use = instead of := or rename inner variable |
references/error-handling.md |
loop variable X captured by func literal |
Pre-1.22 loop var capture |
Go 1.22+ fixes this; for older: copy variable before closure |
- |
possible misuse of sync.WaitGroup |
Add called inside goroutine |
Call Add before starting goroutine, not inside it |
references/concurrency.md |
context.Background used in long-lived operation |
Missing context propagation |
Accept context.Context as first parameter; pass from caller |
references/concurrency.md |
go directive in go.mod too old |
go.mod version < required feature |
Run go mod edit -go=<version> to update |
references/modules-and-deps.md |
Any ioutil.* usage |
Deprecated since Go 1.16 |
ioutil.ReadAll -> io.ReadAll; ioutil.ReadFile -> os.ReadFile; etc. |
references/modern-go.md |
| HTTP handler decodes body without size limit |
DoS via unbounded request body |
Wrap r.Body with http.MaxBytesReader(w, r.Body, maxBytes) |
references/security.md |
http.Server{} without timeouts |
Vulnerable to slowloris attacks |
Set ReadTimeout, WriteTimeout, IdleTimeout |
references/security.md |
Proactive Behaviors
These are the rules for when to use tools without being asked:
- Verify before asserting: run
go doc <pkg>.<Symbol> before claiming any API signature you have not used in this session. This is the single most important behavior - wrong signatures waste the user's time.
- Vet after structural changes: run
go vet ./... after creating new files, adding exported functions, or modifying concurrency code.
- Format check before done: run
gofmt -d <file> before presenting code as complete. If it produces output, the code has formatting issues.
- Race detection for concurrency: run
go test -race -count=1 ./... after modifying code involving goroutines, channels, shared state, or sync primitives.
- Version gate features: check the
go directive in go.mod before suggesting features from newer versions. Use the version feature table above.
- Modernize with go fix: when reviewing existing code, run
go fix -diff ./... to identify modernization opportunities. Present the diff to the user before applying.
- Never suggest deprecated APIs:
ioutil (deprecated 1.16), math/rand.Seed (unnecessary since 1.20), // +build (replaced by //go:build).
- Prefer errors.Is/As/AsType: over type assertions or string matching on errors. Use
errors.AsType[T] on Go 1.26+.
- Limit HTTP request bodies: when writing HTTP handlers that decode request bodies, always use
http.MaxBytesReader to prevent denial-of-service via unbounded uploads. This is easy to forget and hard to catch in code review.
- Set HTTP server timeouts: when creating
http.Server, always set ReadTimeout, WriteTimeout, and IdleTimeout. A server without timeouts is vulnerable to slowloris attacks.
When NOT to run tools:
- Do not run
go test when only editing comments or documentation
- Do not run
go vet when the user is just asking a question, not writing code
- Do not run
go doc for universally known functions (fmt.Println, len, append, etc.)
Idiomatic Go Principles
These are the philosophical foundations. When reviewing or writing Go code, apply these as judgment calls, not rigid rules:
- Clear is better than clever. Readable code is maintainable code. Prefer explicit control flow over clever one-liners.
- Accept interfaces, return structs. Functions should accept the smallest interface that satisfies their needs and return concrete types. This maximizes flexibility for callers and clarity for the API.
- Define interfaces at the consumer, not the provider. The package that uses an interface should define it, keeping it as small as needed.
- Errors are values. Handle them, don't ignore them. Wrap with context using
fmt.Errorf("doing X: %w", err). See references/error-handling.md.
- Make the zero value useful. Design types so their zero value is valid and usable (e.g.,
sync.Mutex, bytes.Buffer).
- Composition over inheritance. Use struct embedding for reuse, not deep hierarchies.
- Keep packages focused. Organize by domain, not by layer. A
user package, not a models package.
- defer for cleanup. Place
defer immediately after acquiring a resource. It communicates cleanup intent right where the resource is opened.
- Unexported by default. Export only what is part of the public API. Unexported symbols can be changed freely.
- Pointer vs value receivers. Be consistent per type. Use value receivers for small, immutable types. Use pointer receivers for mutation or large structs. A type with any pointer receiver should use pointer receivers everywhere.
Reference Router
Open the reference file that matches the question. Load only one at a time.
Foundations
- Error handling (wrapping, sentinel errors, error types,
errors.Is/As/AsType, errors.Join) -> references/error-handling.md
- Concurrency (goroutines, channels, sync primitives, context, patterns, pitfalls) ->
references/concurrency.md
- Testing (table tests, subtests, benchmarks, fuzzing, golden files, coverage, helpers) ->
references/testing.md
Modern Go
- Version-gated features (1.21-1.26 features, deprecated patterns,
go fix guide) -> references/modern-go.md
Applied Topics
- Performance (profiling, pprof, PGO, escape analysis, benchstat, allocation reduction) ->
references/performance.md
- Interface and API design (small interfaces, composition, functional options, generics) ->
references/interfaces-and-design.md
- Modules and dependencies (go.mod, versioning, workspace mode, vendoring) ->
references/modules-and-deps.md
- Security (input validation, SQL injection, path traversal, TLS, crypto, govulncheck) ->
references/security.md
For a problem-based router ("I need to..."), see references/_index.md.
Verification Checklist
Before declaring work done on Go code:
gofmt -d . produces no output
go vet ./... produces no diagnostics
go build ./... succeeds
go test -race -count=1 ./... passes
- No deprecated patterns (
ioutil, math/rand.Seed, // +build)
- Error values wrapped with
%w where callers need errors.Is/errors.As
- Exported functions and types have doc comments
context.Context is threaded through where cancellation matters
- HTTP handlers use
http.MaxBytesReader for request body limits
- HTTP servers have
ReadTimeout, WriteTimeout, IdleTimeout set
go mod tidy has been run if dependencies changed
1---2name: go-dev3description: Go development with toolchain-first verification workflow. Use whenever the user (1) writes, modifies, debugs, or reviews Go code, (2) works with go.mod, go.sum, or Go module dependencies, (3) writes or runs Go tests, benchmarks, or fuzz tests, (4) mentions go doc, go vet, go fix, go test, go build, go mod, gofmt, staticcheck, golangci-lint, govulncheck, or pprof, (5) asks about Go error handling (errors.Is/As/AsType/Join), concurrency (goroutines, channels, sync, context), interfaces, or package design, (6) encounters Go compiler errors, test failures, or race conditions, (7) profiles Go code for performance or works with PGO, (8) asks about Go best practices, code review, or idiomatic Go, (9) works with files ending in .go or _test.go, (10) wants to modernize Go code to 1.21-1.26 features. Trigger this skill proactively when the user is working in a Go codebase even if they do not explicitly ask for Go help - the toolchain-first workflow (verify APIs with go doc before coding, run go vet after) catches bugs4---56# Go Development78## Session Init910At the start of any Go session, detect the project's Go version:11121. Read `go.mod` and extract the `go` directive (e.g., `go 1.26`)132. This version controls which language features and stdlib APIs are available143. If you are about to suggest a feature gated behind a newer version, stop and note the incompatibility1516### Version Feature Table1718| Version | Key additions |19| ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------- |20| 1.21 | `log/slog`, `slices`, `maps`, `min`/`max`/`clear` builtins, `context.AfterFunc`, `context.WithoutCancel`, `sync.OnceFunc`/`OnceValue`, PGO auto |21| 1.22 | `for i := range n`, `math/rand/v2`, enhanced `http.ServeMux` routing (method+pattern), loopvar semantic change |22| 1.23 | `iter.Seq`/`iter.Seq2`, range-over-func, `unique.Handle`, `structs.HostLayout` |23| 1.24 | `testing.T.Context`, `testing.T.Chdir`, `os.Root`, generic type aliases, `go tool` runs module tools, `testing/synctest`, `omitzero` JSON tag |24| 1.25 | `sync.WaitGroup.Go`, `testing.T.Attr`, `testing.T.Output`, `sync.Map` range-over-func, `os.OpenRoot` |25| 1.26 | `errors.AsType[T]`, `testing.T.ArtifactDir`, `go test -artifacts`, `go fix` command (21 fixers), new vet analyzers (waitgroup, hostport), `new(expr)` shorthand |2627## Toolchain-First Workflow2829This is the core of this skill. Go ships a powerful toolchain - use it instead of guessing.3031### Before Writing Code3233When about to use a stdlib or third-party API you are not certain about, verify the signature first:3435```bash36go doc <package>.<Symbol> # exact function/type/method37go doc -all <package>.<Type> # full type with all methods38go doc -src <package>.<Symbol> # source code when implementation matters39```4041Token efficiency matters: `go doc fmt.Fprintf` returns 5 lines. `go doc fmt` returns hundreds. Always use the most specific query that answers your question.4243For third-party packages, they must be importable (in go.mod) before `go doc` works. For stdlib, it always works.4445### After Writing or Modifying Code4647Pick the verification level that matches the scope of the change:4849**Full** - new files, unfamiliar APIs, concurrency code, public interface changes:5051```bash52gofmt -d . # format check (should produce no output)53go vet ./... # static analysis54go build ./... # compilation check55go test -race -count=1 ./... # tests with race detector, cache bypassed56```5758Or use the bundled script: `${CLAUDE_SKILL_DIR}/scripts/go-quality-check.sh ./...`5960**Standard** - modifying existing code in patterns the project already uses:6162```bash63go vet ./...64go test -count=1 -run TestRelevant ./path/to/pkg/...65```6667**Light** - formatting, comments, documentation, renaming:6869```bash70gofmt -d <changed-file>71```7273### When Modernizing Code7475Go 1.26 introduced `go fix`, which applies automated improvements:7677```bash78go fix -diff ./... # preview changes as unified diff79go fix ./... # apply all fixes80```8182This replaces patterns like `interface{}` with `any`, `sort.Slice` with `slices.Sort`, manual `wg.Add/Done` with `wg.Go`, and many more. Always preview with `-diff` first.8384### When Debugging Test Failures8586```bash87go test -v -run TestName -count=1 ./pkg/... # verbose, cache-bypassed88go test -race -count=1 ./... # if concurrency is involved89go test -coverprofile=c.out ./... && go tool cover -func=c.out # coverage gaps90```9192### When Adding Dependencies93941. Prefer stdlib when the stdlib solution is adequate952. Run `go doc` on the candidate package to verify its API before committing to it963. `go get <module>@latest && go mod tidy`974. `go mod why <module>` to verify it is actually used9899## Tool Command Reference100101### go doc102103| Pattern | What it returns |104| ------------------------------ | ----------------------------------- |105| `go doc fmt` | Package synopsis |106| `go doc fmt.Fprintf` | Specific function signature and doc |107| `go doc -all fmt.Stringer` | Full type including all methods |108| `go doc -src fmt.Fprintf` | Source code of the function |109| `go doc -short fmt` | One-line per symbol |110| `go doc -u net/http.Transport` | Include unexported fields |111| `go doc cmd/go` | Go command documentation |112113### go vet analyzers (37 total)114115| Analyzer | What it catches |116| -------------- | ------------------------------------------ |117| `appends` | Missing values after append |118| `assign` | Useless assignments |119| `atomic` | Common sync/atomic mistakes |120| `bools` | Boolean operator mistakes |121| `buildtag` | Invalid `//go:build` directives |122| `composites` | Unkeyed composite literals |123| `copylocks` | Locks passed by value |124| `defers` | Common defer mistakes |125| `errorsas` | Wrong types passed to `errors.As` |126| `hostport` | Bad address format for `net.Dial` |127| `httpresponse` | HTTP response handling mistakes |128| `loopclosure` | Loop variable capture in nested functions |129| `lostcancel` | Context cancel function not called |130| `printf` | Printf format string mismatches |131| `shadow` | Variable shadowing (via `-vettool`) |132| `slog` | Invalid structured logging calls |133| `stdversion` | Uses of too-new stdlib symbols |134| `structtag` | Malformed struct tags |135| `tests` | Mistaken test/example/benchmark signatures |136| `unmarshal` | Non-pointer passed to unmarshal |137| `unusedresult` | Unused results from certain calls |138| `waitgroup` | Misuses of sync.WaitGroup |139140(Run `go tool vet help` for the full list of all 37.)141142### go fix fixers (21 total, Go 1.26+)143144| Fixer | What it modernizes |145| ------------------ | ----------------------------------------------------------- |146| `any` | `interface{}` -> `any` |147| `fmtappendf` | `[]byte(fmt.Sprintf(...))` -> `fmt.Appendf` |148| `forvar` | Remove redundant loop variable re-declarations |149| `mapsloop` | Explicit map loops -> `maps` package calls |150| `minmax` | if/else chains -> `min`/`max` builtins |151| `newexpr` | Simplify with `new(expr)` (1.26) |152| `omitzero` | `omitempty` -> `omitzero` for struct fields |153| `rangeint` | 3-clause for -> `for i := range n` |154| `slicescontains` | Loop searches -> `slices.Contains` |155| `slicessort` | `sort.Slice` -> `slices.Sort` |156| `stringsbuilder` | String concatenation `+=` -> `strings.Builder` |157| `stringscut` | `strings.Index` patterns -> `strings.Cut` |158| `stringscutprefix` | `HasPrefix`/`TrimPrefix` -> `CutPrefix` |159| `stringsseq` | `Split`/`Fields` ranges -> `SplitSeq`/`FieldsSeq` iterators |160| `testingcontext` | `context.WithCancel` in tests -> `t.Context()` |161| `waitgroup` | `wg.Add(1); go func() { defer wg.Done()... }` -> `wg.Go(f)` |162163(Run `go tool fix help` for the full list.)164165### go test key flags166167| Flag | Purpose |168| ------------------- | ------------------------------------------------------- |169| `-race` | Enable race detector |170| `-count=1` | Bypass test cache |171| `-run <regex>` | Run only matching tests |172| `-v` | Verbose output |173| `-short` | Skip long-running tests (tests check `testing.Short()`) |174| `-shuffle=on` | Randomize test order |175| `-failfast` | Stop on first failure |176| `-cover` | Enable coverage analysis |177| `-coverprofile=f` | Write coverage profile to file |178| `-coverpkg=pattern` | Apply coverage to matching packages |179| `-bench=<regex>` | Run matching benchmarks |180| `-benchmem` | Report allocations in benchmarks |181| `-benchtime=5s` | Benchmark duration |182| `-fuzz=<regex>` | Run matching fuzz tests |183| `-timeout=10m` | Test timeout (default 10m) |184| `-cpuprofile=f` | Write CPU profile |185| `-memprofile=f` | Write memory profile |186| `-artifacts` | Store test artifacts in output directory (1.26+) |187188### go build key flags189190| Flag | Purpose |191| --------------------------------- | ----------------------------------------------------- |192| `-race` | Enable race detector |193| `-pgo=auto` | Profile-guided optimization (auto uses `default.pgo`) |194| `-gcflags='-m'` | Show escape analysis |195| `-gcflags='-S'` | Show assembly output |196| `-ldflags='-s -w'` | Strip debug info (smaller binary) |197| `-ldflags='-X main.version=v1.0'` | Embed build-time values |198| `-trimpath` | Remove filesystem paths from binary |199| `-tags=<list>` | Build constraint tags |200| `-o <file>` | Output file path |201202### go mod subcommands203204| Command | Purpose |205| ---------------------- | -------------------------------- |206| `go mod tidy` | Sync go.mod/go.sum with imports |207| `go mod download` | Download modules to cache |208| `go mod graph` | Print module dependency graph |209| `go mod vendor` | Create vendored copy |210| `go mod verify` | Verify dependencies match go.sum |211| `go mod why <mod>` | Explain why a module is needed |212| `go mod edit -go=1.26` | Update go directive |213214### gofmt flags215216| Flag | Purpose |217| ---- | -------------------------------------- |218| `-d` | Print diff (do not modify files) |219| `-l` | List files with formatting differences |220| `-s` | Simplify code |221| `-w` | Write changes to files |222223### External tools224225Check availability before use. These are not part of the Go toolchain:226227| Tool | Check | Purpose |228| --------------- | --------------------- | ------------------------------------------- |229| `staticcheck` | `which staticcheck` | Extended static analysis beyond go vet |230| `golangci-lint` | `which golangci-lint` | Meta-linter running 100+ linters |231| `govulncheck` | `which govulncheck` | Scan dependencies for known vulnerabilities |232233If unavailable, `go vet` covers the most critical checks. Do not block on missing external tools.234235## Common Diagnostics236237| Diagnostic | Cause | Fix | Reference |238| ------------------------------------------------- | --------------------------------------- | -------------------------------------------------------------------------- | ------------------------------------- |239| `declared and not used` | Unused variable | Remove it or use it | - |240| `imported and not used` | Unused import | Remove import; use `_` alias only during active development | - |241| `cannot use X as type Y` | Type mismatch | Run `go doc` on both types; check interface satisfaction | `references/interfaces-and-design.md` |242| `data race detected` | Concurrent unsynchronized access | Use mutex, channel, or atomic; see concurrency patterns | `references/concurrency.md` |243| `err is shadowed during return` | `:=` in inner scope shadows outer `err` | Use `=` instead of `:=` or rename inner variable | `references/error-handling.md` |244| `loop variable X captured by func literal` | Pre-1.22 loop var capture | Go 1.22+ fixes this; for older: copy variable before closure | - |245| `possible misuse of sync.WaitGroup` | `Add` called inside goroutine | Call `Add` before starting goroutine, not inside it | `references/concurrency.md` |246| `context.Background used in long-lived operation` | Missing context propagation | Accept `context.Context` as first parameter; pass from caller | `references/concurrency.md` |247| `go directive in go.mod too old` | go.mod version < required feature | Run `go mod edit -go=<version>` to update | `references/modules-and-deps.md` |248| Any `ioutil.*` usage | Deprecated since Go 1.16 | `ioutil.ReadAll` -> `io.ReadAll`; `ioutil.ReadFile` -> `os.ReadFile`; etc. | `references/modern-go.md` |249| HTTP handler decodes body without size limit | DoS via unbounded request body | Wrap `r.Body` with `http.MaxBytesReader(w, r.Body, maxBytes)` | `references/security.md` |250| `http.Server{}` without timeouts | Vulnerable to slowloris attacks | Set `ReadTimeout`, `WriteTimeout`, `IdleTimeout` | `references/security.md` |251252## Proactive Behaviors253254These are the rules for when to use tools without being asked:255256- **Verify before asserting**: run `go doc <pkg>.<Symbol>` before claiming any API signature you have not used in this session. This is the single most important behavior - wrong signatures waste the user's time.257- **Vet after structural changes**: run `go vet ./...` after creating new files, adding exported functions, or modifying concurrency code.258- **Format check before done**: run `gofmt -d <file>` before presenting code as complete. If it produces output, the code has formatting issues.259- **Race detection for concurrency**: run `go test -race -count=1 ./...` after modifying code involving goroutines, channels, shared state, or sync primitives.260- **Version gate features**: check the `go` directive in `go.mod` before suggesting features from newer versions. Use the version feature table above.261- **Modernize with go fix**: when reviewing existing code, run `go fix -diff ./...` to identify modernization opportunities. Present the diff to the user before applying.262- **Never suggest deprecated APIs**: `ioutil` (deprecated 1.16), `math/rand.Seed` (unnecessary since 1.20), `// +build` (replaced by `//go:build`).263- **Prefer errors.Is/As/AsType**: over type assertions or string matching on errors. Use `errors.AsType[T]` on Go 1.26+.264- **Limit HTTP request bodies**: when writing HTTP handlers that decode request bodies, always use `http.MaxBytesReader` to prevent denial-of-service via unbounded uploads. This is easy to forget and hard to catch in code review.265- **Set HTTP server timeouts**: when creating `http.Server`, always set `ReadTimeout`, `WriteTimeout`, and `IdleTimeout`. A server without timeouts is vulnerable to slowloris attacks.266267When NOT to run tools:268269- Do not run `go test` when only editing comments or documentation270- Do not run `go vet` when the user is just asking a question, not writing code271- Do not run `go doc` for universally known functions (`fmt.Println`, `len`, `append`, etc.)272273## Idiomatic Go Principles274275These are the philosophical foundations. When reviewing or writing Go code, apply these as judgment calls, not rigid rules:276277- **Clear is better than clever.** Readable code is maintainable code. Prefer explicit control flow over clever one-liners.278- **Accept interfaces, return structs.** Functions should accept the smallest interface that satisfies their needs and return concrete types. This maximizes flexibility for callers and clarity for the API.279- **Define interfaces at the consumer, not the provider.** The package that uses an interface should define it, keeping it as small as needed.280- **Errors are values.** Handle them, don't ignore them. Wrap with context using `fmt.Errorf("doing X: %w", err)`. See `references/error-handling.md`.281- **Make the zero value useful.** Design types so their zero value is valid and usable (e.g., `sync.Mutex`, `bytes.Buffer`).282- **Composition over inheritance.** Use struct embedding for reuse, not deep hierarchies.283- **Keep packages focused.** Organize by domain, not by layer. A `user` package, not a `models` package.284- **defer for cleanup.** Place `defer` immediately after acquiring a resource. It communicates cleanup intent right where the resource is opened.285- **Unexported by default.** Export only what is part of the public API. Unexported symbols can be changed freely.286- **Pointer vs value receivers.** Be consistent per type. Use value receivers for small, immutable types. Use pointer receivers for mutation or large structs. A type with any pointer receiver should use pointer receivers everywhere.287288## Reference Router289290Open the reference file that matches the question. Load only one at a time.291292### Foundations293294- **Error handling** (wrapping, sentinel errors, error types, `errors.Is`/`As`/`AsType`, `errors.Join`) -> `references/error-handling.md`295- **Concurrency** (goroutines, channels, sync primitives, context, patterns, pitfalls) -> `references/concurrency.md`296- **Testing** (table tests, subtests, benchmarks, fuzzing, golden files, coverage, helpers) -> `references/testing.md`297298### Modern Go299300- **Version-gated features** (1.21-1.26 features, deprecated patterns, `go fix` guide) -> `references/modern-go.md`301302### Applied Topics303304- **Performance** (profiling, pprof, PGO, escape analysis, benchstat, allocation reduction) -> `references/performance.md`305- **Interface and API design** (small interfaces, composition, functional options, generics) -> `references/interfaces-and-design.md`306- **Modules and dependencies** (go.mod, versioning, workspace mode, vendoring) -> `references/modules-and-deps.md`307- **Security** (input validation, SQL injection, path traversal, TLS, crypto, govulncheck) -> `references/security.md`308309For a problem-based router ("I need to..."), see `references/_index.md`.310311## Verification Checklist312313Before declaring work done on Go code:3143151. `gofmt -d .` produces no output3162. `go vet ./...` produces no diagnostics3173. `go build ./...` succeeds3184. `go test -race -count=1 ./...` passes3195. No deprecated patterns (`ioutil`, `math/rand.Seed`, `// +build`)3206. Error values wrapped with `%w` where callers need `errors.Is`/`errors.As`3217. Exported functions and types have doc comments3228. `context.Context` is threaded through where cancellation matters3239. HTTP handlers use `http.MaxBytesReader` for request body limits32410. HTTP servers have `ReadTimeout`, `WriteTimeout`, `IdleTimeout` set32511. `go mod tidy` has been run if dependencies changed