Install
$ agentstack add skill-kinhluan-skills-golang-development Open-source listing, not yet scanned by AgentStack. Follow the source repository for install instructions.
Security review
⚠ Flagged1 finding(s); flagged for manual review. · v0.1.0 How review works →
- • Prompt-injection patterns
- • Secret / credential exfiltration
- • Dangerous shell & filesystem operations
- • Untrusted network calls
- • Known-malicious package signatures
- high Destructive filesystem operation.
What it can access
- ● Network access Used
- ● Filesystem access Used
- ● Shell / process execution Used
- ● Environment & secrets Used
- ✓ 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.
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 Development
Modern Go development covering project structure, modules, generics, concurrency patterns, testing, web frameworks, gRPC, databases, CLI tools, linting, and production deployment. Targets Go 1.22+ with focus on 1.23+ and 1.24+ features.
> "Clear is better than clever." — The Go Proverbs
1. Project Setup & Modules
Go Modules (go.mod)
Single source of truth for dependencies and module path.
module github.com/example/myapp
go 1.23
require (
github.com/gin-gonic/gin v1.10.0
github.com/jackc/pgx/v5 v5.7.0
google.golang.org/grpc v1.68.0
)
require (
github.com/stretchr/testify v1.9.0 // indirect
)
Key commands:
go mod init github.com/example/myapp # initialize module
go get github.com/gin-gonic/gin # add dependency
go get -u ./... # update all dependencies
go mod tidy # remove unused, add missing
go mod download # download to module cache
go mod vendor # create vendor/ directory
go work init ./api ./worker # Go workspace (multi-module)
Standard Project Layout
myapp/
├── api/ # API definitions (protobuf, OpenAPI)
│ └── proto/
├── cmd/ # Application entry points
│ ├── api/
│ │ └── main.go
│ └── worker/
│ └── main.go
├── internal/ # Private application code
│ ├── domain/ # Business logic (entities, value objects)
│ ├── service/ # Use cases / application services
│ ├── repository/ # Data access layer
│ ├── handler/ # HTTP/gRPC handlers
│ └── config/ # Configuration
├── pkg/ # Public library code (reusable)
│ └── utils/
├── migrations/ # Database migrations
├── scripts/ # Build and deployment scripts
├── configs/ # Configuration files
├── test/ # Integration and e2e tests
├── go.mod
├── go.sum
├── Makefile
├── Dockerfile
└── README.md
Rules:
cmd//main.go— one main per applicationinternal/— cannot be imported by external modulespkg/— reusable packages, stable APIs
2. Go 1.22+ / 1.23+ / 1.24+ Features
Go 1.22 — Enhanced For Loops
// Loop variables are now per-iteration (no closure bugs)
funcs := []func(){}
for i := 0; i b { // ERROR: comparable doesn't support >
return a
}
return b
}
// Correct: use constraints.Ordered
import "golang.org/x/exp/constraints"
func Max[T constraints.Ordered](a, b T) T {
if a > b {
return a
}
return b
}
// Generic struct
type Stack[T any] struct {
items []T
}
func (s *Stack[T]) Push(v T) {
s.items = append(s.items, v)
}
func (s *Stack[T]) Pop() (T, bool) {
var zero T
if len(s.items) == 0 {
return zero, false
}
v := s.items[len(s.items)-1]
s.items = s.items[:len(s.items)-1]
return v, true
}
// Type sets
type Number interface {
~int | ~int64 | ~float64 // ~ allows underlying types
}
func Sum[T Number](vals []T) T {
var sum T
for _, v := range vals {
sum += v
}
return sum
}
Interfaces & Embedding
// Interface composition
type Reader interface {
Read(p []byte) (n int, err error)
}
type Writer interface {
Write(p []byte) (n int, err error)
}
type ReadWriter interface {
Reader
Writer
}
// Any (alias for interface{})
func PrintAny(v any) {
fmt.Printf("%T: %v\n", v, v)
}
// Type assertions and switches
func Describe(v any) string {
switch val := v.(type) {
case string:
return "string: " + val
case int:
return fmt.Sprintf("int: %d", val)
case fmt.Stringer:
return val.String()
default:
return "unknown"
}
}
4. Error Handling
Idiomatic Error Handling
// Sentinel errors
var ErrNotFound = errors.New("resource not found")
var ErrInvalidInput = errors.New("invalid input")
// Error wrapping
func LoadUser(id string) (*User, error) {
user, err := db.QueryUser(id)
if err != nil {
return nil, fmt.Errorf("loading user %s: %w", id, err)
}
if user == nil {
return nil, fmt.Errorf("user %s: %w", id, ErrNotFound)
}
return user, nil
}
// Error checking
user, err := LoadUser("123")
if err != nil {
if errors.Is(err, ErrNotFound) {
http.Error(w, "Not found", http.StatusNotFound)
return
}
log.Printf("unexpected error: %v", err)
http.Error(w, "Internal error", http.StatusInternalServerError)
return
}
// Error type assertion
var notFound *NotFoundError
if errors.As(err, ¬Found) {
fmt.Printf("Resource type: %s, ID: %s\n", notFound.Resource, notFound.ID)
}
Custom Error Types
type NotFoundError struct {
Resource string
ID string
}
func (e *NotFoundError) Error() string {
return fmt.Sprintf("%s %s not found", e.Resource, e.ID)
}
// Validation errors with multiple fields
type ValidationError struct {
Field string
Message string
}
type ValidationErrors []ValidationError
func (v ValidationErrors) Error() string {
var msgs []string
for _, e := range v {
msgs = append(msgs, fmt.Sprintf("%s: %s", e.Field, e.Message))
}
return "validation failed: " + strings.Join(msgs, "; ")
}
5. Concurrency
Goroutines & Channels
// Basic goroutine
go func() {
fmt.Println("running concurrently")
}()
// Buffered channel
ch := make(chan int, 10)
go func() {
for i := range 5 {
ch <- i
}
close(ch)
}()
for v := range ch {
fmt.Println(v)
}
// Select for multiplexing
select {
case v := <-ch1:
fmt.Println("from ch1:", v)
case v := <-ch2:
fmt.Println("from ch2:", v)
case <-time.After(5 * time.Second):
fmt.Println("timeout")
default:
fmt.Println("no channel ready")
}
Context — Request Scoping & Cancellation
// Create context with timeout
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
// Pass through call chain
func ProcessRequest(ctx context.Context, req Request) (*Response, error) {
// Check cancellation
select {
case <-ctx.Done():
return nil, ctx.Err() // context.DeadlineExceeded or context.Canceled
default:
}
// Pass to downstream
user, err := userService.Get(ctx, req.UserID)
if err != nil {
return nil, err
}
// ...
}
// Context with values (request-scoped metadata)
type contextKey string
const requestIDKey contextKey = "request-id"
func WithRequestID(ctx context.Context, id string) context.Context {
return context.WithValue(ctx, requestIDKey, id)
}
func RequestIDFrom(ctx context.Context) string {
if id, ok := ctx.Value(requestIDKey).(string); ok {
return id
}
return ""
}
sync Package Patterns
// WaitGroup for goroutine synchronization
var wg sync.WaitGroup
for i := range 3 {
wg.Add(1)
go func(id int) {
defer wg.Done()
fmt.Printf("worker %d done\n", id)
}(i)
}
wg.Wait()
// Mutex for shared state
type Counter struct {
mu sync.Mutex
count int
}
func (c *Counter) Inc() {
c.mu.Lock()
defer c.mu.Unlock()
c.count++
}
// RWMutex for read-heavy workloads
type Cache struct {
mu sync.RWMutex
data map[string]string
}
func (c *Cache) Get(key string) (string, bool) {
c.mu.RLock()
defer c.mu.RUnlock()
v, ok := c.data[key]
return v, ok
}
func (c *Cache) Set(key, value string) {
c.mu.Lock()
defer c.mu.Unlock()
c.data[key] = value
}
// sync.Once for one-time initialization
var (
db *sql.DB
dbOnce sync.Once
)
func GetDB() *sql.DB {
dbOnce.Do(func() {
var err error
db, err = sql.Open("postgres", dsn)
if err != nil {
log.Fatal(err)
}
})
return db
}
// sync.Map for concurrent map (rarely needed, prefer RWMutex)
var m sync.Map
m.Store("key", "value")
if v, ok := m.Load("key"); ok {
fmt.Println(v)
}
errgroup — Concurrent Error Handling
import "golang.org/x/sync/errgroup"
func ProcessBatch(ctx context.Context, items []Item) error {
g, ctx := errgroup.WithContext(ctx)
g.SetLimit(10) // max concurrent
for _, item := range items {
item := item // capture loop variable (pre-1.22)
g.Go(func() error {
return processItem(ctx, item)
})
}
if err := g.Wait(); err != nil {
return fmt.Errorf("batch processing: %w", err)
}
return nil
}
Worker Pools
func WorkerPool(ctx context.Context, jobs <-chan Job, numWorkers int) <-chan Result {
results := make(chan Result, numWorkers)
var wg sync.WaitGroup
for range numWorkers {
wg.Add(1)
go func() {
defer wg.Done()
for job := range jobs {
select {
case <-ctx.Done():
return
default:
results <- process(job)
}
}
}()
}
go func() {
wg.Wait()
close(results)
}()
return results
}
6. Testing
Table-Driven Tests
func TestCalculate(t *testing.T) {
tests := []struct {
name string
a, b int
op string
expected int
wantErr bool
}{
{"add", 2, 3, "+", 5, false},
{"subtract", 5, 3, "-", 2, false},
{"divide by zero", 5, 0, "/", 0, true},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, err := Calculate(tt.a, tt.b, tt.op)
if tt.wantErr {
if err == nil {
t.Errorf("expected error, got nil")
}
return
}
if err != nil {
t.Errorf("unexpected error: %v", err)
return
}
if got != tt.expected {
t.Errorf("Calculate(%d, %d, %q) = %d, want %d",
tt.a, tt.b, tt.op, got, tt.expected)
}
})
}
}
testify — Assertions & Mocks
import "github.com/stretchr/testify/assert"
import "github.com/stretchr/testify/require"
import "github.com/stretchr/testify/mock"
func TestSomething(t *testing.T) {
// Assert continues on failure
assert.Equal(t, 42, result)
assert.NoError(t, err)
// Require stops test on failure
require.NotNil(t, obj)
require.NoError(t, err)
// Now safe to use obj
assert.Equal(t, "expected", obj.Name)
}
// Mock with testify/mock
type MockRepository struct {
mock.Mock
}
func (m *MockRepository) GetUser(id string) (*User, error) {
args := m.Called(id)
if args.Get(0) == nil {
return nil, args.Error(1)
}
return args.Get(0).(*User), args.Error(1)
}
func TestService(t *testing.T) {
repo := new(MockRepository)
repo.On("GetUser", "123").Return(&User{ID: "123", Name: "Alice"}, nil)
svc := NewService(repo)
user, err := svc.GetUser("123")
require.NoError(t, err)
assert.Equal(t, "Alice", user.Name)
repo.AssertExpectations(t)
}
Fuzzing (Go 1.18+)
func FuzzParse(f *testing.F) {
// Seed corpus
f.Add("hello")
f.Add("12345")
f.Fuzz(func(t *testing.T, input string) {
result, err := Parse(input)
if err != nil {
t.Skip() // invalid input is ok
}
// Invariant: result must be valid
if result.Len() < 0 {
t.Errorf("negative length: %d", result.Len())
}
})
}
go test -fuzz=FuzzParse -fuzztime=30s ./...
Benchmarks
func BenchmarkProcess(b *testing.B) {
data := generateLargeDataset()
b.ResetTimer()
for range b.N {
Process(data)
}
}
// Memory allocation benchmark
func BenchmarkAlloc(b *testing.B) {
b.ReportAllocs()
for range b.N {
_ = make([]byte, 1024)
}
}
go test -bench=. -benchmem ./...
Integration Tests
//go:build integration
func TestDatabase(t *testing.T) {
if testing.Short() {
t.Skip("skipping integration test")
}
db := setupTestDB(t)
defer teardownTestDB(t, db)
// Run tests against real database
}
go test -tags=integration ./...
go test -short ./... # skip integration
7. HTTP Servers
Standard Library (net/http)
package main
import (
"encoding/json"
"log"
"net/http"
"time"
)
type Handler struct {
service Service
}
func (h *Handler) GetUser(w http.ResponseWriter, r *http.Request) {
id := r.PathValue("id") // Go 1.22+ path values
user, err := h.service.GetUser(r.Context(), id)
if err != nil {
if errors.Is(err, ErrNotFound) {
http.Error(w, "Not found", http.StatusNotFound)
return
}
log.Printf("error: %v", err)
http.Error(w, "Internal error", http.StatusInternalServerError)
return
}
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(user)
}
func main() {
mux := http.NewServeMux()
h := &Handler{service: NewService()}
// Go 1.22+ routing
mux.HandleFunc("GET /users/{id}", h.GetUser)
mux.HandleFunc("POST /users", h.CreateUser)
mux.HandleFunc("GET /users", h.ListUsers)
server := &http.Server{
Addr: ":8080",
Handler: mux,
ReadTimeout: 5 * time.Second,
WriteTimeout: 10 * time.Second,
IdleTimeout: 120 * time.Second,
}
log.Println("Server starting on :8080")
if err := server.ListenAndServe(); err != nil {
log.Fatal(err)
}
}
Chi Router
import "github.com/go-chi/chi/v5"
import "github.com/go-chi/chi/v5/middleware"
r := chi.NewRouter()
r.Use(middleware.Logger)
r.Use(middleware.Recoverer)
r.Use(middleware.RequestID)
r.Use(middleware.Timeout(30 * time.Second))
r.Route("/api/v1", func(r chi.Router) {
r.Use(authMiddleware)
r.Get("/users", listUsers)
r.Post("/users", createUser)
r.Get("/users/{id}", getUser)
r.Put("/users/{id}", updateUser)
r.Delete("/users/{id}", deleteUser)
})
http.ListenAndServe(":8080", r)
Gin
import "github.com/gin-gonic/gin"
r := gin.Default()
r.GET("/users/:id", func(c *gin.Context) {
id := c.Param("id")
user, err := service.GetUser(c.Request.Context(), id)
if err != nil {
if errors.Is(err, ErrNotFound) {
c.JSON(404, gin.H{"error": "not found"})
return
}
c.JSON(500, gin.H{"error": "internal error"})
return
}
c.JSON(200, user)
})
r.POST("/users", func(c *gin.Context) {
var req CreateUserRequest
if err := c.ShouldBindJSON(&req); err != nil {
c.JSON(400, gin.H{"error": err.Error()})
return
}
user, err := service.CreateUser(c.Request.Context(), req)
if err != nil {
c.JSON(500, gin.H{"error": err.Error()})
return
}
c.JSON(201, user)
})
r.Run(":8080")
Middleware Patterns
// Logging middleware
func LoggingMiddleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
start := time.Now()
next.ServeHTTP(w, r)
log.Printf("%s %s %v", r.Method, r.URL.Path, time.Since(start))
})
}
// Authentication middleware
func AuthMiddleware(next
…
## Source & license
This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.
- **Author:** [kinhluan](https://github.com/kinhluan)
- **Source:** [kinhluan/skills](https://github.com/kinhluan/skills)
- **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.