Standards go
Use this skill when writing or reviewing Go code or making Go architecture and API design decisions. Provides idiomatic Go patterns, error handling, resource management, generics, and design pattern guidance.From its SKILL.md
npx -y skills add pecigonzalo/agent-skills --skill standards-goAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
2 things to look at
- 28 days oldThe repository was created 28 days ago. New is not bad, but a brand new repository carrying a familiar-sounding name is the shape a typosquat arrives in, and there has been no time for anyone else to find a problem with it.
- 0 stars0 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
SKILL.md
16.0 KB, ~3.7k tokens by cl100k_base, as published. Nobody here has run it
Go Standards
Provides: Idiomatic Go patterns, error handling, resource management, naming/package conventions, API/type design, and lightweight Go-specific pattern guidance. For concurrency, testing, and performance, load dedicated subskills.
Primary references:
Quick Reference
Golden Rule: Explicit is better than implicit; clarity beats cleverness
Style principles (priority order):
| Principle | Key question |
|---|---|
| Clarity | Can a reader understand what and why? |
| Simplicity | Is this the simplest approach? |
| Concision | Is the signal-to-noise ratio high? |
| Maintainability | Can this be safely modified later? |
| Consistency | Does this match surrounding code? |
Do:
- Run
gofmt/goimportson every save - Use MixedCaps for identifiers; avoid underscores (except test names and rare low-level interop)
- Return
errorlast; wrap with%w; check witherrors.Is/errors.As(1.13+) deferrelease immediately after acquisition- Pass
context.Contextas the first argument to blocking calls - Accept interfaces, return concrete types
- Design zero values to be usable
- Prefer standard helpers available in your Go version (
slices,maps,cmp,min/max) - Use
anyinstead ofinterface{}when unconstrained (1.18+)
Don't:
- Hand-align code or use underscores in identifiers
- Stutter exported names (
bufio.BufReader→ usebufio.Reader) - Discard errors with
_silently - Store
context.Contextin structs - Use
panicas flow control - Use dot imports outside tests
- Name packages
util,common, orhelpers - Use
init()for anything beyond simple side-effect-free registration - Use naked returns in non-trivial functions
- Define interfaces in consumers, not implementations
- Use bare
string/intcontext keys - Use
http.NewRequestfor outbound calls that must respect a deadline: usehttp.NewRequestWithContext
Key commands (only when needed):
go test ./... # baseline validation
go test -race ./... # when touching concurrency
go mod tidy # when deps changed
Formatting & Tooling
- Use
goimports(orgofmt) on save; CI should reject unformatted files. - Use
go vet ./...in CI. - Use
golangci-lintas the unified linter runner when configured. - Keep
//go:generatedeterministic; track generator tool dependencies viatools.go+//go:build toolswhen needed. - Keep import groups simple: stdlib, external, internal (enforced by
goimports). - Restrict blank imports (
_) to real side-effect registration use cases.
Code Style
Reduce Nesting
Handle error cases and special conditions first; return early or continue to keep the happy path unindented.
Local Consistency
When multiple styles are acceptable and no rule applies, match the style of the surrounding file/package. Do not introduce a second convention without a strong reason.
Least Mechanism
Prefer the simplest tool that works:
- core language constructs (struct/slice/map/channel)
- standard library
- well-adopted libraries
Add dependencies and abstraction only when they clearly improve correctness, simplicity at call sites, or performance.
Control Flow Idioms
ifwith initializer: scope short-lived variables to the block:if err := file.Chmod(0664); err != nil { return err }.:=redeclaration rule: a variable in the same scope can reappear on the left of:=if at least one other variable is new. Shadowing trap::=in an inner scope creates a new variable: the outer one is silently unchanged.rangeover strings iterates runes (not bytes):for i, r := range syields Unicode code points;iis the byte offset.- Switch: no implicit fallthrough; expression-less switch (
switch { case cond: }) switches ontrue; comma-separated cases share a body; use labeled break to exit an enclosing loop from within a switch.
Reduce Scope of Variables
Declare variables as close as possible to their use. Prefer if/switch initializers to keep temporary values scoped to the block, and avoid pre-declaring var x far above where it is used.
Raw String Literals
Use raw string literals (backticks) to avoid hand-escaped strings: `unknown error:"test"` instead of "unknown error:\"test\"".
Naming & Packages
- Package names: lowercase, single word, matches directory name. Avoid
util,common,helpers,misc. - Exported names must not stutter:
http.Clientnothttp.HTTPClient;bufio.Readernotbufio.BufReader. - Use MixedCaps (camelCase / PascalCase) for identifiers; no underscores. Exceptions:
Test*/Benchmark*/Example*in*_test.go; low-level OS/cgo interop. - Getters named as the field:
Owner()notGetOwner(); setters:SetOwner(v). UseCompute/Fetchfor expensive operations. - Single-method interfaces: suffix with
-er(io.Reader,http.Handler); define at point of use, not in the implementing package. - Doc comments on every exported symbol:
// FunctionName does X.
Documentation (godoc)
- Comment style: Start with the name being documented; use a full sentence. Example:
// A Request represents a request to run a command. - Package comment: Every package needs exactly one; place it in
doc.gofor large packages. - Parameters / config: Document only non-obvious behavior and edge cases.
- Context cancellation: Implied: document only when behavior differs.
- Concurrency: Read-only operations are assumed safe; mutating assumed unsafe. Add a note only when ambiguous.
- Cleanup: Always state when the caller must release a resource.
- Errors: Document sentinel errors and custom error types: use pointer form (
*PathError) forerrors.Astargets. - Godoc formatting: Blank line between paragraphs; indent code blocks by two extra spaces.
Initialisms and Acronyms
Initialisms (URL, ID, HTTP, etc.) must be cased uniformly: ParseURL,
HTTPClient, userID. Avoid mixed forms like userId or ParseUrl.
Avoid Predeclared Names
Do not name variables, parameters, fields, or methods after Go's predeclared identifiers (error, string, int, len, make, new, close). Shadowing creates subtle bugs.
Avoiding Repetition
Names should not feel redundant when read in full context. Consider the package qualifier, receiver type, and surrounding code: widget.New() not widget.NewWidget(); db.Load() not db.LoadFromDatabase().
API & Type Design
Read the API and type design guide when designing exported APIs, interfaces, constructors, options, or type sets.
Project Structure
cmd/myapp/main.go # Minimal: wire dependencies and call into internal packages
internal/ # Private packages; cannot be imported by external modules
pkg/ # Public library code (optional; omit if all consumers are internal)
api/ # API definitions (OpenAPI specs, protobuf files)
configs/ # Configuration files
testdata/ # Test fixtures; ignored by go build
- Keep
mainpackages thin: business logic belongs ininternal/. - Prefer
internal/overpkg/unless you intentionally publish an importable API. testdata/is the conventional home for golden files, fixtures, and fuzz corpora.
File Organization
- Group declarations:
import (...), thenconst (...),var (...),type (...)when related. - Keep functions grouped by receiver; keep exported APIs first.
- Place constructors (
NewT/newT) right after the type definition, before methods. - Keep plain helper functions (no receiver) near the end of the file.
Build constraints and workspaces
- Use
//go:buildsyntax (not legacy// +build). - Use
go workin multi-module repos when local cross-module iteration is needed; avoid committinggo.workwhen modules are independently versioned.
Error Handling
- Return
erroras the last return value. Never discard with_without an explanatory comment. - Wrap errors for context:
fmt.Errorf("open config: %w", err). Use%w(not%v) so callers can unwrap. - Check wrapped errors with
errors.Isanderrors.As(orerrors.AsTypeif available in your project Go version). - Sentinel errors: declare as package-level vars (
var ErrFoo = errors.New("foo")) so callers can match without string comparison. - Combine multiple errors with
errors.Join(err1, err2)(1.20+) instead of manual concatenation. - Custom error types: define struct types when callers need structured
fields; unwrap with
errors.As. panicis program-fatal. Userecoveronly at package or handler boundaries (e.g., HTTP middleware). Never use panic/recover as a substitute for returning errors.
Return the error Interface, Not a Concrete Type
Always return the error interface from exported functions. Returning a concrete type (e.g., *os.PathError) creates a typed-nil trap: a nil pointer compares non-nil as an interface value.
Error Strings
Error strings should be lowercase and should not end with punctuation. Exception: capitalize when beginning with an exported name or proper noun.
Avoid In-Band Errors
Do not use magic sentinel values (-1, "", nil) to signal failure. Use multiple return values: func Lookup(key string) (string, bool) or func Parse(key string) (int, error).
Indent Error Flow
Handle errors first and return early; do not put the normal path in an else branch. Avoid if x, err := f(); err != nil { ... } else { use x }: declare x separately when it lives beyond a few lines.
%v vs %w
- Use
%wfor internal propagation where callers may match/unwrap. - Use
%vat service boundaries where you intentionally hide internals.
Handle Errors Once
Each error must be handled exactly once. Never log and return the same error.
| Strategy | When to use |
|---|---|
| Wrap and return | Caller is better positioned to handle it |
| Log and degrade | The error is non-fatal; execution can continue |
| Match and handle | You can recover from specific conditions; return others |
if err := db.QueryRow(ctx, q, id).Scan(&u); err != nil {
if errors.Is(err, sql.ErrNoRows) {
return nil, ErrNotFound
}
return nil, fmt.Errorf("get user %s: %w", id, err)
}
init() Rules
Avoid init(): prefer an explicit initialization function called by main(). When unavoidable (e.g., database/sql driver registration), init() must be: completely deterministic, free of ordering dependencies, must not read env vars or os.Args, and must not perform I/O.
Exit and log.Fatal
Call os.Exit or log.Fatal* only in main(). All other functions must return errors. Prefer the run() error pattern:
func main() {
if err := run(); err != nil {
log.Fatal(err)
}
}
func run() error {
// ... business logic returning errors ...
return nil
}
Resource Management
deferrelease immediately after acquisition:f, err := os.Open(name); if err != nil { ... }; defer f.Close().- Deferred call arguments are evaluated at the
deferstatement, not at call time. - Pass
context.Contextas the first argument to blocking/cancellable functions. Do not store context in structs. - Check errors from
Close()on write paths (e.g.,gzip.Writer,bufio.Writer).
Context Patterns
- No custom context types. Always accept
context.Context; embedding extra methods breaks composability. - Data placement order: function parameters → receiver fields → package-level globals → context values. Context values are only for request-scoped, cross-cutting data (request IDs, trace IDs, auth tokens).
- Context immutability: safe to pass the same
ctxto multiple sequential or concurrent calls. context.Background(): only at program entry points (main, top-level goroutines, tests). Everywhere else, accept and forwardctx.- Always
defer cancel()immediately after deriving a context. - Use
http.NewRequestWithContext(neverhttp.NewRequest) so outbound requests respect the caller's deadline.
Typed context keys: never use bare string or int as a key:
// Unexported type scoped to this package: impossible for other packages to collide
type contextKey string
const (
requestIDKey contextKey = "requestID"
userIDKey contextKey = "userID"
)
func WithRequestID(ctx context.Context, id string) context.Context {
return context.WithValue(ctx, requestIDKey, id)
}
func RequestID(ctx context.Context) (string, bool) {
id, ok := ctx.Value(requestIDKey).(string)
return id, ok
}
Generics (1.18+)
Use generics to remove true type-parameterized duplication; do not reach for them by default.
- Prefer concrete types and small interfaces first.
- Use minimal constraints (
any,comparable, or narrow union constraints). - Avoid generic data structures unless they provide clear ergonomic or correctness benefits beyond stdlib helpers.
- Do not use
anywhere an interface better expresses behavior.
Modern Go by Version
Check project Go version first (go.mod). Prefer modern stdlib functionality
available in that version.
High-value defaults to prefer when available:
slices/maps/cmphelpers over manual loops and boilerplatemin/max,clear, and other builtins over ad-hoc patterns- improved context/test APIs (
With*Cause,t.Context(), etc.) - modern loop and ServeMux idioms in newer Go versions
High-value examples often not auto-fixed by modernize:
- API boundaries: use
slices.Clone/maps.Cloneto avoid aliasing mutable caller state. - HTTP routing: use method-aware
http.ServeMuxpatterns andr.PathValuewhere supported. - Cancellation semantics: prefer
context.WithTimeoutCause/context.WithDeadlineCausewhen error attribution matters. - Tests/benchmarks: use
t.Context()andb.Loop()when your Go version supports them. - WaitGroup ergonomics: prefer
wg.Go(fn)in newer Go versions.
When uncertain about version behavior, verify with official Go release notes.
Skill Loading Triggers
| Situation | Also load |
|---|---|
| Writing any Go code | standards-code |
| Writing Go tests, benchmarks, fuzz tests | standards-go-testing, standards-testing |
| Goroutines, channels, sync, context patterns | standards-go-concurrency |
| Profiling, tracing, allocation, GC tuning | standards-go-performance, standards-observability |
| Auth, secrets, user input, crypto | standards-security |
| Implementing features/fixes (TDD) | role-developer |
| API/package/service design | role-architect |
| Go PR review | role-code-review |
Verification Checklist
- No formatting/lint/vet failures (prefer repo task runner; use
golangci-lintwhen configured) - Required tests pass
- Concurrency changes were race-checked when goroutines/sync were touched
- Dependency metadata is clean when dependencies changed
Note: file list is sampled.
What ships with it: 1 file
7.8 KB alongside SKILL.md
references/
- api-and-type-design.md7.8 KB
Gives 0 of the 12 instructions most architecture codebase skills give in ~3.7k tokens
Counted across 811 of the 1,134 authors here whose files we hold, read 2026-08-07
- Ask the user which candidate to explorein 45 of 811, across 15 files
- Apply the deletion test to suspected shallow modulesin 43 of 811, across 15 files
- Read any relevant architecture decision records firstin 31 of 811, across 8 files
- Use exact glossary terms in every suggestionin 30 of 811, across 10 files
- Accept dependencies instead of creating themin 24 of 811, across 5 files
- Include before and after visualisations for each candidatein 24 of 811, across 5 files
- Read the domain glossary before exploringin 24 of 811, across 6 files
- Return results instead of producing side effectsin 23 of 811, across 4 files
- Explore the codebase for shallow modules and frictionin 23 of 811, across 3 files
- Introduce seams only where things varyin 22 of 811, across 3 files
- Reduce the number of methodsin 21 of 811, across 2 files
- Design deep modules with small interfacesin 21 of 811, across 3 files
Said here and by no other author read
- run gofmt on every save
- return errors as the last value
- wrap errors with percent w
- defer resource release immediately after acquisition
- accept interfaces and return concrete types
- return early to reduce nesting
Grouped from the skills themselves: near-identical wordings counted once, and counted by distinct author, so one author publishing three of these counts once. Length counted with cl100k_base; the agent that loads this file may tokenize it differently.