Agent skill
go
Go engineering best practices and idioms. This skill should be used when writing, reviewing, or refactoring Go code. Triggers on any .go file work, Go module operations, go test, go build, go run, go vet, go generate, or when the user mentions Go, golang, goroutines, channels, context, Go interfaces, Go error handling, Go testing, or Go concurrency. ALWAYS use this skill when Go code is involved, even for simple functions.
Install this agent skill to your Project
npx add-skill https://github.com/JoaquinCampo/Skills/tree/main/go
SKILL.md
Go Engineering Doctrine
Write Go that is explicit, boring, concrete, package-oriented, easy to test, easy to operate, and hard to misunderstand.
Worldview
- Simplicity over cleverness
- Explicit over implicit
- Concrete over abstract
- Mechanical consistency over personal style
- Small surfaces over sprawling frameworks
- Boring code over surprising code
When in doubt, choose the option that makes the code easier to read, easier to test, and easier to change in six months.
Canonical Defaults
- The standard library is the default. Every dependency must earn its place.
gofmtis mandatory. No style debates. Formatting is solved mechanically.go testis the default test runner.go test -racefor concurrency-sensitive code.context.Contextis mandatory for request-scoped operations that may block or be canceled.slogfor structured logging unless there is a clear reason not to.staticcheckis the default static analyzer.
Reference Selection Guide
Read the relevant reference files before writing or reviewing code in that area.
| Task | Reference | Key Topics |
|---|---|---|
| Error handling, wrapping, sentinel errors | references/errors.md |
%w, errors.Is/As, log-or-return rule, error chains |
| Writing or reviewing tests | references/testing.md |
Table-driven tests, httptest, mocking strategy, race detection, benchmarks |
| Goroutines, channels, synchronization | references/concurrency.md |
Goroutine lifecycle, context cancellation, errgroup, channels vs mutexes |
| Creating packages, naming, project layout | references/packages.md |
Package naming, export discipline, cmd/internal layout, avoiding circular imports |
| HTTP handlers, middleware, servers | references/http.md |
Thin handlers, decode-validate-call-encode pattern, middleware, graceful shutdown |
| Setting up or configuring linters | references/linting.md |
gofmt, staticcheck, golangci-lint config, recommended linter set |
| Considering or writing generics | references/generics.md |
Concrete-first rule, good/bad uses, type constraints, common patterns |
| Configuration loading, env vars, startup | references/config.md |
Explicit structs, validation at load, passing config pieces, secrets |
| Interface design, abstraction decisions | references/interfaces.md |
Consumer-side interfaces, small interfaces, when to use/avoid |
For general code review, read: references/errors.md, references/packages.md, references/interfaces.md.
For new service scaffolding, read: references/packages.md, references/http.md, references/config.md.
For debugging concurrency issues, read: references/concurrency.md, references/testing.md.
For refactoring or restructuring, read: references/packages.md, references/interfaces.md, references/errors.md.
Core Rules (Always Apply)
1. Standard Library First
Start with the standard library. Do not import a library to save a few lines. Good reasons to add a dependency: materially better correctness, interoperability, observability, or developer productivity in a repeated pattern. Bad reasons: "everyone uses it" or "the stdlib is verbose."
2. Favor Concrete Types
Accept and return concrete types by default. Introduce interfaces only when they simplify a real boundary. Do not design around imagined future implementations.
3. Interfaces Belong Where Consumed
Define interfaces in the package that uses them, not the package that implements them. Keep interfaces small. One-method interfaces are often ideal. If there is only one implementation and no real substitution boundary, skip the interface.
4. Errors Are Values
Handle errors explicitly. Wrap with context via fmt.Errorf("operation: %w", err). Use errors.Is/errors.As for comparison. Log at process boundaries, not everywhere. Never discard errors silently.
5. Panic Is for Programmer Errors Only
Acceptable: impossible internal invariants, irrecoverable startup failures. Not acceptable: I/O failure, validation failure, request handling, control flow.
6. Context for Cancellation and Deadlines
Pass context.Context as the first parameter when work may block or be canceled. Do not store context in structs. Do not use context as a dependency bag.
7. Concurrency Is for Coordination
Every goroutine must have a lifecycle. Every spawned goroutine must be cancellable, bounded, or intentionally fire-and-forget. If sequential code is fast enough, keep it sequential.
8. Generics Are Not the Starting Point
Write the concrete version first. Use generics when they remove real duplication. If the generic version is harder to explain than the concrete version, prefer concrete.
9. Validate at Boundaries
Validate external input at ingress (HTTP handlers, CLI parsing, config loading, queue consumers). After validation, internal code assumes stronger invariants.
10. Keep Package APIs Small
Export the minimum. Keep implementation details unexported. Every exported name is a maintenance burden and a compatibility promise.
11. HTTP Handlers Should Be Thin
Handlers: decode input, validate, call application logic, encode output, map errors. Handlers should not: contain business workflows, direct SQL, hidden retries, or orchestrate the system.
12. Testing Is Part of Design
Prefer table-driven tests where they improve clarity. Test behavior, not implementation trivia. Prefer real types over mocks unless the boundary is expensive or external.
13. Logging Serves Operations
Prefer structured logs. Log at meaningful boundaries. Do not spam for every successful step. Do not both log and bubble the same error. Never log secrets.
14. Structs Are Data; Methods Are for Cohesion
Keep structs simple. Put methods on a type when behavior truly belongs to that type. Do not turn every data shape into an object with a large method set. Do not hide business workflows inside transport structs.
15. Prefer Explicit Constructors Only When They Add Value
Use a constructor when you need to enforce invariants, inject dependencies, or set safe defaults. Do not write constructors for every struct just because other languages do.
16. Reflection Is a Last Resort
Avoid reflection unless clearly necessary. If used, isolate it tightly and document why. Prefer explicit code over clever reflection.
17. Public APIs Evolve by Addition
For reusable packages: add, do not change or remove. Think about compatibility before exporting. Every public API is a promise.
Red Flags
These indicate non-idiomatic or overengineered Go:
- Interfaces everywhere / giant "service" interfaces
util,common,helperspackages- Reflection in business logic
- Generics before concrete code exists
- Context stored on structs
- Hidden globals
- Panics in normal control flow
- Handlers full of business logic
- Excessive framework usage
- Logging at every stack layer
- Unbounded goroutines
- Channels where a mutex or plain function call would do
- Large exported surfaces with unclear compatibility intent
Modus Operandi
- Beautiful over ugly: tidy packages, short files, clear names, consistent formatting.
- Explicit over implicit: state assumptions, make control flow obvious.
- Simple over complex: use the simplest design that fully solves the problem.
- Flat over nested: keep control flow shallow, prefer early returns.
- Sparse over dense: short functions, small package APIs, concise comments.
- Readability counts: optimize for the next reader, not the current author.
- Practicality beats purity: use the boring, reliable solution first.
- Errors must not pass silently: handle explicitly, wrap with context, return meaningfully.
- One obvious way: recommend one best path, not five equal ones.
- Now over never: deliver a correct, minimal solution first.
- Never over right now: if something is unsafe or fragile, stop and say so.
- Hard to explain equals bad idea: if the approach cannot be justified simply, simplify it.
Recommended Agent Skills
Expand your agent's capabilities with these related and highly-rated skills.
sparse-retrieval-eval
Evaluate sparse retrieval models on standard IR benchmarks (BEIR, MIRACL, mMARCO). Covers all IR metrics (nDCG@k, Recall@k, MAP, MRR), dataset loading, sparse corpus encoding to CSR matrices, IDF-weighted retrieval, caching, and result interpretation. Triggers on: evaluate retrieval, BEIR benchmark, nDCG, recall@k, sparse retrieval evaluation, MIRACL evaluation, information retrieval metrics, IR evaluation, search quality metrics.
wandb-plot
Download and generate plots from Weights & Biases runs. Use when you need to: - List projects you have access to - List runs in a W&B project - Inspect available metrics for a run - Download existing plot images from a run - Generate line plots from metric history (loss, accuracy, etc.)
fastapi
FastAPI best practices and conventions. Use when working with FastAPI APIs and Pydantic models for them. Keeps FastAPI code clean and up to date with the latest features and patterns, updated with new versions. Write new code or refactor and update old code.
kvpress
kvpress (NVIDIA) KV-cache compression for HuggingFace LLMs. Use when: kvpress imports, compression_ratio, press(model) context managers, StreamingLLMPress, SnapKVPress, ExpectedAttentionPress, TOVAPress, KnormPress, KV-cache eviction, token pruning during generation, or attention sink methods.
plantuml
Create, edit, and render PlantUML diagrams. Triggers on: architecture diagrams, flowcharts, sequence diagrams, data models, state machines, visual documentation.
qdrant-sparse
Qdrant sparse vector operations: collection creation with SparseVectorParams, Modifier.IDF for miniCOIL/SPLADE/BM42, upserting SparseVector points, sparse search, hybrid search with prefetch + RRF/DBSF fusion, converting model outputs to SparseVector format, payload filtering, and performance tuning. Covers the sparse vector gap not handled by the official Qdrant MCP (which only supports dense vectors via FastEmbed).
Didn't find tool you were looking for?