go-clean-architecture
Use when scaffolding or refactoring a Go service into a framework-agnostic clean (hexagonal) architecture: Domain, Usecase, Repository, Delivery layers, inward…
Use when creating Go packages, organizing imports, managing dependencies, or structuring a Go project. Covers meaningful package names, package size, import grouping (stdlib first, then external), blank/dot imports, the run() pattern in main, init() restrictions, and CLI flag
$ npx -y skills add muratmirgun/gophers --skill go-packages --agent claude-codeHow it fires
How this skill gets triggered: by you, by Claude, or both.
/go-packagesContext preview
The summary Claude sees to decide when to auto-load this skill.
Use when creating Go packages, organizing imports, managing dependencies, or structuring a Go project. Covers meaningful package names, package size, import grouping (stdlib first, then external), blank/dot imports, the run() pattern in main, init() restrictions, and CLI flag
name: go-packages description: "Use when creating Go packages, organizing imports, managing dependencies, or structuring a Go project. Covers meaningful package names, package size, import grouping (stdlib first, then external), blank/dot imports, the run() pattern in main, init() restrictions, and CLI flag conventions. Apply proactively when starting a new module or splitting a growing codebase, even if the user did not explicitly ask about package layout. Does not cover identifier naming inside packages (see go-naming)." license: MIT compatibility: "Designed for Claude Code or similar AI coding agents. Plain Go (any supported version)." allowed-tools: Read Edit Write Glob Grep Bash(go:*) Bash(golangci-lint:*)
A package is a unit of meaning, not a folder of files. Name it for what it provides, keep imports tidy, and put startup logic where it belongs.
1. **Package names describe what the package provides.** `util`, `helper`, `common`, `misc` are not names. 2. **Imports are grouped: stdlib first, then external.** `goimports` will keep this honest. 3. **Avoid `init()`** — and when unavoidable, keep it deterministic and I/O-free. 4. **`os.Exit` / `log.Fatal` only inside `main`.** Library code returns errors. 5. **Use the `run()` pattern** so `main` has a single exit point and deferred cleanup runs. 6. **CLI flags belong in `package main`.** Libraries take configuration as parameters. 7. **Blank imports** belong in `main` or tests. **Dot imports** are essentially never appropriate.
| Question | If "yes" | |---|---| | Can you state the package's purpose in one sentence? | Probably right-sized | | Do its files never share unexported symbols? | Likely two packages glued by directory | | Do distinct caller groups touch distinct files? | Split along caller boundaries | | Is the godoc index so long callers cannot find things? | Split for discoverability | | Does splitting create import cycles? | Don't split |
> Read [references/package-layout.md](references/package-layout.md) when deciding how to split a growing package, organizing `cmd/`, `internal/`, or designing a library API surface.
// Good — meaningful db := spannertest.NewDatabaseFromFile(...) _, err := f.Seek(0, io.SeekStart) // Bad — vague db := test.NewDatabaseFromFile(...) _, err := f.Seek(0, common.SeekStart)
Generic words may appear as part of a name (`stringutil`, `iotest`) but not as the whole name. Match the package to a concept the caller already knows.
import (
"fmt"
"os"
"github.com/foo/bar"
"rsc.io/goversion/version"
)| Rule | Guidance | |---|---| | Group order | stdlib, then external; extended order may also separate protos and side-effect imports | | Renaming | Avoid unless there is a collision; rename the more-local import | | Blank import (`import _`) | Only `main` and tests | | Dot import (`import .`) | Effectively never; rare in test files for circular deps |
> Read [references/imports-and-main.md](references/imports-and-main.md) for extended import grouping, proto `pb` suffixes, the `run()` pattern, and CLI flag conventions.
When you must use `init()`, make it:
1. Deterministic — same result every run. 2. Independent of the order of other `init()`s. 3. Free of environment state (env vars, working dir, args). 4. Free of I/O (filesystem, network, syscalls).
Acceptable uses:
If your `init` reads a file or calls a network API, refactor it into an explicit `Setup()` the caller invokes.
func main() {
if err := run(); err != nil {
log.Fatal(err)
}
}
func run() error {
// all the real work
return nil
}Why:
func main() {
outputDir := flag.String("output_dir", ".", "directory for output files")
flag.Parse()
if err := mylib.Generate(*outputDir); err != nil {
log.Fatal(err)
}
}> Read [references/init-and-globals.md](references/init-and-globals.md) for the boundaries between safe init-time computation, mutable globals, and dependency injection.
| Anti-pattern | Why it hurts | Do this instead | |---|---|---| | `package util` | Meaningless name; import conflicts | Name after the concept | | One huge package with 50 files | Hard to navigate, slow builds | Split by responsibility | | `init()` reads config from disk | Side effect at import time | Explicit `Setup()` in `main` | | `log.Fatal` in library code | Skips defers, untestable | Return an error | | `os.Exit` in a request handler | Same — plus crashes the server | Return an error to the framework | | `import _ "pkg"` in a library | Side effects on every importer | Register explicitly | | `import . "pkg"` to "save typing" | Tools lose track of where names come from | Use the package qualifier | | Library reads a flag at import time | Untestable, non-reusable | Accept config as parameter |
26 production-grade Go skills for Claude Code, Gemini CLI, and opencode. Battle-tested patterns from the Go community — codified as triggerable AI skills.
Repo: muratmirgun/gophers
Use when scaffolding or refactoring a Go service into a framework-agnostic clean (hexagonal) architecture: Domain, Usecase, Repository, Delivery layers, inward…
Invoke this skill to systematically review a Go change against community style standards before merging. Walks the diff topic by topic — formatting, errors,…
Use when writing or reviewing Go code for clarity, formatting, control flow, variable declarations, switch usage, and function design. Covers the priority…
Use when writing or reviewing concurrent Go code — goroutines, channels, select, mutexes, atomics, errgroup, singleflight, worker pools, or fan-out/fan-in…
Use when designing, propagating, or debugging context.Context flow in Go — first-parameter placement, deadlines and cancellation, request-scoped values,…
Use when writing conditionals, loops, switches, type switches, or blank-identifier patterns in Go. Covers if-with-initialization, guard clauses, early returns,…