AgentStack
SKILL verified Apache-2.0 Self-run

Google Go Style

skill-cicdteam-google-go-style-google-go-style · by cicdteam

Use when writing, reviewing, or refactoring Go code; when handling errors (fmt.Errorf, %w, sentinel, errors.Is, errors.As); when deciding between panic, error return, and log.Fatal; when writing tests (table-driven, t.Helper, t.Fatal vs t.Error, goroutines); when designing API surface (option struct, variadic options, channel direction, context); when naming functions, methods, packages, receiver…

No reviews yet
0 installs
17 views
0.0% view→install

Install

$ agentstack add skill-cicdteam-google-go-style-google-go-style

✓ scanned · ✓ verified — works with Claude Code, Cursor, and more.

Security review

✓ Passed

No issues found. Passed automated security review. · v0.1.0 How review works →

  • Prompt-injection patterns
  • Secret / credential exfiltration
  • Dangerous shell & filesystem operations
  • Untrusted network calls
  • Known-malicious package signatures

What it can access

  • Network access No
  • Filesystem access No
  • Shell / process execution No
  • Environment & secrets No
  • Dynamic code execution No

From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.

Are you the author of Google Go Style? Claim this listing to set pricing, connect Stripe payouts, and keep 70% of every sale.
Sign up to claim

About

Google Go Style — Skill

Derived from the Google Go Style Guide, © Google LLC, licensed CC-BY 3.0. This skill is a derivative digest, not a verbatim reproduction.

Codifies the Google Go Style Guide (canonical + normative + best-practices) into actionable rules.

The full guide is large. This file holds only what should be in your head on every Go change. For deeper rules, load the matching references/*.md. For unusual situations, WebFetch the source — the guide is normative.

Quick Rules

Apply on every line of Go you write or review.

Naming

  • No Get prefix on getters. User(), not GetUser(). Exception: the underlying concept is "get" (HTTP GET).
  • Don't repeat the package name in identifiers. bytes.Buffer, not bytes.BytesBuffer. widget.New, not widget.NewWidget.
  • Receiver names: 1–2 letters, abbreviation of the type, consistent across all methods. Never this, self, me, or _ (unless unused). func (c *Config), not func (config *Config).
  • Initialisms keep one case. URL, ID, HTTP, DB. Exported: UserID, ServeHTTP. Unexported: userID, urlPath. Never Url, Id, Http.
  • Test doubles end in Stub / Fake / Spy / Mock (or describe behaviour: AlwaysCharges, AlwaysDeclines).
  • No util / common / helper / model package names. They invite import renames at every call site. Name by what the package provides.
  • No underscores in identifiers (except *_test.go test/benchmark/example names, and packages imported only by generated code).
  • Local variable scope ↔ name length. i, c, db for tight loops; userCount, pollInterval for file scope. Don't drop letters to save typing (Sandbox, not Sbx).

Errors

  • fmt.Errorf("doing X: %w", err) — wrap with %w at the end, so the chain prints newest→oldest as outer: middle: inner.
  • %w only when callers need errors.Is / errors.As on the underlying error. Otherwise use %v.
  • %w at the start is for sentinel wrappers only: fmt.Errorf("%w: invalid header", ErrParse). Category first, details after.
  • Sentinel name: ErrFoo at package level: var ErrNotFound = errors.New("not found").
  • Don't duplicate context the underlying error already carries. os.Open errors already include the path — fmt.Errorf("could not open settings.txt: %v", err) is wrong; use a higher-level annotation: fmt.Errorf("launch codes unavailable: %v", err).
  • Don't add bare "failed: %v" wrappers. They add no information; just return err.
  • Either log it or return it — not both. Pick one. Letting the caller log avoids spam.
  • Error strings: lowercase, no trailing punctuation, no \n. fmt.Errorf("something bad happened"), not "Something bad happened.".
  • Cross-process boundaries (gRPC/RPC): use canonical codes via status.Errorf(codes.X, ...) rather than wrapping internal errors raw with %w.
  • error is the last return value. A function taking context.Context should usually return error.

For more, see references/errors.md.

Panics

  • Don't panic for normal error handling. Return error and multiple return values.
  • log.Fatal over panic for terminal conditions in main / init. Fatal does not run deferred functions; that's the point.
  • Panics never cross package boundaries in public APIs. Convert to error at the API edge with a top-level defer recover() that re-panics on unknown payloads.
  • MustX is for package-level vars and tests only. MustParse, template.Must. Not for runtime user input.
  • Don't recover() to suppress crashes. Corrupted state propagates further; better is monitoring + crash + fix.
  • panic("unreachable") after log.Fatalf is the idiom — the compiler doesn't know Fatal doesn't return.

For more, see references/panics.md.

Tests

  • No assertion libraries / helpers (assert.Equal, require.NotNil). Use if got != want { t.Errorf(...) }. For complex types: cmp.Equal / cmp.Diff from go-cmp.
  • t.Error over t.Fatal by default — keep going, report all failures in one run. t.Fatal only when continuing is meaningless (setup failed, cascading errors would mislead).
  • Inside t.Run subtests: use t.Fatal to skip just that case. Outside subtests in a table loop: t.Error + continue.
  • NEVER call t.Fatal (FailNow, Fatalf, SkipNow) from a goroutine other than the test's own. Use t.Error from worker goroutines; t.Fatal only after wg.Wait() from the main goroutine.
  • **Table-driven tests use named struct fields**, not positional: {name: "empty", input: "", want: ""}.
  • Test helpers that fail setup call t.Helper() + t.Fatalf. This makes the failure point to the test line, not the helper line.
  • Failure message format: YourFunc(%v) = %v, want %v — function name, inputs, got, want, in that order.

For more, see references/tests.md.

Variables and strings

  • := for non-zero init, var x T for zero values. i := 42, but var coords Point (not coords := Point{}).
  • var t []string, not t := []string{} for empty slices. Empty slice and nil slice behave the same for len, cap, range, append.
  • new(T) vs &T{}: both are fine for zero values; new reads as "zero value placeholder", &T{} is more common when fields are filled.
  • Never == on nil for slices. Use len(s) == 0. APIs must not distinguish nil from empty.
  • Strings: + for 2–3 short literals; fmt.Sprintf for formatting; strings.Builder in loops; text/template for templates.
  • Pre-size with make([]T, 0, n) / make(map[K]V, n) only when n is known and the code is performance-sensitive. Default to zero-init.
  • No shadowing in nested scopes. if *x { ctx, cancel := ...; } shadows ctx outside the if. Use ctx, cancel = ... with = and var cancel func() declared above.

For more, see references/strings-and-vars.md.

API design

  • context.Context is the first parameter. func F(ctx context.Context, ...) error. Even in test helpers.
  • Never store context.Context in a struct. Pass it through every method that needs it.
  • No global mutable state. Pass dependencies through constructors / function parameters (DI).
  • Take interfaces, return concrete types. The consumer of an interface defines it, not the implementer.
  • Channel direction in signatures. <-chan T for receive-only, chan<- T for send-only.
  • Many parameters → option struct (call site reads as labelled fields). 3+ optional / API expected to grow → option struct. Don't put context.Context in option structs.
  • Variadic functional options (...Option) only when most callers pass nothing, options need parameters, or third parties define options.
  • Avoid *string, *io.Reader parameters "to save bytes". Pass values; use pointers for large structs and protobuf messages.

For more, see references/api-design.md.

Documentation

  • Doc comments are full sentences starting with the symbol's name. // Encode writes the JSON encoding of req to w.
  • Document WHY, not WHAT. The code already says what.
  • Document significant sentinel errors and error types the function returns.
  • Document cleanup contracts (Close, Stop, deferred resources).
  • Document concurrency-safety only when non-obvious (read-only methods are assumed safe; mutating ones are assumed unsafe — say so when that doesn't hold).
  • Don't document that ctx.Done cancels the function — that's the contract of context.Context.

For more, see references/documentation.md.

Package layout

  • internal/ for packages not part of the public API.
  • Avoid util / common / helper. Name by domain.
  • Imports grouped: stdlib / third-party / proto / blank-side-effect. Blank imports only in main or tests.
  • No import . ever (in Google codebase).
  • Proto imports get a pb suffix: foopb "path/to/foo_go_proto".

For more, see references/package-layout.md.

Decision Matrices

%v vs %w when wrapping an error

| Situation | Choose | Why | |---|---|---| | Caller will errors.Is / errors.As to inspect the chain | %w | Preserves type/sentinel through the chain | | Crossing an external boundary (RPC, IPC, storage); caller wants canonical codes | %v (or status.Errorf) | Don't leak internal error types over the wire | | Logging or human-display only; no programmatic inspection | %v | %w adds chain semantics nobody uses | | Same error is logged here AND returned upward | %v | Wrapping a logged-then-returned error confuses the chain | | Sentinel categorisation first (ErrParse-style) | %w at start: "%w: detail" | Reader sees the category first | | Adding context around a wrapped error (the common case) | %w at end: "context: %w" | Chain prints newest→oldest naturally: outer: middle: inner | | Underlying error already carries this info | nothing — return err | Wrapping without adding info is noise | | Just propagating without analysis | nothing — return err | Don't wrap for the sake of wrapping |

Function arguments: positional vs option struct vs variadic options

| Situation | Choose | Why | |---|---|---| | ≤ 3 parameters, all required, all distinct types | Positional args | Smallest mechanism | | Many parameters, most callers set most of them | Option struct (last param) | Self-documenting field names; grows without breaking call sites | | Many parameters, most callers set none | Variadic options (...Option) | Zero overhead at simple call sites | | Options need failure validation | Variadic options returning error | Can't validate in struct construction | | Third-party packages must define options | Variadic options with exported Option type | Struct fields can't be extended | | Same option set used by multiple functions | Option struct | Reuse + share + write helpers on the struct | | context.Context | First positional arg, never in option struct | Convention |

panic vs log.Fatal vs error return

| Situation | Choose | Why | |---|---|---| | Library detects normal failure | error return | Caller decides | | Library detects an "impossible" invariant violation | error return or log.Fatal | Caller can't recover anyway | | Bad flag/config in main / init | log.Exit (no stack) | Stack trace useless; user wants the message | | Internal package consistency check that has been verified by tests | log.Fatal | More reliable than panic (no defer deadlock risk) | | Parser internals that always have a matching recover at the API edge | panic of a private type | Plumbing errors through deep recursion is noise | | Package-level var initializer needs a value derived from a fallible call | MustX (panics) | Init-time only; init cannot return errors | | HTTP handler crashes mid-request | never recover() to mask it | State is corrupted; let the process crash and restart |

t.Error vs t.Fatal vs t.Errorf + continue

| Situation | Choose | |---|---| | Multiple independent assertions in one Test*, all should run | t.Error / t.Errorf for each | | Setup failure — rest of test cannot proceed | t.Fatal / t.Fatalf | | First failure makes subsequent assertions misleading (e.g. encoded ≠ expected, can't decode meaningfully) | t.Fatalf then continue with t.Errorf | | Table loop without subtests, this case is broken | t.Errorf + continue | | Inside t.Run(...) subtest, this case is broken | t.Fatal (skips this subtest only) | | Worker goroutine inside a test | t.Errorf only (NEVER t.Fatal) | | Test helper called from main test goroutine | t.Helper() + t.Fatalf is fine |

Variable declaration form

| Situation | Choose | Example | |---|---|---| | Initializing with a known non-zero value | := | i := 42 | | Need a zero value, ready for use | var x T | var coords Point, var s []string | | Need a *T to a zero value | new(T) or &T{} | msg := new(pb.Bar) | | Need a *T to a value with fields | &T{...} | c := &Config{Port: 8080} | | Empty slice for return / accumulation | var s []T | not s := []T{} | | Empty map (must be initialized to write) | make(map[K]V) or map[K]V{} | nil map can be read but not written | | Pre-sized slice/map (perf-sensitive, size known) | make([]T, 0, n) / make(map[K]V, n) | Don't over-pre-allocate |

Reference Files

Load on demand:

  • references/errors.md — detailed error structure, wrapping rules, sentinels, RPC boundaries, errors.Is/As.
  • references/naming.md — receivers, initialisms, repetition, test doubles, util-package antipattern, shadowing.
  • references/api-design.md — option struct vs variadic options, channel direction, DI, interfaces, generics.
  • references/tests.md — Test funcs vs helpers, table-driven, subtests, goroutines, acceptance testing, cmp.
  • references/panics.md — when allowed (invariants, parsers with recover, init), when forbidden, log.Fatal vs log.Exit.
  • references/documentation.md — godoc conventions, what to document, what to skip, contexts, errors, cleanup.
  • references/package-layout.md — package size, file structure, imports, internal/, side-effect imports.
  • references/strings-and-vars.md — concatenation choices, zero values, size hints, new vs &T{}, shadowing.

Authoritative Sources

When in doubt, especially for unusual situations, WebFetch the source section before writing the code. The Google Go Style Guide is the normative authority — this skill is a digest, not a replacement.

  • https://google.github.io/styleguide/go/index — overview, normativity definitions
  • https://google.github.io/styleguide/go/guide — canonical + normative core principles
  • https://google.github.io/styleguide/go/decisions — normative detailed decisions
  • https://google.github.io/styleguide/go/best-practices — non-normative patterns and discussions

For Go fundamentals not covered here, read Effective Go.

Source & license

This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.

Install and usage instructions live in the source repository linked above.

Reviews

No reviews yet — be the first.

Versions

  • v0.1.0 Imported from the upstream source.