Commit 7371c1922df9

Vincent Demeester <vincent@sbr.pm>
2025-12-04 16:11:41
docs: Enhance golang skill with official best practices and separate Nix integration
- Replace repository-specific content with generic Go best practices from official sources - Separate Nix-specific content to nix-integration.md for cleaner skill organization - Update skill name to TitleCase (Golang) following naming conventions Co-Authored-By: Claude <noreply@anthropic.com> Signed-off-by: Vincent Demeester <vincent@sbr.pm>
1 parent 1b57cb4
Changed files (2)
dots
.config
claude
dots/.config/claude/skills/golang/nix-integration.md
@@ -0,0 +1,301 @@
+# Go and Nix Integration
+
+This document provides guidance when working with Go projects that use Nix for building and packaging.
+
+## When to Use This Document
+
+This integration guide applies when:
+- You detect `flake.nix`, `default.nix`, or `shell.nix` in the project root
+- The project is in a Nix-managed repository (contains `/pkgs` or `/tools` with Nix definitions)
+- The user explicitly mentions Nix or NixOS
+
+## Project Structure for Nix-Based Go Projects
+
+### Typical Layout in ~/src/home Repository
+```
+tools/<tool-name>/
+├── cmd/
+│   └── <tool-name>/
+│       └── main.go          # Entry point
+├── internal/                # Private application code
+│   ├── config/
+│   ├── handlers/
+│   └── models/
+├── pkg/                     # Public library code (if needed)
+├── go.mod                   # Module definition
+├── go.sum                   # Dependency checksums
+├── README.md
+└── *_test.go               # Tests alongside code
+
+pkgs/<tool-name>/
+└── default.nix             # Nix package definition
+```
+
+### Multi-Architecture Support
+- Build for x86_64-linux and aarch64-linux
+- Nix handles cross-compilation automatically
+- Custom packages exposed via overlays in `/overlays`
+
+## Building Go Tools with Nix
+
+### Build Commands
+```bash
+# Build a Go tool package
+nix build .#<package-name>
+
+# Install to profile
+nix profile install .#<package-name>
+
+# Check what would be built
+nix build .#<package-name> --dry-run
+
+# Build for specific architecture
+nix build .#<package-name> --system aarch64-linux
+```
+
+### Development Shell
+```bash
+# Enter dev shell with Go tools available
+nix develop
+
+# Run tests in development shell
+cd tools/<tool-name>
+go test ./...
+
+# Format code (pre-commit hooks use gofmt)
+gofmt -w .
+```
+
+## Package Definition with buildGoModule
+
+### Basic Package Definition
+```nix
+# In pkgs/<package-name>/default.nix
+{ lib, buildGoModule }:
+
+buildGoModule {
+  pname = "tool-name";
+  version = "1.0.0";
+
+  # Source from tools directory
+  src = ../../tools/tool-name;
+
+  # Vendor hash for dependency management
+  # Set to lib.fakeHash initially, then update with actual hash
+  vendorHash = "sha256-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=";
+
+  # Build flags (optional)
+  ldflags = [
+    "-s"
+    "-w"
+    "-X main.version=${version}"
+  ];
+
+  # Metadata
+  meta = with lib; {
+    description = "Tool description";
+    homepage = "https://github.com/user/repo";
+    license = licenses.mit;
+    maintainers = [ ];
+  };
+}
+```
+
+### Updating Vendor Hash
+```bash
+# Initial build to get vendor hash
+nix build .#<package-name> 2>&1 | grep "got:"
+
+# Copy the hash from the error message to vendorHash in default.nix
+```
+
+### Common buildGoModule Options
+```nix
+buildGoModule {
+  # ... other options ...
+
+  # Exclude certain packages from building
+  excludedPackages = [ "cmd/debug-tool" ];
+
+  # Skip tests during build
+  doCheck = false;
+
+  # Additional build inputs
+  nativeBuildInputs = [ pkg-config ];
+  buildInputs = [ sqlite ];
+
+  # Post-install steps
+  postInstall = ''
+    installShellCompletion --cmd tool-name \
+      --bash <($out/bin/tool-name completion bash) \
+      --zsh <($out/bin/tool-name completion zsh)
+  '';
+
+  # CGO settings
+  CGO_ENABLED = 0;  # Static binary
+}
+```
+
+## Testing in Nix Environment
+
+### Running Tests
+```bash
+# From repository root
+nix develop
+cd tools/<tool-name>
+go test ./...
+
+# With coverage
+go test -cover ./...
+
+# Verbose output
+go test -v ./...
+```
+
+### Pre-commit Hooks
+The repository uses pre-commit hooks for Go:
+- `gofmt` for formatting
+- Can be installed with `make install-hooks`
+
+```bash
+# Install hooks
+make install-hooks
+
+# Run pre-commit checks manually
+make pre-commit
+```
+
+## Integration with Repository Build System
+
+### Makefile Targets (if available)
+```bash
+# Build Go tools via Nix
+make build
+
+# Run tests
+make test
+
+# Format code
+make fmt
+
+# Clean build artifacts
+make clean
+```
+
+## Dependency Management with Nix
+
+### Adding Dependencies
+```bash
+# Add Go dependency normally
+cd tools/<tool-name>
+go get github.com/pkg/errors
+go mod tidy
+
+# Update Nix package vendorHash
+nix build .#<package-name>  # Will show new hash
+```
+
+### Updating Dependencies
+```bash
+# Update Go modules
+cd tools/<tool-name>
+go get -u ./...
+go mod tidy
+
+# Update vendorHash in pkgs/<package-name>/default.nix
+# Rebuild to verify
+nix build .#<package-name>
+```
+
+## Common Patterns
+
+### Tool with Subcommands
+```nix
+buildGoModule {
+  pname = "multi-tool";
+  version = "1.0.0";
+  src = ../../tools/multi-tool;
+
+  # Build only the main command
+  subPackages = [ "cmd/multi-tool" ];
+
+  vendorHash = "sha256-...";
+}
+```
+
+### Tool with Static Assets
+```nix
+buildGoModule {
+  pname = "web-tool";
+  version = "1.0.0";
+  src = ../../tools/web-tool;
+
+  vendorHash = "sha256-...";
+
+  # Embed static assets
+  preBuild = ''
+    cp -r ${../../tools/web-tool/assets} ./assets
+  '';
+}
+```
+
+### Tool Requiring External Dependencies
+```nix
+{ lib, buildGoModule, pkg-config, sqlite }:
+
+buildGoModule {
+  pname = "db-tool";
+  version = "1.0.0";
+  src = ../../tools/db-tool;
+
+  nativeBuildInputs = [ pkg-config ];
+  buildInputs = [ sqlite ];
+
+  vendorHash = "sha256-...";
+
+  # Enable CGO for database drivers
+  CGO_ENABLED = 1;
+}
+```
+
+## Troubleshooting
+
+### Vendor Hash Mismatch
+```bash
+# Problem: vendorHash error during build
+# Solution: Update hash with the one shown in error message
+nix build .#<package-name> 2>&1 | grep "got:"
+```
+
+### Missing Dependencies
+```bash
+# Problem: Missing system libraries
+# Solution: Add to buildInputs or nativeBuildInputs
+buildInputs = [ pkg-config sqlite ];
+```
+
+### Test Failures in Nix Build
+```bash
+# Problem: Tests fail during nix build but pass with `go test`
+# Solution: Disable tests in package definition
+doCheck = false;
+
+# Or fix test dependencies
+checkInputs = [ git ];
+```
+
+## Best Practices for Nix + Go
+
+1. **Keep go.mod/go.sum updated**: Always run `go mod tidy` after dependency changes
+2. **Update vendorHash promptly**: Don't commit package definitions with incorrect hashes
+3. **Test in nix develop**: Ensure tools work in Nix environment before building package
+4. **Use proper source paths**: Reference tool sources with relative paths (e.g., `../../tools/name`)
+5. **Document build requirements**: Note any special build flags or dependencies in README
+6. **Leverage overlays**: Add custom packages to overlays for repository-wide availability
+7. **Version consistently**: Keep version in sync between go.mod and default.nix
+
+## Resources
+
+- Nix Manual: https://nixos.org/manual/nix/stable/
+- buildGoModule documentation: https://nixos.org/manual/nixpkgs/stable/#sec-language-go
+- Repository structure: See `/pkgs` and `/tools` directories for examples
dots/.config/claude/skills/golang/SKILL.md
@@ -1,101 +1,315 @@
 ---
-name: golang
-description: Go development best practices and patterns. USE WHEN writing Go code, designing Go projects, working with Go tools, testing, or integrating Go with Nix.
+name: Golang
+description: Go development best practices and patterns. USE WHEN writing Go code, designing Go projects, working with Go tools, testing, or Go package development.
 ---
 
 # Go Development Best Practices
 
 ## Purpose
-Guide Go development following best practices and project conventions.
+Guide Go development following official standards, community best practices, and idiomatic patterns from Effective Go and the Go team's code review guidelines.
 
-## Project Structure (for tools in ~/src/home)
+## Core Principles
 
-### Standard Layout
+1. **Clarity over cleverness**: Write simple, readable code that's easy to maintain
+2. **Gofmt is law**: Always format code with `gofmt` - no exceptions
+3. **Handle errors explicitly**: Errors are values that must be deliberately processed
+4. **Share by communicating**: Use channels and goroutines for concurrency
+5. **Prefer composition**: Embed types and use interfaces over inheritance patterns
+
+## Standard Project Structure
+
+### Recommended Layout
 ```
-tools/<tool-name>/
+myproject/
 ├── cmd/
-│   └── <tool-name>/
-│       └── main.go          # Entry point
+│   └── myapp/
+│       └── main.go          # Application entry points
 ├── internal/                # Private application code
 │   ├── config/
 │   ├── handlers/
 │   └── models/
-├── pkg/                     # Public library code (if needed)
+├── pkg/                     # Public library code (optional)
+│   └── utils/
+├── api/                     # API definitions (OpenAPI, protobuf)
+├── configs/                 # Configuration files
+├── docs/                    # Documentation
+├── scripts/                 # Build and analysis scripts
+├── test/                    # Additional test data
 ├── go.mod                   # Module definition
 ├── go.sum                   # Dependency checksums
 ├── README.md
 └── *_test.go               # Tests alongside code
 ```
 
-### Integration with Nix
-- Tools source: `/tools/<tool-name>/`
-- Custom packages: `/pkgs/` (exposed via overlays)
-- Testing: Run from tool directory with `go test ./...`
-- Multi-arch: Build for x86_64-linux and aarch64-linux
+### Key Directories
 
-## Best Practices
+- **`cmd/`**: Main applications - each subdirectory is a separate binary
+- **`internal/`**: Private code that cannot be imported by other projects
+- **`pkg/`**: Public libraries that can be imported by external projects
+- **`api/`**: API specifications and protocol definitions
 
-### Code Organization
+**Start simple**: Don't create all directories upfront. Add structure as complexity grows.
 
-#### Package Naming
-- Use lowercase, single-word names
-- No underscores or camelCase
-- Example: `package config`, `package handler`
+## Writing Idiomatic Go
 
-#### File Naming
-- Use lowercase with underscores for multi-word names
-- Example: `http_client.go`, `user_handler.go`
-- Test files: `*_test.go`
+### Formatting and Style
 
-### Writing Idiomatic Go
+**Always use gofmt**
+```bash
+# Format all files in current directory and subdirectories
+gofmt -w .
+
+# Use goimports to also manage imports
+goimports -w .
+```
+
+**Follow standard formatting**:
+- Use tabs for indentation (gofmt handles this)
+- No strict line length, but wrap long lines for readability
+- Group imports: standard library, third-party, local
 
-#### Error Handling
 ```go
-// Good: Wrap errors with context
-if err := doSomething(); err != nil {
+import (
+    "fmt"
+    "os"
+
+    "github.com/pkg/errors"
+    "github.com/spf13/cobra"
+
+    "myproject/internal/config"
+)
+```
+
+### Naming Conventions
+
+**Packages**
+- Lowercase, single-word names: `package config`, `package handler`
+- No underscores or mixedCaps in package names
+- Choose clear, concise names that describe the package's purpose
+
+**Variables and Functions**
+- Use `mixedCaps` or `MixedCaps`, never underscores
+- Exported names start with uppercase: `UserController`, `ProcessData`
+- Private names start with lowercase: `userCount`, `processRequest`
+- Short names in small scopes: `i`, `err`, `ok`, `buf`
+- Descriptive names in larger scopes: `userRepository`, `configManager`
+
+**Getters and Setters**
+```go
+// Good: Getters don't use "Get" prefix
+user.Name()      // not user.GetName()
+user.SetName(n)  // Setter keeps "Set"
+
+// Good: For interfaces with single method
+type Reader interface {
+    Read(p []byte) (n int, err error)
+}
+```
+
+**Constants**
+- Use `MixedCaps`: `MaxRetries`, `DefaultTimeout`
+- Or group in const blocks with clear names
+
+### Commentary and Documentation
+
+**Package Comments**
+```go
+// Package regexp implements regular expression search.
+//
+// The syntax of the regular expressions accepted is:
+//
+//     regexp:
+//         concatenation { '|' concatenation }
+package regexp
+```
+
+**Function Comments**
+```go
+// Compile parses a regular expression and returns, if successful,
+// a Regexp object that can be used to match against text.
+func Compile(str string) (*Regexp, error) {
+```
+
+**Key principles**:
+- Doc comments should be complete sentences
+- Start with the name of the element being described
+- Explain what, why, and any non-obvious behavior
+- Document errors that can be returned
+
+### Error Handling
+
+**Check every error**
+```go
+// Good: Handle errors immediately
+result, err := doSomething()
+if err != nil {
     return fmt.Errorf("failed to do something: %w", err)
 }
 
-// Good: Check errors immediately
-result, err := fetchData()
+// Bad: Ignoring errors
+result, _ := doSomething()  // Never do this
+```
+
+**Wrap errors with context**
+```go
+// Use %w to wrap errors for programmatic inspection
+if err := os.Remove(file); err != nil {
+    return fmt.Errorf("removing %s: %w", file, err)
+}
+
+// Use %v for simple annotation without inspection
+if err := validate(data); err != nil {
+    return fmt.Errorf("validation failed: %v", err)
+}
+```
+
+**Check error types when needed**
+```go
+if errors.Is(err, os.ErrNotExist) {
+    // Handle file not found
+}
+
+var pathErr *os.PathError
+if errors.As(err, &pathErr) {
+    // Access pathErr.Path, pathErr.Op
+}
+```
+
+**Error handling patterns**
+```go
+// Good: Keep normal path at minimal indentation
+value, err := someOperation()
 if err != nil {
     return err
 }
+// Continue with value...
 
-// Bad: Ignoring errors
-result, _ := fetchData()  // Don't do this
+// Good: Early returns for error conditions
+if user == nil {
+    return errors.New("user cannot be nil")
+}
+if !user.IsActive {
+    return errors.New("user is not active")
+}
+// Continue with valid user...
 ```
 
-#### Use context.Context
+### Interfaces
+
+**Design principles**
+- Interfaces define behavior, not data
+- Prefer small, focused interfaces (often single-method)
+- Define interfaces where they're used, not where they're implemented
+- Accept interfaces, return concrete types
+
 ```go
-// Good: Accept context as first parameter
-func ProcessRequest(ctx context.Context, req *Request) error {
-    // Use ctx for cancellation, deadlines, values
-    select {
-    case <-ctx.Done():
-        return ctx.Err()
-    case result := <-process(req):
-        return result
+// Good: Small, focused interface
+type Reader interface {
+    Read(p []byte) (n int, err error)
+}
+
+// Good: Compose interfaces
+type ReadWriter interface {
+    Reader
+    Writer
+}
+
+// Good: Define interface in consumer package
+// Package needs something that can save data
+type DataSaver interface {
+    Save(data []byte) error
+}
+```
+
+### Concurrency
+
+**Goroutines**
+```go
+// Good: Make it clear when goroutines exit
+func process(ctx context.Context) {
+    done := make(chan bool)
+
+    go func() {
+        defer close(done)
+        // Do work
+        for {
+            select {
+            case <-ctx.Done():
+                return
+            default:
+                doWork()
+            }
+        }
+    }()
+
+    <-done
+}
+```
+
+**Channels**
+```go
+// Good: Specify channel direction in function signatures
+func producer(out chan<- int) {
+    out <- 42
+    close(out)
+}
+
+func consumer(in <-chan int) {
+    for val := range in {
+        fmt.Println(val)
     }
 }
+
+// Good: Use buffered channels for resource limiting
+requests := make(chan *Request, 100)
 ```
 
-#### Prefer Composition Over Inheritance
+**Share by communicating**
 ```go
-// Good: Embed types for composition
-type Server struct {
-    logger *Logger
-    cache  *Cache
+// Good: Use channels instead of shared memory
+type result struct {
+    value int
+    err   error
 }
 
-// Good: Define interfaces
-type DataStore interface {
-    Get(key string) ([]byte, error)
-    Set(key string, value []byte) error
+resultCh := make(chan result)
+go func() {
+    val, err := compute()
+    resultCh <- result{val, err}
+}()
+
+res := <-resultCh
+if res.err != nil {
+    // handle error
 }
 ```
 
-#### Keep Functions Small and Focused
+### Context Usage
+
+**Always use context**
+```go
+// Good: Accept context as first parameter
+func FetchUser(ctx context.Context, id string) (*User, error) {
+    req, err := http.NewRequestWithContext(ctx, "GET", url, nil)
+    if err != nil {
+        return nil, err
+    }
+    // ...
+}
+
+// Good: Propagate context through call chains
+func ProcessRequest(ctx context.Context, req *Request) error {
+    user, err := FetchUser(ctx, req.UserID)
+    if err != nil {
+        return err
+    }
+    return SaveData(ctx, user)
+}
+```
+
+### Function Design
+
+**Keep functions small and focused**
 ```go
 // Good: Single responsibility
 func validateEmail(email string) error {
@@ -105,36 +319,42 @@ func validateEmail(email string) error {
     return nil
 }
 
-// Bad: Doing too much
-func processUserAndSendEmail(user User) error {
-    // Validation
-    // Database operations
-    // Email sending
-    // Logging
-    // ... (too many responsibilities)
+func createUser(name, email string) (*User, error) {
+    if err := validateEmail(email); err != nil {
+        return nil, err
+    }
+    return &User{Name: name, Email: email}, nil
 }
 ```
 
-### Naming Conventions
+**Use options pattern for complex configuration**
+```go
+type ServerOption func(*Server)
 
-#### Variables
-- Use camelCase for local variables: `userCount`, `httpClient`
-- Use short names in small scopes: `i`, `err`, `ok`
-- Use descriptive names in larger scopes: `userRepository`, `configManager`
+func WithTimeout(d time.Duration) ServerOption {
+    return func(s *Server) {
+        s.timeout = d
+    }
+}
 
-#### Functions and Methods
-- Use camelCase: `getUserByID`, `processRequest`
-- Exported functions start with uppercase: `NewClient`, `ProcessData`
-- Getters don't use "Get" prefix: `user.Name()`, not `user.GetName()`
+func NewServer(addr string, opts ...ServerOption) *Server {
+    s := &Server{addr: addr, timeout: 30 * time.Second}
+    for _, opt := range opts {
+        opt(s)
+    }
+    return s
+}
 
-#### Constants
-- Use camelCase or uppercase with underscores
-- Exported: `MaxRetries`, `DefaultTimeout`
-- Private: `defaultBufferSize`, `maxConnections`
+// Usage
+srv := NewServer(":8080",
+    WithTimeout(10*time.Second),
+    WithMaxConns(100))
+```
 
 ## Testing
 
 ### Table-Driven Tests
+
 ```go
 func TestValidateEmail(t *testing.T) {
     tests := []struct {
@@ -152,13 +372,19 @@ func TestValidateEmail(t *testing.T) {
             email:   "userexample.com",
             wantErr: true,
         },
+        {
+            name:    "empty email",
+            email:   "",
+            wantErr: true,
+        },
     }
 
     for _, tt := range tests {
         t.Run(tt.name, func(t *testing.T) {
             err := validateEmail(tt.email)
             if (err != nil) != tt.wantErr {
-                t.Errorf("validateEmail() error = %v, wantErr %v", err, tt.wantErr)
+                t.Errorf("validateEmail(%q) error = %v, wantErr %v",
+                    tt.email, err, tt.wantErr)
             }
         })
     }
@@ -166,49 +392,129 @@ func TestValidateEmail(t *testing.T) {
 ```
 
 ### Test Organization
-- Tests in same package: `package mypackage`
-- Tests in separate package: `package mypackage_test` (black-box testing)
-- Use subtests with `t.Run()` for clarity
-- Mock external dependencies using interfaces
+
+**Black-box vs White-box testing**
+```go
+// White-box: same package, can access internals
+package mypackage
+
+func TestInternalFunction(t *testing.T) { }
+
+// Black-box: separate package, tests public API only
+package mypackage_test
+
+import "myproject/mypackage"
+
+func TestPublicAPI(t *testing.T) { }
+```
+
+**Test helpers**
+```go
+// Mark test helpers with t.Helper()
+func assertEqual(t *testing.T, got, want int) {
+    t.Helper()
+    if got != want {
+        t.Errorf("got %d, want %d", got, want)
+    }
+}
+```
+
+**Use t.Error over t.Fatal**
+```go
+// Good: t.Error allows other tests to continue
+func TestMultipleChecks(t *testing.T) {
+    if got := compute(1); got != 2 {
+        t.Errorf("compute(1) = %d, want 2", got)
+    }
+    if got := compute(2); got != 4 {
+        t.Errorf("compute(2) = %d, want 4", got)
+    }
+}
+
+// Use t.Fatal only when continuing makes no sense
+func TestSetup(t *testing.T) {
+    db, err := setupDatabase()
+    if err != nil {
+        t.Fatalf("setupDatabase() failed: %v", err)
+    }
+    // Can't continue without db
+}
+```
 
 ### Test Coverage
-- Aim for meaningful coverage, not 100%
-- Focus on critical paths and edge cases
-- Use `go test -cover ./...` to check coverage
-- Don't test trivial code
 
-### Running Tests
 ```bash
-# Run all tests
-go test ./...
-
-# Run with coverage
+# Run tests with coverage
 go test -cover ./...
 
-# Run specific test
-go test -run TestValidateEmail
+# Generate coverage profile
+go test -coverprofile=coverage.out ./...
 
-# Verbose output
-go test -v ./...
+# View coverage in browser
+go tool cover -html=coverage.out
 
-# Run tests before committing
-go test ./...
+# Check coverage for specific packages
+go test -cover ./internal/...
+```
+
+**Coverage guidelines**:
+- Aim for meaningful coverage, not arbitrary percentages
+- Focus on critical business logic and edge cases
+- Don't test trivial code (getters, setters)
+- Use coverage to find untested code paths, not as a goal
+
+### Benchmarking
+
+```go
+func BenchmarkCompute(b *testing.B) {
+    input := generateInput()
+
+    b.ResetTimer() // Reset timer after setup
+    for i := 0; i < b.N; i++ {
+        compute(input)
+    }
+}
+
+func BenchmarkComputeParallel(b *testing.B) {
+    input := generateInput()
+
+    b.RunParallel(func(pb *testing.PB) {
+        for pb.Next() {
+            compute(input)
+        }
+    })
+}
+```
+
+```bash
+# Run benchmarks
+go test -bench=. ./...
+
+# With memory allocation stats
+go test -bench=. -benchmem ./...
+
+# CPU profiling
+go test -bench=. -cpuprofile=cpu.prof
+
+# Analyze profile
+go tool pprof cpu.prof
 ```
 
 ## Common Patterns
 
 ### Configuration Management
+
 ```go
 type Config struct {
-    Port     int           `json:"port"`
-    Timeout  time.Duration `json:"timeout"`
-    LogLevel string        `json:"log_level"`
+    Port     int           `json:"port" yaml:"port"`
+    Timeout  time.Duration `json:"timeout" yaml:"timeout"`
+    LogLevel string        `json:"log_level" yaml:"log_level"`
 }
 
 func LoadConfig(path string) (*Config, error) {
     data, err := os.ReadFile(path)
     if err != nil {
-        return nil, fmt.Errorf("reading config: %w", err)
+        return nil, fmt.Errorf("reading config file: %w", err)
     }
 
     var cfg Config
@@ -221,164 +527,89 @@ func LoadConfig(path string) (*Config, error) {
 ```
 
 ### Graceful Shutdown
+
 ```go
 func main() {
     ctx, cancel := context.WithCancel(context.Background())
     defer cancel()
 
+    // Listen for interrupt signals
     sigChan := make(chan os.Signal, 1)
     signal.Notify(sigChan, os.Interrupt, syscall.SIGTERM)
 
     go func() {
         <-sigChan
-        log.Println("Shutting down...")
+        log.Println("Shutdown signal received, cleaning up...")
         cancel()
     }()
 
     if err := run(ctx); err != nil {
-        log.Fatal(err)
+        log.Fatalf("Application error: %v", err)
     }
 }
+
+func run(ctx context.Context) error {
+    // Application logic with context
+    <-ctx.Done()
+    return cleanup()
+}
 ```
 
 ### HTTP Client with Timeout
+
 ```go
+// Good: Configure timeouts and connection pooling
 client := &http.Client{
     Timeout: 10 * time.Second,
     Transport: &http.Transport{
         MaxIdleConns:        100,
         MaxIdleConnsPerHost: 10,
         IdleConnTimeout:     90 * time.Second,
+        TLSHandshakeTimeout: 10 * time.Second,
     },
 }
-```
 
-## Nix Integration
+// Use context for per-request timeout
+ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
+defer cancel()
 
-### Building
-```bash
-# Build a Go tool package
-nix build .#<package-name>
-
-# Install to profile
-nix profile install .#<package-name>
-
-# Check what would be built
-nix build .#<package-name> --dry-run
-```
-
-### Testing in Nix
-```bash
-# Enter dev shell
-nix develop
-
-# Run tests
-cd tools/<tool-name>
-go test ./...
-```
-
-### Package Definition
-```nix
-# In pkgs/<package-name>/default.nix
-{ lib, buildGoModule }:
-
-buildGoModule {
-  pname = "tool-name";
-  version = "1.0.0";
-
-  src = ../../tools/tool-name;
-
-  vendorHash = "sha256-...";
-
-  meta = with lib; {
-    description = "Tool description";
-    license = licenses.mit;
-  };
+req, err := http.NewRequestWithContext(ctx, "GET", url, nil)
+if err != nil {
+    return err
 }
+
+resp, err := client.Do(req)
+if err != nil {
+    return err
+}
+defer resp.Body.Close()
 ```
 
-## Common Commands
+### Resource Management with sync.Pool
 
-### Formatting and Linting
-```bash
-# Format code
-gofmt -w .
-
-# Organize imports
-goimports -w .
-
-# Vet code
-go vet ./...
-
-# Run linter
-golangci-lint run
-
-# Fix linter issues automatically
-golangci-lint run --fix
-```
-
-### Dependency Management
-```bash
-# Add dependency
-go get github.com/pkg/errors
-
-# Update dependencies
-go get -u ./...
-
-# Tidy modules
-go mod tidy
-
-# Verify dependencies
-go mod verify
-
-# Vendor dependencies
-go mod vendor
-```
-
-### Build and Run
-```bash
-# Build
-go build -o bin/myapp cmd/myapp/main.go
-
-# Run
-go run cmd/myapp/main.go
-
-# Install
-go install ./cmd/myapp
-```
-
-## Performance
-
-### Benchmarking
 ```go
-func BenchmarkFunction(b *testing.B) {
-    for i := 0; i < b.N; i++ {
-        doSomething()
-    }
+// Good: Reuse expensive objects
+var bufferPool = sync.Pool{
+    New: func() interface{} {
+        return new(bytes.Buffer)
+    },
+}
+
+func processData(data []byte) error {
+    buf := bufferPool.Get().(*bytes.Buffer)
+    defer bufferPool.Put(buf)
+    buf.Reset()
+
+    // Use buffer
+    buf.Write(data)
+    return process(buf)
 }
 ```
 
-### Profiling
-```bash
-# CPU profiling
-go test -cpuprofile cpu.prof -bench .
-
-# Memory profiling
-go test -memprofile mem.prof -bench .
-
-# Analyze profile
-go tool pprof cpu.prof
-```
-
-### Optimization Tips
-- Use sync.Pool for frequently allocated objects
-- Prefer slices over arrays when size varies
-- Use buffered channels appropriately
-- Avoid premature optimization - profile first!
-
 ## Common Pitfalls to Avoid
 
 ### ❌ Goroutine Leaks
+
 ```go
 // Bad: Goroutine never exits
 go func() {
@@ -401,35 +632,212 @@ go func(ctx context.Context) {
 ```
 
 ### ❌ Race Conditions
+
 ```go
 // Bad: Concurrent map access
 var cache = make(map[string]string)
 
-// Good: Use sync.Map or mutex
+func get(key string) string {
+    return cache[key]  // Race!
+}
+
+// Good: Use sync.Map for concurrent access
 var cache sync.Map
+
+func get(key string) string {
+    val, _ := cache.Load(key)
+    if val != nil {
+        return val.(string)
+    }
+    return ""
+}
+
+// Or use mutex for complex operations
+type Cache struct {
+    mu   sync.RWMutex
+    data map[string]string
+}
+
+func (c *Cache) Get(key string) string {
+    c.mu.RLock()
+    defer c.mu.RUnlock()
+    return c.data[key]
+}
 ```
 
 ### ❌ Defer in Loops
+
 ```go
-// Bad: Defers accumulate
+// Bad: Defers accumulate until function exits
 for _, file := range files {
     f, _ := os.Open(file)
     defer f.Close()  // Won't close until function exits!
 }
 
-// Good: Close immediately
+// Good: Close immediately or use function wrapper
 for _, file := range files {
     func() {
-        f, _ := os.Open(file)
+        f, err := os.Open(file)
+        if err != nil {
+            log.Printf("error opening %s: %v", file, err)
+            return
+        }
         defer f.Close()
+        processFile(f)
     }()
 }
 ```
 
+### ❌ Pointer to Loop Variable
+
+```go
+// Bad: All goroutines will use the last value
+for _, val := range values {
+    go func() {
+        process(val)  // Bug: val is the loop variable!
+    }()
+}
+
+// Good: Pass value as parameter
+for _, val := range values {
+    go func(v string) {
+        process(v)
+    }(val)
+}
+```
+
+### ❌ Nil Channel Operations
+
+```go
+// Bad: Sending/receiving on nil channel blocks forever
+var ch chan int
+ch <- 1  // Blocks forever!
+
+// Good: Initialize channels
+ch := make(chan int)
+ch <- 1
+```
+
+## Tooling
+
+### Essential Commands
+
+```bash
+# Format code
+gofmt -w .
+goimports -w .
+
+# Vet code for common mistakes
+go vet ./...
+
+# Run tests
+go test ./...
+go test -v ./...          # Verbose
+go test -cover ./...      # With coverage
+go test -race ./...       # Race detector
+
+# Dependency management
+go mod tidy               # Clean up dependencies
+go mod verify             # Verify dependencies
+go get -u ./...           # Update dependencies
+
+# Build
+go build -o bin/myapp ./cmd/myapp
+go install ./cmd/myapp
+
+# Cross-compilation
+GOOS=linux GOARCH=amd64 go build
+GOOS=darwin GOARCH=arm64 go build
+```
+
+### Linting
+
+```bash
+# Install golangci-lint
+go install github.com/golangci/golangci-lint/cmd/golangci-lint@latest
+
+# Run all linters
+golangci-lint run
+
+# Auto-fix issues
+golangci-lint run --fix
+
+# Run specific linters
+golangci-lint run --enable=gosec,exhaustive
+```
+
+### Profiling
+
+```bash
+# CPU profiling
+go test -cpuprofile cpu.prof -bench .
+go tool pprof cpu.prof
+
+# Memory profiling
+go test -memprofile mem.prof -bench .
+go tool pprof mem.prof
+
+# Block profiling (find blocking goroutines)
+go test -blockprofile block.prof -bench .
+go tool pprof block.prof
+
+# Analyze in browser
+go tool pprof -http=:8080 cpu.prof
+```
+
+## Performance Best Practices
+
+1. **Profile before optimizing**: Use `pprof` to find actual bottlenecks
+2. **Use appropriate data structures**:
+   - Slices for sequential access
+   - Maps for key-value lookups
+   - Channels for communication
+3. **Preallocate when size is known**:
+   ```go
+   items := make([]Item, 0, expectedSize)
+   ```
+4. **Reuse objects with sync.Pool**: For frequently allocated objects
+5. **Avoid unnecessary allocations**:
+   - Use string builders instead of concatenation
+   - Reuse buffers when possible
+6. **Benchmark critical paths**: Write benchmarks for performance-critical code
+7. **Use buffered channels appropriately**: Avoid blocking on channel operations
+
+## Nix Integration
+
+> **Note**: If you detect Nix usage in this project (presence of `flake.nix`, `default.nix`, or Nix package definitions), refer to `nix-integration.md` in this skill directory for detailed Nix-specific build instructions, package definitions, and integration patterns.
+
+Quick check for Nix:
+- Look for `flake.nix`, `default.nix`, or `shell.nix` in project root
+- Check for `/pkgs` or `/tools` directories with Nix definitions
+- User mentions Nix, NixOS, or buildGoModule
+
 ## Resources
 
-- Effective Go: https://go.dev/doc/effective_go
-- Go Code Review Comments: https://github.com/golang/go/wiki/CodeReviewComments
-- Standard library documentation: https://pkg.go.dev/std
+### Official Documentation
+- [Effective Go](https://go.dev/doc/effective_go) - Core Go programming guide
+- [Go Code Review Comments](https://go.dev/wiki/CodeReviewComments) - Common code review issues
+- [Go Standard Library](https://pkg.go.dev/std) - Documentation and examples
+- [Google Go Style Guide](https://google.github.io/styleguide/go/) - Production best practices
 
-Remember: Write clear, simple, idiomatic Go code. When in doubt, check the standard library for examples.
+### Tools
+- [gofmt](https://pkg.go.dev/cmd/gofmt) - Code formatter
+- [goimports](https://pkg.go.dev/golang.org/x/tools/cmd/goimports) - Import management
+- [golangci-lint](https://golangci-lint.run/) - Comprehensive linter
+- [gopls](https://github.com/golang/tools/tree/master/gopls) - Language server
+
+### Learning Resources
+- [Go by Example](https://gobyexample.com/) - Practical examples
+- [Go Playground](https://go.dev/play/) - Try Go in browser
+- [Uber Go Style Guide](https://github.com/uber-go/guide/blob/master/style.md) - Additional patterns
+
+---
+
+**Remember**: Write clear, simple, idiomatic Go code. When in doubt, consult Effective Go and the standard library for guidance. The Go community values simplicity, readability, and maintainability above cleverness.
+
+**Sources**:
+- [Effective Go](https://go.dev/doc/effective_go)
+- [Go Code Review Comments](https://go.dev/wiki/CodeReviewComments)
+- [Google Go Style Guide](https://google.github.io/styleguide/go/)
+- [Go Best Practices 2025](https://www.bacancytechnology.com/blog/go-best-practices)
+- [Go Coding Standards](https://leapcell.medium.com/go-coding-official-standards-and-best-practices-5e84f4dbc8ad)