go-architecture-review — Claude Code skill for Go architecture
This skill reviews Go package structure, dependency direction, and module boundaries. Use it to assess an existing codebase or plan a refactor.
npx skills add eduardo-sl/go-agent-skills --skill go-architecture-review -a claude-codeWhat go-architecture-review does
The skill judges architecture against the project’s needs, so a small service does not get layers just for the sake of having them. It checks package responsibilities and how dependencies cross layers. Ask for a refactor plan and it returns an ordered migration path; for a new service, it gives structural guidance instead of auditing existing code.
For large repositories, it builds a dependency map with go list ./... and import statements, then reviews package design, wiring, configuration, and dependency direction. Findings point to package paths and file lines. The skill is read-only, and it requires the Go toolchain.
It does not cover Go coding style or endpoint design; those are handled by the separate go-coding-standards and go-api-design skills.
What it helps with
- spot circular dependencies between packages
- check whether dependencies point inward
- assess whether package structure fits the project
- plan a staged refactor from a monolith into modules
Example prompts for the agent
- Review this Go project’s architecture and cite a file and line for each finding.
- Suggest a package layout for a new Go service with HTTP and a database.
- Write a safe, ordered plan for splitting this monolith into modules.
How to install go-architecture-review
1Skills CLI (Vercel)
npx skills add eduardo-sl/go-agent-skills --skill go-architecture-review -a claude-code2Manually: put the files in place
~/.claude/skills/go-architecture-review/SKILL.mdCopy the whole skill folder; for one project use .claude/skills/go-architecture-review/
1Skills CLI (Vercel)
npx skills add eduardo-sl/go-agent-skills --skill go-architecture-review -a codex2Manually: put the files in place
.agents/skills/go-architecture-review/SKILL.mdFor all projects use ~/.agents/skills/
1Skills CLI (Vercel)
npx skills add eduardo-sl/go-agent-skills --skill go-architecture-review -a cursor2Manually: put the files in place
.cursor/skills/go-architecture-review/SKILL.mdCursor also reads .agents/skills/ and .claude/skills/
1GitHub CLI
gh skill install eduardo-sl/go-agent-skills go-architecture-review2Manually: put the files in place
.github/skills/go-architecture-review/SKILL.md1Skills CLI (Vercel)
npx skills add eduardo-sl/go-agent-skills --skill go-architecture-review -a gemini-cli2Platform CLI
gemini skills install https://github.com/eduardo-sl/go-agent-skills --path 'skills/(architecture)/go-architecture-review'Manually: put the files in place
.devin/skills/go-architecture-review/SKILL.mdThe legacy .windsurf/skills/ path still works
Skills CLI (Vercel)
npx skills add eduardo-sl/go-agent-skills --skill go-architecture-review -a opencodeClaude.ai
Zip the folder and upload it in Settings → Capabilities → Skills
Step by step, with commands for each platform: How to install skills in Claude Code: five ways
Questions about go-architecture-review
How do I install go-architecture-review in Claude Code?
Run npx skills add eduardo-sl/go-agent-skills --skill go-architecture-review -a claude-code. The skill file is at ~/.claude/skills/go-architecture-review/SKILL.md.
What does go-architecture-review do?
It examines Go project structure, package dependencies, and layer boundaries. It can report architecture findings or produce a sequenced refactoring plan, without editing files.
Does go-architecture-review need the Go toolchain?
Yes. It requires the Go toolchain and only reads the project; it does not modify code.
Source text
SKILL.md · MIT
---
name: go-architecture-review
description: >
Review Go project architecture: package structure, dependency direction,
layering, separation of concerns, domain modeling, and module boundaries.
Use when reviewing architecture, designing package layout, evaluating
dependency graphs, or refactoring monoliths into modules. Trigger
examples: "review architecture", "package structure", "project layout",
"dependency direction", "clean architecture Go", "module boundaries".
Not for: code-level style (go-coding-standards), endpoint design
(go-api-design).
user-invocable: true
license: MIT
compatibility: Designed for Claude Code or similar AI coding agents working on Go projects. Requires the Go toolchain. Read-only: this skill reports findings, it does not edit code.
allowed-tools: Read Glob Grep Bash(go:*) Bash(gofmt:*)
metadata:
author: eduardo-sl
version: "1.3.0"
---
# Go Architecture Review
Good architecture makes the next change easy. Bad architecture makes every change scary.
Detailed reference material, loaded on demand:
- `references/layout-and-wiring.md` — the full reference directory tree and
a composition-root `main.go`.
Read a reference file only when the summary below is not enough.
## Operating Modes
Pick the mode that matches the request before starting:
- **Layout review** (default) — assess an existing codebase against the
sections below and report violations with severity.
- **Refactor plan** — same assessment, but the deliverable is an ordered
migration plan (smallest safe steps first), not just findings.
- **New service consultation** — asked "how should I structure X":
apply sections 1-3 as prescriptive guidance instead of review checks.
## Match the Architecture to the Problem
Judge a codebase against the structure its problem needs, not the most
elaborate one available. Over-architecture is a finding too.
| Situation | Fitting structure |
|---|---|
| CLI, small service, one data store, little business logic | Flat `main` + a few packages; no layers for their own sake |
| Typical service: HTTP/gRPC in front, a database behind | Handler → service → store, interfaces at the consumer (sections 1-2) |
| Several adapters (HTTP, gRPC, queue, CLI) over the same rules, or infrastructure expected to change | Ports and adapters: a pure core, adapters on the edge |
| Large domain, several teams, rules that differ by sub-domain | Bounded contexts as top-level packages, each layered inside, talking through explicit APIs or events |
Signs of too much: interfaces with one implementation per layer, mapping
structs copied unchanged through three layers, a "domain" package with no
behavior. Signs of too little: SQL in handlers, business rules spread
across transport code, packages that import each other in both directions.
## Auditing Large Codebases
For repositories with many packages, build the dependency picture before
judging it:
1. Map the module: `go list ./...` for packages, then import statements
to trace dependency direction.
2. Run independent passes: (a) layout vs section 1, (b) dependency
direction vs section 2, (c) wiring and config vs sections 3+5,
(d) package design vs section 4.
3. If your environment supports delegating work to parallel sub-agents
or tasks, assign each pass to one; synthesize at the end — dependency
findings often explain layout findings.
4. Cite package paths and `file.go:line` in every finding.
## 1. Standard Project Layout
The reference layout: `cmd/<binary>/main.go` per binary, project-private
code under `internal/` (`domain`, `service`, `store/<backend>`,
`handler`, `config`), `pkg/` only for genuinely reusable code, plus
`api/` for OpenAPI/proto and `migrations/`. Full tree:
`references/layout-and-wiring.md`. For scaffolding a new project, the
go-project-layout skill owns the procedure.
### Key Rules:
- `internal/` enforces encapsulation at the compiler level. Use it aggressively.
- `pkg/` is for genuinely reusable packages. When in doubt, use `internal/`.
- `cmd/` main packages should be thin — wire dependencies and call `Run()`.
- One `main.go` per binary, minimal logic inside.
## 2. Dependency Direction
Dependencies MUST flow inward. Domain core has zero external dependencies:
```text
handlers → services → domain ← stores
↓ ↓ ↓
(net/http) (pure Go) (database/sql)
```
Rules:
- `domain/` imports NOTHING from the project. No `store`, no `handler`, no `config`.
- `service/` depends on `domain/` types and interfaces, NOT on concrete stores.
- `handler/` depends on `service/` interfaces.
- `store/` implements interfaces defined in `service/` or `domain/`.
- Circular dependencies are a 🔴 BLOCKER. The compiler catches them, but design should prevent them.
```go
// ✅ Good — service defines the interface it needs
// internal/service/user.go
type UserStore interface {
GetByID(ctx context.Context, id string) (*domain.User, error)
Create(ctx context.Context, user *domain.User) error
}
type UserService struct {
store UserStore // depends on interface, not postgres.Store
}
// internal/store/postgres/user.go
type Store struct { db *sql.DB }
// Implements service.UserStore without importing the service package
func (s *Store) GetByID(ctx context.Context, id string) (*domain.User, error) { ... }
```
## 3. Main Package Wiring
`main.go` is the composition root. Wire everything here:
Read config, build the logger, open connections, construct stores →
services → handlers in that order, mount routes, run the server. No
business logic. Example: `references/layout-and-wiring.md`.
Avoid dependency injection frameworks. Go's explicit wiring is a feature.
If wiring gets complex, use Google's `wire` for compile-time DI code generation.
## 4. Package Design Principles
### One package = one purpose
```go
// ✅ Good — clear purpose
package orderservice // business rules for orders
package postgres // PostgreSQL data access
package httphandler // HTTP transport layer
// ❌ Bad — grab-bag packages
package utils // what ISN'T a util?
package common // everything and nothing
package models // types without behavior
```
### Avoid package stuttering
```go
// ❌ Bad — package name repeated in type
package user
type UserService struct{} // user.UserService
// ✅ Good
package user
type Service struct{} // user.Service
```
### Package cohesion over size
A package with 20 related files is better than 20 packages with 1 file each.
Split packages when they have distinct responsibilities, not when they get big.
## 5. Configuration
```go
type Config struct {
Addr string `env:"ADDR" envDefault:":8080"`
DatabaseURL string `env:"DATABASE_URL,required"`
LogLevel string `env:"LOG_LEVEL" envDefault:"info"`
Timeout time.Duration `env:"TIMEOUT" envDefault:"30s"`
}
```
Rules:
- All config from environment variables (12-factor).
- Validate at startup, fail fast with clear messages.
- No config scattered across packages — centralize in `internal/config`.
- Never hardcode values. Not even "just for now."
## 6. Init Functions
Avoid `init()`. It runs implicitly, makes testing harder, and creates hidden dependencies.
```go
// ❌ Bad — hidden side effects
func init() {
db, _ = sql.Open("postgres", os.Getenv("DB_URL"))
}
// ✅ Good — explicit initialization
func NewStore(dsn string) (*Store, error) {
db, err := sql.Open("postgres", dsn)
if err != nil {
return nil, fmt.Errorf("open db: %w", err)
}
return &Store{db: db}, nil
}
```
Exception: registering drivers or codecs is acceptable in `init()`:
```go
func init() {
sql.Register("custom", &CustomDriver{})
}
```
## Architecture Review Checklist
- 🔴 No circular dependencies between packages
- 🔴 Domain types have zero infrastructure dependencies
- 🔴 No business logic in `cmd/` main packages
- 🔴 No `init()` with side effects (DB connections, HTTP calls)
- 🟡 `internal/` used for project-private packages
- 🟡 Interfaces defined at the consumer, not the producer
- 🟡 Configuration centralized and validated at startup
- 🟡 Dependency direction flows inward (handlers → services → domain)
- 🟢 Package names are short, singular, descriptive
- 🟢 No `utils/`, `common/`, `helpers/` packages
- 🟢 Main package is a thin composition root
- 🟢 Structure is proportional to the domain — no layers or interfaces without a second reason to exist
© eduardo-sl · MIT · eduardo-sl/go-agent-skills