diff --git a/.claude-plugin/plugin.json b/.claude-plugin/plugin.json
index e14a947..01bd009 100644
--- a/.claude-plugin/plugin.json
+++ b/.claude-plugin/plugin.json
@@ -1,6 +1,6 @@
{
"name": "go-coding",
- "version": "0.2.1",
+ "version": "0.3.0",
"description": "Idiomatic Go coding standards for AI assistants — formatting, errors, concurrency, testing, layout.",
"author": {
"name": "Cadasto B.V.",
diff --git a/.cursor-plugin/plugin.json b/.cursor-plugin/plugin.json
index 96dc804..56068c8 100644
--- a/.cursor-plugin/plugin.json
+++ b/.cursor-plugin/plugin.json
@@ -1,6 +1,6 @@
{
"name": "go-coding",
- "version": "0.2.1",
+ "version": "0.3.0",
"description": "Idiomatic Go coding standards for AI assistants — formatting, errors, concurrency, testing, layout.",
"author": {
"name": "Cadasto B.V.",
diff --git a/AGENTS.md b/AGENTS.md
index 0cc41c5..795aab5 100644
--- a/AGENTS.md
+++ b/AGENTS.md
@@ -6,7 +6,7 @@ This file provides guidance to AI coding assistants (Claude Code, Cursor, and co
The **Go Coding Plugin** is an AI plugin by Cadasto B.V. that teaches AI coding assistants **idiomatic Go coding standards** — formatting, naming, error handling, concurrency, testing, and project layout — through skills, commands, agents, hooks, and Cursor rules. It targets **both Claude Code and Cursor** from a single shared component set.
-> **Current status — v0.2.0.** A complete dual-host (Claude Code + Cursor) Go-standards set that validates clean (`./scripts/validate.sh` + `claude plugin validate .`): the auto-invoked `go-coding` **router** skill; the focused standards skills `go-errors`, `go-concurrency`, `go-testing`, `go-idioms`, `go-linting`, `go-layout`; the read-only `go-reviewer` agent; the user-invoked `/go-explain` and `/go-lint-setup` skills; a shipped `references/golangci.v2.yml`; the `rules/go-context.mdc` Cursor rule; and host-agnostic `session-start` + `format-on-save` hooks. Do not assume a file is present because it is documented here — check first.
+> **Current status — v0.3.0.** A complete dual-host (Claude Code + Cursor) Go-standards set, baselined on **Go 1.26** (1.26.4+) with version-gated guidance that still holds for 1.25 modules, that validates clean (`./scripts/validate.sh` + `claude plugin validate .`): the auto-invoked `go-coding` **router** skill; the focused standards skills `go-errors`, `go-concurrency`, `go-testing`, `go-idioms`, `go-linting`, `go-layout`; the read-only `go-reviewer` agent; the user-invoked `/go-explain` and `/go-lint-setup` skills; a shipped `references/golangci.v2.yml`; the `rules/go-context.mdc` Cursor rule; and host-agnostic `session-start` + `format-on-save` hooks. Do not assume a file is present because it is documented here — check first.
## Domain Context
diff --git a/CHANGELOG.md b/CHANGELOG.md
index d316228..e55b4e2 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -7,6 +7,21 @@ The format is based on Keep a Changelog, and this project adheres to Semantic Ve
- Keep a Changelog: https://keepachangelog.com/en/1.1.0/
- Semantic Versioning: https://semver.org/spec/v2.0.0.html
+## [0.3.0] - 2026-07-01
+
+Retargets the standards baseline to **Go 1.26** (1.26.4+) while keeping version-gated guidance valid for 1.25 modules.
+
+### Added
+- Skills: `go-idioms` — `new(expr)` row (Go 1.26 pointer/optional-field initialization) and a note on self-referencing generic type parameters.
+- Skills: `go-testing` — `testing/cryptotest.SetGlobalRandom` for deterministic crypto tests (Go 1.26); note that the pre-1.25 `GOEXPERIMENT=synctest` (`synctest.Run`) API was removed in Go 1.26.
+- Skills: `go-concurrency` — experimental `goroutineleak` profile in `runtime/pprof` (Go 1.26) as a toolchain-native complement to `goleak`.
+
+### Changed
+- Skills / agent / Cursor rule: standards baseline moved from Go 1.25 to **Go 1.26** in `go-coding`, `go-idioms`, `go-linting`, `go-explain`, the `go-reviewer` agent, and `rules/go-context.mdc`; all keep working against 1.25 modules via the `Since`/`go.mod` version-gating already in `go-idioms`.
+- Skills: `go-idioms`, `go-linting`, `go-coding`, `rules/go-context.mdc` — frame `go fix ./...` as the canonical modernizer runner on Go 1.26 (rewritten atop the analysis framework), with `golangci-lint --enable-only=modernize` for CI reproducibility and older toolchains.
+- Docs: `docs/install.md` and `README.md` — minimum host toolchain raised to **Go 1.26.x** (1.26.4+); tarball example updated to `go1.26.4`; `gopls` pin moved to `v0.22.x` (the line that adds Go 1.26 support).
+- Manifests: `version` → `0.3.0` in both `.claude-plugin/plugin.json` and `.cursor-plugin/plugin.json`.
+
## [0.2.1] - 2026-06-18
### Added
diff --git a/README.md b/README.md
index 1d6b571..ac91ca9 100644
--- a/README.md
+++ b/README.md
@@ -15,7 +15,7 @@ Or from a local working copy: `claude plugin add /path/to/go-coding-plugin`.
**Cursor**: add this repository as a plugin (Settings → Plugins). See [`docs/install.md`](docs/install.md) for both hosts.
-**Prerequisites** — the plugin installs without a Go toolchain, but its hooks and enforcement guidance expect **Go 1.25.x** plus `gofmt`, `gofumpt`, `goimports`, and `gopls` on the host `PATH`. See [Host toolchain (minimal requirements)](docs/install.md#host-toolchain-minimal-requirements) for what each tool drives and copy-paste install commands.
+**Prerequisites** — the plugin installs without a Go toolchain, but its hooks and enforcement guidance expect **Go 1.26.x** (minimum 1.26.4; still works against 1.25 modules) plus `gofmt`, `gofumpt`, `goimports`, and `gopls` on the host `PATH`. See [Host toolchain (minimal requirements)](docs/install.md#host-toolchain-minimal-requirements) for what each tool drives and copy-paste install commands.
## Component surface
diff --git a/agents/go-reviewer.md b/agents/go-reviewer.md
index bdc9a17..587735c 100644
--- a/agents/go-reviewer.md
+++ b/agents/go-reviewer.md
@@ -43,7 +43,7 @@ tools:
- Bash
---
-You are **go-reviewer**, a reviewer of idiomatic, correct Go (Go 1.25, golangci-lint v2). You supply
+You are **go-reviewer**, a reviewer of idiomatic, correct Go (Go 1.26, works with 1.25+; golangci-lint v2). You supply
the judgment a linter cannot — the bugs and smells that survive `gofmt`, `go vet`, and
`golangci-lint`. You are **read-only**: you report findings, you never edit code.
@@ -94,8 +94,9 @@ the judgment a linter cannot — the bugs and smells that survive `gofmt`, `go v
non-atomic reads of those fields); `sync.Mutex`/`WaitGroup` copied by value; a map written
concurrently without a lock; check-then-act races.
- **Stale modernization debt** — code `modernize`/`go fix` would rewrite (range-int, `min`/`max`,
- `slices`/`maps`, `strings.Cut`, `cmp.Or`, pre-1.22 loop-var copies). Low severity; point at
- `golangci-lint run --enable-only=modernize`.
+ `slices`/`maps`, `strings.Cut`, `cmp.Or`, pre-1.22 loop-var copies; on Go 1.26 modules also
+ pointer-helper temps that `new(expr)` replaces). Low severity; point at `go fix ./...` (Go 1.26) or
+ `golangci-lint run --enable-only=modernize`. Gate suggestions on the module's `go.mod` version.
- **slog hot-path waste** — building a per-call logger instead of `logger.With(...)`; formatting or
allocating before a level check; key-value variadic on a hot path instead of `slog.LogAttrs`.
diff --git a/docs/install.md b/docs/install.md
index ec7e35b..9ad021c 100644
--- a/docs/install.md
+++ b/docs/install.md
@@ -41,51 +41,51 @@ Add this repository as a plugin (Cursor **Settings → Plugins**, via Git URL or
## Host toolchain (minimal requirements)
-Installing the plugin itself needs no Go toolchain — it is pure Markdown + JSON. But its **enforcement** layer only delivers value when the standard Go tools are on the host `PATH`: the `format-on-save` hook shells out to a formatter, the golangci-lint v2 reference config lists `gofumpt`/`goimports` as formatters, and the recommended official `gopls-lsp` plugin (`@claude-plugins-official`) drives `gopls`. The plugin targets **Go 1.25** + golangci-lint v2.
+Installing the plugin itself needs no Go toolchain — it is pure Markdown + JSON. But its **enforcement** layer only delivers value when the standard Go tools are on the host `PATH`: the `format-on-save` hook shells out to a formatter, the golangci-lint v2 reference config lists `gofumpt`/`goimports` as formatters, and the recommended official `gopls-lsp` plugin (`@claude-plugins-official`) drives `gopls`. The plugin targets **Go 1.26** + golangci-lint v2, and its version-gated idiom guidance still works against 1.25 modules.
At minimum the host should provide:
| Tool | Provided by | Used for | If missing |
|------|-------------|----------|------------|
-| **Go 1.25.x** | [go.dev/dl](https://go.dev/dl/) / package manager | everything; satisfies `go.mod` `go 1.25.x` | no toolchain at all |
+| **Go 1.26.x** (min 1.26.4) | [go.dev/dl](https://go.dev/dl/) / package manager | everything; satisfies `go.mod` `go 1.26.x` (and 1.25 modules); `go fix ./...` runs the modernizers | no toolchain at all |
| **`gofmt`** | the Go distribution | `format-on-save.sh` fallback (`gofmt -w -s`) | n/a — always ships with Go |
| **`gofumpt`** | `go install` | `format-on-save.sh` primary (`gofumpt -w`), stricter gofmt superset | hook degrades to `gofmt` |
| **`goimports`** | `go install` | `goimports` formatter in the golangci-lint v2 config (import grouping/pruning) | import-group formatting skipped |
-| **`gopls`** (v0.21.1) | `go install` | the `gopls-lsp` plugin (defs/refs/diagnostics/rename/vulncheck) | no code intelligence |
+| **`gopls`** (v0.22.x) | `go install` | the `gopls-lsp` plugin (defs/refs/diagnostics/rename/vulncheck) | no code intelligence |
### Install / upgrade Go (official tarball, Linux)
-Pick the latest **1.25.x** patch from and the build matching your platform (`linux-amd64` shown):
+Pick the latest **1.26.x** patch (1.26.4 or newer) from and the build matching your platform (`linux-amd64` shown):
```bash
-# replace the version with the current latest 1.25.x patch
-curl -fLO https://go.dev/dl/go1.25.11.linux-amd64.tar.gz
+# replace the version with the current latest 1.26.x patch (1.26.4+)
+curl -fLO https://go.dev/dl/go1.26.4.linux-amd64.tar.gz
sudo rm -rf /usr/local/go # remove any prior install (don't overlay)
-sudo tar -C /usr/local -xzf go1.25.11.linux-amd64.tar.gz
+sudo tar -C /usr/local -xzf go1.26.4.linux-amd64.tar.gz
export PATH=$PATH:/usr/local/go/bin # add to your shell profile if not already present
-go version # → go version go1.25.11 linux/amd64
+go version # → go version go1.26.4 linux/amd64
```
-> macOS/Windows or a package manager (Homebrew `go`, `winget`, distro packages) work equally well — the only requirement is that `go version` reports **1.25.x**. `gofmt` is included in every Go distribution, so nothing extra is needed for the hook's fallback path.
+> macOS/Windows or a package manager (Homebrew `go`, `winget`, distro packages) work equally well — the only requirement is that `go version` reports **1.26.x** (1.26.4+). `gofmt` is included in every Go distribution, so nothing extra is needed for the hook's fallback path.
### Install the supporting tools
-`go install` drops binaries in `$(go env GOPATH)/bin` (default `~/go/bin`) — make sure that directory is on your `PATH`. Run these **after** Go is in place so they compile against your 1.25 toolchain:
+`go install` drops binaries in `$(go env GOPATH)/bin` (default `~/go/bin`) — make sure that directory is on your `PATH`. Run these **after** Go is in place so they compile against your 1.26 toolchain:
```bash
go install mvdan.cc/gofumpt@latest # stricter gofmt superset (hook primary)
go install golang.org/x/tools/cmd/goimports@latest # import grouping / pruning
-go install golang.org/x/tools/gopls@v0.21.1 # language server for the gopls-lsp plugin (pinned: v0.21.1, verified against Go 1.25.x)
+go install golang.org/x/tools/gopls@v0.22.0 # language server for the gopls-lsp plugin (pinned: v0.22.x — the gopls line that adds Go 1.26 support; use @latest for the newest patch)
```
Verify:
```bash
-go version # → 1.25.x
+go version # → 1.26.x (1.26.4+)
command -v gofmt # ships with Go (in GOROOT/bin)
gofumpt --version
command -v goimports # goimports has no --version flag
-gopls version # → golang.org/x/tools/gopls v0.21.1
+gopls version # → golang.org/x/tools/gopls v0.22.x
```
These are **host-only** dev tools; the plugin still works without them (the format hook degrades to `gofmt`, then to a silent no-op). Full-tree `golangci-lint` runs separately — often in a pinned container — so it does not depend on these host binaries.
diff --git a/rules/go-context.mdc b/rules/go-context.mdc
index 0d683ed..fc4fd5e 100644
--- a/rules/go-context.mdc
+++ b/rules/go-context.mdc
@@ -1,5 +1,5 @@
---
-description: Go coding standards — idiomatic Go (Go 1.25, golangci-lint v2) for .go files. Mirrors the go-coding router skill for Cursor.
+description: Go coding standards — idiomatic Go (Go 1.26, works with 1.25+; golangci-lint v2) for .go files. Mirrors the go-coding router skill for Cursor.
globs: ["**/*.go"]
alwaysApply: false
---
@@ -17,10 +17,10 @@ This Cursor rule mirrors the `go-coding` router skill — apply it when editing
|---|---|---|
| Formatting | `gofmt`/`gofumpt` (+ `goimports`) — machine-enforced | — |
| Static analysis / bugs | `go vet ./...`, `golangci-lint run` | `go-linting` |
-| Modern idioms | `golangci-lint run --enable-only=modernize`, `go fix ./...` | `go-idioms` |
+| Modern idioms | `go fix ./...` (Go 1.26 runs the modernizers natively), or `golangci-lint run --enable-only=modernize` | `go-idioms` |
| Errors | `golangci-lint run --enable-only=errorlint` | `go-errors` |
| Concurrency | `go test -race ./...`, `go vet ./...` | `go-concurrency` |
-| Testing | `go test -race ./...`; `testing/synctest` (1.25) for time/concurrency | `go-testing` |
+| Testing | `go test -race ./...`; `testing/synctest` (since 1.25) for time/concurrency | `go-testing` |
| Layout | judgment | `go-layout` |
Ground every judgment call in a cited source — Effective Go, Go Code Review Comments, the Google
diff --git a/skills/go-coding/SKILL.md b/skills/go-coding/SKILL.md
index 43df66b..749a9fc 100644
--- a/skills/go-coding/SKILL.md
+++ b/skills/go-coding/SKILL.md
@@ -1,6 +1,6 @@
---
name: go-coding
-description: Go coding-standards router and entry point for idiomatic Go (Go 1.25, golangci-lint v2). This skill should be used when a Go task spans multiple areas, is unspecified, or the question is which tool or standard applies — it routes each topic to the deterministic tool (gofmt/gofumpt, go vet, golangci-lint v2 + modernize, go test -race), to the gopls-lsp plugin for code intelligence, and then to the focused go-* skill that owns it. For a single, already-identified topic prefer that skill directly (errors → go-errors, concurrency → go-concurrency, testing → go-testing, idioms/modernization → go-idioms, linter config → go-linting, layout → go-layout). Not for non-Go languages or domain/business rules.
+description: Go coding-standards router and entry point for idiomatic Go (Go 1.26, works with 1.25+; golangci-lint v2). This skill should be used when a Go task spans multiple areas, is unspecified, or the question is which tool or standard applies — it routes each topic to the deterministic tool (gofmt/gofumpt, go vet, go fix / golangci-lint v2 modernize, go test -race), to the gopls-lsp plugin for code intelligence, and then to the focused go-* skill that owns it. For a single, already-identified topic prefer that skill directly (errors → go-errors, concurrency → go-concurrency, testing → go-testing, idioms/modernization → go-idioms, linter config → go-linting, layout → go-layout). Not for non-Go languages or domain/business rules.
---
# go-coding — Go standards router
@@ -19,10 +19,10 @@ Two principles from the project research drive it:
|---|---|---|
| Formatting | `gofmt -l` / `gofumpt -l` (+ `goimports`) — machine-enforced, non-negotiable | — |
| Static analysis / likely bugs | `go vet ./...`, `golangci-lint run` | `go-linting` |
-| Modern idioms (range-int, `min`/`max`, `slices`/`maps`, `wg.Go`, `strings.Cut`) | `golangci-lint run --enable-only=modernize`, or `go fix ./...` | `go-idioms` |
+| Modern idioms (range-int, `min`/`max`, `slices`/`maps`, `wg.Go`, `strings.Cut`, `new(expr)`) | `go fix ./...` (Go 1.26 applies the full modernizer suite natively), or `golangci-lint run --enable-only=modernize` on older toolchains | `go-idioms` |
| Errors (`%w`, `errors.Is`/`As`, `errors.Join`, sentinel/typed) | `golangci-lint run --enable-only=errorlint` | `go-errors` |
| Concurrency (goroutine leaks, ctx lifecycle, atomics) | `go test -race ./...`, `go vet ./...` | `go-concurrency` |
-| Testing (table-driven, `t.Parallel`, `B.Loop`, `testing/synctest`) | `go test -race ./...`; use `testing/synctest` (stable in 1.25) for time/concurrency tests | `go-testing` |
+| Testing (table-driven, `t.Parallel`, `B.Loop`, `testing/synctest`) | `go test -race ./...`; use `testing/synctest` (stable since 1.25) for time/concurrency tests | `go-testing` |
| Project layout (`internal/`, start-flat) | judgment — see sources below | `go-layout` |
| Code intelligence (defs/refs/diagnostics/rename/vulncheck) | install the **`gopls-lsp`** plugin | — |
diff --git a/skills/go-concurrency/SKILL.md b/skills/go-concurrency/SKILL.md
index a9010e1..dbc2c8b 100644
--- a/skills/go-concurrency/SKILL.md
+++ b/skills/go-concurrency/SKILL.md
@@ -7,6 +7,9 @@ description: Idiomatic, leak-free Go concurrency. This skill should be used when
Deterministic backstop: `go test -race ./...`, `go vet ./...` (catches copylocks, lost cancel),
and `go.uber.org/goleak`. The race detector is the source of truth — run it before reasoning.
+On **Go 1.26+** the runtime also ships an experimental `goroutineleak` profile in `runtime/pprof`
+that reports leaked goroutines — a toolchain-native complement to `goleak` for leak hunts (enable it
+with `GOEXPERIMENT=goroutineleakprofile` at build time).
## Rules
@@ -28,11 +31,12 @@ and `go.uber.org/goleak`. The race detector is the source of truth — run it be
a concurrent map write panics; `-race` catches it.
- **Channels:** close on the *send* side, never the receive side; a `nil` channel blocks forever
(useful for disabling a `select` arm, a bug everywhere else).
-- **Testing time/concurrency:** use **`testing/synctest`** (stable in Go 1.25) — fake clock +
+- **Testing time/concurrency:** use **`testing/synctest`** (stable since Go 1.25) — fake clock +
deterministic scheduling. See `go-testing`.
## Sources
-- synctest — ; Go 1.25 release notes —
+- synctest — ; Go 1.25/1.26 release notes —
+- `goroutineleak` profile (Go 1.26, experimental) —
- Code Review Comments (Goroutine Lifetimes, Contexts) —
- Uber Go Style Guide (Concurrency) —
diff --git a/skills/go-explain/SKILL.md b/skills/go-explain/SKILL.md
index 4df9161..70422f5 100644
--- a/skills/go-explain/SKILL.md
+++ b/skills/go-explain/SKILL.md
@@ -18,8 +18,9 @@ Cover, in a few lines:
4. **Source** — cite one authoritative reference: Effective Go, Go Code Review Comments, the Google
or Uber Go style guide, a `go.dev/blog` post, or `pkg.go.dev`.
-Tailor to the repo's Go version when a `go.mod` is present — don't recommend a Go 1.25 idiom for an
-older module. For a fuller treatment, route to the matching skill: `go-errors`, `go-concurrency`,
+Tailor to the repo's Go version when a `go.mod` is present — don't recommend a Go 1.26 idiom (e.g.
+`new(expr)`) for a module pinned to 1.25 or older. For a fuller treatment, route to the matching
+skill: `go-errors`, `go-concurrency`,
`go-testing`, `go-idioms`, `go-linting`, or `go-layout`.
Keep it tight — this is a lookup, not a lecture. If `$ARGUMENTS` is empty, ask what to explain.
diff --git a/skills/go-idioms/SKILL.md b/skills/go-idioms/SKILL.md
index 1f57668..f0e835e 100644
--- a/skills/go-idioms/SKILL.md
+++ b/skills/go-idioms/SKILL.md
@@ -1,24 +1,29 @@
---
name: go-idioms
-description: Modern idiomatic Go (the `modernize` linter set). This skill should be used when the user writes, reviews, or modernizes Go and wants current-version idioms — range-over-int, `min`/`max`, `slices`/`maps`, `strings.Cut`, `cmp.Or`, `sync.OnceFunc`, iterators, `slog.LogAttrs`, dropped loop-var copies. Framed so advice equals tooling (`golangci-lint --enable-only=modernize` / `go fix`). Errors→`go-errors`, concurrency→`go-concurrency`, tests→`go-testing`. Not for golangci-lint configuration (use `go-linting`) or non-Go languages.
+description: Modern idiomatic Go (the `modernize` analyzer set). This skill should be used when the user writes, reviews, or modernizes Go and wants current-version idioms — range-over-int, `min`/`max`, `slices`/`maps`, `strings.Cut`, `cmp.Or`, `sync.OnceFunc`, iterators, `slog.LogAttrs`, `new(expr)` (Go 1.26), dropped loop-var copies. Framed so advice equals tooling (`go fix ./...` on Go 1.26, or `golangci-lint --enable-only=modernize`). Errors→`go-errors`, concurrency→`go-concurrency`, tests→`go-testing`. Not for golangci-lint configuration (use `go-linting`) or non-Go languages.
---
# go-idioms — modern Go (modernize)
-**Advice == tooling.** The `modernize` analyzer (in `golang.org/x/tools`, the same engine as gopls
-and `go fix`) flags and usually auto-fixes everything below. Run it, don't hand-audit:
+**Advice == tooling.** The `modernize` analyzers flag and usually auto-fix everything below. Run
+them, don't hand-audit. As of **Go 1.26** the rewritten `go fix` is the canonical runner — it ships
+the full modernizer suite in the toolchain itself:
```
-golangci-lint run --enable-only=modernize --fix # or: go fix ./...
+go fix ./... # Go 1.26+: applies the built-in modernizers
+golangci-lint run --enable-only=modernize --fix # any toolchain (same analyzers, via golangci-lint)
```
-This skill explains *why* and catches what review notices before the linter runs. **Check `go.mod`
-first** — don't apply a Go 1.25 idiom to a repo pinned older.
+Both draw on the same `golang.org/x/tools` engine as gopls, so their fixes agree. This skill
+explains *why* and catches what review notices before the tool runs. **Check `go.mod` first** —
+gate each idiom on the module's Go version (the `Since` column below); don't apply a Go 1.26 idiom to
+a repo pinned to 1.25 or older.
## Prefer → over (since)
| Prefer | Over | Since |
|---|---|---|
+| `new(expr)` — e.g. `Field: new(30)`, `new(int64(req.Limit))` | a `ptr[T](v)` helper (auto-rewritten by the `newexpr` fixer) or a hand-written `tmp := v; &tmp`, for optional/pointer fields | 1.26 |
| `for i := range n` | `for i := 0; i < n; i++` | 1.22 |
| `min(a, b)` / `max(a, b)` builtins | hand-rolled helpers | 1.21 |
| *(drop)* `x := x` loop-var copy | pre-1.22 capture workaround | 1.22 |
@@ -33,13 +38,16 @@ first** — don't apply a Go 1.25 idiom to a repo pinned older.
| `for b.Loop()` | `for i := 0; i < b.N; i++` → `go-testing` | 1.24 |
| typed `atomic.Int64` | bare-int `atomic.Add*` → `go-concurrency` | 1.19 |
-Idioms are a moving target — let the linter (pinned to the repo's toolchain) be the source of
-truth so advice never drifts from the user's `go fix`.
+Idioms are a moving target — let the tool (pinned to the repo's toolchain) be the source of
+truth so advice never drifts from the user's `go fix`. Go 1.26 also lifts the ban on a generic type
+referencing itself in its own type-parameter list (e.g. `type Adder[A Adder[A]] interface{ Add(A) A }`),
+so self-referential constraints no longer need a workaround — but that's a hand-written pattern, not
+something a modernizer rewrites.
## Sources
- `modernize` —
-- `go fix` / tool evolution — ; range-over-func —
-- `slog` — ; Go 1.21–1.25 release notes
+- `go fix` (rewritten in 1.26) — ; range-over-func —
+- `slog` — ; Go 1.21–1.26 release notes (`new(expr)`, self-ref generics — )
---
*Decomposition inspired by [`samber/cc-skills-golang`](https://github.com/samber/cc-skills-golang) (MIT © 2026 Samuel Berthe); rules grounded in the sources above.*
diff --git a/skills/go-linting/SKILL.md b/skills/go-linting/SKILL.md
index dfd0f89..887b95e 100644
--- a/skills/go-linting/SKILL.md
+++ b/skills/go-linting/SKILL.md
@@ -44,7 +44,11 @@ formatters:
- **Pin the version in CI** for reproducibility (the Cadasto Go repos pin `v2.11.4`); a version
drift silently changes the rule set.
- `modernize` is the single highest-leverage linter — it operationalizes most `go-idioms` rules on
- the same engine as gopls/`go fix`, so the plugin's advice stays consistent with the toolchain.
+ the same engine as gopls/`go fix`, so the plugin's advice stays consistent with the toolchain. As
+ of **Go 1.26** the rewritten `go fix ./...` runs that same modernizer suite from the toolchain
+ itself; keep `modernize` in golangci-lint for CI reproducibility and to cover toolchains older
+ than 1.26. Use golangci-lint built with a Go version ≥ the module's toolchain (Go 1.26 support
+ landed in the golangci-lint releases built with 1.26).
- Adopt the shipped reference config `references/golangci.v2.yml`, or run `/go-lint-setup` to
scaffold it into a repo (it won't overwrite an existing config without asking).
diff --git a/skills/go-testing/SKILL.md b/skills/go-testing/SKILL.md
index 4389557..a83458b 100644
--- a/skills/go-testing/SKILL.md
+++ b/skills/go-testing/SKILL.md
@@ -18,19 +18,25 @@ Deterministic backstop: `go test -race ./...` (always, in CI), `go test -bench`,
- **`-race` is non-negotiable** for any code touching goroutines; wire it into CI.
- **Goroutine-leak detection:** `go.uber.org/goleak` — `goleak.VerifyTestMain(m)` or per-test
`defer goleak.VerifyNone(t)`.
-- **`testing/synctest` (stable Go 1.25) is the default for time/concurrency tests** — timeouts,
+- **`testing/synctest` (stable since Go 1.25) is the default for time/concurrency tests** — timeouts,
tickers, retries, `context` cancellation. It runs the bubble on a *fake clock* with deterministic
scheduling, so "5-second" waits complete in microseconds and flakiness disappears. Wrap with
`synctest.Test(t, func(t *testing.T){ … })`; `synctest.Wait()` blocks until every goroutine in the
- bubble is durably blocked. Reach for it instead of `time.Sleep`-based polling.
+ bubble is durably blocked. Reach for it instead of `time.Sleep`-based polling. (The pre-1.25
+ `GOEXPERIMENT=synctest` API — `synctest.Run` — was removed in Go 1.26; use the stable `synctest.Test`.)
- **Fuzzing** (`func FuzzX(f *testing.F)`) for parsers, codecs, and anything consuming untrusted
bytes. **Golden files** (an `-update` flag writing `testdata/*.golden`) for large structured output.
+- **Deterministic crypto tests (Go 1.26):** `testing/cryptotest.SetGlobalRandom(t, seed)` pins a
+ deterministic randomness source for the test's duration — reach for it instead of hand-injecting a
+ custom `io.Reader` when testing code that draws from `crypto/rand`. It's process-global, so it
+ can't run inside a `t.Parallel()` test (or one with a parallel ancestor).
- **Assertions:** stdlib + small helpers (`t.Helper()`) is often enough; `testify` is fine — match
the repo, don't mix styles.
## Sources
- synctest — ; `testing.B.Loop` —
-- `testing` package — ; Go 1.22/1.24/1.25 release notes
+- `testing` package — ; Go 1.22/1.24/1.25/1.26 release notes —
+- `testing/cryptotest` (Go 1.26) —
- `go.uber.org/goleak` —
---