go-code-review
Invoke this skill to systematically review a Go change against community style standards before merging. Walks the diff topic by…
Use when scaffolding or refactoring a Go service into a framework-agnostic clean (hexagonal) architecture: Domain, Usecase, Repository, Delivery layers, inward dependency rule, 'framework/database is a detail'. Apply when untangling a monolith or checking whether business logic
Claude Code
$ npx -y skills add muratmirgun/gophers --skill go-clean-architecture --agent claude-code
Codex
$ npx skills add muratmirgun/gophers --skill go-clean-architecture -a codex -y
Cursor
$ npx skills add muratmirgun/gophers --skill go-clean-architecture -a cursor -y
Gemini CLI
$ npx skills add muratmirgun/gophers --skill go-clean-architecture -a gemini-cli -y
GitHub Copilot
$ npx skills add muratmirgun/gophers --skill go-clean-architecture -a github-copilot -y
OpenCode
$ npx skills add muratmirgun/gophers --skill go-clean-architecture -a opencode -y
Windsurf
$ npx skills add muratmirgun/gophers --skill go-clean-architecture -a windsurf -y
name: go-clean-architecture description: "Use when scaffolding or refactoring a Go service into a framework-agnostic clean (hexagonal) architecture: Domain, Usecase, Repository, Delivery layers, inward dependency rule, 'framework/database is a detail'. Apply when untangling a monolith or checking whether business logic is testable without HTTP or DB." license: MIT compatibility: "Designed for Claude Code or similar AI coding agents. Requires Go 1.21+. Framework-agnostic: works with Gin, Echo, Fiber, Chi, or net/http; swap freely." allowed-tools: Read Edit Write Glob Grep Bash(go:*) Bash(golangci-lint:*)
A Go service organized into four concentric layers — Domain, Usecase, Repository, Delivery — where source code depends *inward only*. Done well, the HTTP framework and the database are interchangeable details; the business logic is testable without either.
This skill is framework-agnostic. Swap Gin for Fiber, Echo, Chi, or `net/http` by replacing the delivery layer — zero changes elsewhere.
1. **Dependency Rule.** Source depends inward: Delivery → Usecase → Domain. Repository implements interfaces declared in Domain. Domain depends on nothing. 2. **Framework is a detail.** Gin/Fiber/Echo/Chi/net-http types live only in `internal/delivery/`. Usecases see plain Go values. 3. **Database is a detail.** SQL, sqlx, sqlc, pgx, GORM live only in `internal/repository/`. Usecases see repository interfaces. 4. **Domain owns the interfaces; layers below provide implementations.** `UserRepository` is an interface in `internal/domain`; the Postgres struct is in `internal/repository` and unexported. 5. **DTOs at the edges.** Delivery layer maps HTTP request bodies to domain inputs and domain entities to response bodies. Usecases never see `*gin.Context`, `http.Request`, or DB rows. 6. **`cmd/<binary>/main.go` is the only place that knows the whole system.** Wiring (DI) is explicit, framework-free Go code.
| Symptom | What clean architecture buys you | |---|---| | HTTP handlers contain SQL | Move SQL into a repository; handlers shrink to 5 lines | | Tests need a running DB | Mock the repository interface; usecase tests run in milliseconds | | Swapping web frameworks is a rewrite | Replace `internal/delivery/http`; nothing else touched | | Business rules duplicated across handlers | Single usecase function, called by HTTP, gRPC, and a CLI | | ORM hooks fire in surprising places | Repository methods are explicit; no hidden behavior |
If the service is a 200-line cron job, this skill is overkill. If it will live 3+ years and grow features, it's the cheapest insurance you can buy.
myapp/
cmd/
api/main.go # entry point: config → DI → start server
worker/main.go # different entry, same Domain & Usecase
internal/
domain/ # entities, value objects, repository INTERFACES, domain errors
user.go
order.go
errors.go
usecase/ # business logic; depends only on domain
user_usecase.go
order_usecase.go
repository/ # implementations of domain interfaces (Postgres, in-memory, ...)
user_postgres.go
order_postgres.go
delivery/ # framework-specific adapters
http/ # Gin/Echo/Chi/net-http handlers and routes
user_handler.go
order_handler.go
grpc/ # gRPC server adapters (if applicable)
pkg/ # exported, importable from outside (if you publish a library)
migrations/ # SQL migrations
config/
go.mod> Read [references/domain.md](references/domain.md), [references/usecase.md](references/usecase.md), [references/repository.md](references/repository.md), and [references/delivery.md](references/delivery.md) for the per-layer responsibilities.
| Layer | Package | Can import | Must not import | |---|---|---|---| | Domain | `internal/domain` | stdlib only | usecase, repository, delivery, frameworks | | Usecase | `internal/usecase` | domain | repository (concrete), delivery, frameworks | | Repository | `internal/repository` | domain, DB driver | delivery, frameworks | | Delivery | `internal/delivery/...` | domain, usecase (via interface), framework | repository (concrete) |
A `golangci-lint` config with `depguard` enforces these rules at CI time.
// Domain — pure interfaces and entities, no I/O.
package domain
type User struct { ID, Email, Name string; CreatedAt time.Time }
type UserRepository interface {
Get(ctx context.Context, id string) (*User, error)
Create(ctx context.Context, u *User) error
}
type UserService interface {
Create(ctx context.Context, in CreateUserInput) (*User, error)
}// Usecase — business logic, depends only on domain interfaces.
type userUsecase struct{ repo domain.UserRepository }
func NewUserUsecase(repo domain.UserRepository) domain.UserService {
return &userUsecase{repo: repo}
}// Repository — concrete adapter, translates driver errors to domain errors.
type postgresUserRepo struct{ db *sql.DB }
func NewUserRepository(db *sql.DB) domain.UserRepository { return &postgresUserRepo{db: db} }// Delivery — HTTP framework lives only here; swap freely.
type UserHandler struct{ svc domain.UserService }
func NewUserHandler(svc domain.UserService) *UserHandler { return &UserHandler{svc: svc} }> Read [references/domain.md](references/domain.md), [references/usecase.md](references/usecase.md), [references/repository.md](references/repository.md), and [references/delivery.md](references/delivery.md) for full code examples per layer.
// cmd/api/main.go — the only place that knows the whole system.
db, _ := sql.Open("postgres", cfg.DBURL)
userRepo := repository.NewUserRepository(db)
userSvc := usecase.NewUserUsecase(userRepo)
userH := de26 production-grade Go skills for Claude Code, Gemini CLI, and opencode. Battle-tested patterns from the Go community — codified as triggerable AI skills.
Invoke this skill to systematically review a Go change against community style standards before merging. Walks the diff topic by…
Use when writing or reviewing Go code for clarity, formatting, control flow, variable declarations, switch usage, and function…
Use when writing or reviewing concurrent Go code — goroutines, channels, select, mutexes, atomics, errgroup, singleflight, worker…
Use when designing, propagating, or debugging context.Context flow in Go — first-parameter placement, deadlines and cancellation,…
Use when writing conditionals, loops, switches, type switches, or blank-identifier patterns in Go. Covers if-with-initialization,…
Use when choosing or operating on Go slices, maps, arrays, strings, or container/* types — including slice internals, capacity…
You MUST use this before any creative work - creating features, building components, adding functionality, modifying behavior, or…
Ask which skill or flow fits your situation. A router over the skills in this repo.