AGENT SKILL

go-idiomatic

Go engineering standards for this repo — package layout, error handling, logging, testing, concurrency and design patterns. TRIGGER — load BEFORE writing or editing Go, not after: any .go, go.mod, go.sum or go.work file is touched, Go or Golang is named, or the working directory contains go.mod and the task is implementation, refactor, review or test-writing. Plain feature requests in a Go repo ("add an endpoint", "extract a helper", "write a test for this") count; the user will not say "idiomatic". Load it even when another skill (tdd, simplify) is active. SKIP only when no Go file is involved and Go is not named.

License 许可
MIT
最近更新
2026-11-11
Stars
★ 0
Forks
0

01 前言 Front Matter

name
go-idiomatic
description
Go engineering standards for this repo — package layout, error handling, logging, testing, concurrency and design patterns. TRIGGER — load BEFORE writing or editing Go, not after: any .go, go.mod, go.sum or go.work file is touched, Go or Golang is named, or the working directory contains go.mod and the task is implementation, refactor, review or test-writing. Plain feature requests in a Go repo ("add an endpoint", "extract a helper", "write a test for this") count; the user will not say "idiomatic". Load it even when another skill (tdd, simplify) is active. SKIP only when no Go file is involved and Go is not named.
allowed-tools
Read, Edit, Write, Glob, Grep, Bash(go:*), Bash(golangci-lint:*), Bash(git:*), Agent

02 资源文件 20

03 SKILL.md 正文

Go Idiomatic

This repo's rules for Go, where they differ from or sharpen general Go practice. The rules below apply to every change; the references hold the detail and worked examples.

Where to Look

Route to the right reference before reading further:

If you're working on… Load this
Goroutines, channels, sync primitives, errgroup, leaks, races references/concurrency.md
Adding a sentinel or error type, translating errors between packages or to HTTP responses, logging where an error came from, cleanup in defer, panic references/errors.md
HTTP middleware: request Content-Type, CSRF, session cookie attributes references/middleware.md
Storing session or reset tokens, password reset or change, encrypting a column references/secrets.md
Giving main or a component a logger, choosing a level, CLI output vs logs references/logging.md
Interface design, zero values, identifier types, typed value sets, anti-patterns references/patterns.md
Writing or reviewing tests, benchmarks, fuzzing, test databases the go-testing skill
Optional fields or return values — when to use Option[T] references/optional.md
Pointer vs value receivers, mutation vs optionality references/value-vs-pointer.md
Scaffolding a Go HTTP client for a third-party API, writing a NewXxxClient, or attaching auth to outbound HTTP calls references/http-client.md
Shelling out with os/exec to git, gh or another CLI, parsing its --json output, faking it in tests references/exec.md
Storing data in SQL: store package boundary, transactions, NULLs, constraint errors, pool setup references/database.md
Rendering html/template for htmx: page vs fragment vs redirect, HX-* headers, .tmpl files the htmx-go-templates skill

Errors and Logging

Nearly every change returns an error or reports one, so these rules apply to all Go work, not only to a task described as error handling:

  1. Wrap with fmt.Errorf("<verb> <noun>: %w", err). Error strings are lowercase, with no punctuation and no "failed to".
  2. Handle an error once: return it with context, or log it at the top of the chain. Never both.
  3. Export a sentinel only when a caller in another package branches on it. Define it where the condition is detected, and translate a dependency's errors into your own at the package seam.
  4. Never discard an error with _ =. Join a cleanup error into the returned error, or log it at Warn when there is nothing to return to.
  5. panic only for programmer errors: Must helpers on constant input, impossible cases.
  6. Only components where an error stops travelling (handlers, workers, long-lived services) take an injected *slog.Logger, as a constructor field. Code below them returns errors and takes no logger. main builds the one logger; nothing calls log.*, slog.Info or slog.Default().
  7. Log messages are constant; variable data goes in snake_case key-value attributes, with err for the error. Never log secrets or personal data.
  8. Output the user asked for goes to an injected io.Writer, not to the logger.

A routine return fmt.Errorf(...) or log line needs only these rules. Load references/errors.md when adding a sentinel or error type, turning an error into an HTTP response, wrapping a driver or outbound-call error, or handling a cleanup error, and references/logging.md when wiring a logger, choosing a level or separating CLI output.


Testing

Writing, editing or reviewing a _test.go file: load the go-testing skill, which owns how Go tests are written, including test databases. What to test (the kinds of test, what each is worth, the reusable patterns) is the repo's testing-policy when it ships one.


Code Organisation

  1. Applications keep main in cmd/<app>/main.go, which only wires dependencies, and everything else under internal/. pkg/ is for library modules imported from outside the repo; in an application it signals a public API that doesn't exist.
  2. Extract shared logic on the third repetition across meaningfully different packages, not the second. A helper coupled to one domain lives in internal/ next to its primary caller.
  3. Name a package by what it does (stringx, idgen, timeutil). utils is allowed only when it is used across many packages and imports nothing from internal/. helpers and common are never allowed: a real name is waiting to be found.
  4. No package-level state such as a global *sql.DB set in init(). Pass dependencies through constructors.
  5. main parses the environment once into a typed config struct, validates it, and exits on a bad value at startup rather than on the first request that needs it. Constructors receive only the fields they use, not the whole struct. Nothing below cmd/ calls os.Getenv.

Function Design

  1. Past 3–4 arguments, group them into a struct, or use functional options (opts ...Option) for a constructor that will grow; a new option is backward-compatible, a new positional argument is not.

  2. Declare complex arguments as named locals before the call instead of nesting constructor calls inline:

    sentAt := time.Now().Add(-24 * time.Hour)
    priority := Priority(3)
    client.Send(NewMessage(sender, recipient, sentAt, priority))
    
  3. Guard and return early; the happy path stays at the bottom, unindented, with no else after a return. Use switch over if/else if chains.

  4. Use pointers for mutation and measurably large structs, values for small immutable types. Never use *T to mean "might not be set"; that is Option[T].


Naming and Comments

Name functions by what they return or do (ParseConfig, IsExpired) and booleans as predicates (canRetry). Abbreviate only by Go convention (ctx, err, id, r, w).

~/.claude/rules/comments.md decides what earns a comment. It is the authority and this skill does not restate or soften it. Read it before editing a file and apply it as written, including its line cap and its exported-identifiers-only rule for doc comments. internal/ is not public API. When reviewing Go code for comment quality, use the clean-comments skill. Do not instruct it to match the file's existing comment density.


Tooling

Run gofmt, goimports, go vet ./... and golangci-lint run before finishing. Leave mechanical rules to the linter rather than restating them here. Never add //nolint to existing violations: fix them, or leave the rule off until they are fixed.


See Also

Skill When to reach for it
go-testing How tests are written: assertions, doubles, tables, test databases
tdd TDD cycle, red-green-refactor, writing the test first
clean-comments Audit and remove explanatory comments across Go code
improve-codebase-architecture Identify structural improvements, shallow modules
simplify Review changed code for quality, reuse, and efficiency after implementation

04 同仓库更多 Skills

O-Marsters-1997
O-Marsters-1997/my-claude-code

vault-recall

Answer the user's conceptual or technical question using their Obsidian vault as well as general knowledge. Use when the user asks a question (not a task) whose topic appears in the vault MOC digest from session start. Not for task instructions, not mid-task, and not for writing to the vault (that is to-vault).

★ 0
O-Marsters-1997
O-Marsters-1997/my-claude-code

ingest

Ingest one external source (an article, course lesson, doc, PDF or URL) into the user's Obsidian vault: save the original to raw/, then build wiki/ pages per the vault's § Ingest. Use when the user types /ingest, or says "ingest this", "add this source to my wiki", "put this article/lesson in the vault as a wiki page". Works from any repo. Routing rule: someone else's words go to wiki/ (this skill); the user's own learnings and decisions go to notes/ (/to-vault).

★ 0
O-Marsters-1997
O-Marsters-1997/my-claude-code

to-tickets

Breaks a source into independently-grabbable GitHub tickets. For a code feature the source is the plan (`docs/plans/<feature>.md`, from /to-plan) and every new or changed symbol lands in exactly one ticket, its signatures copied into the ticket body; a non-code feature is cut from the PRD's slices. Cuts tickets for one feature per run. If a code feature has no approved plan, offers /to-plan instead of cutting from prose. In a repo that runs command-centre, also emits `[[task]]` blocks into its config; in a plain treepad repo, emits a Batch Manifest instead so the tickets materialise as stacked worktrees.

★ 0
O-Marsters-1997
O-Marsters-1997/my-claude-code

to-seams

Records an agreed-but-unlanded cross-repo interface as a seam: the file a consumer's agent gets pasted into its prompt as ground truth, plus the `[[seam]]` block command-centre reads for the retirement pointer. Use when two repos need to build against an interface neither has landed yet — "record a seam for X", "we agreed on this schema, seam it", "add a seam so Y can build against Z's new field". Halts for approval before writing either file.

Skill与智能体开发
★ 0
O-Marsters-1997
O-Marsters-1997/my-claude-code

to-roadmap

Prioritises settled features into a Now / Next / Later kanban board, rendered as a self-contained ./ideas/roadmap.html. Each card is a feature, not a ticket — one card later becomes several tickets via /to-prd -> /to-plan -> /to-tickets. Boards the features in ./docs/approach.md, or the "## Accepted ideas" in ./ideas/CONTEXT.md when there is no approach doc. The approach doc is settled truth: this assigns tiers and reasons about ordering, it never re-litigates what was decided.

产品经理
★ 0
O-Marsters-1997
O-Marsters-1997/my-claude-code

to-prd

Turns one feature idea into a PRD built on journeys: a one-line problem, journeys (each ending in an observable state) and delivery slices that say what is usable after each. Interviews, explores the codebase, and saves to docs/prds/<feature>.md. Covers exactly one feature: given a multi-feature source, ask which one. Reads any approach doc or ideate report as priors so it doesn't re-ask what's settled, but needs none. Starts the per-feature spine (/to-prd -> /to-plan -> /to-tickets).

产品经理
★ 0