go-packages▌
cxuu/golang-skills · updated Apr 8, 2026
When this skill does NOT apply: For naming individual identifiers within a package, see go-naming. For organizing functions within a single file, see go-functions. For configuring linters that enforce import rules, see go-linting.
Go Packages and Imports
When this skill does NOT apply: For naming individual identifiers within a package, see go-naming. For organizing functions within a single file, see go-functions. For configuring linters that enforce import rules, see go-linting.
Package Organization
Avoid Util Packages
Package names should describe what the package provides. Avoid generic names
like util, helper, common — they obscure meaning and cause import
conflicts.
// Good: Meaningful package names
db := spannertest.NewDatabaseFromFile(...)
_, err := f.Seek(0, io.SeekStart)
// Bad: Vague names obscure meaning
db := test.NewDatabaseFromFile(...)
_, err := f.Seek(0, common.SeekStart)
Generic names can be used as part of a name (e.g., stringutil) but should
not be the entire package name.
Package Size
| Question | Action |
|---|---|
| Can you describe its purpose in one sentence? | No → split by responsibility |
| Do files never share unexported symbols? | Those files could be separate packages |
| Distinct user groups use different parts? | Split along user boundaries |
| Godoc page overwhelming? | Split to improve discoverability |
Do NOT split just because a file is long, to create single-type packages, or if it would create circular dependencies.
Read references/PACKAGE-SIZE.md when deciding whether to split or combine packages, organizing files within a package, or structuring CLI programs.
Imports
Imports are organized in groups separated by blank lines. Standard library packages always come first. Use goimports to manage this automatically.
import (
"fmt"
"os"
"github.com/foo/bar"
"rsc.io/goversion/version"
)
Quick rules:
| Rule | Guidance |
|---|---|
| Grouping | stdlib first, then external. Extended: stdlib → other → protos → side-effects |
| Renaming | Avoid unless collision. Rename the most local import. Proto packages get pb suffix |
Blank imports (import _) |
Only in main packages or tests |
Dot imports (import .) |
Never use, except for circular-dependency test files |
Read references/IMPORTS.md when organizing imports with extended grouping, renaming proto packages, or deciding on blank/dot imports.
Avoid init()
Avoid init() where possible. When unavoidable, it must be:
- Completely deterministic
- Independent of other
init()ordering - Free of environment state (env vars, working dir, args)
- Free of I/O (filesystem, network, system calls)
Acceptable uses: complex expressions that can't be single assignments,
pluggable hooks (e.g., database/sql dialects), deterministic precomputation.
Read references/PACKAGE-SIZE.md when you need to refactor init() into explicit functions or understand acceptable init() uses.
Exit in Main
Call os.Exit or log.Fatal* only in main(). All other functions should
return errors.
Why: Non-obvious control flow, untestable, defer statements skipped.
Best practice: Use the run() pattern — extract logic into
func run() error, call from main() with a single exit point:
func main() {
if err := run(); err != nil {
log.Fatal(err)
}
}
Read references/PACKAGE-SIZE.md when implementing the run() pattern, structuring CLI subcommands, or choosing flag naming conventions.
Command-Line Flags
Advisory: Define flags only in
package main.
- Flag names use
snake_case:--output_dirnot--outputDir - Libraries should accept configuration as parameters, not read flags directly — this keeps them testable and reusable
- Prefer the standard
flagpackage; usepflagonly when POSIX conventions (double-dash, single-char shortcuts) are required
// Good: Flag in main, passed as parameter to library
func main() {
outputDir := flag.String("output_dir", ".", "directory for output files")
flag.Parse()
if err := mylib.Generate(*outputDir); err != nil {
log.Fatal(err)
}
}
Related Skills
- Package naming: See go-naming when choosing package names, avoiding stuttering, or naming exported symbols
- Error handling across packages: See go-error-handling when wrapping errors at package boundaries with
%wvs%v - Import linting: See go-linting when configuring goimports local-prefixes or enforcing import grouping
- Global state: See go-defensive when replacing
init()with explicit initialization or avoiding mutable globals
Discussion
Product Hunt–style comments (not star reviews)- No comments yet — start the thread.
Ratings
4.6★★★★★27 reviews- ★★★★★Advait Gupta· Dec 24, 2024
Keeps context tight: go-packages is the kind of skill you can hand to a new teammate without a long onboarding doc.
- ★★★★★Pratham Ware· Dec 20, 2024
I recommend go-packages for anyone iterating fast on agent tooling; clear intent and a small, reviewable surface area.
- ★★★★★Arya Taylor· Dec 8, 2024
We added go-packages from the explainx registry; install was straightforward and the SKILL.md answered most questions upfront.
- ★★★★★Sakura Garcia· Nov 27, 2024
Useful defaults in go-packages — fewer surprises than typical one-off scripts, and it plays nicely with `npx skills` flows.
- ★★★★★Mia Garcia· Nov 15, 2024
go-packages is among the better-maintained entries we tried; worth keeping pinned for repeat workflows.
- ★★★★★Sakura Johnson· Nov 7, 2024
I recommend go-packages for anyone iterating fast on agent tooling; clear intent and a small, reviewable surface area.
- ★★★★★Hiroshi Yang· Oct 26, 2024
go-packages reduced setup friction for our internal harness; good balance of opinion and flexibility.
- ★★★★★Charlotte Thomas· Oct 18, 2024
go-packages has been reliable in day-to-day use. Documentation quality is above average for community skills.
- ★★★★★Hana Yang· Oct 6, 2024
go-packages fits our agent workflows well — practical, well scoped, and easy to wire into existing repos.
- ★★★★★Dev Rao· Sep 25, 2024
Keeps context tight: go-packages is the kind of skill you can hand to a new teammate without a long onboarding doc.
showing 1-10 of 27