cmd/sgai/skel/.sgai/skills/coding-practices/go-code-review/SKILL.md
Go code review checklist based on official Go style guides. When reviewing Go code for style, idioms, and best practices
npx skillsauth add sandgardenhq/sgai go-code-reviewInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Comprehensive code review checklist based on official Go style guides.
For deeper information, fetch these URLs:
gofmt or goimportsRun: gofmt -w . or goimports -w .
util, common, misc, api, types, interfaceschubby.File not chubby.ChubbyFilec, i, rc for Clientme, this, selfURL or url, never UrlServeHTTP not ServeHttpxmlHTTPRequest or XMLHTTPRequestappID not appIdOwner() not GetOwner()SetOwner() is fine-er suffix (Reader, Writer)// Request represents a request to run a command.
type Request struct { ... }
// Encode writes the JSON encoding of req to w.
func Encode(w io.Writer, req *Request) { ... }
package clause (no blank line)// Package math provides basic constants and mathematical functions.
package math
_, err := Foo() then ignored)fmt.Errorf("something bad") not "Something bad."// GOOD
if err != nil {
return err
}
// normal code
// BAD
if err != nil {
// error
} else {
// normal
}
func F(ctx context.Context, ...)context.Background() only with good reasongo test -race// GOOD - consumer defines interface
package consumer
type Thinger interface { Thing() bool }
// BAD - producer defines interface
package producer
type Thinger interface { Thing() bool }
func NewThinger() Thinger { ... }
var t []string (nil slice)t := []string{} only when needed (JSON encoding)*string and *io.Reader usually wrongcrypto/rand for keys, not math/randcrypto/rand.Text() for random textimport (
"fmt"
"os"
"github.com/foo/bar"
)
import _ "pkg" only in main package or testsif got != tt.want {
t.Errorf("Foo(%q) = %d; want %d", tt.in, got, tt.want)
}
TestFunctionName format// Avoid
func (n *Node) Parent1() (node *Node) {}
// Better
func (n *Node) Parent1() *Node {}
// OK when clarifying
func (f *Foo) Location() (lat, long float64, err error)
// GOOD
func Lookup(key string) (value string, ok bool)
// BAD
func Lookup(key string) string // returns "" on not found
// GOOD - switch with direct evaluation
switch status := getStatus(); status {
case StatusPending:
return "pending"
case StatusActive:
return "active"
case StatusDone:
return "done"
default:
return "unknown"
}
// BAD - long if-else chain
if status := getStatus(); status == StatusPending {
return "pending"
} else if status == StatusActive {
return "active"
} else if status == StatusDone {
return "done"
} else {
return "unknown"
}
// Type switch
var i interface{} = "hello"
switch v := i.(type) {
case string:
fmt.Println("string:", v)
case int:
fmt.Println("int:", v)
default:
fmt.Println("unknown type")
}
// GOOD - comma-separated cases
switch kind {
case "admin", "owner", "superadmin":
grantFullAccess()
}
slices.Sort instead of sort.Sliceslices.Sort instead of sort.Ints/sort.Float64s/sort.Stringsslices.Contains instead of manual search loopsslices.Equal instead of manual slice comparisonslices.Delete instead of append pattern for slice deletionmaps.Clone instead of manual map copy loopsmaps.Equal instead of manual map comparisonmaps.Keys/maps.Values (Go 1.23+) for iteration// GOOD - modern idioms
slices.Sort(items)
if slices.Contains(items, target) { ... }
clone := maps.Clone(original)
// BAD - unnecessary manual implementation
sort.Slice(items, func(i, j int) bool { return items[i] < items[j] })
sort.Ints(items)
for _, item := range items {
if item == target { found = true; break }
}
clone := make(map[K]V, len(original))
for k, v := range original { clone[k] = v }
cmp.Ordered constraint used for comparable typesany constraint only when truly type-agnostictime.Now() callstime.Now() in business logic// GOOD - testable time handling
type Clock interface { Now() time.Time }
type Service struct { clock Clock }
// BAD - untestable
func (s *Service) IsExpired() bool {
return time.Now().After(s.expiresAt)
}
iter.Seq or iter.Seq2sync.WaitGroup.Go for fire-and-forget goroutineswg.Go(fn) is equivalent to go func() { wg.Wait(); fn() }() but simplergo func() { defer wg.Done(); fn() }() for simpler error handling// GOOD - Go 1.24+ WaitGroup.Go pattern
var wg sync.WaitGroup
for _, task := range tasks {
wg.Go(func() {
process(task) // err handled inside
})
}
wg.Wait()
// ACCEPTABLE - traditional pattern still works
var wg sync.WaitGroup
for _, task := range tasks {
wg.Add(1)
go func(t Task) {
defer wg.Done()
process(t)
}(task)
}
wg.Wait()
{ ... } wrapping code without if/for/switch// BAD - bare block adds unnecessary indentation
msg := buildFlowMessage()
{
multiModelSection := processMultiModel()
// ... 30+ lines
}
// GOOD - flatten the code
msg := buildFlowMessage()
multiModelSection := processMultiModel()
// ... (unindented)
goimports -w .)response.txt after file-based transport removal)return, panic, break in loops (unless in defer)// BAD - unreachable code after return
func foo() {
return
fmt.Println("this never runs") // dead code
}
// GOOD - remove unreachable code
func foo() {
return
}
For fast reviews, check these critical items:
## Code Review: [scope]
### Critical Issues
[Must fix before merge]
### Important Issues
[Should fix]
### Minor Issues
[Nice to have]
### Strengths
[What's done well]
### Verdict: [PASS/NEEDS WORK]
documentation
Start, stop, and steer agentic sessions in sgai workspaces. Use when you need to launch AI agent sessions, halt running sessions, or inject steering instructions to guide the agent mid-execution without stopping it.
development
Monitor sgai workspace status, events, progress, diffs, and workflow diagrams. Use when you need to observe what agents are doing, track progress, get the current state of all workspaces, subscribe to real-time updates via SSE, or inspect code changes.
development
Access agents, skills, and code snippets available in sgai workspaces. Use when you need to discover what agents are defined in a workspace, browse available skills, get skill instructions, find code snippets by language, or retrieve snippet content for a specific task.
data-ai
Handle agent questions and work gates in sgai workspaces. Use when an agent is blocked waiting for human input, when you need to respond to multi-choice questions, approve work gates, or provide free-text answers to agent queries.