4.4 KiB
4.4 KiB
CLAUDE.md — Agent Instructions
This file is read automatically by Claude Code at the start of every session. Keep it concise — the agent needs signal, not essays.
Project overview
Go 1.24 template / PoC starter. Demonstrates: structured logging (zap), config (viper), interfaces + mocks (mockery), linting (golangci-lint), security scanning (gosec, govulncheck), git hooks, devcontainer, VSCode tasks.
Module: github.com/your-org/go-template — update this when you fork.
Project structure
cmd/app/main.go composition root — wires deps, no logic here
internal/config/ Viper config loader (config.Load)
internal/logger/ Zap wrapper with WithField / WithFields
internal/greeter/ Example domain package (delete or repurpose)
mocks/greeter/ Generated mocks — regenerate with `make mocks`
config/dev.yaml Local dev config (committed, no secrets)
tools.go Tool version pinning (build tag: tools)
.golangci.yml Linter rules
.mockery.yaml Mockery code-gen config
.githooks/pre-commit Runs gofmt + golangci-lint + gosec before commit
Project rules
- Module imports — always use the full module path
github.com/your-org/go-template/... - Packages — keep
cmd/thin (wiring only); business logic belongs ininternal/ - Interfaces — define interfaces where they are used, not where they are implemented
- Errors — wrap with
fmt.Errorf("context: %w", err); never swallow errors silently - Logging — use
log.WithField("key", val)for structured context, neverfmt.Sprintfin log messages - Config — all configuration through
internal/config; no hard-coded values in logic packages - Secrets — never commit
.envfiles or credentials; use env var overrides of config keys
Code style
- Follow
gofmt+goimportsformatting (enforced by linter and git hook) - Imports: stdlib → blank line → external → blank line → internal (goimports handles this)
- Error variables:
errfor local,ErrFoofor package-level sentinels - Constructors:
New(deps...) *Typepattern - Comment every exported symbol (golangci-lint will warn if missing)
- Max line length: 120 chars (configured in
.golangci.yml) - Prefer explicit over clever; PoC code should be readable first
Testing rules
- All tests use testify (
assertfor soft checks,requirefor stop-on-fail) - Test files:
package foo_test(black-box) unless white-box access is needed - Mock dependencies via mockery-generated mocks with
EXPECT()chains - Use
logger.NewNop()when the test doesn't care about log output - Table-driven tests with
t.Run("description", ...)for multiple cases - The race detector is enabled in CI (
make test-race); don't introduce data races - Never use
time.Sleepin tests; use channels orrequire.Eventually
Development commands
make init # first-time setup: fetch deps, install tools, git hooks
make build # compile to ./bin/app
make run # go run with config/dev.yaml
make test # run all tests
make test-race # tests + race detector
make lint # golangci-lint
make lint-fix # auto-fix lint issues
make security # gosec + govulncheck
make mocks # regenerate all mocks
make generate # run all //go:generate directives
make clean # remove bin/ and mocks/
VSCode: Ctrl+Shift+B = build, Ctrl+Shift+T = test.
Debug: use launch config "Debug: app" (F5).
Adding new features (checklist)
- Define the interface in
internal/<domain>/ - Write the implementation and its unit tests
- Add the interface to
.mockery.yamland runmake mocks - Wire it in
cmd/app/main.go - Run
make lint testbefore committing
Known pitfalls
mocks/are committed intentionally — regenerate after interface changesgovulncheckmakes network calls; excluded from pre-commit hook (run manually)config/dev.yamlis committed but never add real credentials heretools.gohas//go:build tools— it won't compile into the binary
Recent work
- 2026-03-05 — Initial template scaffolded: config, logger, greeter example, mocks, git hooks, devcontainer, VSCode tasks, golangci-lint, Makefile.