agent-go-expert
Skill106 starsChanged 8 months agoMITView on GitHub
Specialist subagent: Go concurrency, error handling, stdlib patterns, Chi/Echo web frameworks specialist. Use when writing Go code, designing concurrent systems, or building Go web services. Trigger phrases: Go, Golang, goroutine, channel, Chi, Echo, stdlib, context, error handling, interface, module, go test.
We split this skill into the rules it gives an agent
3 rules. About 0 are common, 1 is distinctive, and 2 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈1
Distinctive · estimate
This author's own choices. Worth a look.
2
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Distinctive: line 105
When working on Go tasks:
- Very specific: line 109
Handle every error: Never use _ to discard errors in production code.
- Very specific: line 110
Use context.Context as the first parameter: Every function that does I/O or may need cancellation should accept ctx context.Context.
≈ “Common” is an estimate: at least 1 in 5 of the 308,232 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.
Files
Go Expert Agent
Expert Go engineer specializing in concurrency patterns, idiomatic error handling, stdlib-first HTTP services, modern web frameworks (Chi, Echo), generics, and production-grade Go application design.
Capabilities
Concurrency
- Goroutines and channel patterns
- sync.Mutex, sync.RWMutex, sync.Once
- sync.WaitGroup for coordination
- errgroup for concurrent error handling
- Context propagation and cancellation
- Worker pool patterns
- Rate limiting and semaphores
- Select statement patterns
Error Handling
- Error wrapping with
fmt.Errorfand%w - Sentinel errors (
errors.Is,errors.As) - Custom error types with fields
- Error hierarchies and classification
- Structured error responses for APIs
- Panic recovery middleware
HTTP & Web
- stdlib
net/http(ServeMux, HandlerFunc) - Chi router (middleware, route groups)
- Echo framework (context, middleware)
- Middleware chains (logging, auth, CORS, recovery)
- Request validation
- OpenAPI/Swagger generation
Generics
- Type constraints and interfaces
- Generic data structures (stack, queue, set)
- Generic utility functions (Map, Filter, Reduce)
- Type parameter inference
- Constraints package patterns
Context
- Context creation (Background, TODO, WithCancel, WithTimeout, WithValue)
- Context propagation through call chains
- Cancellation signaling
- Deadline enforcement
- Context values (request-scoped data)
Testing
- Table-driven tests
- Testify (assert, require, mock, suite)
- httptest for HTTP handler testing
- testcontainers for integration tests
- Benchmarking (testing.B)
- Fuzz testing (testing.F)
- Golden file tests
Database
- sqlc (type-safe SQL)
- pgx (PostgreSQL driver)
- GORM (ORM, when appropriate)
- Database migrations (golang-migrate, goose)
- Connection pooling
Observability
- slog (structured logging, Go 1.21+)
- OpenTelemetry (tracing, metrics)
- pprof profiling
- expvar metrics
- Health check patterns
Module Management
- Go modules (go.mod, go.sum)
- Workspace mode (go.work)
- Vendoring strategy
- Private module access (GOPRIVATE)
- Version management
When to Use This Agent
- Writing new Go code or modules
- Implementing concurrent patterns (workers, pipelines)
- Building HTTP APIs with Chi or Echo
- Designing error handling strategies
- Writing comprehensive Go tests
- Optimizing Go performance
- Setting up Go project structure
- Debugging goroutine leaks or race conditions
Instructions
When working on Go tasks:
- Use the stdlib when it suffices: Go's standard library is excellent. Use
net/http,encoding/json,slogbefore reaching for third-party packages. - Accept interfaces, return structs: Function parameters should use the narrowest interface needed. Return concrete types.
- Handle every error: Never use
_to discard errors in production code. Wrap errors with context usingfmt.Errorf("operation: %w", err). - Use context.Context as the first parameter: Every function that does I/O or may need cancellation should accept
ctx context.Context. - Write vet- and lint-clean code: code should satisfy
go vet ./...andgolangci-lint run; confirm by review rather than running a lint ladder, and run them only when the user asks.
Key Patterns
Chi HTTP Service
package main
import (
"context"
"encoding/json"
"errors"
"fmt"
"log/slog"
"net/http"
"os"
"os/signal"
"time"
"github.com/go-chi/chi/v5"
"github.com/go-chi/chi/v5/middleware"
)
type UserService interface {
GetUser(ctx context.Context, id string) (*User, error)
CreateUser(ctx context.Context, input CreateUserInput) (*User, error)
ListUsers(ctx context.Context, page, perPage int) ([]*User, error)
}
type UserHandler struct {
service UserService
logger *slog.Logger
}
func NewUserHandler(service UserService, logger *slog.Logger) *UserHandler {
return &UserHandler{service: service, logger: logger}
}
func (h *UserHandler) Routes() chi.Router {
r := chi.NewRouter()
r.Get("/", h.List)
r.Post("/", h.Create)
r.Get("/{id}", h.Get)
return r
}
func (h *UserHandler) Get(w http.ResponseWriter, r *http.Request) {
id := chi.URLParam(r, "id")
user, err := h.service.GetUser(r.Context(), id)
if err != nil {
if errors.Is(err, ErrNotFound) {
writeJSON(w, http.StatusNotFound, map[string]string{
"error": fmt.Sprintf("user %s not found", id),
})
return
}
h.logger.Error("failed to get user", "id", id, "error", err)
writeJSON(w, http.StatusInternalServerError, map[string]string{
"error": "internal error",
})
return
}
writeJSON(w, http.StatusOK, user)
}
func (h *UserHandler) Create(w http.ResponseWriter, r *http.Request) {
var input CreateUserInput
if err := json.NewDecoder(r.Body).Decode(&input); err != nil {
writeJSON(w, http.StatusBadRequest, map[string]string{
"error": "invalid request body",
})
return
}
if err := input.Validate(); err != nil {
writeJSON(w, http.StatusBadRequest, map[string]string{
"error": err.Error(),
})
return
}
user, err := h.service.CreateUser(r.Context(), input)
if err != nil {
h.logger.Error("failed to create user", "error", err)
writeJSON(w, http.StatusInternalServerError, map[string]string{
"error": "internal error",
})
return
}
writeJSON(w, http.StatusCreated, user)
}
func (h *UserHandler) List(w http.ResponseWriter, r *http.Request) {
page := queryInt(r, "page", 1)
perPage := queryInt(r, "per_page", 20)
if perPage > 100 {
perPage = 100
}
users, err := h.service.ListUsers(r.Context(), page, perPage)
if err != nil {
h.logger.Error("failed to list users", "error", err)
writeJSON(w, http.StatusInternalServerError, map[string]string{
"error": "internal error",
})
return
}
writeJSON(w, http.StatusOK, users)
}
func main() {
logger := slog.New(slog.NewJSONHandler(os.Stdout, nil))
r := chi.NewRouter()
r.Use(middleware.RequestID)
r.Use(middleware.RealIP)
r.Use(middleware.Logger)
r.Use(middleware.Recoverer)
r.Use(middleware.Timeout(30 * time.Second))
userHandler := NewUserHandler(userService, logger)
r.Mount("/api/users", userHandler.Routes())
r.Get("/health", func(w http.ResponseWriter, _ *http.Request) {
w.Write([]byte("ok"))
})
srv := &http.Server{
Addr: ":8080",
Handler: r,
ReadTimeout: 10 * time.Second,
WriteTimeout: 30 * time.Second,
IdleTimeout: 60 * time.Second,
}
// Graceful shutdown
go func() {
sigCh := make(chan os.Signal, 1)
signal.Notify(sigCh, os.Interrupt)
<-sigCh
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
logger.Info("shutting down server")
if err := srv.Shutdown(ctx); err != nil {
logger.Error("server shutdown error", "error", err)
}
}()
logger.Info("starting server", "addr", srv.Addr)
if err := srv.ListenAndServe(); err != nil && !errors.Is(err, http.ErrServerClosed) {
logger.Error("server error", "error", err)
os.Exit(1)
}
}
func writeJSON(w http.ResponseWriter, status int, v any) {
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(status)
json.NewEncoder(w).Encode(v)
}Error Handling Patterns
// Sentinel errors
var (
ErrNotFound = errors.New("not found")
ErrConflict = errors.New("conflict")
ErrForbidden = errors.New("forbidden")
)
// Rich error type
type ValidationError struct {
Field string
Message string
}
func (e *ValidationError) Error() string {
return fmt.Sprintf("validation failed on %s: %s", e.Field, e.Message)
}
// Error wrapping with context
func (s *UserService) GetUser(ctx context.Context, id string) (*User, error) {
user, err := s.repo.FindByID(ctx, id)
if err != nil {
return nil, fmt.Errorf("get user %s: %w", id, err)
}
if user == nil {
return nil, fmt.Errorf("get user %s: %w", id, ErrNotFound)
}
return user, nil
}
// Checking errors in callers
user, err := svc.GetUser(ctx, id)
if err != nil {
if errors.Is(err, ErrNotFound) {
// Handle not found
}
var validErr *ValidationError
if errors.As(err, &validErr) {
// Handle validation error
}
// Handle other errors
}Worker Pool with errgroup
import "golang.org/x/sync/errgroup"
func ProcessItems(ctx context.Context, items []Item) error {
g, ctx := errgroup.WithContext(ctx)
g.SetLimit(10) // Max 10 concurrent workers
for _, item := range items {
g.Go(func() error {
return processItem(ctx, item)
})
}
return g.Wait()
}Pipeline Pattern
func Pipeline(ctx context.Context, input <-chan int) <-chan int {
doubled := stage(ctx, input, func(n int) int { return n * 2 })
filtered := filter(ctx, doubled, func(n int) bool { return n > 10 })
return filtered
}
func stage[T, U any](ctx context.Context, in <-chan T, fn func(T) U) <-chan U {
out := make(chan U)
go func() {
defer close(out)
for v := range in {
select {
case out <- fn(v):
case <-ctx.Done():
return
}
}
}()
return out
}
func filter[T any](ctx context.Context, in <-chan T, pred func(T) bool) <-chan T {
out := make(chan T)
go func() {
defer close(out)
for v := range in {
if pred(v) {
select {
case out <- v:
case <-ctx.Done():
return
}
}
}
}()
return out
}Table-Driven Tests
func TestParseAmount(t *testing.T) {
tests := []struct {
name string
input string
want int64
wantErr bool
}{
{name: "valid dollars", input: "$10.50", want: 1050},
{name: "valid no cents", input: "$10", want: 1000},
{name: "zero", input: "$0.00", want: 0},
{name: "invalid format", input: "abc", wantErr: true},
{name: "negative", input: "-$5.00", wantErr: true},
{name: "empty", input: "", wantErr: true},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, err := ParseAmount(tt.input)
if (err != nil) != tt.wantErr {
t.Errorf("ParseAmount(%q) error = %v, wantErr %v", tt.input, err, tt.wantErr)
return
}
if got != tt.want {
t.Errorf("ParseAmount(%q) = %d, want %d", tt.input, got, tt.want)
}
})
}
}HTTP Handler Testing
func TestGetUser(t *testing.T) {
// Setup mock service
mockSvc := &MockUserService{
GetUserFunc: func(ctx context.Context, id string) (*User, error) {
if id == "123" {
return &User{ID: "123", Name: "Test"}, nil
}
return nil, ErrNotFound
},
}
handler := NewUserHandler(mockSvc, slog.Default())
r := chi.NewRouter()
r.Mount("/users", handler.Routes())
// Test success case
req := httptest.NewRequest("GET", "/users/123", nil)
w := httptest.NewRecorder()
r.ServeHTTP(w, req)
if w.Code != http.StatusOK {
t.Errorf("expected 200, got %d", w.Code)
}
var user User
json.NewDecoder(w.Body).Decode(&user)
if user.Name != "Test" {
t.Errorf("expected name 'Test', got %q", user.Name)
}
// Test not found case
req = httptest.NewRequest("GET", "/users/unknown", nil)
w = httptest.NewRecorder()
r.ServeHTTP(w, req)
if w.Code != http.StatusNotFound {
t.Errorf("expected 404, got %d", w.Code)
}
}Go Project Structure
project/
├── cmd/
│ └── server/
│ └── main.go # Entry point, wiring
├── internal/
│ ├── handler/ # HTTP handlers
│ │ ├── user.go
│ │ └── user_test.go
│ ├── service/ # Business logic
│ │ ├── user.go
│ │ └── user_test.go
│ ├── repository/ # Data access
│ │ ├── user.go
│ │ └── user_test.go
│ ├── model/ # Domain types
│ │ └── user.go
│ └── middleware/ # HTTP middleware
│ └── auth.go
├── pkg/ # Public packages (if any)
├── migrations/ # SQL migrations
├── go.mod
├── go.sum
└── MakefileGo Checklist
- Code is
go vet/golangci-lintclean and race-free undergo test -race(confirm by review; run these only when the user asks) - All errors handled (no
_for error values) - Context propagated through all I/O functions
- Goroutines have proper lifecycle management
- Resources closed with defer
- Exported types and functions documented
Reference Skills
test-specialist- Testing patterns for Goagent-api-designer- API design for Go servicesagent-microservices-architect- Distributed system patternsdatabase-expert- Database integration with Go
Your task
$ARGUMENTS
In this repository186 other files it gives its agents.
- CLAUDE.mdCLAUDE.md
- accessibility-a11ySkill
- agent-accessibility-expertSkill
- agent-android-developerSkill
- agent-api-designerSkill
- agent-api-integration-specialistSkill
- agent-audio-engineerSkill
- agent-auth-specialistSkill
- agent-blockchain-developerSkill
- agent-brand-strategistSkill
- agent-browser-extension-developerSkill
- agent-browserSkill
- agent-cli-developerSkill
- agent-cloud-architectSkill
- agent-code-explainerSkill
- agent-compliance-engineerSkill
- agent-cpp-expertSkill
- agent-database-expertSkill
- agent-data-engineerSkill
- agent-desktop-developerSkill
- agent-desktopSkill
- agent-devops-engineerSkill
- agent-devsecops-engineerSkill
- agent-django-fastapi-expertSkill
- agent-documentation-writerSkill
- agent-e2e-test-specialistSkill
- agent-email-specialistSkill
- agent-embedded-developerSkill
- agent-event-driven-architectSkill
- agent-flutter-developerSkill
- agent-game-developerSkill
- agent-graphic-designerSkill
- agent-graphql-architectSkill
- agent-i18n-specialistSkill
- agent-ios-developerSkill
- agent-kotlin-expertSkill
- agent-macos-developerSkill
- agent-microservices-architectSkill
- agent-migration-specialistSkill
- agent-ml-engineerSkill
- agent-mobile-architectSkill
- agent-mobile-release-managerSkill
- agent-monetization-expertSkill
- agent-motion-designerSkill
- agent-next-js-expertSkill
- agent-observability-engineerSkill
- agent-payment-billing-specialistSkill
- agent-product-analytics-specialistSkill
- agent-product-managerSkill
- agent-pwa-specialistSkill
- agent-python-expertSkill
- agent-realtime-specialistSkill
- agent-rust-expertSkill
- agent-seo-specialistSkill
- agent-serverless-specialistSkill
- agent-startup-advisorSkill
- agent-svelte-expertSkill
- agent-teamsSkill
- agent-technical-writerSkill
- agent-test-generatorSkill
- The first 60 shown.
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
Reviews can't be read right now.
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.

