God Handler — 300 lines of business logic in an HTTP handler
Validation, DB queries, Redis calls, event publishing — all in one function. The agent "just made it work" without layering.
AI agents write code fast, but without architectural constraints, they produce unmaintainable spaghetti. vibe-go provides the structure so AI produces production-grade Go from day one.
"Vibe coding" — letting AI write code by intuition without engineering rigor. It feels productive until it isn't.
AI generates code that works in isolation. Each file follows a different pattern. No consistent layering, no dependency direction. Three months in, the codebase is a maze.
Without clear interfaces, the agent reads 50 files to understand how to add one field. The context window fills with boilerplate before reaching the actual task.
Agent A writes storage logic that imports service types. Agent B adds a handler that calls the DB directly. Nobody notices until the refactor costs 10x.
Sprint 1: AI generates a working feature. Sprint 2: new feature conflicts with Sprint 1's architecture. Sprint 3: AI suggests rewriting everything. Sound familiar?
Patterns we've seen repeated across AI-generated Go projects.
Validation, DB queries, Redis calls, event publishing — all in one function. The agent "just made it work" without layering.
viper.Get("db.host") everywhereScattered config access makes testing impossible. No dependency injection, no explicit contracts between components.
AI defaults to fmt.Println or log.Println. No trace_id, no structured fields, no level control. Production debugging becomes guesswork.
fmt.Errorf("something failed")No structured error codes, no layer attribution. When an API returns 500, you have no idea if it's a DB issue, a business rule violation, or a gateway timeout.
Agent creates a record, then publishes an event. If the event publish fails, the record exists but nobody knows about it. No Outbox pattern.
Agent generates mocks that return hardcoded values. Tests pass, but the code doesn't actually work in production. No integration tests at all.
Agent picks whatever it's seen most in training data. The project ends up with three HTTP frameworks, two ORMs, and four logging libraries.
No /healthz, no /readyz, no pprof, no metrics endpoint. Kubernetes can't tell if the service is alive. Observability is an afterthought.
Not another framework. A scaffold with architectural constraints baked in. AI agents work within the structure — not against it.
L5-Gateway ══> Connect handler, middleware, routing │ L3-Authz ══> Permission check, rate limiting │ L4-Service ══> Business orchestration, validation // interfaces.go │ L2-Domain ══> Pure Go structs, state machine, events // zero deps │ L1-Storage ══> Ent, PostgreSQL, Redis, Outbox
Dependency direction locked. check_architecture.sh validates at CI time. Agent can't accidentally violate boundaries.
Core defines interfaces, plugins implement them. DI in main.go. Swap Meilisearch for Elasticsearch — zero changes to business logic.
Each task = one module × one layer. Self-contained context, precise interface contracts, executable acceptance criteria.
L{layer}{seq} error codes. Every error carries its layer. L4_601 = service validation failed. No guessing.
Business writes and event publishing in one transaction. No lost events, no eventual consistency surprises.
Logging: slog. Config: koanf. ORM: ent. HTTP: net/http. Every choice is made. Agent focuses on business, not bike-shedding.
| Category | Choice | Why |
|---|---|---|
| API | connect-go | gRPC + HTTP dual-mode, one proto file |
| Protobuf | buf | Code gen, lint, breaking change detection |
| ORM | ent (pgx) | Type-safe, code-gen, graph relations |
| Config | koanf | YAML + env, explicit DI, no global singleton |
| Logging | log/slog | Stdlib, zero deps, JSON handler |
| Cache | go-redis/v9 | Cache + event stream + distributed lock |
| ID | oklog/ulid | Globally unique, time-sortable |
| Tracing | OpenTelemetry | OTLP export, probability sampling |
| Metrics | Otel + Prometheus | :9090/metrics, standard format |
| Migration | golang-migrate | Versioned SQL, CLI + library |
| Testing | testify + gomock + testcontainers | Unit / integration / E2E coverage |
| Docs | buf + connectrpc/reflection | Proto is the contract, no Swagger needed |
vibe-go's task breakdown is designed to work with LRA (Long-Running Agent) — a task management tool purpose-built for AI agent multi-turn development.
Each task carries its own context: goal, contracts, dependencies, conventions, acceptance criteria. Agent starts cold and still delivers.
Multiple agents can work in parallel. Each task is claimed atomically — no conflicts, no duplicated work.
Constitution-based checks ensure every task meets the bar before marking complete. Tests pass, lint clean, architecture valid.
LRA is not required. Use your own workflow if you prefer. But the task breakdown format and agent workflow are designed with LRA in mind.
$ pip install long-run-agent
Clone the scaffold, fill in your CLAUDE.md, hand it to an agent. Architecture is pre-decided. The agent just writes business code.
View on GitHub