# Google Go Style

> 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…

- **Type:** Skill
- **Install:** `agentstack add skill-cicdteam-google-go-style-google-go-style`
- **Verified:** Yes — security-reviewed for prompt injection and unsafe behavior
- **Seller:** [cicdteam](https://agentstack.voostack.com/s/cicdteam)
- **Installs:** 0
- **Category:** [Developer Tools](https://agentstack.voostack.com/c/developer-tools)
- **Latest version:** 0.1.0
- **License:** Apache-2.0
- **Upstream author:** [cicdteam](https://github.com/cicdteam)
- **Source:** https://github.com/cicdteam/google-go-style/tree/main/plugins/google-go-style/skills/google-go-style

## Install

```sh
agentstack add skill-cicdteam-google-go-style-google-go-style
```

Requires the [AgentStack CLI](https://agentstack.voostack.com/docs/cli). Works with Claude Code, Cursor, and any MCP-compatible agent.

## About

# Google Go Style — Skill

_Derived from the [Google Go Style Guide](https://google.github.io/styleguide/go/), © Google LLC, licensed [CC-BY 3.0](https://creativecommons.org/licenses/by/3.0/). This skill is a derivative digest, not a verbatim reproduction._

Codifies the [Google Go Style Guide](https://google.github.io/styleguide/go) (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](https://go.dev/doc/effective_go).

## Source & license

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

- **Author:** [cicdteam](https://github.com/cicdteam)
- **Source:** [cicdteam/google-go-style](https://github.com/cicdteam/google-go-style)
- **License:** Apache-2.0

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

## Pricing

- **Free** — Free

## Security capabilities

Automated source analysis of v0.1.0 — what this tool can access:

- **Network access:** no
- **Filesystem access:** no
- **Shell / process execution:** no
- **Environment & secrets:** no
- **Dynamic code execution:** no

*"Yes" means the capability is present in the source — more access means more to trust, not that it is unsafe.*


## Versions

- **0.1.0** — security scan: passed — Imported from the upstream source.

## Links

- Listing page: https://agentstack.voostack.com/l/skill-cicdteam-google-go-style-google-go-style
- Seller: https://agentstack.voostack.com/s/cicdteam
- Browse the marketplace: https://agentstack.voostack.com/browse

---
Listed on AgentStack — the marketplace for AI agent skills and MCP servers. Every listing is security-reviewed. Creators keep 70%.
