| name | modern-golang-skill |
| description | Claude-optimized modern Go engineering skill, fused from the JetBrains Go modernize guidelines (54 version-tagged idioms), an idiomatic-Go pattern catalog (23 design patterns), the Go 1.26/1.27 release-feature notes, and two design theories: the APOSD/CS190 philosophy ("is this design good to change?") and the CSE 331 correctness engineering ("how do I know the code is right?"). Teaches version-aware idiomatic Go (reach for the stdlib first: slices.*, maps.*, errors.Is / errors.AsType, range-over-int, any, clear, min/max, cmp.Or, wg.Go), modern module/dependency layout, tooling (gofmt / go vet / golangci-lint), and concurrency/error/context correctness. Use when the user writes, reviews, refactors, modernizes, or debugs Go code; asks about Go idioms, go.mod/module layout, interfaces, goroutine/error/context patterns, stdlib replacement, or go test/benchmarks; asks what changed in recent Go (1.26/1.27); or asks "is this design good to change" / "can I prove this code is right" on a Go codebase. Bilingual triggers: "写 Go", "Go 教程", "学 Go", "Go 评审", "golang", "go vet", "go.mod", "改造成现代 Go", "Go 升级". Make sure to use this skill whenever the user mentions these even if they do not ask for the skill by name — Claude under-triggers. Backed by the bundled JetBrains modernize guidelines, the ECC idiom-pattern catalog, the Go 1.26/1.27 release notes, and the bundled APOSD + CSE 331 design-theory references. Outputs: modernized Go code with per-idiom Before/After, a code-review report (design smells + correctness invariants), a scaffolded module, and a version-feature answer with GODEBUG/GOEXPERIMENT escape hatches. ALSO use whenever a Go codebase has stale idioms (hand-rolled search loops, interface{}, err == target), module/ dependency-pinning, concurrency questions, or correctness/design concerns (a loop with no stated invariant, a broken subtype, a leaked representation), even if the user does not name Go. Do NOT use for non-Go languages or generic (non-Go) architecture review. |
modern-golang-skill
Reference / engineering catalog, fused from five layers: Go idioms (JG), Go design
patterns (ECC), Go 1.26/1.27 release features (GL), APOSD design philosophy, and CSE 331
correctness. Not a linear tutorial — each concern is a catalog loaded on demand. Version-
aware: idioms are filtered to the project's actual Go version before any rewrite. Three
lenses ride together: write modern Go, design it well (APOSD), prove it right (CSE 331).
Purpose
A reference/engineering catalog for modern Go: idiomatic, version-aware code; clean,
changeable design; and code you can actually prove correct. It is consulted on demand, by
concern, rather than read front to back. Use the knowledge-dispatch table below to pick the
reference, then reach for the specific concern. The inline core rules give just enough to
reason without loading a reference; the references hold the full teaching.
Philosophy (condensed)
Write modern Go.
- stdlib-first: replace a manual search loop,
if chain, nil check, or boilerplate helper
with the stdlib symbol that names the operation — slices.*, maps.*, errors.Is,
cmp.Or, min/max, clear, strings.Cut.
- newest idiom your target version supports: filter each idiom to
Since Go X.Y ≤ target.
- write intent, not mechanics; honor the guarded rules (e.g. prefer
encoding/json/v2
only for new code; guard any migration).
Design it well (APOSD lens).
- complexity = dependencies + obscurity; complexity is incremental and zero-tolerance.
- deep module, information hiding: small interface, large implementation; the interface
must not leak the implementation.
- define errors away: design so certain errors cannot occur, rather than handling them.
Prove it right (CSE 331 lens).
- a function of moderate complexity needs a stated spec (pre/post + modifies); a loop needs
an invariant + a variant.
- an ADT needs a representation invariant (RI) + abstraction function (AF), must not leak
its representation, and a subtype must preserve behavior (LSP).
The full APOSD and CSE 331 teaching lives in design-theory.md
and correctness.md; SKILL.md carries only the summary above.
Version resolution (the critical step)
Before you rewrite or judge anything, determine the project's Go version, in order:
go.mod go directive.
go.work go directive.
- local toolchain (
/usr/local/go/VERSION, or go env GOTOOLCHAIN).
- else the requested/pinned version or
--go-version.
Then filter every idiom to Since Go X.Y ≤ target. Go 1.27 is the primary target; Go
1.26 is the prior-major / backward-compat layer — never present a 1.26 feature as newest. A
module pinned to an older go directive makes a newer idiom a compile error, so respect the
pin (see gotchas.md language-version gating). When a symbol is
marked [VERIFY] in version-features.md, confirm it at
go.dev/doc/go1.26 before teaching it as 1.26.
Knowledge dispatch
| Concern | Reference | Reach for it when |
|---|
| Write / modernize a Go function | idioms.md | replacing a loop, manual scan, if chain, or boilerplate helper; the Before/After + Since Go X.Y. |
| Design a package, error handling, interfaces | patterns.md | designing package/interface shape, error wrapping/typed errors, worker pool, context, errgroup, options. |
| What changed in recent Go | version-features.md | a 1.26/1.27 feature is named, or a release question; GODEBUG/GOEXPERIMENT escape hatches. |
| Tooling / verification | tooling.md | gofmt/goimports, go vet, go test flags, golangci-lint, the JetBrains modernize CLI, go fix. |
| Module, dependency, version gating | gotchas.md | go.mod/go.work, MVS, pinning (replace/exclude/toolchain/GOTOOLCHAIN), migration watchlist. |
| Is this design good to change? | design-theory.md | design review, refactor judgment, the 14 principles + 13 APOSD smells, design-it-twice. |
| How do I know this code is right? | correctness.md | spec/contract, Hoare/wp, loop invariant+variant, ADT RI/AF, representation exposure, LSP, property tests. |
| Final pass before ship | review-checklist.md | the unified exit gate: Part A Go regressions, Part B APOSD smells, Part C CSE 331 flags, Part D tooling. |
| Scaffold a new module | scripts/new-module.sh |
Workflow (phases)
- Scaffold — if new,
scripts/new-module.sh <module-path> --go=<ver>. Confirm the
go.mod go directive matches the target version.
- Write — write the code against the target version's idioms; reach into idioms.md /
patterns.md for the concern.
- Modernize — apply the idioms from the inline core, from the version tag downward
(
Since Go X.Y ≤ target), using idiomatic Before/After.
- Verify — run
scripts/fmt-vet-test.sh (default dry-run; --race for concurrency),
then scripts/bench.sh if performance matters.
- Review — apply both lenses: the APOSD smells from design-theory.md (is it good to
change?) and the CSE 331 invariants from correctness.md (is it right?), then reconcile
against review-checklist.md the second lens is done.
- Learn/Upgrade — when a new Go minor ships, re-derive the feature reference; check
migration watchlist items and GODEBUG removals in version-features.md, and re-reconcile
review-checklist.md Part D.
Inline core rules
Enough to reason without loading a reference; every entry lives fully in the file linked.
Since Go X.Y is source-of-truth in idioms.md.
Idioms (stdlib-first) — full Before/After in idioms.md
for i := range n — range over int; replaces for i := 0; i < n; i++ (1.22) — range_over_int
any — replaces interface{} (1.18) — any
errors.Is(err, t) — replaces err == t across wrapping (1.13) — errors_is
errors.AsType[T](err) — replaces errors.As + target var (1.26, [VERIFY]) — errors_as_type
slices.Contains(a, x) — membership test (1.21) — slices_contains
slices.Index / slices.IndexFunc — index search (1.21) — slices_index
slices.Sort / slices.SortFunc + cmp.Compare — replaces sort.Ints / sort.Slice (1.21) — slices_sort, slices_sort_func
slices.Clone / bytes.Clone / strings.Clone — copy (1.21) — slices_clone
slices.Max / slices.Min — replaces hand-written max/min (1.21) — slices_max_min
maps.Clone(m) / maps.Copy(dst, src) — map copy (1.21) — maps_clone, maps_copy
maps.DeleteFunc(m, f) — delete by predicate (1.21) —
Go design one-liners — patterns.md
- zero value is useful: make the zero value a usable state — core-principles
- accept interfaces, return structs — decouple callers from the concrete type
- wrap errors with
%w; never ignore an error; check with errors.Is/errors.As, never ==
- worker pool:
wg.Go (1.25+) collapses Add/go/Done boilerplate
- context for cancellation/timeouts; errgroup for coordinated goroutines; avoid goroutine leaks (
select on ctx.Done())
- small, focused interfaces; define them where used; avoid package-level mutable state; preallocate slices when size is known
Design one-liners (APOSD) — design-theory.md
- complexity = dependencies + obscurity
- deep module: small interface, large implementation; interface must not leak implementation
- define errors away: make certain errors impossible, not just handled
- design twice for a non-trivial interface, then choose or fuse
Correctness one-liners (CSE 331) — correctness.md
- a function of moderate complexity needs a stated spec (pre/post + modifies)
- a loop needs an invariant + a variant (proves termination)
- an ADT needs RI + AF,
NewX is the RI gate, and it must not leak representation
- a subtype must preserve behavior (LSP), not just structure
Report / exit format
Every review/refactor ends with a fixed report skeleton; fill every field, and say "N/A"
where it does not apply.
背景 → 目标/版本 → 现状分析 → 改进/新设计 → 验证与权衡 → 行动项
- 背景: what the code or change is for.
- 目标/版本: the target Go version (see Version resolution) and what "modern" means there.
- 现状分析: each smell / invariant violation, why it matters, and the reference that flags it.
- 改进/新设计: the fix or new design, with Before/After code.
- 验证与权衡: what you ran (gate, tests, bench) and what you gave up.
Correctness-verification section (required whenever you claim a function/loop/ADT is correct):
- Spec assumed: state the pre/post conditions and modifies clause you assumed for the
function, and where they came from (doc comment, caller contract, or a stated assumption).
- Loop invariant + variant: state the invariant that holds before each iteration and the
variant that is non-negative and decreases each step, and how together they prove the loop
reaches its postcondition.
- How checked: whether by hand (Hoare / weakest-precondition), by property test
(
testing/quick / rapid / fuzzing), by go test -race, or by go vet -copylocks; name
the check actually run.
- ADT: state the RI and AF, confirm
NewX is the only RI gate, and confirm no internal
mutable reference is returned (a representation-exposure check).
Exit gate — the work is done only when all three hold:
scripts/fmt-vet-test.sh passes (default dry-run; --race for concurrency code).
references/review-checklist.md — Part A/B/C all "no", Part D all pass.
- State the Go version used (e.g.
go.mod go 1.27, toolchain 1.27.x).
Scripts invocation
Absolute paths, runnable from anywhere. All default to dry-run or read-only except where noted.
/home/ares/.claude/skills/modern-golang-skill/scripts/fmt-vet-test.sh [--race] [--apply] [package...]
(default package ./...). Gates gofmt -l, go vet, go build, go test; --race adds
-race; --apply writes (gofmt -w/goimports -w), default is dry-run. stdout: one
PASS:/FAIL: per check + a final RESULT: line; exit 0 only if all pass.
/home/ares/.claude/skills/modern-golang-skill/scripts/bench.sh [package]
(default ./...). Runs go test -bench=. -benchmem -run='^$', emits BENCH <name> <ns/op> <B/op> <allocs/op> rows + RESULT: OK; nonzero if go test cannot compile/run.
/home/ares/.claude/skills/modern-golang-skill/scripts/new-module.sh <module-path> [--go=1.27] [--dir=<out>] [--apply] [--force]
scaffolds from assets/ (go.mod, Makefile, README, .golangci.yml,
cmd/<name>/main.go, one _test.go). Dry-run by default; prints CREATE/WOULD CREATE;
refuses overwrite without --force.
When to reach for the sub-resources
- "write a modern Go function" → idioms.md (Before/After +
Since Go X.Y).
- "design a package / error handling / interfaces / worker pool" → patterns.md.
- "did Go change this / what's new in 1.26 or 1.27" → version-features.md.
- "run gofmt / go vet / go test / golangci-lint / modernize" → tooling.md.
- "go.mod / go.work / dependency pinning / version gating" → gotchas.md.
- "is this design good to change / should I refactor this" → design-theory.md.
- "is this code correct / prove this loop or ADT / LSP / representation leak" → correctness.md.
- "final pass before I ship" → review-checklist.md.
Provenance
Each reference carries its source tag; the fused exit gate (review-checklist.md) combines all.