agentsclimarketplace

Go code style

Skill muratmirgun/gophers/skills/go-code-style

26 production-grade Go skills for Claude Code, Gemini CLI, and opencode.

Install
npx -y skills add muratmirgun/gophers --skill go-code-style

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

One thing to look at

  • 8 stars8 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.

What its author says it does

Copied from the file, not written here

Use when writing or reviewing Go code for clarity, formatting, control flow, variable declarations, switch usage, and function design. Covers the priority order (clarity > simplicity > concision > maintainability > consistency), gofmt rules, early-return / no-else patterns, switch over if-else chains, slice/map initialization, and value-vs-pointer choices. Apply proactively to every Go change, even when the user has not asked about style.

The file declares its own license as MIT. That is the author’s claim about this one file, and it is not the same thing as the license GitHub reports for the repository, which is listed with the other numbers below.

SKILL.md

7.3 KB, as published. Nobody here has run it

Go Code Style

gofmt handles the mechanical layout. This skill covers the decisions a formatter cannot make: where to break complexity, when to invert an if, when a switch beats an else if chain, and how to pick value vs pointer arguments. The rule of thumb is the Go Proverb: clear is better than clever.

Core Rules

  1. Run gofmt/goimports. No exceptions, no debates.
  2. Handle errors and edge cases first, return early, keep the happy path at minimum indentation.
  3. Eliminate unnecessary else when the if body ends in return/break/continue.
  4. Prefer switch over if/else if chains that compare the same value.
  5. Initialize slices and maps explicitly, never let a nil map reach a write.
  6. Pass small values; pass pointers when mutating or when the type is large (~128B+).

Style Priority Order

Apply in this order when two principles collide.

PriorityQuestionBeats
1. ClarityCan a reader understand intent without extra context?everything else
2. SimplicityIs this the simplest expression of the idea?concision, consistency
3. ConcisionDoes every line earn its place?consistency
4. MaintainabilityWill this be safe to modify?consistency
5. ConsistencyDoes it match nearby code?

A "consistent" piece of bad code is still bad code. Clarity wins.

Read references/formatting-and-layout.md for line-breaking, multi-line signatures, file/declaration order.

Control Flow

Early return: keep the happy path flat

func process(data []byte) (*Result, error) {
    if len(data) == 0 {
        return nil, errors.New("empty data")
    }
    parsed, err := parse(data)
    if err != nil {
        return nil, fmt.Errorf("parsing: %w", err)
    }
    return transform(parsed), nil
}

No unnecessary else

When the if body unconditionally exits (return/break/continue), drop the else. For assignments, prefer default-then-override:

// Good
lvl := slog.LevelInfo
if debug {
    lvl = slog.LevelDebug
}

Switch over if/else chains

When all branches compare the same value, switch makes intent explicit and exhaustive can verify completeness:

switch status {
case StatusActive:
    activate()
case StatusInactive:
    deactivate()
case StatusPaused:
    pause()
default:
    panic(fmt.Sprintf("unexpected status: %d", status))
}

A tagless switch replaces a chain of unrelated if/else if conditions — first matching case wins.

Extract complex conditions

When an if has 3+ operands, hoist into named booleans so the names document the business rule:

isAdmin := user.Role == RoleAdmin
isOwner := resource.OwnerID == user.ID
if isAdmin || isOwner || permissions.Has(PermOverride) {
    allow()
}

Read references/control-flow.md for tagless switch, guard clauses, and labelled break/continue.

Variable Declarations

Use := for non-zero initializers, var when the zero value is the start.

var count int          // start at 0
name := "default"      // non-zero
var buf bytes.Buffer   // zero value is ready to use

Initialize slices and maps explicitly

A nil map panics on write; a nil slice JSON-encodes to null (a UX surprise for API consumers).

users := []User{}                       // explicit empty
m := map[string]int{}                   // explicit empty
users = make([]User, 0, len(ids))       // preallocate when size is known
m = make(map[string]int, len(items))    // preallocate map buckets

Do not speculatively preallocate large capacities — make([]T, 0, 1000) wastes memory when the common case is 10.

Composite literals: name the fields

srv := &http.Server{
    Addr:         ":8080",
    ReadTimeout:  5 * time.Second,
    WriteTimeout: 10 * time.Second,
}

Positional fields break the moment the type adds or reorders a field.

Function Design and Argument Passing

  • Short and focused, ≤ 4 parameters. Beyond that, use an options struct or functional options.
  • Parameter order: ctx context.Context first, then inputs, then output destinations.
  • range over index loops (range n since Go 1.22).
  • Pass small values, pointers for mutation / large structs (~128B+) / meaningful nil. *string, *int parameters add indirection with no real saving. sync.Mutex and types embedding one are never copied — go vet copylocks catches it.

Anti-Patterns

Anti-patternWhy it hurtsDo this instead
Deeply nested if chainsHappy path scrolls off-screenInvert, return early
if ok { return a } else { return b }else is dead weightDrop the else
if x == A else if x == B else if x == CReader has to verify all comparisons share xswitch x { ... }
Positional struct literalBreaks silently on field reorderNamed fields
Nil map writeRuntime panicmake(...) or map literal
*string, *int parameter to "save copy"Adds indirection, no real savingPass value
Long parameter listsHard to call, hard to extendOptions struct or WithXxx opts

Verification Checklist

  • gofmt -l . produces no output and goimports -l . is clean.
  • No function body indented past three tab stops without justification.
  • No if ... return; else ... in modified code.
  • All maps and slices declared without literal use make with a sensible capacity.
  • Composite literals use named fields for non-trivial struct types.
  • ctx context.Context is the first parameter on every function that takes one.
  • golangci-lint run passes with gocritic, revive, and gocyclo enabled.

Enforce With Linters

These rules are largely mechanical and a linter will catch them in CI:

  • gofmt, gofumpt, goimports — formatting.
  • gocritic, revive — style heuristics, including if-return, early-return.
  • gocyclo, funlen — function complexity / length.
  • wsl_v5 — whitespace lines for separation between blocks.

Add to .golangci.yml and run golangci-lint run in CI.

References

Keep looking

Skills are one crate of 328,083. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.