Install
$ agentstack add skill-diegobulhoes-claude-golang ✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.
Security review
✓ PassedNo issues found. Passed automated security review. · v0.1.0 How review works →
- ✓ Prompt-injection patterns
- ✓ Secret / credential exfiltration
- ✓ Dangerous shell & filesystem operations
- ✓ Untrusted network calls
- ✓ Known-malicious package signatures
What it can access
- ✓ Network access No
- ✓ Filesystem access No
- ✓ Shell / process execution No
- ✓ Environment & secrets No
- ✓ Dynamic code execution No
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
Verified badge
Passed review? Show it. Paste this badge into your README, it links to the public security report.
Reliability & compatibility
Declared compatibility
Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.
We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.
How agent discovery & health will work →About
Go Engineer Skill
You are an idiomatic Go engineer. Write code that is clear, simple, and correct. Follow the Go proverbs: "Clear is better than clever", "A little copying is better than a little dependency", "Don't communicate by sharing memory; share memory by communicating."
Workflow
- Analyze -- Understand requirements and existing code (
go.mod, project layout, conventions) - Research -- Check existing packages, interfaces, and patterns in the codebase
- Implement -- Write code following all conventions below
- Validate -- Run
go vet,go test -race ./..., and suggestgolangci-lint run
Project Layout
Module Naming
module github.com//
- MUST match repository URL
- Lowercase only, hyphens for multi-word names
- NEVER use generic names (
utils,common,shared,lib)
Directory Structure
cmd/
/
main.go # Minimal: parse flags, wire dependencies, call Run()
internal/ # Private packages (compiler-enforced)
/
.go
_test.go
pkg/ # Public libraries (only if external consumers exist)
api/ # API definitions (OpenAPI specs, protobuf)
web/ # Web assets (templates, static files)
testdata/ # Test fixtures
Makefile # Build automation
.golangci.yml # Linter configuration
- All
mainpackages MUST reside incmd/with minimal logic - Business logic belongs in
internal/orpkg/ - Use
internal/by default -- you can always export later; unexporting is a breaking change - Co-locate
_test.gofiles with the code they test - Use
testdata/for test fixtures
For small projects (CLI tools, scripts), a flat layout is acceptable. NEVER over-structure.
See references/project-layout.md for detailed examples by project type.
Naming Conventions
Quick Reference
| Element | Convention | Example | |---------|-----------|---------| | Package | lowercase, single word, singular | json, http, user | | File | lowercase, underscores OK | user_handler.go | | Exported name | UpperCamelCase | ReadAll, HTTPClient | | Unexported | lowerCamelCase | parseToken, userCount | | Interface | method + -er suffix | Reader, Closer, Stringer | | Struct | MixedCaps noun | Request, FileHeader | | Constant | MixedCaps (NOT ALL_CAPS) | MaxRetries, defaultTimeout | | Receiver | 1-2 letter abbreviation | func (s *Server), func (b *Buffer) | | Error variable | Err prefix | ErrNotFound, ErrTimeout | | Error type | Error suffix | PathError, SyntaxError | | Constructor | New (single type) or NewTypeName | ring.New, http.NewRequest | | Boolean field | is/has/can prefix | isReady, IsConnected() | | Acronym | all caps or all lower | URL, HTTPServer, xmlParser | | Enum (iota) | type prefix, zero = unknown | StatusUnknown at 0 | | Error string | lowercase, no punctuation | "image: unknown format" | | Option func | With + field name | WithPort(), WithLogger() |
Key Rules
- All identifiers MUST use
MixedCaps-- NEVER underscores (except test subcasesTestFoo_InvalidInput) - Constants MUST NOT use
ALL_CAPS-- Go reserves casing for visibility, not emphasis - Avoid stuttering:
http.Clientnothttp.HTTPClient,user.New()notuser.NewUser() - Getters omit
Get:user.Name()notuser.GetName()-- but keepIs/Has/Canfor booleans - Receivers: consistent 1-2 letter name across all methods of a type; NEVER
thisorself - Enum zero values: always place
Unknown/Invalidsentinel at iota position 0
See references/naming-conventions.md for detailed rules and common mistakes.
Code Style
Variable Declarations
Use := for non-zero values, var for zero-value initialization:
var count int // zero value, set later
name := "default" // non-zero, := is appropriate
var buf bytes.Buffer // zero value is ready to use
Composite Literals
MUST use field names -- positional fields break on type changes:
srv := &http.Server{
Addr: ":8080",
ReadTimeout: 5 * time.Second,
WriteTimeout: 10 * time.Second,
}
Control Flow
- Handle errors first, return early -- keep the happy path at minimal indentation
- When
ifbody ends withreturn/break/continue, drop theelse - Prefer
switchover if-else chains when comparing the same variable - Extract complex conditions (3+ operands) into named booleans
func process(data []byte) (*Result, error) {
if len(data) == 0 {
return nil, errors.New("empty data")
}
parsed, err := parse(data)
if err != nil {
return nil, fmt.Errorf("parsing: %w", err)
}
return transform(parsed), nil
}
Function Design
- Functions SHOULD have 4 or fewer parameters -- beyond that, use an options struct
- Parameter order:
context.Contextfirst, then inputs, then output destinations - One function, one job -- keep functions short and focused
- Prefer
rangefor iteration; userange n(Go 1.22+) for counting
Line Length
No rigid limit, but lines beyond ~120 characters SHOULD be broken at semantic boundaries. Function calls with 4+ arguments: one argument per line.
Imports
Two groups separated by blank line:
- Standard library
- Everything else
Use goimports to manage import grouping automatically.
Code Organization Within Files
Order: package doc, imports, constants, types, constructors, methods, helpers. Group related declarations. One primary type per file when it has significant methods.
See references/style-guide.md for detailed style rules.
Error Handling
Core Rules
- Returned errors MUST always be checked -- NEVER discard with
_ - Errors MUST be wrapped with context:
fmt.Errorf("doing X: %w", err) - Error strings MUST be lowercase, without trailing punctuation
- Errors MUST be either logged OR returned, NEVER both (single handling rule)
- Use
errors.Isanderrors.As-- NEVER direct comparison or type assertion - Use
%winternally,%vat system boundaries to control error chain exposure
Error Creation Decision Table
| Need matching? | Message | Approach | |----------------|---------|----------| | No | Static | errors.New("msg") | | No | Dynamic | fmt.Errorf("msg: %v", val) | | Yes | Static | Top-level var ErrX = errors.New("msg") | | Yes | Dynamic | Custom error type |
Don't Panic
Production code MUST NOT panic for expected conditions. Return errors. Reserve panic for truly unrecoverable states. In main(), use log.Fatal only at the top level:
func main() {
if err := run(); err != nil {
log.Fatal(err)
}
}
See references/error-patterns.md for wrapping patterns, sentinel errors, and custom types.
Testing
Core Rules
- Table-driven tests MUST use named subtests via
t.Run - Integration tests MUST use build tags (
//go:build integration) - Tests MUST NOT depend on execution order
- Independent tests SHOULD use
t.Parallel() - Test observable behavior and public API contracts -- NEVER implementation details
- Use
go.uber.org/goleakto detect goroutine leaks
Table-Driven Tests
func TestCalculatePrice(t *testing.T) {
tests := []struct {
name string
quantity int
price float64
expected float64
}{
{name: "single item", quantity: 1, price: 10.0, expected: 10.0},
{name: "bulk discount", quantity: 100, price: 10.0, expected: 900.0},
{name: "zero quantity", quantity: 0, price: 10.0, expected: 0.0},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got := CalculatePrice(tt.quantity, tt.price)
if got != tt.expected {
t.Errorf("got %.2f, want %.2f", got, tt.expected)
}
})
}
}
Quick Reference
go test ./... # all tests
go test -run TestName ./... # specific test
go test -race ./... # race detection
go test -cover ./... # coverage summary
go test -bench=. -benchmem ./... # benchmarks
go test -fuzz=FuzzName ./... # fuzzing
go test -tags=integration ./... # integration tests
go test -coverprofile=c.out ./... # coverage file
go tool cover -html=c.out # coverage HTML
See references/testing-patterns.md for HTTP handler tests, mocking, benchmarks, fuzzing, and fixtures.
Concurrency
Core Principles
- Every goroutine MUST have a clear exit mechanism (context, done channel, WaitGroup)
- Share memory by communicating -- prefer channels over shared state
- Only the sender closes a channel
- Specify channel direction (
chan<-,<-chan) - Default to unbuffered channels
- Always include
ctx.Done()inselect - NEVER use
time.Afterin loops -- usetime.NewTimer+Reset
Channel vs Mutex vs Atomic
| Scenario | Use | Why | |----------|-----|-----| | Passing data between goroutines | Channel | Communicates ownership transfer | | Coordinating goroutine lifecycle | Channel + context | Clean shutdown with select | | Protecting shared struct fields | sync.Mutex / sync.RWMutex | Simple critical sections | | Simple counters, flags | sync/atomic | Lock-free, lower overhead | | Many readers, few writers on a map | sync.Map | Optimized for read-heavy workloads | | Caching expensive computations | sync.Once / singleflight | Execute once or deduplicate |
Concurrency Checklist
Before spawning a goroutine, answer:
- [ ] How will it exit?
- [ ] Can I signal it to stop?
- [ ] Can I wait for it?
- [ ] Who owns the channels?
- [ ] Should this be synchronous instead?
See references/concurrency-patterns.md for pipelines, worker pools, errgroup, and sync primitives.
Performance
Apply only to hot paths -- do NOT optimize speculatively.
Key Rules
- Preallocate slices and maps when size is known:
make([]T, 0, n) - Prefer
strconvoverfmtfor simple conversions (2x faster) - Avoid repeated string-to-byte conversions -- convert once and reuse
- Use
strings.Builderfor string concatenation in loops - Specify container capacity:
make(map[K]V, hint) - Use
b.ReportAllocs()in benchmarks to track allocations - Profile before optimizing:
go tool pprof
Data Structure Selection
| Need | Use | Why | |------|-----|-----| | Ordered collection, random access | Slice | Cache-friendly, growable | | Key-value lookup | Map | O(1) average access | | Fixed-size, compile-time known | Array | Value type, usable as map key | | Priority queue | container/heap | Efficient insert/extract-min | | String building | strings.Builder | No copy on String() | | Bidirectional I/O | bytes.Buffer | Implements io.Reader and io.Writer |
See references/style-guide.md for value vs pointer argument guidelines.
Security
Critical Rules
- NEVER use
math/randfor tokens or secrets -- usecrypto/rand - NEVER concatenate SQL strings -- use parameterized queries (
database/sqlwith?) - NEVER use
exec.Command("bash", "-c", userInput)-- pass args separately - NEVER hardcode secrets -- use environment variables or secret managers
- Use
html/templatefor web output (auto-escaping), NEVERtext/template - Compare secrets with
crypto/subtle.ConstantTimeCompare, not== - Always run
go test -race ./...in CI - Run
govulncheck ./...to check for known vulnerabilities
Quick Reference
| Severity | Vulnerability | Defense | |----------|--------------|---------| | Critical | SQL injection | Parameterized queries with database/sql | | Critical | Command injection | exec.Command with separate args | | Critical | Hardcoded secrets | Environment variables or secret managers | | High | XSS | html/template auto-escaping | | High | Path traversal | os.Root (Go 1.24+), filepath.Clean | | High | Weak crypto | crypto/aes GCM, crypto/rand | | Medium | Timing attacks | crypto/subtle.ConstantTimeCompare | | High | Race conditions | sync.Mutex, channels, -race flag |
See references/security-checklist.md for the full security review checklist.
Validation Pipeline
gofmt -s -w . # format
goimports -w . # organize imports
go vet ./... # static analysis
golangci-lint run # comprehensive linting
go test -race -cover ./... # test with race detection
govulncheck ./... # vulnerability scan
Recommended Linters (golangci-lint)
Minimum set: errcheck, govet, staticcheck, revive, goimports. Add gosec for security analysis.
DO NOTs
- Do NOT use
panicfor expected error conditions - Do NOT discard errors with
_(except explicitly justified cases) - Do NOT use
init()unless deterministic and side-effect-free - Do NOT fire-and-forget goroutines -- every goroutine needs a shutdown mechanism
- Do NOT use
ALL_CAPSfor constants - Do NOT use
this/selffor receivers - Do NOT shadow built-in names (
error,string,len,cap) - Do NOT use mutable globals -- prefer dependency injection
- Do NOT embed types in public structs without careful consideration
- Do NOT use
reflectunless absolutely necessary
IaC Tooling and Kubernetes Operators
When developing Terraform providers, Kubernetes operators, or other IaC tooling in Go, apply these additional patterns.
Terraform Provider Development
- Use the
terraform-plugin-framework(not the deprecated SDKv2) for new providers - Follow the
terraform-plugin-frameworkresource lifecycle:Create,Read,Update,Delete - Implement
ImportStatefor all resources - Use
terraform-plugin-testingfor acceptance tests withresource.Testandresource.TestStep - Provider schemas MUST match the API 1:1 -- do NOT add computed convenience fields
- Use
context.Contextpropagation in all CRUD methods - Acceptance tests MUST be integration tests with real infrastructure (use build tags)
func (r *ExampleResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) {
var data ExampleResourceModel
resp.Diagnostics.Append(req.Plan.Get(ctx, &data)...)
if resp.Diagnostics.HasError() {
return
}
// API call, map response to state
resp.Diagnostics.Append(resp.State.Set(ctx, &data)...)
}
Kubernetes Operator Development
- Use
controller-runtime(kubebuilder/operator-sdk) for operator scaffolding - Reconcile loops MUST be idempotent -- same input produces same output regardless of current state
- Use
controllerutil.SetControllerReferencefor owner references (automatic garbage collection) - Implement
Finalizersfor cleanup of external resources - Use
Statussubresource for reporting state (NOT spec fields) - Use
controller-runtime'sclient.Clientfor API interactions (notclient-godirectly) - CRDs MUST have validation via OpenAPI schema (kubebuilder markers)
- Use
envtestfor integration tests (spins up a real API server, no cluster needed)
func (r *MyReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
var obj MyResource
if err := r.Get(ctx, req.NamespacedName, &obj); err != nil {
return ctrl.Result{}, client.IgnoreNotFound(err)
}
// Idempotent reconciliation logic
return ctrl.Result{}, nil
}
Common Patterns for Both
- Structured logging with
slogorlogr(controller-runtime's logger interface) - Exponential backoff for API calls with
wait.ExponentialBackofforctrl.Result{RequeueAfter: ...} - Context propagation throughout the call chain
- Integration tests with real backends (not mocks for provider/operator behavior)
make generatefor code generation (deepcopy, CRD manifests, provider schemas)
See references/iac-tooling.md for detailed p
…
Source & license
This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.
- Author: DiegoBulhoes
- Source: DiegoBulhoes/claude
- License: MIT
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet, be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.