go-packages — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited go-packages (Agent Skill) and scored it 100/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 0 high-severity and 0 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 0 flagged
Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
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.
util, helper, common, misc are not names.goimports will keep this honest.main has a single exit point and deferred cleanup runs.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 when deciding how to split a growing package, organizingcmd/,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 for extended import grouping, protopbsuffixes, therun()pattern, and CLI flag conventions.
init()When you must use init(), make it:
init()s.Acceptable uses:
database/sql drivers).If your init reads a file or calls a network API, refactor it into an explicit Setup() the caller invokes.
mainfunc main() {
if err := run(); err != nil {
log.Fatal(err)
}
}
func run() error {
// all the real work
return nil
}Why:
log.Fatal and os.Exit skip defer. Anywhere except main, that means leaked files, half-flushed buffers, undeleted temp dirs.run() pattern gives you one place to log a clean error and one place to set the exit code.package main.snake_case: --output_dir, not --outputDir.flag.Lookup.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 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 |
goimports cleaninit() performs I/O or depends on env statemain is a single if err := run(); err != nil { log.Fatal(err) }os.Exit / log.Fatal* outside mainpackage mainimport . and no blank import outside main/testscmd/, internal/, public API surfacerun() pattern, flag conventionsinit is acceptable, mutable globals, DI~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.