This skill should be used when writing, reviewing, or refactoring Go code. It covers Go idioms, error handling, concurrency patterns, project structure, API patterns (HTTP, gRPC, GraphQL), security practices, documentation standards, and mandatory post-change verification.
From mnpx claudepluginhub molcajeteai/plugin --plugin mThis skill uses the workspace's default tool permissions.
references/api-patterns.mdreferences/concurrency.mdreferences/error-handling.mdreferences/patterns.mdreferences/post-change-protocol.mdreferences/project-structure.mdreferences/security.mdreferences/transactions.mdSearches, retrieves, and installs Agent Skills from prompts.chat registry using MCP tools like search_skills and get_skill. Activates for finding skills, browsing catalogs, or extending Claude.
Searches prompts.chat for AI prompt templates by keyword or category, retrieves by ID with variable handling, and improves prompts via AI. Use for discovering or enhancing prompts.
Executes pre-written implementation plans: critically reviews, follows bite-sized steps exactly, runs verifications, tracks progress with checkpoints, uses git worktrees, stops on blockers.
Quick reference for writing idiomatic, production-quality Go code. Each section summarizes the key rules — reference files provide full examples and edge cases.
MixedCaps or mixedCaps, never underscores. Exported names start with uppercase.i for loop index, r for reader, ctx for context. Longer names for longer scopes.http.Client, not http.HTTPClient.er suffix: Reader, Writer, Stringer.HTTPClient, userID, xmlParser.ctx context.Context is always the first parameter. Never store context in structs.sync.Mutex{} works without initialization. bytes.Buffer{} is an empty buffer ready for writes.NewServer(opts...).type Option func(*Server)
func WithPort(port int) Option {
return func(s *Server) { s.port = port }
}
func NewServer(opts ...Option) *Server {
s := &Server{port: 8080} // sensible defaults
for _, opt := range opts {
opt(s)
}
return s
}
Go errors are values. Handle them explicitly — never ignore them.
_ only when you explicitly document why.fmt.Errorf("operation failed: %w", err) to add context while preserving the error chain.var ErrNotFound = errors.New("not found").errors.Is and errors.As — Never compare error strings. Use errors.Is(err, ErrNotFound) or errors.As(err, &target).panic for truly unrecoverable situations (programmer errors, impossible states). Never panic in library code.error interface for errors that carry structured data (status codes, field names).// Sentinel error
var ErrUserNotFound = errors.New("user not found")
// Wrapping with context
user, err := repo.FindByID(ctx, id)
if err != nil {
return fmt.Errorf("finding user %s: %w", id, err)
}
// Checking wrapped errors
if errors.Is(err, ErrUserNotFound) {
return nil, status.Error(codes.NotFound, "user not found")
}
See references/error-handling.md for sentinel error patterns, errgroup usage, and custom error types.
Go's concurrency primitives are powerful but require discipline to use safely.
context.Context to all goroutines. Check ctx.Done() in long-running loops.sync.Mutex to protect shared state.context.WithCancel, context.WithTimeout, or channel signaling.sync.WaitGroup for fan-out — Use WaitGroup when launching multiple goroutines and waiting for all to complete.errgroup.Group for error propagation — When any goroutine failure should cancel the rest.g, ctx := errgroup.WithContext(ctx)
for _, item := range items {
g.Go(func() error {
return process(ctx, item)
})
}
if err := g.Wait(); err != nil {
return fmt.Errorf("processing items: %w", err)
}
See references/concurrency.md for worker pools, fan-out/fan-in, sync primitives, and common pitfalls.
project/
├── cmd/
│ └── server/
│ └── main.go # Entry point, wiring only
├── internal/ # Private application code
│ ├── config/ # Configuration loading
│ ├── handler/ # HTTP/gRPC handlers
│ ├── service/ # Business logic
│ ├── repository/ # Data access
│ └── model/ # Domain types
├── pkg/ # Public library code (if any)
├── migrations/ # Database migrations
├── Makefile # Build, test, lint commands
├── go.mod
└── go.sum
internal/ for application code — Everything the application needs, nothing external should import.cmd/ for entry points — Minimal code. Wire dependencies and start the server.pkg/ only when needed — Only for code genuinely intended for external consumption. Most projects don't need pkg/.main.go per binary — Each binary gets its own directory under cmd/.See references/project-structure.md for hexagonal architecture, flat structure, and when to choose each.
func (h *Handler) GetUser(w http.ResponseWriter, r *http.Request) {
id := chi.URLParam(r, "id")
user, err := h.service.FindByID(r.Context(), id)
if err != nil {
h.respondError(w, r, err)
return
}
h.respondJSON(w, r, http.StatusOK, user)
}
Chain middleware for cross-cutting concerns: logging, auth, rate limiting, CORS, request ID.
r := chi.NewRouter()
r.Use(middleware.RequestID)
r.Use(middleware.Logger)
r.Use(middleware.Recoverer)
r.Use(corsMiddleware)
r.Use(authMiddleware)
Resolver files are regenerated by gqlgen. Never put implementation logic in resolver files — delegate to helper functions.
// user.resolvers.go — generated, delegation only
func (r *queryResolver) Viewer(ctx context.Context) (*model.Viewer, error) {
return r.resolveViewer(ctx)
}
// user_helpers.go — all implementation
func (r *queryResolver) resolveViewer(ctx context.Context) (*model.Viewer, error) {
userID, err := auth.UserIDFromContext(ctx)
if err != nil {
return nil, err
}
return r.service.GetViewer(ctx, userID)
}
See references/api-patterns.md for middleware patterns, gRPC service definitions, error response conventions, and GraphQL best practices.
For multi-service operations that need atomicity, use the context-propagated transaction pattern: DBExecutor interface + transaction-in-context + lifecycle hooks (OnCommit/OnRevert/OnError).
See references/transactions.md for the full pattern, implementation, and multi-service examples.
$1, $2 placeholders (pgx) or ? placeholders (database/sql).// ✅ Correct — parameterized
row := db.QueryRow(ctx, "SELECT * FROM users WHERE id = $1", userID)
// ❌ Wrong — string concatenation
row := db.QueryRow(ctx, "SELECT * FROM users WHERE id = " + userID)
golang.org/x/crypto/bcrypt).See references/security.md for CORS configuration, bcrypt usage, and encryption patterns.
Follow godoc conventions:
// Package <name> ....// Server represents....Example test functions for complex APIs. They serve as both docs and tests.http.Server comment says "Server represents...", not "HTTPServer represents...".// Package auth provides JWT-based authentication and authorization.
package auth
// Token represents a signed JWT access token with its expiration time.
type Token struct {
Value string
ExpiresAt time.Time
}
// NewToken creates a signed JWT token for the given user ID.
// The token expires after the configured TTL.
func NewToken(userID string, ttl time.Duration) (*Token, error) {
After every code change, run this 5-step verification. No exceptions.
# 1. Format
gofmt -w .
# or: make fmt
# 2. Lint
golangci-lint run ./...
# or: make lint
# 3. Vet
go vet ./...
# or: make vet
# 4. Build
go build ./...
# or: make build
# 5. Test
go test -race ./...
# or: make test
-race — The race detector catches data races that tests alone miss.fmt, lint, vet, build, test targets.See references/post-change-protocol.md for the full verification workflow and troubleshooting.
StringSlice type that just wraps []string adds complexity without benefit.repo.FindUser(ctx, id) is better than service.GetUser(ctx, id) that just calls repo.FindUser(ctx, id).internal/.Every Go project must have a Makefile with at minimum:
.PHONY: build run test fmt lint vet generate
build:
go build -o bin/app ./cmd/server
run: build
./bin/app
test:
go test -race -cover ./...
fmt:
gofmt -w .
lint:
golangci-lint run ./...
vet:
go vet ./...
generate:
go generate ./...
pprof to identify bottlenecks. Never optimize without data.go test -bench to measure optimization impact.sync.Pool for frequently allocated objects. Pre-allocate slices with make([]T, 0, capacity).| File | Description |
|---|---|
| references/error-handling.md | Sentinel errors, wrapping patterns, errgroup, custom error types |
| references/concurrency.md | Worker pools, fan-out/fan-in, sync primitives, goroutine leak prevention |
| references/patterns.md | Functional options, interface composition, builder pattern |
| references/project-structure.md | Standard layout, hexagonal architecture, flat structure |
| references/api-patterns.md | HTTP handlers, middleware, gRPC services, GraphQL resolver delegation |
| references/security.md | Input validation, SQL injection prevention, bcrypt, CORS, encryption |
| references/transactions.md | Context-propagated transactions, DBExecutor, lifecycle hooks, multi-service atomicity |
| references/post-change-protocol.md | Mandatory 5-step verification workflow |