Skip to content
Development
Skill

/modern-go

Modernize Go code by applying version-appropriate idioms and APIs (gofix-style transformations). Scans go.mod for the Go version, then transforms Go source files to use modern patterns—from Go 1.0 through 1.26+. Use when the user says "现代化","现代Go语言", "地道的", "idiomatic",

From plugin
goal-workflow-skills
20717 skills
Install
$ npx -y skills add smallnest/goal-workflow --skill modern-go --agent claude-code

How it fires

How this skill gets triggered: by you, by Claude, or both.

  • Fires itselfAuto-invocation. Claude auto-loads it when your prompt matches the work.Auto-invocation is when the right skill fires by itself at the right moment, driven by a FLOW.md router and a hook, instead of you invoking it by name. It is the difference between a skill being installed and a skill actually getting used.Read the full definition →
  • You can call itInvoke it directly when you want it.
  • Slash command/modern-go

Context preview

The summary Claude sees to decide when to auto-load this skill.

Modernize Go code by applying version-appropriate idioms and APIs (gofix-style transformations). Scans go.mod for the Go version, then transforms Go source files to use modern patterns—from Go 1.0 through 1.26+. Use when the user says "现代化","现代Go语言", "地道的", "idiomatic",

SKILL.md

modern-go.SKILL.md
name: modern-go
description: Modernize Go code by applying version-appropriate idioms and APIs (gofix-style transformations). Scans go.mod for the Go version, then transforms Go source files to use modern patterns—from Go 1.0 through 1.26+. Use when the user says "现代化","现代Go语言", "地道的", "idiomatic",  "modernize", "modern-go", "update Go code", "gofix", or wants to upgrade Go idioms.

modern-go

Modernize Go source code by applying version-appropriate idioms, APIs, and language features. Works like `go fix` plus additional transformations curated from the Go team's modernize analysis passes and community best practices.

Usage

Invoke this skill when the user asks to modernize Go code. By default, modernize the entire project; the user may specify a file or directory instead.

When invoked: 1. Detect the project's Go version from `go.mod` (the `go` directive). 2. Find all `.go` files in the target scope (excluding `vendor/`, `.git/`, `testdata/`). 3. For each file, apply **all transformations for versions ≤ the project's Go version**, starting from the oldest to the newest. 4. After all transformations, print a summary of what was changed and what was skipped.

If the user specifies a file or directory, limit the scope to that path.

Transformation Catalog

Each transformation includes a **Go version** gate—only apply when the project's `go.mod` version ≥ that version. Never apply a transformation that requires a version higher than the project declares.

Go 1.0+ — `time.Since`

| Before | After | |---|---| | `time.Now().Sub(start)` | `time.Since(start)` |

// before
elapsed := time.Now().Sub(start)
// after
elapsed := time.Since(start)

Go 1.8+ — `time.Until`

| Before | After | |---|---| | `deadline.Sub(time.Now())` | `time.Until(deadline)` |

// before
remaining := deadline.Sub(time.Now())
// after
remaining := time.Until(deadline)

Go 1.10+ — `strings.Builder` (loop concatenation)

| Before | After | |---|---| | `s += item` in a loop | `var b strings.Builder; b.WriteString(item)` |

// before
s := ""
for _, item := range items {
    s += item
}
// after
var b strings.Builder
for _, item := range items {
    b.WriteString(item)
}
s := b.String()

Only when `+=` concatenation happens inside a loop.

Go 1.13+ — `errors.Is`

| Before | After | |---|---| | `err == io.EOF` | `errors.Is(err, io.EOF)` |

// before
if err == io.EOF {
    return
}
// after
if errors.Is(err, io.EOF) {
    return
}

Go 1.17+ — `//go:build` constraints (plusbuild)

| Before | After | |---|---| | `// +build linux` + `//go:build linux` (both present) | keep only `//go:build linux` |

// before
//go:build linux && amd64
// +build linux,amd64

package foo
// after
//go:build linux && amd64

package foo

The `plusbuild` modernizer removes obsolete `// +build` constraint lines once the equivalent `//go:build` line is present (the `//go:build` syntax landed in Go 1.17). Only strip the old line when a matching `//go:build` already exists — never drop the sole constraint.

Go 1.17+ — `unsafe.Add` / `unsafe.Slice` (unsafefuncs)

| Before | After | |---|---| | `unsafe.Pointer(uintptr(ptr) + uintptr(n))` | `unsafe.Add(ptr, n)` | | `(*[n]T)(unsafe.Pointer(p))[:]` slice construction | `unsafe.Slice(p, n)` |

// before — pointer arithmetic via uintptr
p2 := unsafe.Pointer(uintptr(ptr) + uintptr(offset))
// after
p2 := unsafe.Add(ptr, offset)
// before — building a slice from a base pointer
s := (*[1 << 30]byte)(unsafe.Pointer(p))[:n:n]
// after
s := unsafe.Slice(p, n)

The `unsafefuncs` modernizer (gopls v0.22.0) rewrites error-prone `uintptr` pointer math into `unsafe.Add` / `unsafe.Slice`, which the compiler and `go vet` understand as GC-safe.

Go 1.18+ — `any`

| Before | After | |---|---| | `interface{}` | `any` |

// before
func decode(v interface{}) error { ... }
// after
func decode(v any) error { ... }

Go 1.18+ — `strings.Cut`

| Before | After | |---|---| | `i := strings.Index(s, sep); ... s[:i], s[i+len(sep):]` | `key, val, found := strings.Cut(s, sep)` |

// before
if i := strings.Index(s, "="); i >= 0 {
    key, val := s[:i], s[i+1:]
}
// after
if key, val, found := strings.Cut(s, "="); found {
    ...
}

Go 1.18+ — `bytes.Cut`

| Before | After | |---|---| | `i := bytes.Index(b, sep); ... b[:i], b[i+len(sep):]` | `before, after, found := bytes.Cut(b, sep)` |

// before
if i := bytes.Index(b, sep); i >= 0 {
    before, after := b[:i], b[i+len(sep):]
}
// after
before, after, found := bytes.Cut(b, sep)

Go 1.19+ — `fmt.Appendf`

| Before | After | |---|---| | `buf = append(buf, fmt.Sprintf(...)...)` | `buf = fmt.Appendf(buf, ...)` |

// before
buf = append(buf, fmt.Sprintf("x=%d", x)...)
// after
buf = fmt.Appendf(buf, "x=%d", x)

Go 1.19+ — Type-safe atomics (atomictypes)

| Before | After | |---|---| | `atomic.StoreInt32(&v, 1)` / `atomic.LoadInt32(&v)` | `var v atomic.Int32; v.Store(1); v.Load()` | | `atomic.AddInt64(&v, 1)` | `var v atomic.Int64; v.Add(1)` | | `atomic.Value` + type assertion | `atomic.Pointer[T]` |

// before
var ready int32
atomic.StoreInt32(&ready, 1)
if atomic.LoadInt32(&ready) == 1 { ... }

// after
var ready atomic.Int32
ready.Store(1)
if ready.Load() == 1 { ... }
// before
var cache atomic.Value
cache.Store(&Config{})
cfg := cache.Load().(*Config)

// after
var cache atomic.Pointer[Config]
cache.Store(&Config{})
cfg := cache.Load()

The `atomictypes` modernizer (gopls v0.22.0, `AtomicTypesAnalyzer`) rewrites both the variable declaration and every call site. Typed wrappers (`atomic.Int32/Int64/Uint32/Uint64/Bool/Pointer[T]`) have identical performance but prevent accidental non-atomic access and fix 64-bit alignment crashes on 32-bit architectures.

Go 1.20+ — `strings.Clone`

| Before | After | |---|---| | `string([]byte(s))` | `strings.Clone(s)` |

// before
s2 := string([]byte(s)) // force
Read more
Ships withgoal-workflow-skills

An AI-driven development workflow — from PRD to shipped code, all within Claude Code.

Get the whole plugin
Stats
213
Stars
30
Forks
Active
Maintenance
HTML
Language
MIT
License
1d ago
Last commit
2mo ago
Created

Repo: smallnest/goal-workflow

Other skills on goal-workflow-skills.