# Go Code Rules Applies to: `**/*.go` Go-specific style and structure. Pairs with `go-testing.md` for tests and the generic `verification.md` / `commits.md` rules. When in doubt, defer to [Effective Go](https://go.dev/doc/effective_go) and the [Go Code Review Comments](https://go.dev/wiki/CodeReviewComments) wiki. ## Formatting Is Not a Choice All code is `gofmt`-clean. The bundle's PostToolUse hook runs `gofmt` and `go vet` on every edit and blocks on a violation, and the pre-commit hook re-checks staged files. Don't hand-format; let the tool decide. Use `goimports` (or your editor's organize-imports) to keep the import block grouped and pruned. ## Errors - Return errors; don't panic across an API boundary. `panic` is for genuinely unrecoverable, programmer-error states (a corrupt invariant), not for control flow or expected failures. - Wrap with context as an error travels up: `fmt.Errorf("load config %s: %w", path, err)`. The `%w` verb preserves the chain for `errors.Is` / `errors.As`. - Handle every error where it occurs. Don't assign to `_` to silence one unless you can state why it's safe in a comment. - Define sentinel errors (`var ErrNotFound = errors.New("not found")`) or typed errors when callers need to branch on the failure; callers match with `errors.Is` / `errors.As`, never on the message string. - Check errors before using the other return value — the value is unspecified when `err != nil`. ## Naming and Shape - Package names are short, lowercase, no underscores or camelCase; the name is part of every call site (`http.Client`, not `httputil.HTTPClient`). Avoid stutter: `chat.Message`, not `chat.ChatMessage`. - Exported identifiers carry a doc comment that begins with the identifier name. Unexported helpers earn a comment when the why isn't obvious. - Accept interfaces, return concrete types. Keep interfaces small — one or two methods — and define them in the consuming package, not alongside the implementation. - Avoid naked returns except in very short functions; named returns that travel more than a few lines hide what's being returned. ## Concurrency - Pass `context.Context` as the first parameter (`ctx context.Context`) through any call chain that does I/O or can block; honor cancellation. Never store a context in a struct. - A goroutine needs a defined lifecycle — know who stops it and how. Don't launch one without a way for it to exit (a closed channel, a cancelled context, a `sync.WaitGroup`). - Share memory by communicating (channels) or guard it (`sync.Mutex`); don't do both for the same state. Run concurrent code under `go test -race`. ## Structure - Keep functions focused. A function that fetches, parses, decodes, and saves is four functions; the test difficulty in `go-testing.md` is the tell. - Zero values should be useful where you can manage it (`bytes.Buffer`, `sync.Mutex` need no constructor). When construction must validate, provide a `NewThing` that returns `(*Thing, error)`. - Don't add an interface, generic, or abstraction for a single implementation. Add it when the second caller arrives, not in anticipation. - `defer` cleanup (`f.Close()`, `mu.Unlock()`) right after acquiring the resource, so the release is visible next to the acquire. ## Dependencies - Keep `go.mod` tidy: run `go mod tidy` after changing imports, commit the resulting `go.mod` and `go.sum` together. - Prefer the standard library. Pull in a dependency when it earns its maintenance and supply-chain cost, not for a function you could write in a few lines. ## What Not to Do - Don't ignore a returned error to make the line shorter. - Don't reach for `interface{}` / `any` when a concrete type or a small generic constraint says what you mean. - Don't refactor surrounding code while fixing a bug — keep the diff scoped. - Don't add comments restating what the code already says; comment the why.