
Go
- 46 installs
- 19 repo stars
- Updated January 20, 2026
- miles990/claude-software-skills
Helps with ai & agent building tasks.
About
go is a Claude Code skill for ai & agent building. It helps solo builders move faster with AI-assisted development.
- go
- AI & Agent Building
- AI-coding skill
Go by the numbers
- 46 all-time installs (skills.sh)
- +1 installs in the week ending Aug 4, 2026 (Skillselion tracking)
- Ranked #7,613 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/miles990/claude-software-skills --skill goAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 46 |
|---|---|
| repo stars | ★ 19 |
| Last updated | January 20, 2026 |
| Repository | miles990/claude-software-skills ↗ |
What it does
Helps with ai & agent building tasks.
Files
Go
Overview
Go programming patterns including concurrency, error handling, and idiomatic Go code.
---
Basic Patterns
Structs and Methods
package main
import (
"encoding/json"
"fmt"
"time"
)
// Struct definition
type User struct {
ID string `json:"id"`
Email string `json:"email"`
Name string `json:"name"`
CreatedAt time.Time `json:"created_at"`
metadata map[string]interface{} // unexported (private)
}
// Constructor function
func NewUser(email, name string) *User {
return &User{
ID: generateID(),
Email: email,
Name: name,
CreatedAt: time.Now(),
metadata: make(map[string]interface{}),
}
}
// Value receiver (for read-only)
func (u User) FullName() string {
return u.Name
}
// Pointer receiver (for mutations or large structs)
func (u *User) SetMetadata(key string, value interface{}) {
u.metadata[key] = value
}
// Embedding (composition)
type Admin struct {
User // Embedded struct
Permissions []string
}
func (a *Admin) HasPermission(perm string) bool {
for _, p := range a.Permissions {
if p == perm {
return true
}
}
return false
}Interfaces
// Interface definition
type Repository interface {
Find(id string) (*User, error)
FindAll() ([]*User, error)
Create(user *User) error
Update(user *User) error
Delete(id string) error
}
// Interface implementation (implicit)
type MemoryRepository struct {
users map[string]*User
}
func NewMemoryRepository() *MemoryRepository {
return &MemoryRepository{
users: make(map[string]*User),
}
}
func (r *MemoryRepository) Find(id string) (*User, error) {
user, ok := r.users[id]
if !ok {
return nil, ErrNotFound
}
return user, nil
}
func (r *MemoryRepository) Create(user *User) error {
r.users[user.ID] = user
return nil
}
// Compile-time interface check
var _ Repository = (*MemoryRepository)(nil)
// Empty interface (any type)
func PrintAny(v interface{}) {
fmt.Printf("%v\n", v)
}
// Type assertion
func ProcessValue(v interface{}) {
switch val := v.(type) {
case string:
fmt.Println("String:", val)
case int:
fmt.Println("Int:", val)
case *User:
fmt.Println("User:", val.Name)
default:
fmt.Println("Unknown type")
}
}---
Error Handling
import (
"errors"
"fmt"
)
// Sentinel errors
var (
ErrNotFound = errors.New("not found")
ErrBadRequest = errors.New("bad request")
)
// Custom error type
type ValidationError struct {
Field string
Message string
}
func (e *ValidationError) Error() string {
return fmt.Sprintf("validation error on %s: %s", e.Field, e.Message)
}
// Error wrapping
func GetUser(id string) (*User, error) {
user, err := repository.Find(id)
if err != nil {
return nil, fmt.Errorf("getting user %s: %w", id, err)
}
return user, nil
}
// Error checking
func ProcessUser(id string) error {
user, err := GetUser(id)
if err != nil {
if errors.Is(err, ErrNotFound) {
return fmt.Errorf("user not found: %s", id)
}
var validationErr *ValidationError
if errors.As(err, &validationErr) {
return fmt.Errorf("validation failed: %s", validationErr.Field)
}
return err
}
// Process user...
return nil
}
// Multi-error handling
type MultiError struct {
Errors []error
}
func (m *MultiError) Error() string {
var msgs []string
for _, err := range m.Errors {
msgs = append(msgs, err.Error())
}
return strings.Join(msgs, "; ")
}
func (m *MultiError) Add(err error) {
if err != nil {
m.Errors = append(m.Errors, err)
}
}
func (m *MultiError) HasErrors() bool {
return len(m.Errors) > 0
}---
Concurrency
Goroutines and Channels
// Basic goroutine
func main() {
go func() {
fmt.Println("Hello from goroutine")
}()
time.Sleep(100 * time.Millisecond)
}
// Channel basics
func worker(jobs <-chan int, results chan<- int) {
for job := range jobs {
results <- job * 2
}
}
func main() {
jobs := make(chan int, 100)
results := make(chan int, 100)
// Start workers
for w := 0; w < 3; w++ {
go worker(jobs, results)
}
// Send jobs
for j := 0; j < 9; j++ {
jobs <- j
}
close(jobs)
// Collect results
for r := 0; r < 9; r++ {
fmt.Println(<-results)
}
}
// Select for multiple channels
func main() {
ch1 := make(chan string)
ch2 := make(chan string)
go func() {
time.Sleep(100 * time.Millisecond)
ch1 <- "one"
}()
go func() {
time.Sleep(200 * time.Millisecond)
ch2 <- "two"
}()
for i := 0; i < 2; i++ {
select {
case msg1 := <-ch1:
fmt.Println("Received:", msg1)
case msg2 := <-ch2:
fmt.Println("Received:", msg2)
case <-time.After(500 * time.Millisecond):
fmt.Println("Timeout")
}
}
}Concurrency Patterns
import (
"context"
"sync"
)
// Worker pool
type WorkerPool struct {
numWorkers int
jobs chan func()
wg sync.WaitGroup
}
func NewWorkerPool(numWorkers int) *WorkerPool {
pool := &WorkerPool{
numWorkers: numWorkers,
jobs: make(chan func(), numWorkers*2),
}
pool.Start()
return pool
}
func (p *WorkerPool) Start() {
for i := 0; i < p.numWorkers; i++ {
go func() {
for job := range p.jobs {
job()
p.wg.Done()
}
}()
}
}
func (p *WorkerPool) Submit(job func()) {
p.wg.Add(1)
p.jobs <- job
}
func (p *WorkerPool) Wait() {
p.wg.Wait()
}
func (p *WorkerPool) Close() {
close(p.jobs)
}
// Fan-out, fan-in
func FanOut(ctx context.Context, input <-chan int, workers int) []<-chan int {
outputs := make([]<-chan int, workers)
for i := 0; i < workers; i++ {
outputs[i] = worker(ctx, input)
}
return outputs
}
func FanIn(ctx context.Context, channels ...<-chan int) <-chan int {
var wg sync.WaitGroup
merged := make(chan int)
output := func(c <-chan int) {
defer wg.Done()
for v := range c {
select {
case merged <- v:
case <-ctx.Done():
return
}
}
}
wg.Add(len(channels))
for _, c := range channels {
go output(c)
}
go func() {
wg.Wait()
close(merged)
}()
return merged
}
// Rate limiter
type RateLimiter struct {
ticker *time.Ticker
tokens chan struct{}
}
func NewRateLimiter(rate int, burst int) *RateLimiter {
rl := &RateLimiter{
ticker: time.NewTicker(time.Second / time.Duration(rate)),
tokens: make(chan struct{}, burst),
}
// Fill initial burst
for i := 0; i < burst; i++ {
rl.tokens <- struct{}{}
}
// Refill tokens
go func() {
for range rl.ticker.C {
select {
case rl.tokens <- struct{}{}:
default:
}
}
}()
return rl
}
func (rl *RateLimiter) Wait(ctx context.Context) error {
select {
case <-rl.tokens:
return nil
case <-ctx.Done():
return ctx.Err()
}
}---
Context
import (
"context"
"time"
)
// Context with timeout
func FetchWithTimeout(url string) ([]byte, error) {
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
req, err := http.NewRequestWithContext(ctx, "GET", url, nil)
if err != nil {
return nil, err
}
resp, err := http.DefaultClient.Do(req)
if err != nil {
return nil, err
}
defer resp.Body.Close()
return io.ReadAll(resp.Body)
}
// Context with values
type contextKey string
const userIDKey contextKey = "userID"
func WithUserID(ctx context.Context, userID string) context.Context {
return context.WithValue(ctx, userIDKey, userID)
}
func GetUserID(ctx context.Context) (string, bool) {
userID, ok := ctx.Value(userIDKey).(string)
return userID, ok
}
// Passing context through layers
func Handler(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
ctx = WithUserID(ctx, r.Header.Get("X-User-ID"))
result, err := ProcessRequest(ctx)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
json.NewEncoder(w).Encode(result)
}
func ProcessRequest(ctx context.Context) (*Result, error) {
// Check for cancellation
select {
case <-ctx.Done():
return nil, ctx.Err()
default:
}
userID, ok := GetUserID(ctx)
if !ok {
return nil, errors.New("user ID not found in context")
}
return fetchData(ctx, userID)
}---
Generics (Go 1.18+)
// Generic function
func Map[T, U any](items []T, fn func(T) U) []U {
result := make([]U, len(items))
for i, item := range items {
result[i] = fn(item)
}
return result
}
func Filter[T any](items []T, predicate func(T) bool) []T {
var result []T
for _, item := range items {
if predicate(item) {
result = append(result, item)
}
}
return result
}
func Reduce[T, U any](items []T, initial U, fn func(U, T) U) U {
result := initial
for _, item := range items {
result = fn(result, item)
}
return result
}
// Generic type constraint
type Number interface {
~int | ~int32 | ~int64 | ~float32 | ~float64
}
func Sum[T Number](items []T) T {
var sum T
for _, item := range items {
sum += item
}
return sum
}
// Generic struct
type Stack[T any] struct {
items []T
}
func (s *Stack[T]) Push(item T) {
s.items = append(s.items, item)
}
func (s *Stack[T]) Pop() (T, bool) {
if len(s.items) == 0 {
var zero T
return zero, false
}
item := s.items[len(s.items)-1]
s.items = s.items[:len(s.items)-1]
return item, true
}
// Usage
stack := &Stack[int]{}
stack.Push(1)
stack.Push(2)
val, ok := stack.Pop() // val = 2, ok = true---
Testing
import (
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
// Basic test
func TestSum(t *testing.T) {
result := Sum([]int{1, 2, 3})
if result != 6 {
t.Errorf("expected 6, got %d", result)
}
}
// Table-driven tests
func TestSumTableDriven(t *testing.T) {
tests := []struct {
name string
input []int
expected int
}{
{"empty", []int{}, 0},
{"single", []int{5}, 5},
{"multiple", []int{1, 2, 3}, 6},
{"negative", []int{-1, 1}, 0},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
result := Sum(tt.input)
assert.Equal(t, tt.expected, result)
})
}
}
// Test with testify
func TestUser(t *testing.T) {
user := NewUser("test@example.com", "Test User")
require.NotNil(t, user)
assert.Equal(t, "test@example.com", user.Email)
assert.Equal(t, "Test User", user.Name)
assert.NotEmpty(t, user.ID)
}
// Benchmark
func BenchmarkSum(b *testing.B) {
items := make([]int, 1000)
for i := range items {
items[i] = i
}
b.ResetTimer()
for i := 0; i < b.N; i++ {
Sum(items)
}
}---
Related Skills
- [[backend]] - Go web services
- [[cloud-platforms]] - Cloud-native Go
- [[system-design]] - System architecture
// Go Module Template
// Usage: Copy to project root and update module name
module github.com/yourorg/yourproject
go 1.22
require (
// Web Framework (choose one)
// github.com/gin-gonic/gin v1.9.1
// github.com/labstack/echo/v4 v4.11.4
// github.com/gofiber/fiber/v2 v2.52.0
// github.com/go-chi/chi/v5 v5.0.11
// Database
// github.com/jackc/pgx/v5 v5.5.2
// github.com/go-sql-driver/mysql v1.7.1
// gorm.io/gorm v1.25.6
// gorm.io/driver/postgres v1.5.4
// Configuration
// github.com/spf13/viper v1.18.2
// github.com/joho/godotenv v1.5.1
// github.com/kelseyhightower/envconfig v1.4.0
// Logging
// go.uber.org/zap v1.26.0
// github.com/rs/zerolog v1.31.0
// log/slog (stdlib, Go 1.21+)
// Validation
// github.com/go-playground/validator/v10 v10.17.0
// Authentication
// github.com/golang-jwt/jwt/v5 v5.2.0
// golang.org/x/oauth2 v0.16.0
// Testing
// github.com/stretchr/testify v1.8.4
// github.com/golang/mock v1.6.0
// Utilities
// github.com/google/uuid v1.5.0
// golang.org/x/sync v0.6.0
)
// Indirect dependencies managed automatically
// require (
// ...
// )
# Go Project Makefile Template
# Usage: Copy to project root
# ===========================================
# Variables
# ===========================================
APP_NAME := myapp
VERSION := $(shell git describe --tags --always --dirty 2>/dev/null || echo "dev")
BUILD_TIME := $(shell date -u +"%Y-%m-%dT%H:%M:%SZ")
COMMIT := $(shell git rev-parse --short HEAD 2>/dev/null || echo "unknown")
# Go settings
GO := go
GOFLAGS := -v
LDFLAGS := -ldflags "-X main.Version=$(VERSION) -X main.BuildTime=$(BUILD_TIME) -X main.Commit=$(COMMIT)"
# Directories
BUILD_DIR := ./bin
CMD_DIR := ./cmd/$(APP_NAME)
PKG_DIR := ./pkg
INTERNAL_DIR := ./internal
# Docker
DOCKER_IMAGE := $(APP_NAME)
DOCKER_TAG := $(VERSION)
# ===========================================
# Default
# ===========================================
.PHONY: all
all: lint test build
# ===========================================
# Development
# ===========================================
.PHONY: run
run: ## Run the application
$(GO) run $(CMD_DIR)/main.go
.PHONY: dev
dev: ## Run with hot reload (requires air)
air
.PHONY: watch
watch: ## Watch for changes (alternative)
watchexec -e go -r "go run $(CMD_DIR)/main.go"
# ===========================================
# Build
# ===========================================
.PHONY: build
build: ## Build binary
$(GO) build $(GOFLAGS) $(LDFLAGS) -o $(BUILD_DIR)/$(APP_NAME) $(CMD_DIR)
.PHONY: build-linux
build-linux: ## Build for Linux
GOOS=linux GOARCH=amd64 $(GO) build $(LDFLAGS) -o $(BUILD_DIR)/$(APP_NAME)-linux-amd64 $(CMD_DIR)
.PHONY: build-darwin
build-darwin: ## Build for macOS
GOOS=darwin GOARCH=amd64 $(GO) build $(LDFLAGS) -o $(BUILD_DIR)/$(APP_NAME)-darwin-amd64 $(CMD_DIR)
GOOS=darwin GOARCH=arm64 $(GO) build $(LDFLAGS) -o $(BUILD_DIR)/$(APP_NAME)-darwin-arm64 $(CMD_DIR)
.PHONY: build-windows
build-windows: ## Build for Windows
GOOS=windows GOARCH=amd64 $(GO) build $(LDFLAGS) -o $(BUILD_DIR)/$(APP_NAME)-windows-amd64.exe $(CMD_DIR)
.PHONY: build-all
build-all: build-linux build-darwin build-windows ## Build for all platforms
.PHONY: install
install: ## Install binary
$(GO) install $(LDFLAGS) $(CMD_DIR)
# ===========================================
# Testing
# ===========================================
.PHONY: test
test: ## Run tests
$(GO) test -v ./...
.PHONY: test-race
test-race: ## Run tests with race detector
$(GO) test -race -v ./...
.PHONY: test-cover
test-cover: ## Run tests with coverage
$(GO) test -coverprofile=coverage.out ./...
$(GO) tool cover -html=coverage.out -o coverage.html
@echo "Coverage report: coverage.html"
.PHONY: test-short
test-short: ## Run short tests only
$(GO) test -short ./...
.PHONY: bench
bench: ## Run benchmarks
$(GO) test -bench=. -benchmem ./...
# ===========================================
# Quality
# ===========================================
.PHONY: lint
lint: ## Run linter
golangci-lint run ./...
.PHONY: fmt
fmt: ## Format code
$(GO) fmt ./...
gofumpt -l -w .
.PHONY: vet
vet: ## Run go vet
$(GO) vet ./...
.PHONY: tidy
tidy: ## Tidy dependencies
$(GO) mod tidy
.PHONY: verify
verify: ## Verify dependencies
$(GO) mod verify
.PHONY: check
check: fmt vet lint test ## Run all checks
# ===========================================
# Generation
# ===========================================
.PHONY: generate
generate: ## Run go generate
$(GO) generate ./...
.PHONY: mock
mock: ## Generate mocks (requires mockgen)
mockgen -source=$(INTERNAL_DIR)/service/user.go -destination=$(INTERNAL_DIR)/service/mock/user_mock.go
.PHONY: swagger
swagger: ## Generate Swagger docs (requires swag)
swag init -g $(CMD_DIR)/main.go -o ./docs
# ===========================================
# Docker
# ===========================================
.PHONY: docker-build
docker-build: ## Build Docker image
docker build -t $(DOCKER_IMAGE):$(DOCKER_TAG) .
.PHONY: docker-push
docker-push: ## Push Docker image
docker push $(DOCKER_IMAGE):$(DOCKER_TAG)
.PHONY: docker-run
docker-run: ## Run Docker container
docker run --rm -p 8080:8080 $(DOCKER_IMAGE):$(DOCKER_TAG)
# ===========================================
# Database
# ===========================================
.PHONY: migrate-up
migrate-up: ## Run migrations up
migrate -path ./migrations -database "$(DATABASE_URL)" up
.PHONY: migrate-down
migrate-down: ## Run migrations down
migrate -path ./migrations -database "$(DATABASE_URL)" down 1
.PHONY: migrate-create
migrate-create: ## Create new migration (usage: make migrate-create name=create_users)
migrate create -ext sql -dir ./migrations -seq $(name)
# ===========================================
# Cleanup
# ===========================================
.PHONY: clean
clean: ## Clean build artifacts
rm -rf $(BUILD_DIR)
rm -f coverage.out coverage.html
.PHONY: clean-cache
clean-cache: ## Clean Go cache
$(GO) clean -cache -testcache
# ===========================================
# Help
# ===========================================
.PHONY: help
help: ## Show this help
@grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-20s\033[0m %s\n", $$1, $$2}'
.DEFAULT_GOAL := help
Go Templates
Configuration templates for Go projects.
Files
| Template | Purpose |
|---|---|
go.mod | Module dependencies template |
Makefile | Build and development commands |
Usage
Initialize Project
# Create project directory
mkdir myproject && cd myproject
# Initialize module
go mod init github.com/yourorg/myproject
# Copy Makefile
cp templates/Makefile ./Makefile
# Update APP_NAME in Makefile
sed -i '' 's/myapp/myproject/g' MakefileMakefile Commands
make help # Show all commands
# Development
make run # Run application
make dev # Run with hot reload (air)
# Build
make build # Build binary
make build-all # Build for all platforms
# Testing
make test # Run tests
make test-cover # Run with coverage
make bench # Run benchmarks
# Quality
make lint # Run linter
make fmt # Format code
make check # Run all checks
# Docker
make docker-build
make docker-runProject Structure
myproject/
├── cmd/
│ └── myproject/
│ └── main.go
├── internal/
│ ├── handler/
│ ├── service/
│ └── repository/
├── pkg/
│ └── (public packages)
├── api/
│ └── (OpenAPI specs)
├── migrations/
├── go.mod
├── go.sum
└── MakefileRecommended Dependencies
Web Framework
| Package | Description |
|---|---|
gin-gonic/gin | High performance, minimalist |
labstack/echo | Feature-rich, extensible |
gofiber/fiber | Express-inspired, fast |
go-chi/chi | Lightweight, idiomatic |
Database
| Package | Description |
|---|---|
jackc/pgx | PostgreSQL driver |
gorm.io/gorm | ORM with associations |
sqlc | Type-safe SQL codegen |
ent | Entity framework |
Configuration
| Package | Description |
|---|---|
spf13/viper | Full-featured config |
kelseyhightower/envconfig | Env vars only |
joho/godotenv | .env file loading |
Build with Version Info
// main.go
var (
Version = "dev"
BuildTime = "unknown"
Commit = "unknown"
)
func main() {
fmt.Printf("%s %s (%s)\n", Version, BuildTime, Commit)
}Build injects these via ldflags:
make build # Uses git tags and commitRequired Tools
# Linter
go install github.com/golangci/golangci-lint/cmd/golangci-lint@latest
# Hot reload
go install github.com/cosmtrek/air@latest
# Formatter
go install mvdan.cc/gofumpt@latest
# Migrations
go install -tags 'postgres' github.com/golang-migrate/migrate/v4/cmd/migrate@latest
# Mock generation
go install github.com/golang/mock/mockgen@latest
# Swagger
go install github.com/swaggo/swag/cmd/swag@latestRelated skills
AI & Agent Buildingagents