go-project-standard
Lean Go module coach. Not a project-layout generator, and not a Make, CI, or Docker author.
Scope
Not here: Make target names (makefile-standard), GitHub Actions (ci-standard), Dockerfile and image build (dockerfile-standard), Compose topology (compose-standard). Full golang-standards/project-layout trees, hard coverage gates, and inventing binaries the repo does not need are out of scope.
Workflow
1. Inspect needs
Inventory: go.mod and Go version, existing packages and main entrypoints, current linter config, tests, tools.go against tool. Read Make and CI only to know where the handoffs are; do not redefine them here.
2. Detect profile
No main is a library. Cobra, urfave/cli, or kong is a cli. Any other binary is a service. Confirm with the human when it is ambiguous. Details: references/profiles.md.
3. Apply standard
Read references/rules.yaml, the source of truth for rule IDs. Full rules: references/go-project-standard.md.
| Artifact | Greenfield start |
|---|---|
| Lint | assets/.golangci.yml.template → .golangci.yml |
| library layout | assets/layout.library.md.template |
| service layout | assets/layout.service.md.template |
| cli layout | assets/layout.cli.md.template |
Replace every Adapt… marker. Migrate brownfield through references/migration-guide.md.
Logic packages get a _test.go. Go 1.24 and up prefer the tool directive over tools.go. The rest is in Hard rules below.
4. YAGNI
- No empty
pkg/"for later". - No full project-layout directory tree.
- No coverage percentage that blocks a merge.
- No inventing Make, CI, or Docker from this skill. Hand off when evidenced.
A config file the standard requires is not "unrequested config". A v2 .golangci.yml ships even when the default linters currently pass.
5. Validate
python3 scripts/validate_go_project.py /path/to/module
python3 scripts/validate_go_project.py /path/to/module --profile service
Errors = fix. Warnings = human review. A structural check is not go test or golangci green.
6. Report
Profile, detected or overridden; layout changes such as cmd/, internal/, or a removed empty pkg/; golangci posture; test posture; validation result; and handoffs, meaning what you found that belongs to makefile-standard, ci-standard, dockerfile-standard, or compose-standard, named but not fixed here.
Hard rules
- MUST ship a valid
go.modat the module root. - MUST use a golangci-lint v2 config (
version: "2"). - MUST NOT set
linters.default: all. - MUST NOT leave an empty cargo-cult
pkg/. - Multi-package binaries use a thin
cmd/<name>/main.go, required when a rootmainsits beside other packages. - Apps must not depend on this repo at runtime.
Exceptions
# go-project-standard: except <rule-id> — <reason>
Every ignored MUST needs an exception line with a non-empty reason.