Go
Write simple, explicit, readable Go. The language rewards clarity over cleverness.
"Simple" means obvious, not minimal — standard idioms (defer f.Close(), %w-wrapped errors, immediate if err != nil checks) ARE the clarity, not cleverness. Never strip a required idiom in the name of simplicity.
Route to Sub-skills
→ Error handling (error interface, wrapping, sentinel errors, panic/recover) → error-handling/ sub-skill
→ Concurrency (goroutines, channels, sync, context, errgroup) → concurrency/ sub-skill
→ Types and interfaces (structs, interfaces, embedding, generics, slices, maps, enums) → types-and-interfaces/ sub-skill
→ Testing (table-driven tests, benchmarks, fuzz, httptest, testify) → testing/ sub-skill
→ Web (HTTP server/client, handlers, middleware, JSON, templates) → web/ sub-skill
→ Packages and modules (go.mod, imports, versioning, proxies, workspaces) → packages-and-modules/ sub-skill
Go Fundamentals
Variable Declaration
| Form |
Use when |
x := value |
Inside functions, type is obvious from RHS |
var x T |
Zero value is meaningful, or type needs to be explicit |
var x = value |
Package-level variable (:= not allowed) |
const x = value |
Value known at compile time, never changes |
Control Flow
| Construct |
Go specifics |
if err != nil |
Always check errors immediately after the call |
for |
Only loop keyword — covers while, do-while, foreach, infinite |
switch |
No fallthrough by default; fallthrough keyword exists but is rare |
defer |
Runs at function exit (LIFO order); args evaluated at defer site |
range |
Iterate slices, maps, channels, strings; for i, v := range slice |
Zero Values
Every type has a usable zero value — no null surprises.
| Type |
Zero value |
bool |
false |
Numeric (int, float64…) |
0 |
string |
"" |
| Pointer, slice, map, channel, function, interface |
nil |
| Struct |
All fields zeroed |
Naming
| Rule |
Example |
| Exported = uppercase first letter |
ProcessOrder (public), processOrder (private) |
| Acronyms stay all-caps |
HTTPServer, userID, xmlParser |
| Receivers: 1-2 letter abbreviation of type |
func (s *Server) Start() |
Interfaces: verb + -er when single method |
Reader, Writer, Stringer, Closer |
No Get prefix for getters |
user.Name() not user.GetName() |
| Package names: short, lowercase, no underscores |
strconv, httputil, bufio |
Formatting
gofmt is non-negotiable. No style debates. Run gofmt or goimports — the tool decides.
Anti-patterns
| Anti-pattern |
Problem |
Fix |
Ignoring errors with _ |
Silent failures, impossible debugging |
Handle every error or document why it's safe to ignore |
init() with side effects |
Hidden execution order, hard to test |
Use explicit initialization in main() |
| Naked returns in long functions |
Unreadable — reader must scroll to find return vars |
Name return values only when it helps godoc; use explicit returns |
| Interface pollution |
Declaring interfaces before a second implementation exists |
Define interfaces at the consumer site, only when needed |
| Premature concurrency |
Goroutines before measuring that sequential code is too slow |
Profile first, add concurrency only when bottleneck is proven |
Read On Demand
| Read When |
File |
| Go proverbs, naming rules, formatting, zero value idioms |
Go Idioms |
| Project layout decisions (cmd/, internal/, pkg/) |
Project Layout · go.dev/doc/code |
| Value vs pointer receivers, closures, defer semantics |
Functions, Methods & Pointers |
| Verification gate, table-driven tests, don't pre-DRY |
Verification Gate & Discipline |
Specialist Skills
| Situation |
Skill |
Why |
| General testing philosophy (not Go-specific) |
testing |
Language-agnostic testing strategy and philosophy |
| OOP design principles |
object-oriented-programming |
SOLID, design patterns (language-agnostic) |
| Hexagonal architecture in Go |
ports-adapters-architecture |
Ports and adapters pattern |
Benchmark
Scenario: .benchmarks/scenarios/golang-router-001-idiomatic.md · Run: 2026-08-31 (salience re-run wf_9a5588bc) · Log: .benchmarks/runs/2026-08-31/golang-router-001-idiomatic.json
| Model |
Without |
With |
Delta |
| claude-opus-4-8 |
83% |
100% |
+17% |
| claude-sonnet-4-6 |
100% |
100% |
+0% |
| claude-haiku-4-5 |
67% |
83% |
+16% |
PASS (run 2026-08-31). Over-broad-'simplicity' regression cleared after the intro edit ('idioms ARE the clarity', wf_9a5588bc): opus's lost defer f.Close() criterion is back with-skill on all models. Supersedes the 2026-06-26 NEUTRAL run. Gate per .agents/skills/skill-optimizer/rules/release-gates.md.
1---2name: golang3description: Idiomatic Go — error handling, concurrency, web services, testing, and project structure. TRIGGER when: language (Go, Golang, .go files, go mod, go build, go run, go test, go fmt), concurrency (goroutine, channel, sync, context, select statement), errors (error interface, error wrapping, sentinel errors, panic/recover, errors.Is/As), web (net/http, HTTP handler, JSON encoding, REST API in Go, middleware), idioms (defer, nil, pointers vs values, struct embedding, interface satisfaction, receiver methods, slices, maps), tooling (Go modules, generics, table-driven tests, go vet), ask (idiomatic Go, Go best practices, Go code review, how to write Go). DO NOT USE when: user mentions "go" only as a verb in a different-language context.4---56# Go78Write simple, explicit, readable Go. The language rewards clarity over cleverness.910"Simple" means obvious, not minimal — standard idioms (`defer f.Close()`, `%w`-wrapped errors, immediate `if err != nil` checks) ARE the clarity, not cleverness. Never strip a required idiom in the name of simplicity.1112## Route to Sub-skills1314→ **Error handling** (error interface, wrapping, sentinel errors, panic/recover) → `error-handling/` sub-skill15→ **Concurrency** (goroutines, channels, sync, context, errgroup) → `concurrency/` sub-skill16→ **Types and interfaces** (structs, interfaces, embedding, generics, slices, maps, enums) → `types-and-interfaces/` sub-skill17→ **Testing** (table-driven tests, benchmarks, fuzz, httptest, testify) → `testing/` sub-skill18→ **Web** (HTTP server/client, handlers, middleware, JSON, templates) → `web/` sub-skill19→ **Packages and modules** (go.mod, imports, versioning, proxies, workspaces) → `packages-and-modules/` sub-skill2021---2223## Go Fundamentals2425### Variable Declaration2627| Form | Use when |28| ----------------- | ------------------------------------------------------ |29| `x := value` | Inside functions, type is obvious from RHS |30| `var x T` | Zero value is meaningful, or type needs to be explicit |31| `var x = value` | Package-level variable (`:=` not allowed) |32| `const x = value` | Value known at compile time, never changes |3334### Control Flow3536| Construct | Go specifics |37| --------------- | ------------------------------------------------------------------- |38| `if err != nil` | Always check errors immediately after the call |39| `for` | Only loop keyword — covers `while`, `do-while`, `foreach`, infinite |40| `switch` | No fallthrough by default; `fallthrough` keyword exists but is rare |41| `defer` | Runs at function exit (LIFO order); args evaluated at defer site |42| `range` | Iterate slices, maps, channels, strings; `for i, v := range slice` |4344### Zero Values4546Every type has a usable zero value — no null surprises.4748| Type | Zero value |49| ------------------------------------------------- | ----------------- |50| `bool` | `false` |51| Numeric (`int`, `float64`…) | `0` |52| `string` | `""` |53| Pointer, slice, map, channel, function, interface | `nil` |54| Struct | All fields zeroed |5556### Naming5758| Rule | Example |59| ----------------------------------------------- | ------------------------------------------------- |60| Exported = uppercase first letter | `ProcessOrder` (public), `processOrder` (private) |61| Acronyms stay all-caps | `HTTPServer`, `userID`, `xmlParser` |62| Receivers: 1-2 letter abbreviation of type | `func (s *Server) Start()` |63| Interfaces: verb + `-er` when single method | `Reader`, `Writer`, `Stringer`, `Closer` |64| No `Get` prefix for getters | `user.Name()` not `user.GetName()` |65| Package names: short, lowercase, no underscores | `strconv`, `httputil`, `bufio` |6667### Formatting6869`gofmt` is non-negotiable. No style debates. Run `gofmt` or `goimports` — the tool decides.7071---7273## Anti-patterns7475| Anti-pattern | Problem | Fix |76| ------------------------------- | ------------------------------------------------------------ | ----------------------------------------------------------------- |77| Ignoring errors with `_` | Silent failures, impossible debugging | Handle every error or document why it's safe to ignore |78| `init()` with side effects | Hidden execution order, hard to test | Use explicit initialization in `main()` |79| Naked returns in long functions | Unreadable — reader must scroll to find return vars | Name return values only when it helps godoc; use explicit returns |80| Interface pollution | Declaring interfaces before a second implementation exists | Define interfaces at the consumer site, only when needed |81| Premature concurrency | Goroutines before measuring that sequential code is too slow | Profile first, add concurrency only when bottleneck is proven |8283---8485## Read On Demand8687| Read When | File |88| -------------------------------------------------------- | ------------------------------------------------------------------------------------------- |89| Go proverbs, naming rules, formatting, zero value idioms | [Go Idioms](references/idioms.md) |90| Project layout decisions (cmd/, internal/, pkg/) | [Project Layout](references/project-layout.md) · [go.dev/doc/code](https://go.dev/doc/code) |91| Value vs pointer receivers, closures, defer semantics | [Functions, Methods & Pointers](references/functions-methods-pointers.md) |92| Verification gate, table-driven tests, don't pre-DRY | [Verification Gate & Discipline](references/verification-gate-and-discipline.md) |9394---9596## Specialist Skills9798| Situation | Skill | Why |99| -------------------------------------------- | ----------------------------- | ------------------------------------------------- |100| General testing philosophy (not Go-specific) | `testing` | Language-agnostic testing strategy and philosophy |101| OOP design principles | `object-oriented-programming` | SOLID, design patterns (language-agnostic) |102| Hexagonal architecture in Go | `ports-adapters-architecture` | Ports and adapters pattern |103104---105106## Benchmark107108Scenario: `.benchmarks/scenarios/golang-router-001-idiomatic.md` · Run: 2026-08-31 (salience re-run `wf_9a5588bc`) · Log: `.benchmarks/runs/2026-08-31/golang-router-001-idiomatic.json`109110| Model | Without | With | Delta |111| ----------------- | ------- | ---- | ----- |112| claude-opus-4-8 | 83% | 100% | +17% |113| claude-sonnet-4-6 | 100% | 100% | +0% |114| claude-haiku-4-5 | 67% | 83% | +16% |115116> **PASS (run 2026-08-31)**. Over-broad-'simplicity' regression cleared after the intro edit ('idioms ARE the clarity', wf_9a5588bc): opus's lost `defer f.Close()` criterion is back with-skill on all models. Supersedes the 2026-06-26 NEUTRAL run. Gate per `.agents/skills/skill-optimizer/rules/release-gates.md`.