# Go

> Write, review, refactor, and test modern Go while loading release-specific guidance newer than the model's knowledge cutoff. Use for any task involving Go source.

- Skill: `cedws/go` (Agent Skill)
- Install (CLI): `npx skillmds@latest add cedws/go`
- Raw SKILL.md: https://api.skillmd.com/api/skills/cedws/go/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: AI & ML
- Author: cedws (https://skillmd.com/u/cedws)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/cedws/go

---


# Go

## Load release supplements

Determine the Go version in use before making Go-specific decisions:

1. Find the `go.mod` governing the files in scope and read its `go` directive. Use that major version as the target, including when a newer `toolchain` directive is present.
2. If no applicable `go.mod` exists, run `go version` and extract the major version from output such as `go version go1.26.3 darwin/arm64`.
3. If neither source establishes a version, use an explicit version from the user's request. Otherwise ask for the target instead of assuming one.

Determine the model's knowledge cutoff. Compare the target Go version and the cutoff with the release table, then load every listed sibling skill whose version is at or below the target and whose release falls after the cutoff. Load selected skills oldest first.

| Go version | Release date | Skill |
| --- | --- | --- |
| 1.21 | 2023-08-08 | `go-1-21` |
| 1.22 | 2024-02-06 | `go-1-22` |
| 1.23 | 2024-08-13 | `go-1-23` |
| 1.24 | 2025-02-11 | `go-1-24` |
| 1.25 | 2025-08-12 | `go-1-25` |
| 1.26 | 2026-02-10 | `go-1-26` |
| 1.27 | 2026-08-19 | `go-1-27` |

## Coding style

### Name non-trivial function literals

When a function literal passed as an argument contains multiple statements or branches, assign it to a descriptively named local variable before the call. Keep only short, obvious callbacks inline.

```go
walkFn := func(path string, entry fs.DirEntry, err error) error {
	if err != nil {
		return err
	}
	if entry.IsDir() {
		return nil
	}
	return visit(path)
}

return filepath.WalkDir(root, walkFn)
```

### Let code breathe

Use blank lines to separate distinct phases of a function, such as initialisation, local helper definitions, the main operation, fallback handling, derived values, and the return. Keep tightly related statements together; do not compress an entire multi-phase function into one uninterrupted block.

```go
func readFile(path string) (Document, error) {
	document := Document{Source: path}

	decodeFn := func(record Record) error {
		document.Records = append(document.Records, record)
		return nil
	}
	if err := decode(path, decodeFn); err != nil {
		return Document{}, err
	}

	if document.ID == "" {
		document.ID = fallbackID(path)
	}

	document.Title = titleFrom(document.Records)

	return document, nil
}
```

### Handle errors immediately

Handle an error immediately after the operation that produced it, preferably with `if err := operation(); err != nil`. Do not keep an `err` variable alive while later work runs and then return it at the end of the function. A plain `err :=` binding is acceptable when the producing operation is the final operation and the error is returned immediately afterwards.

```go
if err := writeDocument(document); err != nil {
	return err
}
recordDocumentWritten(document)
return nil
```

### Use slices helpers for membership

For Go 1.21 or later, use `slices.Contains` instead of manually ranging over a slice solely to test whether it contains a comparable value. Use `slices.ContainsFunc` when membership requires a predicate.

```go
if slices.Contains(formats, format) {
	return formatDocument(format)
}
```

### Collapse repeated parameter types

When adjacent function parameters have the same type, write the type once after the final name. Apply the same style to function declarations, methods, and function literals.

```go
func join(left, right string) string {
	return left + right
}
```

### Keep struct literals consistently shaped

Write a struct literal either entirely on one line or across multiple lines with exactly one field assignment per line. Never put multiple field assignments on the same line inside a multi-line struct literal.

```go
point := Point{X: 1, Y: 2}

point := Point{
	X: 1,
	Y: 2,
}
```

### Extract dense iteration bodies

Keep iteration loops focused on control flow. When each iteration scans, converts, and enriches a value, extract that work into a helper named for the result.

```go
for rows.Next() {
	conversation, err := scanConversation(rows, source)
	if err != nil {
		return nil, err
	}
	conversations = append(conversations, conversation)
}
return conversations, rows.Err()
```

### Pass contexts explicitly

Never store a `context.Context` in a struct. Pass it explicitly as the first parameter to every operation that needs it, usually named `ctx`.

```go
type Worker struct{}

func (worker *Worker) Run(ctx context.Context) error {
	return process(ctx)
}
```

### Prefer formatting around literal text

Use concatenation when directly joining string variables. Prefer `fmt.Sprintf` when combining values with fixed text instead of alternating between variables, literals, and `+` operators.

```go
message := fmt.Sprintf("%s abc %s", left, right)
```

### Prefer stream processing

Prefer APIs that consume an `io.Reader` or produce output through an `io.Writer`. Process data incrementally instead of buffering an entire input or output solely to pass it to another API. Buffer only when the operation genuinely requires the complete value in memory.

```go
var payload Payload
if err := json.NewDecoder(request.Body).Decode(&payload); err != nil {
	return err
}
```

