
Go Best Practices
- 34 installs
- 217 repo stars
- Updated March 19, 2026
- poteto/noodle
go-best-practices is a Claude Code skill for ai & agent building.
About
go-best-practices is a Claude Code skill for ai & agent building. It helps solo builders move faster with AI-assisted development.
- go-best-practices
- AI & Agent Building
- AI-coding skill
Go Best Practices by the numbers
- 34 all-time installs (skills.sh)
- Ranked #8,855 of 16,546 AI & Agent Building skills by installs in the Skillselion catalog
- Data as of Aug 4, 2026 (Skillselion catalog sync)
npx skills add https://github.com/poteto/noodle --skill go-best-practicesAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 34 |
|---|---|
| repo stars | ★ 217 |
| Last updated | March 19, 2026 |
| Repository | poteto/noodle ↗ |
How do I helps with ai & agent building tasks.?
Helps with ai & agent building tasks.
Who is it for?
Best when you're working on ai & agent building and need structured help with go best practices.
Skip if: Teams with no ai & agent building needs, or anyone wanting a generic chat assistant without this specific workflow.
When should I use this skill?
When you need to helps with ai & agent building tasks., or when go-best-practices is a claude code skill for ai & agent building.
What you get
Structured output aligned to go-best-practices: go-best-practices, AI & Agent Building.
Files
Go Best Practices
| Pattern | When to apply |
|---|---|
| Minimal main | New binaries |
| Single bootstrap | App wiring across modes |
| Ordered shutdown | Long-running processes |
| Non-blocking fanout | Channel-based event systems |
| Concurrency testing | Any goroutine code |
| Layered config | Multi-source configuration |
| Cross-platform paths | File/config path resolution |
| Secure debug logging | HTTP client instrumentation |
| Golden test matrices | Rendering / output components |
| Focused linters | CI pipeline setup |
Read references/patterns.md for code examples.
Rules
1. main.go is a stub. Call cmd.Execute() and nothing else. Gate diagnostics (pprof) behind env vars.
2. One bootstrap path. All modes (interactive, headless, test) share the same initialization function. Two paths will drift.
3. Ordered shutdown. Cancel dependents before their dependencies, then run independent cleanup in parallel under a timeout context. WaitGroup the parallel phase.
4. Never block the sender. Non-blocking channel sends with an explicit drop policy. Log drops at debug level. Document the policy.
5. Test concurrency mechanically. testing/synctest for deterministic timing, goleak.VerifyNone for leak detection, dedicated regression tests for timer/channel deadlocks.
6. Explicit config precedence. Global → project → flags. Walk up from CWD to discover project configs, reverse so closest wins, deep-merge.
7. Centralize platform paths. One function per concern. Resolution order: env override → XDG → platform default → fallback.
8. Redact secrets in debug logs. Wrap http.RoundTripper. Filter headers matching authorization, api-key, token, secret. Gate on debug level to skip allocation in prod.
9. Golden tests over matrices. Cross dimensions (layout × theme × size) as parallel subtests. Sweep continuous ranges to catch off-by-one bugs.
10. Focused linters, not all linters. Enable what catches real bugs (bodyclose, noctx, tparallel). Disable noisy defaults. Add project-specific checks as scripts. Always -race in tests.
Go Best Practices — Code Patterns
1. Minimal main
func main() {
if os.Getenv("APP_PROFILE") != "" {
go func() {
slog.Info("Serving pprof", "addr", "localhost:6060")
http.ListenAndServe("localhost:6060", nil) //nolint:errcheck
}()
}
cmd.Execute()
}Import _ "net/http/pprof" for side-effect registration. The env gate keeps diagnostics out of the production path.
2. Single Bootstrap Path
func setupApp(cmd *cobra.Command) (*App, error) {
cfg, err := config.Load(cwd)
if err != nil {
return nil, err
}
db, err := openDB(ctx, cfg.DataDir)
if err != nil {
return nil, err
}
return NewApp(ctx, db, cfg)
}Every mode calls setupApp. One path, one set of bugs.
3. Ordered Graceful Shutdown
func (a *App) Shutdown() {
// Phase 1: cancel dependents that must finish before resources close.
a.workers.CancelAll()
// Phase 2: independent cleanup in parallel with a shared timeout.
var wg sync.WaitGroup
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
for _, fn := range a.cleanups {
wg.Go(func() {
if err := fn(ctx); err != nil {
slog.Error("Cleanup failed", "error", err)
}
})
}
wg.Wait()
}- Ordered phases — dependents before their dependencies.
- Shared timeout context bounds the entire parallel phase.
- Register cleanup funcs during setup, run them at teardown.
4. Non-Blocking Fanout
Publisher — drop on full channel
func (b *Broker[T]) Publish(event T) {
b.mu.RLock()
defer b.mu.RUnlock()
for ch := range b.subs {
select {
case ch <- event:
default:
// Slow subscriber — drop, never block publisher.
}
}
}Consumer — timeout-bounded forward
func forward[T any](ctx context.Context, in <-chan T, out chan<- T, timeout time.Duration) {
timer := time.NewTimer(0)
<-timer.C
defer timer.Stop()
for {
select {
case v, ok := <-in:
if !ok { return }
// Safe timer reset: Stop, drain, Reset.
if !timer.Stop() {
select {
case <-timer.C:
default:
}
}
timer.Reset(timeout)
select {
case out <- v:
case <-timer.C:
slog.Debug("Dropped message", "reason", "slow consumer")
case <-ctx.Done():
return
}
case <-ctx.Done():
return
}
}
}The Stop → drain → Reset sequence prevents timer leaks and deadlocks. Always write a dedicated test for this (see pattern 5).
5. Concurrency Testing
synctest for deterministic timing
func TestNormalFlow(t *testing.T) {
synctest.Test(t, func(t *testing.T) {
ch := make(chan int, 1)
go func() { ch <- 42 }()
time.Sleep(10 * time.Millisecond)
synctest.Wait()
select {
case v := <-ch:
require.Equal(t, 42, v)
default:
t.Fatal("expected value")
}
})
}goleak for goroutine leak detection
func TestNoLeak(t *testing.T) {
defer goleak.VerifyNone(t)
// ... test that starts goroutines ...
}Add goleak.VerifyNone to at least one test per concurrent subsystem.
Deadlock regression tests
func TestTimerDrainDeadlock(t *testing.T) {
synctest.Test(t, func(t *testing.T) {
// Reproduce the exact sequence that triggered the deadlock.
// Publish → timeout fires (drop) → publish again → cancel.
done := make(chan struct{})
go func() {
// ... exercise the code path ...
close(done)
}()
select {
case <-done:
case <-time.After(5 * time.Second):
t.Fatal("hung — likely timer drain deadlock")
}
})
}Test fixture pattern
type fixture struct {
cancel context.CancelFunc
wg sync.WaitGroup
out chan Msg
}
func newFixture(t *testing.T) *fixture {
t.Helper()
ctx, cancel := context.WithCancel(t.Context())
t.Cleanup(cancel)
f := &fixture{cancel: cancel, out: make(chan Msg, 10)}
// wire up goroutines ...
return f
}Use t.Context() and t.Cleanup to tie lifecycle to the test.
6. Layered Config Loading
func discoverConfigs(cwd string) []string {
paths := []string{globalConfigPath()} // lowest priority
found, _ := walkUpFor(cwd, "app.json", ".app.json")
slices.Reverse(found) // closest to CWD = highest priority
return append(paths, found...)
}
func loadConfigs(paths []string) (*Config, error) {
var layers [][]byte
for _, p := range paths {
data, err := os.ReadFile(p)
if errors.Is(err, fs.ErrNotExist) { continue }
if err != nil { return nil, fmt.Errorf("reading %s: %w", p, err) }
if len(data) == 0 { continue }
layers = append(layers, data)
}
merged := deepMergeJSON(layers...)
var cfg Config
return &cfg, json.Unmarshal(merged, &cfg)
}Precedence: global (lowest) → discovered project configs (closest to CWD wins) → CLI flags (highest). Missing and empty files silently skipped.
7. Cross-Platform Paths
func configDir() string {
if v := os.Getenv("APP_CONFIG_DIR"); v != "" {
return v
}
if v := os.Getenv("XDG_CONFIG_HOME"); v != "" {
return filepath.Join(v, appName)
}
return filepath.Join(home(), ".config", appName)
}
func dataDir() string {
if v := os.Getenv("APP_DATA_DIR"); v != "" {
return v
}
if v := os.Getenv("XDG_DATA_HOME"); v != "" {
return filepath.Join(v, appName)
}
if runtime.GOOS == "windows" {
base := cmp.Or(os.Getenv("LOCALAPPDATA"),
filepath.Join(os.Getenv("USERPROFILE"), "AppData", "Local"))
return filepath.Join(base, appName)
}
return filepath.Join(home(), ".local", "share", appName)
}One function per path concern. Resolution: env override → XDG → platform default → fallback. Centralize in a single file.
8. Secure Debug HTTP Logging
type debugTransport struct{ base http.RoundTripper }
func (d *debugTransport) RoundTrip(req *http.Request) (*http.Response, error) {
if slog.Default().Enabled(req.Context(), slog.LevelDebug) {
slog.Debug("HTTP request", "method", req.Method, "url", req.URL)
}
start := time.Now()
resp, err := d.base.RoundTrip(req)
if err == nil && slog.Default().Enabled(req.Context(), slog.LevelDebug) {
slog.Debug("HTTP response",
"status", resp.StatusCode,
"headers", redactHeaders(resp.Header),
"ms", time.Since(start).Milliseconds())
}
return resp, err
}
func redactHeaders(h http.Header) map[string][]string {
out := make(map[string][]string, len(h))
for k, v := range h {
lk := strings.ToLower(k)
if strings.Contains(lk, "authorization") ||
strings.Contains(lk, "api-key") ||
strings.Contains(lk, "token") ||
strings.Contains(lk, "secret") {
out[k] = []string{"[REDACTED]"}
} else {
out[k] = v
}
}
return out
}Gate on slog.LevelDebug to skip body drain / allocation in production. If logging request/response bodies, drain and restore via io.NopCloser.
9. Golden Test Matrices
func TestRender(t *testing.T) {
for name, layout := range layouts {
t.Run(name, func(t *testing.T) {
for name, theme := range themes {
t.Run(name, func(t *testing.T) {
t.Parallel()
w := NewWidget(WithLayout(layout), WithTheme(theme))
golden.RequireEqual(t, []byte(w.Render()))
})
}
})
}
}- Dimension maps produce N*M subtests, all parallel.
golden.RequireEqualdiffs against committed.goldenfiles (update with
-update flag).
- Sweep continuous ranges (width 1-120, height 1-30) to catch off-by-one
rendering bugs.
10. Focused Linters + CI
.golangci.yml
version: "2"
linters:
enable:
- bodyclose # unclosed HTTP response bodies
- noctx # HTTP requests without context
- sqlclosecheck # unclosed sql.Rows
- tparallel # missing t.Parallel()
- staticcheck # comprehensive static analysis
- misspell # comment/string typos
- gofumpt # strict formatting
disable:
- errcheck # too noisy — use explicit checks where it mattersTask runner
tasks:
test:
cmds: [go test -race -failfast ./...]
lint:
cmds:
- task: lint:custom
- golangci-lint run --timeout=5m
lint:custom:
cmds: [./scripts/check_log_style.sh]Project-specific lint script
#!/bin/bash
if grep -rE 'slog\.(Error|Info|Warn|Debug)\("[a-z]' --include="*.go" .; then
echo "Log messages must start with a capital letter." && exit 1
fiAlways -race in tests. -failfast for local iteration. Custom scripts for style rules that golangci-lint can't express.
Related skills
FAQ
What does go-best-practices do?
go-best-practices is a Claude Code skill for ai & agent building.
When should I use go-best-practices?
When you need to helps with ai & agent building tasks., or when go-best-practices is a claude code skill for ai & agent building.
What are the main capabilities?
go-best-practices; AI & Agent Building; AI-coding skill.