go-core-idioms

SkillMonitoring & ops

Use when writing or reviewing idiomatic sequential Go — error handling, slog logging, generics, interfaces, style. Not for concurrency (go-concurrency).

Available today. Use it from your connected AI after setup.

Connect ahel once, and every AI you use reads what you have installed.

Then ask your AI: use the go-core-idioms skill

What this skill tells your AI

The instructions your AI receives, as published by fusengine/agents in plugins/go-expert/skills/go-core-idioms/SKILL.md and read by ahel’s review.

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:

  1. fuse-ai-pilot:explore-codebase - Map existing error/logging/interface patterns
  2. fuse-ai-pilot:research-expert - Verify latest Go docs via Context7/Exa
  3. mcp__context7__query-docs - Confirm stdlib signatures (errors, log/slog)

After implementation, run fuse-ai-pilot:sniper for validation.


Overview

FeatureDescription
Error handlingExplicit if err != nil, %w wrapping, errors.Join, errors.AsType (1.26)
Structured logginglog/slog stdlib — handlers, attrs, groups, LogValuer
GenericsType params, constraints, self-referential types (1.26)
InterfacesSmall, consumer-side — "accept interfaces, return structs"
Modernizersgo fix auto-applies dozens of idiom/API fixers (1.26)

Critical Rules

  1. Explicit if err != nil - No sugar exists; never discard with _ = err
  2. Wrap with %w, not %v - Preserves the chain for errors.Is/As/AsType
  3. Accept interfaces, return structs - Define interfaces where consumed, not where produced
  4. Value receivers by default - Use pointer receivers only for mutation or large structs
  5. 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

TopicReferenceWhen to Consult
Error handlingerror-handling.mdWrapping, sentinels, errors.Join, AsType
Structured loggingslog-logging.mdChoosing handlers, attrs, groups, perf
Generics & 1.26generics-and-1.26.mdType params, self-ref types, new(expr)
Interfaces & styleinterfaces-and-style.mdInterface placement, naming, receivers

Templates

TemplateWhen to Use
error-patterns.mdBuilding an error strategy for a package
slog-setup.mdWiring 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

Signals

GitHub stars
27
Forks
4
Last commit
Sep 2026
Advanced
Catalog kind
skill
Gateway key
go-core-idioms
Source
github.com/fusengine/agents