go-clean-architecture
Use when scaffolding or refactoring a Go service into a framework-agnostic clean (hexagonal) architecture: Domain, Usecase, Repository, Delivery layers, inward…
Use when organising functions in a Go file, formatting signatures, designing return values, or naming Printf-style helpers. Covers in-file ordering (type → ctor → exported → unexported → utils), multi-line signature shape, naked-parameter clarity, pointer-vs-value receivers, and
$ npx -y skills add muratmirgun/gophers --skill go-functions --agent claude-codeHow it fires
How this skill gets triggered: by you, by Claude, or both.
/go-functionsContext preview
The summary Claude sees to decide when to auto-load this skill.
Use when organising functions in a Go file, formatting signatures, designing return values, or naming Printf-style helpers. Covers in-file ordering (type → ctor → exported → unexported → utils), multi-line signature shape, naked-parameter clarity, pointer-vs-value receivers, and
name: go-functions description: "Use when organising functions in a Go file, formatting signatures, designing return values, or naming Printf-style helpers. Covers in-file ordering (type → ctor → exported → unexported → utils), multi-line signature shape, naked-parameter clarity, pointer-vs-value receivers, and the `f`-suffix rule. Apply proactively to any new function. Functional options: see go-functional-options." license: MIT compatibility: "Designed for Claude Code or similar AI coding agents. Plain Go (any supported version)." allowed-tools: Read Edit Write Glob Grep Bash(go:*) Bash(golangci-lint:*)
A function's surface is read more often than its body. Optimize for the reader: predictable ordering in the file, signatures that scan, no hidden bool flags.
1. **Order by use, not alphabet.** Types → constructors → exported methods → unexported → utilities. 2. **Keep signatures on one line when reasonable.** When wrapping, every parameter on its own line with a trailing comma. 3. **Never pass `*Interface`.** Pass the interface value; the underlying data can already be a pointer. 4. **Replace naked `bool`/`int` parameters with named types** or add `/* name */` comments at call sites. 5. **Printf-style functions end in `f`** so `go vet` can check the format. 6. **Prefer `%q` over `%s` plus manual quoting** when formatting strings for errors and logs.
type Server struct{ ... }
func NewServer(...) *Server { ... } // constructor next to type
func (s *Server) Start(ctx context.Context) error { ... } // exported
func (s *Server) Stop() error { ... }
func (s *Server) acceptLoop() { ... } // unexported
func parseAddr(s string) (string, error) { ... } // file-local helperRules:
1. Types and their constructors sit together at the top. 2. Exported methods come before unexported ones. 3. File-local helpers go at the bottom. 4. Within a section, follow rough call order.
// Fits on one line — keep it on one line
func Sum(xs []int) int
// Too long — break with every param on its own line
func (r *Repo) SaveTransaction(
ctx context.Context,
userID string,
tx Transaction,
opts ...SaveOption,
) (string, error) {
...
}The trailing comma is required and `gofmt`-stable.
// Bad — what does `true` mean?
NewServer(":8080", true, 30, false)
// Better — call-site comments
NewServer(":8080", true /* tls */, 30 /* maxConn */, false /* readonly */)
// Best — named types or options
NewServer(":8080", WithTLS(), WithMaxConn(30))When a single bool is genuinely binary and obvious from the function name (`SetVerbose(true)`), it's fine.
> Read [references/signatures.md](references/signatures.md) for return-value styles, naked returns, function-as-parameter formatting, and the variadic-options call-site shape.
// Bad
func process(r *io.Reader) { ... }
// Good
func process(r io.Reader) { ... }An interface value already carries a pointer-sized data word. `*io.Reader` is a pointer to an interface — almost always a mistake.
Functions that accept a format string should end in `f`:
func Logf(format string, args ...any)
`go vet` then checks that `%s`, `%d`, etc. match the argument types.
When formatting strings into errors or logs, prefer `%q`:
return fmt.Errorf("unknown key %q", key) // unknown key "foo\nbar"`%q` quotes and escapes; `%s` plus manual quoting (`"key \"" + key + "\""`) is fragile.
> Read [references/printf-and-stringer.md](references/printf-and-stringer.md) for `%v` vs `%s` vs `%q`, implementing `fmt.Stringer` safely, avoiding `String()` infinite recursion, and `fmt.Formatter`.
db.Open(addr,
db.WithCache(false),
db.WithLogger(log),
db.WithRetries(3),
)Each option on its own line, trailing comma. Use this layout whenever the call doesn't fit on a single line.
A constructor immediately follows its type. Use the short form when no error is possible:
type Counter struct{ n int }
func NewCounter() *Counter { return &Counter{} }Return an error when construction can fail:
func NewClient(addr string) (*Client, error) { ... }Don't expose a half-built type through a constructor that "always succeeds" but requires `Init()` afterward.
| Anti-pattern | Why it hurts | Do this instead | |---|---|---| | Methods scattered randomly in the file | Hard to navigate | Group by type, exported-first | | Five-argument wrapped signature with no trailing comma | `gofmt` keeps reformatting | Trailing comma | | `func process(r *io.Reader)` | Pointer to interface | Pass `io.Reader` | | `Log(msg string, format bool, ...)` | Combines two concerns; `vet` blind | Separate `Log` and `Logf` | | `Open(":8080", true, false, 30)` | Unreadable booleans | Named options or `/* */` comments | | `fmt.Errorf("got %s", key)` for arbitrary key | Special chars unclear in output | `%q` | | Returning `*MyError` (concrete pointer) | Typed-nil interface trap | Return `error` |
26 production-grade Go skills for Claude Code, Gemini CLI, and opencode. Battle-tested patterns from the Go community — codified as triggerable AI skills.
Repo: muratmirgun/gophers
Use when scaffolding or refactoring a Go service into a framework-agnostic clean (hexagonal) architecture: Domain, Usecase, Repository, Delivery layers, inward…
Invoke this skill to systematically review a Go change against community style standards before merging. Walks the diff topic by topic — formatting, errors,…
Use when writing or reviewing Go code for clarity, formatting, control flow, variable declarations, switch usage, and function design. Covers the priority…
Use when writing or reviewing concurrent Go code — goroutines, channels, select, mutexes, atomics, errgroup, singleflight, worker pools, or fan-out/fan-in…
Use when designing, propagating, or debugging context.Context flow in Go — first-parameter placement, deadlines and cancellation, request-scoped values,…
Use when writing conditionals, loops, switches, type switches, or blank-identifier patterns in Go. Covers if-with-initialization, guard clauses, early returns,…