Skip to main content
ClaudeWave
Skill74 repo starsupdated 7d ago

go-architect

Go-architect provides guidance on structuring Go web servers using net/http 1.22+ routing, organizing project layouts with flat or modular patterns, implementing graceful shutdown with signal handling, and applying dependency injection principles. Use this skill when designing new Go applications, refactoring existing projects for better architecture, or reviewing code that needs to follow standard library first patterns with explicit composition and minimal global state.

Install in Claude Code
Copy
git clone --depth 1 https://github.com/existential-birds/beagle /tmp/go-architect && cp -r /tmp/go-architect/plugins/beagle-go/skills/go-architect ~/.claude/skills/go-architect
Then start a new Claude Code session; the skill loads automatically.

SKILL.md

# Lead Go Architect

## Quick Reference

| Topic | Reference |
|-------|-----------|
| Flat vs modular project layout, migration signals | [references/project-structure.md](references/project-structure.md) |
| Graceful shutdown with signal handling | [references/graceful-shutdown.md](references/graceful-shutdown.md) |
| Dependency injection patterns, testing seams | [references/dependency-injection.md](references/dependency-injection.md) |

## Core Principles

1. **Standard library first** -- Use `net/http` and the Go 1.22+ enhanced `ServeMux` for routing. Only reach for a framework (chi, echo, gin) when you have a concrete need the stdlib cannot satisfy (e.g., complex middleware chains, regex routes).
2. **Dependency injection over globals** -- Pass databases, loggers, and services through struct fields and constructors, never package-level `var`.
3. **Explicit over magic** -- No `init()` side effects, no framework auto-wiring. `main.go` is the composition root where everything is assembled visibly.
4. **Small interfaces, big structs** -- Define interfaces at the consumer, keep them narrow (1-3 methods). Concrete types carry the implementation.

## Hard gates

Use this sequence when implementing or reviewing work that claims to follow this skill. Do not skip ahead; each step has a **pass condition** you can answer with tooling or a concrete file path.

1. **Toolchain vs APIs** — If the code uses Go 1.22+ `ServeMux` features (method+path patterns like `"GET /x/{id}"`, `r.PathValue`, or `{path...}`): run `go version` and **pass** only if the reported toolchain is **go1.22+**. If the project must stay on an older Go, **pass** only by not using those APIs (use a compatible router or older patterns) and say so in the review or PR.
2. **Composition root** — **Pass** when `main.go` or `cmd/.../main.go` visibly constructs the server and injects shared dependencies (DB, logger, config). **Fail** if shared dependencies are wired in `init()` or package-level `var` instead of explicit construction in `main` (or a `run()` called from `main`).
3. **Production HTTP shutdown** — For a long-lived HTTP service, **pass** only if shutdown uses `http.Server.Shutdown` with a **bounded** context (e.g. `context.WithTimeout`) after waiting on `signal.NotifyContext` (or equivalent). Cite the file path when reporting; see [references/graceful-shutdown.md](references/graceful-shutdown.md) for the full pattern.
4. **No env/globals in handlers** — **Pass** when handlers and domain code take dependencies via structs/arguments. **Fail** if handlers read `os.Getenv` for secrets or use package-level `var` for DB/clients (loading env in `main` or a dedicated config package is fine).

## Go 1.22+ Enhanced Routing

Go 1.22 upgraded `http.ServeMux` with method-based routing and path parameters, eliminating the most common reason for third-party routers.

### Method-Based Routing and Path Parameters

```go
mux := http.NewServeMux()
mux.HandleFunc("GET /api/users", s.handleListUsers)
mux.HandleFunc("GET /api/users/{id}", s.handleGetUser)
mux.HandleFunc("POST /api/users", s.handleCreateUser)
mux.HandleFunc("DELETE /api/users/{id}", s.handleDeleteUser)
```

### Extracting Path Parameters

```go
func (s *Server) handleGetUser(w http.ResponseWriter, r *http.Request) {
    id := r.PathValue("id")
    if id == "" {
        http.Error(w, "missing id", http.StatusBadRequest)
        return
    }

    user, err := s.users.GetUser(r.Context(), id)
    if err != nil {
        s.logger.Error("getting user", "err", err, "id", id)
        http.Error(w, "internal error", http.StatusInternalServerError)
        return
    }

    w.Header().Set("Content-Type", "application/json")
    json.NewEncoder(w).Encode(user)
}
```

### Wildcard and Exact Match

```go
// Exact match on trailing slash -- serves /api/files/ only
mux.HandleFunc("GET /api/files/", s.handleListFiles)

// Wildcard to end of path -- /api/files/path/to/doc.txt
mux.HandleFunc("GET /api/files/{path...}", s.handleGetFile)
```

### Routing Precedence

The new `ServeMux` uses most-specific-wins precedence:

- `GET /api/users/{id}` is more specific than `GET /api/users/`
- `GET /api/users/me` is more specific than `GET /api/users/{id}`
- Method routes take precedence over method-less routes

## Server Struct Pattern

The Server struct is the central dependency container for your application. It holds all shared dependencies and implements `http.Handler`.

```go
type Server struct {
    db     *sql.DB
    logger *slog.Logger
    router *http.ServeMux
}

func NewServer(db *sql.DB, logger *slog.Logger) *Server {
    s := &Server{
        db:     db,
        logger: logger,
        router: http.NewServeMux(),
    }
    s.routes()
    return s
}

func (s *Server) routes() {
    s.router.HandleFunc("GET /api/users/{id}", s.handleGetUser)
    s.router.HandleFunc("POST /api/users", s.handleCreateUser)
    s.router.HandleFunc("GET /healthz", s.handleHealth)
}

func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
    s.router.ServeHTTP(w, r)
}
```

### Middleware Wrapping

Apply middleware at the `http.Server` level or per-route:

```go
// Wrap entire server
httpServer := &http.Server{
    Addr:    ":8080",
    Handler: requestLogger(s),
}

// Or per-route
s.router.Handle("GET /api/admin/", adminOnly(http.HandlerFunc(s.handleAdmin)))
```

### Middleware Signature

```go
func requestLogger(next http.Handler) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        start := time.Now()
        next.ServeHTTP(w, r)
        slog.Info("request", "method", r.Method, "path", r.URL.Path, "dur", time.Since(start))
    })
}
```

## Project Structure

Choose based on project size:

- **Flat structure** -- single package, all files in root. Best for CLIs, small services, < ~10 handlers. See [references/project-structure.md](references/project-structure.md).
- **Modular/domain-driven** -- `cmd/`, `internal/` with domain packages. For larger apps with
release-tagSlash Command

tag and push a release after the release PR is merged

releaseSlash Command

create a release PR (auto-detects previous tag)

deepagents-architectureSkill

Guides architectural decisions for Deep Agents applications. Use when deciding between Deep Agents vs alternatives, choosing backend strategies, designing subagent systems, or selecting middleware approaches.

deepagents-code-reviewSkill

Reviews Deep Agents code for bugs, anti-patterns, and improvements. Use when reviewing code that uses create_deep_agent, backends, subagents, middleware, or human-in-the-loop patterns. Catches common configuration and usage mistakes.

deepagents-implementationSkill

Implements agents using Deep Agents. Use when building agents with create_deep_agent, configuring backends, defining subagents, adding middleware, or setting up human-in-the-loop workflows.

langgraph-architectureSkill

Guides architectural decisions for LangGraph applications. Use when deciding between LangGraph vs alternatives, choosing state management strategies, designing multi-agent systems, or selecting persistence and streaming approaches.

langgraph-code-reviewSkill

Reviews LangGraph code for bugs, anti-patterns, and improvements. Use when reviewing code that uses StateGraph, nodes, edges, checkpointing, or other LangGraph features. Catches common mistakes in state management, graph structure, and async patterns.

langgraph-implementationSkill

Implements stateful agent graphs using LangGraph. Use when building graphs, adding nodes/edges, defining state schemas, implementing checkpointing, handling interrupts, or creating multi-agent systems with LangGraph.