skills/go-best-practices/SKILL.md
Use when reading or writing Go files (.go, go.mod).
npx skillsauth add awfixers-stuff/opencode-config go-best-practicesInstall 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.
Follows type-first, functional, and error handling patterns from CLAUDE.md. This skill covers language-specific idioms only.
Use Go's type system to prevent invalid states at compile time.
Custom types for domain primitives:
// Distinct types prevent mixing up IDs
type UserID string
type OrderID string
func GetUser(id UserID) (*User, error) {
// Compiler prevents passing OrderID here
}
// Methods attach behavior to the type
func (id UserID) String() string {
return string(id)
}
Interfaces for behavior contracts:
// Define what you need, not what you have
type UserRepository interface {
GetByID(ctx context.Context, id UserID) (*User, error)
Save(ctx context.Context, user *User) error
}
// Accept interfaces, return structs
func ProcessInput(r io.Reader) ([]byte, error) {
return io.ReadAll(r)
}
Enums with iota and exhaustive switch:
type Status int
const (
StatusActive Status = iota + 1
StatusInactive
StatusPending
)
func ProcessStatus(s Status) (string, error) {
switch s {
case StatusActive:
return "processing", nil
case StatusInactive:
return "skipped", nil
case StatusPending:
return "waiting", nil
default:
return "", fmt.Errorf("unhandled status: %v", s)
}
}
Functional options for flexible construction:
type ServerOption func(*Server)
func WithPort(port int) ServerOption {
return func(s *Server) { s.port = port }
}
func NewServer(opts ...ServerOption) *Server {
s := &Server{port: 8080, timeout: 30 * time.Second}
for _, opt := range opts {
opt(s)
}
return s
}
// Usage: NewServer(WithPort(3000), WithTimeout(time.Minute))
Embed for composition:
type Timestamps struct {
CreatedAt time.Time
UpdatedAt time.Time
}
type User struct {
Timestamps // User gains CreatedAt, UpdatedAt
ID UserID
Email string
}
Wrap errors with %w to preserve the chain for errors.Is / errors.As:
out, err := client.Do(ctx, req)
if err != nil {
return nil, fmt.Errorf("fetch widget failed: %w", err)
}
Use log/slog with structured key-value pairs:
import "log/slog"
var log = slog.With("component", "widgets")
func createWidget(name string) (*Widget, error) {
log.Debug("creating widget", "name", name)
widget := &Widget{Name: name}
log.Debug("created widget", "id", widget.ID)
return widget, nil
}
development
Use when starting dev servers, watchers, tilt, or any process expected to outlive the conversation. Provides zmx session management patterns for long-lived processes.
development
Zig testing skill for writing and running tests. Use when using zig build test, writing comptime tests, using test filters, working with test allocators to detect leaks, or using Zig's built-in fuzz testing (0.14+). Activates on queries about Zig tests, zig test, zig build test, comptime testing, test allocators, Zig fuzz testing, or detecting memory leaks in Zig tests.
development
Zig debugging skill. Use when debugging Zig programs with GDB or LLDB, interpreting Zig runtime panics, using std.debug.print for tracing, configuring debug builds, or debugging Zig programs in VS Code. Activates on queries about debugging Zig, Zig panics, zig gdb, zig lldb, std.debug.print, Zig stack traces, or Zig error return traces.
tools
Zig cross-compilation skill. Use when cross-compiling Zig programs to different targets, using Zig's built-in cross-compilation for embedded, WASM, Windows, ARM, or using zig cc to cross-compile C code without a system cross-toolchain. Activates on queries about Zig cross-compilation, zig target triples, zig cc cross-compile, Zig embedded targets, or Zig WASM.