Go code review
26 production-grade Go skills for Claude Code, Gemini CLI, and opencode.
npx -y skills add muratmirgun/gophers --skill go-code-reviewAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
One thing to look at
- 8 stars8 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
What its author says it does
Copied from the file, not written here
Invoke this skill to systematically review a Go change against community style standards before merging. Walks the diff topic by topic — formatting, errors, naming, concurrency, interfaces, data structures, security, declarations, functions, style, logging, imports, generics, testing — flagging issues with line references and severity (must-fix / should-fix / nit). Apply proactively before any Go PR ships.
The file declares its own license as MIT. That is the author’s claim about this one file, and it is not the same thing as the license GitHub reports for the repository, which is listed with the other numbers below.
SKILL.md
8.9 KB, as published. Nobody here has run it
Go Code Review
A repeatable, opinionated review pass for Go code. Read the diff file by file, walk each topic in order, flag findings with file:line references, then group by severity.
Core Rules
- Mechanical checks first. Never start a human review until
gofmt,go vet, andgolangci-lintare clean. They free your attention for what tools cannot catch. - One file at a time, topic by topic. Walk the diff in order and apply each topic checklist below. Switching topics mid-file loses the thread.
- Every finding cites a rule.
file:lineplus the rule name (go-naming: initialisms) — never a bare opinion. - Severity is non-negotiable. Must-Fix (correctness/security/data-loss/broken contract) blocks merge; Should-Fix (significant design or style issue); Nit (small preference, flag once).
- Drop what you cannot defend. After flagging, re-read and remove any finding you would not stand behind in a thread.
- Praise non-trivial improvements. A review without acknowledgement teaches only avoidance.
Review Procedure
- Run mechanical checks:
gofmt -d ./...,go vet ./...,golangci-lint run ./...,go test ./... -race -short. - Read the diff one file at a time. For each file, walk the topic checklists below in order.
- Flag every issue with
file:lineand the rule name that justifies it. - After all files are reviewed, re-read flagged items and drop any you cannot justify.
- Group findings by Must Fix / Should Fix / Nit using the rubric below.
Use references/review-template.md when writing up the review for consistent severity grouping and tone.
Automated Checks
gofmt -l ./... && go vet ./... && golangci-lint run ./... && go test ./... -race -short
Fix anything the tools find before continuing. See go-linting for setup.
Formatting
-
gofmt/goimportsclean; long lines break by semantics, not column count
Documentation
- Exported symbols documented (starts with name, ends with
.); package comment adjacent topackageclause; non-trivial unexported have intent comments; named returns only when they clarify
See go-documentation.
Error Handling
- No discarded errors (
_ = f()) without a written justification - Error strings are lowercase with no trailing punctuation
- Errors wrap with
%wwhen the caller may want to inspect;%vonly when hiding is deliberate - No in-band magic values (
-1,"",nil) for failure — multi-return with anerrororok bool - Error path comes first; the success path stays unindented
- Each error is handled exactly once (log or return, not both)
See go-error-handling.
Naming
-
MixedCaps/mixedCapsonly — no underscores orSCREAMING_SNAKE - Initialisms are uniformly cased:
URL,ID,HTTP,XMLHTTPRequest,serveHTTP - Short names for short scopes (
i,r,ctx); longer names for wider scopes - Receiver names are one or two letters, consistent across methods; no
this/self/me - Packages don't stutter (
http.Server, nothttp.HTTPServer) - Package names avoid
util,helpers,common,misc - No identifiers shadow builtins (
len,error,cap,new,make,copy,any)
See go-naming and go-packages.
Declarations
- Related
var/const/typeare in grouped blocks; unrelated kept separate -
varfor intentional zero values;:=for computed locals - Variables scoped as narrowly as is readable (if-init where it fits)
- Struct literals use field names; zero-value fields are omitted
- Enums start at
iota + 1(or zero is explicitly meaningful) -
anyinstead ofinterface{}in new code
See go-declarations.
Control Flow
- No
elseafter a returning/breaking/continuingif; no:=shadowing of outerctx/err; map iteration is order-agnostic; labeledbreak/continuefor switch-in-loop
See go-control-flow.
Functions
- File order: type → constructor → exported → unexported → utilities; wrapped signatures one-per-line; no pointer-to-interface; bool/int params renamed via type or commented; printf-style helpers end in
f
See go-functions.
Interfaces
- Defined in the consumer package; not "just for mocking" on the implementor; consistent receivers per type; compile-time
var _ I = (*T)(nil)on exported implementations
See go-interfaces.
Concurrency
- Goroutine lifetimes clear (bounded by
ctx.Done()or documented); APIs synchronous by default;context.Contextfirst param, never struct field; lock order documented; sender closes channels
Example to flag (pkg/worker/worker.go:42):
go s.process(req) // ✗ no ctx, no done signal — leak on shutdown
vs. acceptable:
s.wg.Add(1)
go func() { defer s.wg.Done(); s.process(ctx, req) }()
See go-concurrency.
Data Structures
-
var t []Tfor nil slices,[]T{}only when empty non-nil is required (JSON output); copies of structs containingsync.Mutexflagged; slice/map at API boundaries copied or borrowing documented
See go-data-structures.
Security & Logging
-
crypto/randfor secret material (nevermath/rand); no librarypanicfor ordinary failures -
log/slog(notlog/fmt.Println); static message + structured attrs; secrets and PII never logged
See go-defensive and go-logging.
Imports
- Grouped: stdlib → external → local; no rename unless collision; no blank import outside
main/tests; no dot imports
See go-packages.
Generics
- Justified by ≥2 real call sites; constraint is the loosest that compiles; no generics-just-for-an-interface
See go-generics.
Testing
- Tests cover the new behavior at the right level; failure messages include what/inputs/got/want
-
httptest.NewServerover hand-rolled mocks;TestMainonly when truly necessary;Example*for non-trivial APIs
Read references/integrative-example.md to see the rules applied together on a small HTTP server.
Read references/severity-rubric.md when deciding whether to label a finding must-fix, should-fix, or nit.
Quick Severity Rubric
| Severity | Examples |
|---|---|
| Must Fix | Race, security bug, swallowed error, broken API, data loss |
| Should Fix | Wrong layer for an interface, panic in a library, leaky goroutine |
| Nit | Name preference, comment phrasing, ordering within a block |
Anti-Patterns
These are reviewer anti-patterns — bad habits to avoid when writing the review itself:
| Anti-pattern | Do this instead |
|---|---|
| "I would have written this differently" | drop it, or cite a concrete rule |
Listing every nit you noticed | flag once, note "× N similar" |
No severity labels; comment without file:line | label Must / Should / Nit; anchor with path:line |
| Reviewing the author, not the code | write about the change, not the person |
| Re-doing the work in the review | point to the rule and let them write it |
| Approving without reading tests | tests are part of the diff |
Verification Checklist
- Every finding has
file:line+ a rule citation; no bare opinions - No duplicates (note "× N similar" if widespread); severity matches the rubric
- Tests were read, not just counted
- Praise included for non-trivial improvements; tone is about the change, never the author
References
- review-template.md — markdown shape for posting a review
- severity-rubric.md — extended must/should/nit guidance
- integrative-example.md — sample HTTP server walked through