Go Core Idioms
Idiomatic sequential Go for 1.26. For anything touching goroutines, channels,
errgroup, or context cancellation, use go-concurrency instead.
Agent Workflow (MANDATORY)
Before ANY implementation, spawn 3 agents in parallel, one Agent call each with a name:
- fuse-ai-pilot:explore-codebase - Map existing error/logging/interface patterns
- fuse-ai-pilot:research-expert - Verify latest Go docs via Context7/Exa
- mcp__context7__query-docs - Confirm stdlib signatures (errors, log/slog)
After implementation, run fuse-ai-pilot:sniper for validation.
Overview
| Feature |
Description |
| Error handling |
Explicit if err != nil, %w wrapping, errors.Join, errors.AsType (1.26) |
| Structured logging |
log/slog stdlib — handlers, attrs, groups, LogValuer |
| Generics |
Type params, constraints, self-referential types (1.26) |
| Interfaces |
Small, consumer-side — "accept interfaces, return structs" |
| Modernizers |
go fix auto-applies dozens of idiom/API fixers (1.26) |
Critical Rules
- Explicit
if err != nil - No sugar exists; never discard with _ = err
- Wrap with
%w, not %v - Preserves the chain for errors.Is/As/AsType
- Accept interfaces, return structs - Define interfaces where consumed, not where produced
- Value receivers by default - Use pointer receivers only for mutation or large structs
- Run
go fix + go vet - Let modernizers migrate to current idioms (1.26)
Architecture
internal/
├── user/
│ ├── user.go # struct + value-receiver methods
│ ├── errors.go # sentinel + typed errors
│ └── repository.go # consumer-side interface, concrete struct returned
└── platform/
└── logging/
└── logger.go # slog setup, one *slog.Logger injected downward
→ See error-patterns.md for full example
Reference Guide
Concepts
| Topic |
Reference |
When to Consult |
| Error handling |
error-handling.md |
Wrapping, sentinels, errors.Join, AsType |
| Structured logging |
slog-logging.md |
Choosing handlers, attrs, groups, perf |
| Generics & 1.26 |
generics-and-1.26.md |
Type params, self-ref types, new(expr) |
| Interfaces & style |
interfaces-and-style.md |
Interface placement, naming, receivers |
Templates
| Template |
When to Use |
| error-patterns.md |
Building an error strategy for a package |
| slog-setup.md |
Wiring a structured logger into an app |
Quick Reference
Wrap and inspect errors
if err != nil {
return fmt.Errorf("load user %d: %w", id, err) // %w keeps the chain
}
// 1.26: type-safe, generic replacement for errors.As
if pathErr, ok := errors.AsType[*fs.PathError](err); ok {
log.Printf("failed path: %s", pathErr.Path)
}
→ See error-handling.md
Structured logging with slog
logger := slog.New(slog.NewJSONHandler(os.Stdout, nil))
logger.Info("user created", "id", id, slog.Duration("took", elapsed))
→ See slog-logging.md
Best Practices
DO
- Keep interfaces one-to-three methods, named at the call site
- Add context on the way up with
%w; check with errors.Is/AsType
- Use
slog.LogAttrs on hot paths to avoid allocation
- Run
go fix to adopt current APIs and idioms automatically (1.26)
DON'T
- Swallow errors (
_ = err) or return bare err when context helps
- Define interfaces next to their implementation "just in case"
- Reach for pointer receivers without a mutation or size reason
- Write Java-esque getters/setters or
IFoo interface prefixes
1---2name: go-core-idioms3description: Use when writing or reviewing idiomatic sequential Go — error handling, slog logging, generics, interfaces, style. Not for concurrency (go-concurrency).4---56<objective>7Covers idiomatic sequential Go 1.26: error handling (%w wrapping, errors.Join,8errors.Is/As, errors.AsType), slog structured logging, generics, small9consumer-side interfaces, naming/style conventions, new(expr), and go fix10modernizers. Does not cover goroutines/channels/errgroup/context concurrency11(see go-concurrency), non-Go languages, or framework-specific code.12</objective>1314# Go Core Idioms1516Idiomatic sequential Go for 1.26. For anything touching goroutines, channels,17`errgroup`, or `context` cancellation, use **go-concurrency** instead.1819## Agent Workflow (MANDATORY)2021Before ANY implementation, spawn 3 agents in parallel, one `Agent` call each with a `name`:22231. **fuse-ai-pilot:explore-codebase** - Map existing error/logging/interface patterns242. **fuse-ai-pilot:research-expert** - Verify latest Go docs via Context7/Exa253. **mcp__context7__query-docs** - Confirm stdlib signatures (errors, log/slog)2627After implementation, run **fuse-ai-pilot:sniper** for validation.2829---3031## Overview3233| Feature | Description |34|---------|-------------|35| **Error handling** | Explicit `if err != nil`, `%w` wrapping, `errors.Join`, `errors.AsType` (1.26) |36| **Structured logging** | `log/slog` stdlib — handlers, attrs, groups, `LogValuer` |37| **Generics** | Type params, constraints, self-referential types (1.26) |38| **Interfaces** | Small, consumer-side — "accept interfaces, return structs" |39| **Modernizers** | `go fix` auto-applies dozens of idiom/API fixers (1.26) |4041---4243## Critical Rules44451. **Explicit `if err != nil`** - No sugar exists; never discard with `_ = err`462. **Wrap with `%w`, not `%v`** - Preserves the chain for `errors.Is`/`As`/`AsType`473. **Accept interfaces, return structs** - Define interfaces where consumed, not where produced484. **Value receivers by default** - Use pointer receivers only for mutation or large structs495. **Run `go fix` + `go vet`** - Let modernizers migrate to current idioms (1.26)5051---5253## Architecture5455```56internal/57├── user/58│ ├── user.go # struct + value-receiver methods59│ ├── errors.go # sentinel + typed errors60│ └── repository.go # consumer-side interface, concrete struct returned61└── platform/62 └── logging/63 └── logger.go # slog setup, one *slog.Logger injected downward64```6566→ See [error-patterns.md](references/templates/error-patterns.md) for full example6768---6970## Reference Guide7172### Concepts7374| Topic | Reference | When to Consult |75|-------|-----------|-----------------|76| **Error handling** | [error-handling.md](references/error-handling.md) | Wrapping, sentinels, `errors.Join`, `AsType` |77| **Structured logging** | [slog-logging.md](references/slog-logging.md) | Choosing handlers, attrs, groups, perf |78| **Generics & 1.26** | [generics-and-1.26.md](references/generics-and-1.26.md) | Type params, self-ref types, `new(expr)` |79| **Interfaces & style** | [interfaces-and-style.md](references/interfaces-and-style.md) | Interface placement, naming, receivers |8081### Templates8283| Template | When to Use |84|----------|-------------|85| [error-patterns.md](references/templates/error-patterns.md) | Building an error strategy for a package |86| [slog-setup.md](references/templates/slog-setup.md) | Wiring a structured logger into an app |8788---8990## Quick Reference9192### Wrap and inspect errors9394```go95if err != nil {96 return fmt.Errorf("load user %d: %w", id, err) // %w keeps the chain97}98// 1.26: type-safe, generic replacement for errors.As99if pathErr, ok := errors.AsType[*fs.PathError](err); ok {100 log.Printf("failed path: %s", pathErr.Path)101}102```103104→ See [error-handling.md](references/error-handling.md)105106### Structured logging with slog107108```go109logger := slog.New(slog.NewJSONHandler(os.Stdout, nil))110logger.Info("user created", "id", id, slog.Duration("took", elapsed))111```112113→ See [slog-logging.md](references/slog-logging.md)114115---116117## Best Practices118119### DO120- Keep interfaces one-to-three methods, named at the call site121- Add context on the way up with `%w`; check with `errors.Is`/`AsType`122- Use `slog.LogAttrs` on hot paths to avoid allocation123- Run `go fix` to adopt current APIs and idioms automatically (1.26)124125### DON'T126- Swallow errors (`_ = err`) or return bare `err` when context helps127- Define interfaces next to their implementation "just in case"128- Reach for pointer receivers without a mutation or size reason129- Write Java-esque getters/setters or `IFoo` interface prefixes