agentleFS
andr-caandr-ca/agentharness/.claude/skills/go-conventions/SKILL.md

go-conventions

Skill1 starsChanged 3 months agoMITView on GitHub

Use when writing, reviewing, or refactoring Go code — naming conventions, receiver naming, error wrapping, interface design, goroutine safety, and common pitfalls (goroutine leaks, defer-in-loop, nil map writes).

4 other projects use a version of this.

Adopted by

Most recently taken up by

The file

Files
SKILL.md

Go Conventions

This file is self-contained for day-to-day use. Deeper reference (needs the full harness checkout): languages/go/CONVENTIONS.md (full examples including godoc comments, context-first concurrency, and table-driven tests).

Naming

  • Unexported: camelCase. Exported: PascalCase.
  • Interfaces: singular, behavior-describing name (Reader, Storer, UserRepository — not IUserRepository).
  • Error sentinels: Err prefix (ErrNotFound, ErrTimeout).
  • Receiver: one or two letters, the type's initials (u *User, not user *User). Keep consistent across all methods of a type.

Errors: wrap with context, return early

// Wrap to preserve the stack — don't swallow context
if err != nil {
    return fmt.Errorf("getUserByID %q: %w", id, err)
}

// Return early — avoid deep nesting
func process(ctx context.Context, id string) error {
    user, err := repo.Find(ctx, id)
    if err != nil {
        return fmt.Errorf("process: find user: %w", err)
    }
    // ... rest of the logic at the same indent level
}

Interfaces: define at the point of use

Declare the interface in the package that uses it, not the package that implements it. A concrete type's package need not know about the interface — io.Reader doesn't live in the os package, and UserRepository should live in the handler/service that calls it, not in the postgres package that provides one.

Pitfalls to catch in review

// Goroutine leak — if nothing reads from result, the goroutine
// blocks forever on the send and is never garbage-collected
go func() {
    result <- compute()  // will block if nobody reads result
}()

// Defer in loop executes at *function* return, not loop iteration
for _, f := range files {
    defer f.Close()  // WRONG — all defers run when function exits
    // RIGHT: use an inner function or close explicitly at end of loop
}

// Write to a nil map panics at runtime
var m map[string]int
m["key"] = 1  // panic: assignment to entry in nil map
// RIGHT: initialize first (use = not :=, m is already declared)
m = make(map[string]int)

// Shadowing err in short variable declaration inside a block
result, err := doSomething()
if err == nil {
    data, err := doAnotherThing()  // this `err` is a new variable
    _ = data
}
// The outer `err` is unchanged; use `=` for the inner one if intended

Export documentation

Exported symbols need a // comment starting with the symbol name:

// User represents an authenticated user in the system.
type User struct { /* ... */ }

// FindByID retrieves a user by their unique identifier.
// Returns ErrNotFound if no user with that ID exists.
func (r *postgresRepo) FindByID(ctx context.Context, id string) (*User, error) { }

Testing

Table-driven tests with t.Run subtests, _test package for black-box tests. See patterns/testing/TDD.md for the broader methodology — this skill covers Go-specific structure only.

Formatting & tooling

gofmt (or goimports) is non-negotiable — all Go code must be formatted. Use golangci-lint for static analysis. go vet is run automatically by go test.

Download now (ZIP)

Does it work?

Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.

No reviews yet

People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.

  • It worked
  • Partly
  • It didn't
What did you use it for? e.g. Reviewing pull requests in a Rails app

Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.

Your trail

Files you open will collect here, so you can find them again.

Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.

Now do this for your own.

Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.