agentleFS
d-padmanabhand-padmanabhan/agent-engineering-handbook/skills/go-rust-systems/SKILL.md

go-rust-systems

Skill17 starsChanged 56 days agoMITView on GitHub

Go and Rust systems programming best practices for performance-critical, concurrent, and safe applications. Covers error handling, ownership/borrowing (Rust), context and goroutines (Go), testing patterns, and production deployment. Use when working with .go, .rs files, Cargo.toml, go.mod, or when asking about Go or Rust development.

  • Installs packages

The file

Show its rules and text

We split this skill into the rules it gives an agent

30 rules. About 0 are common, 13 are distinctive, and 17 are very specific to this project.

  • ≈0

    Common · estimate

    Many files like this have a rule of this kind.

  • ≈13

    Distinctive · estimate

    This author's own choices. Worth a look.

  • 17

    Very specific

    Tied to their project's names, files or tools. Probably skip.

  • Common
  • Distinctive
  • Very specific
  1. Very specific:

    Use golangci-lint as the primary aggregated lint gate.

    line 34
  2. Distinctive:

    Use function-level CRAP analysis only when complexity plus low coverage would help prioritize test and refactoring work.

    line 48
  3. Very specific:

    Do not use a single letter grade or /100 score as a required quality gate.

    line 53
  4. Very specific:

    Prefer switch for multi-way dispatch on one expression (and type switches).

    line 110
  5. Distinctive:

    Every exported package, type, function, method, constant, and variable has an idiomatic doc comment.

    line 114
  6. Distinctive:

    Document errors, concurrency safety, ownership, blocking, side effects, and resource lifecycle when they are part of the contract.

    line 117
  7. Distinctive:

    Do not add comments to obvious unexported helpers or comments that merely restate a signature.

    line 118
  8. Distinctive:

    Keep comments accurate when behavior changes.

    line 119
  9. Very specific:

    Follow the Go idioms reference (${HANDBOOK_ROOT}/skills/go-rust-systems/references/go-idioms.md) for examples.

    line 121
  10. Very specific:

    Use explicit http.Server values with ReadHeaderTimeout, ReadTimeout, WriteTimeout, and IdleTimeout.

    line 128
  11. Very specific:

    Use Decoder.DisallowUnknownFields() for public JSON APIs.

    line 132
  12. Distinctive:

    Avoid exported mutable policy/guardrail registries

    line 138
  13. Very specific:

    Keep test helpers in *_test.go

    line 139
  14. Very specific:

    Avoid side-effectful init().

    line 140
  15. Very specific:

    Keep go.mod module/toolchain pinned and run go mod tidy / go mod verify in CI

    line 141
  16. Distinctive:

    Use the latest supported stable Go toolchain compatible with the deployment and module policy.

    line 144
  17. Distinctive:

    Use semgrep + pre-commit checks for these patterns because standard linting does not catch all of them reliably.

    line 146
  18. Distinctive:

    When you add a new Go hardening expectation:

    line 151
  19. Very specific:

    Add the requirement to rules/210-go.mdc under HTTP Client Hardening (MUST).

    line 153
  20. Distinctive:

    Add detection guidance (semgrep/pre-commit) in the same rule file.

    line 154
  21. Very specific:

    Update at least one concrete reference example under skills/go-rust-systems/references/.

    line 156
  22. Very specific:

    Use //! for crate and module documentation and /// for public items.

    line 165
  23. Distinctive:

    Document public library APIs.

    line 166
  24. Distinctive:

    Keep public parameters, return types, generic bounds, associated types, and lifetimes explicit where Rust syntax requires them.

    line 167
  25. Very specific:

    Add # Examples, # Errors, and # Panics only when they improve the caller contract.

    line 168
  26. Distinctive:

    Document ownership, borrowing, mutation, blocking, cancellation, side effects, thread safety, and resource lifecycle when callers need that …

    line 169
  27. Very specific:

    Put a nearby // SAFETY: comment before each unsafe block to state the invariant that makes the operation valid.

    line 170
  28. Very specific:

    Prefer intra-doc links such as [User] over duplicated prose.

    line 171
  29. Very specific:

    Follow the Rust documentation reference (${HANDBOOK_ROOT}/skills/go-rust-systems/references/rust-documentation.md) for crate front pages, …

    line 173
  30. Very specific:

    Use the observability skill (${HANDBOOK_ROOT}/skills/observability/SKILL.md) for cross-language event schemas, sensitive-data policy, …

    line 344

≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
SKILL.md

Go & Rust Systems Programming

When to Use Which

Use CaseGoRust
Web services, APIs✅ Excellent✅ Good
CLI tools✅ Excellent✅ Excellent
Systems programming✅ Good✅ Excellent
Memory-critical apps⚠️ GC overhead✅ Zero-cost
Concurrency✅ Goroutines✅ Fearless
Learning curve✅ Easy⚠️ Steeper

Go Quick Reference

Essential Commands

go mod init <module>          # Initialize new module
go mod tidy                   # Add missing, remove unused
go test -race ./...          # Run with race detector
go test -cover ./...         # Show coverage
golangci-lint run            # Run all linters
govulncheck ./...            # Check vulnerabilities

Go Code Quality Signals

Use golangci-lint as the primary aggregated lint gate. Pin its version, commit its configuration, and enable linters deliberately. For full CI diagnostics, disable the default output caps:

issues:
  max-issues-per-linter: 0
  max-same-issues: 0

The caps affect how many findings are displayed; they are not quality thresholds. A clean run complements rather than replaces gofmt, go vet, go test -race, coverage evidence, and govulncheck.

Use function-level CRAP analysis only when complexity plus low coverage would help prioritize test and refactoring work. Configure a reviewed threshold and treat the result as a hotspot signal, not a project health score or correctness proof.

Do not use a single letter grade or /100 score as a required quality gate. The hosted Go Report Card service is retired. gocode-score and codescore are experimental advisory tools with limited adoption, so do not add them by default. Never weaken checks or add unjustified suppressions merely to improve a score.

Critical Patterns

// 1. Always check errors
result, err := someFunc()
if err != nil {
    return fmt.Errorf("operation failed: %w", err)  // Wrap with context
}

// 2. Use context for cancellation
func processData(ctx context.Context, data []string) error {
    for _, item := range data {
        select {
        case <-ctx.Done():
            return ctx.Err()  // Respect cancellation
        default:
            // Process item
        }
    }
    return nil
}

// 3. Defer cleanup immediately
file, err := os.Open("file.txt")
if err != nil {
    return err
}
defer file.Close()  // Defer right after open

// 4. Table-driven tests
func TestAdd(t *testing.T) {
    tests := []struct {
        name string
        a, b int
        want int
    }{
        {"positive", 1, 2, 3},
        {"negative", -1, -2, -3},
    }
    for _, tt := range tests {
        t.Run(tt.name, func(t *testing.T) {
            if got := Add(tt.a, tt.b); got != tt.want {
                t.Errorf("Add() = %v, want %v", got, tt.want)
            }
        })
    }
}

Control flow: switch vs if / else

Prefer switch for multi-way dispatch on one expression (and type switches); keep if for errors, booleans, guards, and two-branch logic. Do not rewrite errors.Is / errors.As chains just to use switch. Detail: rules/210-go.mdc (Simplicity & Idiomatic Go) and references/go-idioms.md.

Go Documentation Contract

  • Every exported package, type, function, method, constant, and variable has an idiomatic doc comment.
  • A declaration comment starts with the exported identifier so go doc associates it correctly.
  • A package comment explains package purpose, scope, and material constraints.
  • Document errors, concurrency safety, ownership, blocking, side effects, and resource lifecycle when they are part of the contract.
  • Do not add comments to obvious unexported helpers or comments that merely restate a signature.
  • Keep comments accurate when behavior changes; stale documentation is a correctness defect.

Follow the Go idioms reference (${HANDBOOK_ROOT}/skills/go-rust-systems/references/go-idioms.md) for examples.

Mandatory Hardening Add-On (Go)

For HTTP/API client code, always apply the hardening checks from rules/210-go.mdc:

  • Use explicit http.Server values with ReadHeaderTimeout, ReadTimeout, WriteTimeout, and IdleTimeout; do not call http.ListenAndServe directly in production services.
  • Bound inbound request bodies with http.MaxBytesReader before JSON decode.
  • Use Decoder.DisallowUnknownFields() for public JSON APIs.
  • Inject or construct explicit *http.Client values with timeouts and transport settings; do not use http.Get, http.Post, or http.DefaultClient in production services.
  • Bound response reads before io.ReadAll
  • Cap Retry-After and server-derived delays
  • Avoid exported mutable policy/guardrail registries
  • Keep test helpers in *_test.go
  • Avoid side-effectful init(); perform app wiring in cmd/<app>/main.go
  • Keep go.mod module/toolchain pinned and run go mod tidy / go mod verify in CI

Use the latest supported stable Go toolchain compatible with the deployment and module policy. Follow the dependency and toolchain currency workflow (${HANDBOOK_ROOT}/skills/core-engineering/references/dependency-and-toolchain-currency.md) for release verification, module updates, govulncheck, and time-boxed exceptions.

Use semgrep + pre-commit checks for these patterns because standard linting does not catch all of them reliably.

How To Maintain Rule/Skill Parity

When you add a new Go hardening expectation:

  1. Add the requirement to rules/210-go.mdc under HTTP Client Hardening (MUST).
  2. Add detection guidance (semgrep/pre-commit) in the same rule file.
  3. Mirror the short operational summary in this SKILL.md section.
  4. Update at least one concrete reference example under skills/go-rust-systems/references/.

This keeps policy (rules), agent behavior (skill), and examples in sync.

Rust Quick Reference

Rust Documentation and Public API Contract

  • Use //! for crate and module documentation and /// for public items.
  • Document public library APIs. Do not document obvious private helpers or restate type information already visible in signatures.
  • Keep public parameters, return types, generic bounds, associated types, and lifetimes explicit where Rust syntax requires them. Let obvious local variables use inference.
  • Add # Examples, # Errors, and # Panics only when they improve the caller contract. Every public unsafe API must include # Safety.
  • Document ownership, borrowing, mutation, blocking, cancellation, side effects, thread safety, and resource lifecycle when callers need that information.
  • Put a nearby // SAFETY: comment before each unsafe block to state the invariant that makes the operation valid.
  • Prefer intra-doc links such as [User] over duplicated prose. Keep links and examples compiling and current.

Follow the Rust documentation reference (${HANDBOOK_ROOT}/skills/go-rust-systems/references/rust-documentation.md) for crate front pages, doctests, safety contracts, lints, and CI verification.

Essential Commands

cargo new my-project          # Create new project
cargo build --release         # Build optimized
cargo test                    # Run tests
cargo test --doc              # Run documentation tests
cargo doc --no-deps           # Build crate documentation
cargo clippy                  # Linting
cargo fmt                     # Format code
cargo audit                   # Security audit

Critical Patterns

// 1. Ownership - each value has one owner
let s1 = String::from("hello");
let s2 = s1;  // s1 moved to s2
// println!("{}", s1);  // Error: value borrowed after move

// 2. Borrowing - references don't take ownership
fn calculate_length(s: &String) -> usize {
    s.len()
}
let s1 = String::from("hello");
let len = calculate_length(&s1);
println!("{} has length {}", s1, len);  // s1 still valid

// 3. Result for error handling
fn parse_number(s: &str) -> Result<i32, ParseIntError> {
    s.parse::<i32>()
}

// Use ? for propagation
fn read_file(path: &str) -> Result<String, std::io::Error> {
    let contents = std::fs::read_to_string(path)?;
    Ok(contents)
}

// 4. Option for nullable values
fn find_user(id: u32) -> Option<User> {
    if id == 0 { None } else { Some(User { id }) }
}

Go Error Handling

// Sentinel errors
var ErrNotFound = errors.New("not found")

// Custom error types
type ValidationError struct {
    Field string
    Issue string
}

func (e *ValidationError) Error() string {
    return fmt.Sprintf("validation failed on %s: %s", e.Field, e.Issue)
}

// Error wrapping
if err != nil {
    return fmt.Errorf("failed to process user %s: %w", id, err)
}

// Error checking
if errors.Is(err, ErrNotFound) { /* handle */ }
var valErr *ValidationError
if errors.As(err, &valErr) { /* handle */ }

Rust Error Handling

use thiserror::Error;

#[derive(Error, Debug)]
pub enum AppError {
    #[error("User not found: {0}")]
    NotFound(String),

    #[error("Database error: {0}")]
    Database(#[from] sqlx::Error),

    #[error("Invalid input: {0}")]
    Validation(String),
}

// Use anyhow for applications, thiserror for libraries
fn process_user(id: &str) -> anyhow::Result<User> {
    let user = find_user(id)
        .ok_or_else(|| anyhow::anyhow!("User {} not found", id))?;
    Ok(user)
}

Go Logging - Default Stack

Default for new code: log/slog (stdlib since 1.21) with the JSON handler. The ecosystem has aligned behind slog as the frontend; backends can be swapped without touching log statements if profiling shows logging is a bottleneck.

opts := &slog.HandlerOptions{AddSource: true, Level: slog.LevelInfo}
slog.SetDefault(slog.New(slog.NewJSONHandler(os.Stderr, opts)))

slog.NewJSONHandler emits one JSON object per physical line, which is suitable for NDJSON container streams. Do not require NDJSON when structured events are exported through OTLP, journald, or another native transport. Follow the observability skill (${HANDBOOK_ROOT}/skills/observability/SKILL.md) for collection, buffering, redaction, rotation, and loss behavior.

Calling conventions, ordered by safety

slog.Info("request", "method", "GET", "status", 200)                    // loose - error-prone
slog.InfoContext(ctx, "request", slog.String("method", "GET"), ...)     // recommended (enables trace correlation)
logger.LogAttrs(ctx, slog.LevelInfo, "request", slog.String(...), ...)  // safest (typed; compile-time)

Trace correlation via otelslog

import "go.opentelemetry.io/contrib/bridges/otelslog"

slog.SetDefault(otelslog.NewLogger("svc", otelslog.WithLoggerProvider(global.GetLoggerProvider())))
// MUST use *Context variants for span correlation:
logger.InfoContext(ctx, "processing", slog.String("order_id", id))

Redaction via LogValuer

type APIKey string
func (APIKey) LogValue() slog.Value { return slog.StringValue("REDACTED") }

Centralizes redaction so call sites cannot leak by accident.

Decision matrix - when to swap backend

NeedChoiceNotes
Defaultslog + JSONHandler~101 ns/op, zero allocs; fast enough for almost everyone
OTel correlationslog + otelslog bridgeDefault if service runs on OpenTelemetry
Profiler shows logging is hotphuslu/log as slog backend~38 ns/op (~2.7x stdlib); single maintainer is the trade-off
Maximum throughput, library API OKzerolog native~25 ns/op, zero allocs; built-in sampling
Extensibility, advanced cores, test observerszap nativezapcore.Core composition, zaptest/observer, AtomicLevel
CLI / TUI, human reads terminalcharmbracelet/log as slog backendColoring, icons, color downsampling
Existing logrusMigrate hot paths to slogDon't start new code on logrus (maintenance mode, ~15x slower than slog)

Footguns:

  • zerolog as slog backend re-encodes WithAttrs per Handle() call - ~46x slower than its native API. Use zerolog natively; don't bridge.
  • zerolog chain without terminal .Msg() / .Send() silently drops the entry AND leaks the pooled Event.
  • zap.SugaredLogger adds 1 alloc per call from variadic boxing.
  • slog ships no TRACE / FATAL levels by default.

Required CI lint

go install github.com/go-simpler/sloglint/cmd/sloglint@latest
sloglint -no-mixed-args -static-msg ./...

For the full rationale, library landscape, and benchmark numbers, see Section 7 (Logging) in rules/210-go.mdc.

Use the observability skill (${HANDBOOK_ROOT}/skills/observability/SKILL.md) for cross-language event schemas, sensitive-data policy, metric cardinality, SLOs, tracing, sampling, alerts, and telemetry pipelines. Keep this section limited to Go integration.


Detailed References

  • Go Patterns: See references/go-patterns.md for concurrency, interfaces, testing
  • Go Idioms: See references/go-idioms.md for Go Proverbs, zero value, dependency management, naming, project layout
  • Go Testing: See references/go-testing.md for table-driven tests, fuzz testing, mocking, integration tests, benchmarks
  • Go Troubleshooting: See references/go-troubleshooting.md for debug logging, Delve, profiling, common errors
  • Go Performance: See references/go-performance.md for evidence-based optimization, profiling, memory management
  • Go AWS Integration: See references/go-aws-integration.md for AWS SDK v2, Lambda patterns, error handling
  • Go CLI Development: See references/go-cli-development.md for cobra, urfave/cli, CLI best practices
  • Go Design Patterns: See references/go-design-patterns.md for factory, strategy, observer patterns
  • Go Generics: See references/go-generics.md for generic functions, types, constraints, interfaces
  • Go Deployment: See references/go-deployment.md for building binaries, Docker, CI/CD, version management
  • Rust Patterns: See references/rust-patterns.md for ownership, lifetimes, async

Download now (ZIP)

Does it work?

Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.

No reviews yet

People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.

  • It worked
  • Partly
  • It didn't
What did you use it for? e.g. Reviewing pull requests in a Rails app

Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.

Your trail

Files you open will collect here, so you can find them again.

Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.

Now do this for your own.

Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.