go-clean-architecture
Use when scaffolding or refactoring a Go service into a framework-agnostic clean (hexagonal) architecture: Domain, Usecase,…
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
Claude Code
$ npx -y skills add muratmirgun/gophers --skill go-functions --agent claude-code
Codex
$ npx skills add muratmirgun/gophers --skill go-functions -a codex -y
Cursor
$ npx skills add muratmirgun/gophers --skill go-functions -a cursor -y
Gemini CLI
$ npx skills add muratmirgun/gophers --skill go-functions -a gemini-cli -y
GitHub Copilot
$ npx skills add muratmirgun/gophers --skill go-functions -a github-copilot -y
OpenCode
$ npx skills add muratmirgun/gophers --skill go-functions -a opencode -y
Windsurf
$ npx skills add muratmirgun/gophers --skill go-functions -a windsurf -y
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.
Use when scaffolding or refactoring a Go service into a framework-agnostic clean (hexagonal) architecture: Domain, Usecase,…
Invoke this skill to systematically review a Go change against community style standards before merging. Walks the diff topic by…
Use when writing or reviewing Go code for clarity, formatting, control flow, variable declarations, switch usage, and function…
Use when writing or reviewing concurrent Go code — goroutines, channels, select, mutexes, atomics, errgroup, singleflight, worker…
Use when designing, propagating, or debugging context.Context flow in Go — first-parameter placement, deadlines and cancellation,…
Use when writing conditionals, loops, switches, type switches, or blank-identifier patterns in Go. Covers if-with-initialization,…
You MUST use this before any creative work - creating features, building components, adding functionality, modifying behavior, or…
Ask which skill or flow fits your situation. A router over the skills in this repo.