Skip to content
Skill · Claude CodeCLAUDE.mdCoding

Go Service Project Instructions

CLAUDE.md for a Go backend service: package layout, error wrapping with %w, table-driven tests, and context propagation rules an agent must follow on every handler.

Use when: Use in a Go HTTP/gRPC service repository so agents write idiomatic Go — wrapped errors, table tests, contexts passed all the way down — instead of patterns imported from other languages.

@libraryNewcomer
0 upvotes0 forks0 comments

The skill file

Claude Code · CLAUDE.md
CLAUDE.md3438 chars
# Project Instructions — Go Service ## Commands ```bash go build ./... # must compile cleanly go test ./... # full suite go test ./internal/orders/ -run TestCreateOrder -v # focused run while iterating go vet ./... # before every commit golangci-lint run # lint config in .golangci.yml — do not edit it to silence findings gofmt -l . # must print nothing; gofmt is non-negotiable ``` Go version is pinned in `go.mod`. Use `go get <module>@<version>` then `go mod tidy` to add dependencies; never edit `go.mod`/`go.sum` by hand. ## Package layout ``` cmd/<service-name>/ # main.go only: flag parsing, wiring, graceful shutdown internal/<domain>/ # one package per domain (orders, billing, users) — business logic internal/platform/ # cross-cutting: db, httpserver, config, logging api/ # transport layer: handlers/proto, request/response types ``` - `cmd/` contains no business logic — if `main.go` exceeds ~150 lines, you are wiring too much there. - Domain packages do not import each other's internals; they communicate through interfaces defined by the **consumer**, not the provider. - Keep interfaces small (1–3 methods) and define them where they are used. Do not create an `interfaces` package. ## Error handling - Wrap with context at every layer boundary: `fmt.Errorf("creating order %s: %w", id, err)`. Lowercase, no trailing punctuation, no "failed to" prefix stacking. - Sentinel errors are package-level vars: `var ErrOrderNotFound = errors.New("order not found")`. Check with `errors.Is`, extract typed errors with `errors.As` — never string-match error text. - Handle an error exactly once: either log it or return it, not both. Logging happens at the top of the call stack (handler/worker), with structured fields. - No `panic` outside of `main` startup invariants. No swallowing errors with `_` unless the line has a comment explaining why it is safe. ## Context discipline - `ctx context.Context` is the first parameter of every function that does I/O, blocks, or calls something that does. No storing contexts in structs. - Propagate the incoming request context all the way to the database/HTTP client — never substitute `context.Background()` mid-stack. - `context.Background()` is allowed only in `main`, tests, and detached background workers (with a comment). - Apply timeouts at the boundary: `ctx, cancel := context.WithTimeout(ctx, 5*time.Second)` in handlers calling external services; always `defer cancel()`. ## Tests - Table-driven tests are the default shape: a slice of named cases, `for _, tc := range cases { t.Run(tc.name, ...) }`. Mark independent subtests with `t.Parallel()`. - Test the exported behavior of a package (`package orders_test`), not private helpers, unless the helper has real complexity. - Use the standard library plus `go-cmp` for diffs; fakes over mocks — hand-write a small in-memory implementation of the consumer interface instead of generating mocks. - Integration tests that need Postgres live behind `//go:build integration` and run with `go test -tags integration ./...`. ## Conventions - Accept interfaces, return concrete types. - Zero values should be useful; constructors (`NewX`) only when invariants must be enforced. - No global mutable state; pass dependencies through struct fields set in `cmd/` wiring.

Install

drop into your repo

Save this to your project or home directory so Claude Code can load it.

path./CLAUDE.md
Discussion

What people are saying

Forks

0 forks of this skill
Loading forks…