Skip to content
Zever
Home

Project layout

Find any Zever package fast: core interfaces, adapter modules, shared helpers, container, ORM, compiler, and CLI.

3 min readEdit on GitHub

Zever is a Go multi-module monorepo (go 1.27.0). Your application imports core interfaces, the adapter modules you choose, and container/. It never imports dsl/.

core/<b> battery interface + Register/Open registry (container resolves)
adapters/<b>/<a> one Go module per adapter; Register() wires it into its core registry
shared/* SDK-free helpers (codec, redisclient, s3opts, retry, ...)
wiring config/ container/ layered config + lazy resolver
language dsl/ .zen compiler frontend (compile time only)
surface orm/ cmd/zever/ typed queries, CLI
  • go.work at the repo root resolves every workspace module locally (176 use entries; examples/external-sms and docs/examples stay outside by design), so go build/test ./... from the root works. CI runs per-module commands with GOWORK=off.
  • Releases are lockstep: one version, with per-module tags <path>/vX.Y.Z made by tools/tag-release.sh.
  • config/ owns decoding (defaults < file < env, strict snake_case keys, RedactedServices); container/ owns construction, caching, retry, and close. Load errors belong to config/, resolution errors to container/.
Path Role Runtime?
config/ Default() zero-infra, strict Load(path), best-effort env, RedactedServices yes
container/ New(cfg) (nil valid), lazy accessors, retry on error, Close(ctx) in dependency order yes
core/<b> Battery interface plus Register/Open registry (for example core/cache, core/db) yes (interfaces)
adapters/<b>/<a> One module per adapter (for example adapters/cache/redis) yes (picked ones)
shared/* SDK-free helpers (codec, redisclient, redisopt, s3opts, retry, …) yes
orm/ NewTable / NewColumn / From, dialect per call, fail-closed errors yes
core/router fiber / stdhttp adapters over http.HandlerFunc yes (interface)
core/middleware HTTP middleware and gRPC interceptors, no registry yes
dsl/ lexer -> parser -> ast -> resolver -> ir.Schema, compile -> backend.Generate no (compile time)
cmd/zever/ Flags-only CLI, dev watch, dev-only tinker no (tool binary)
tools/ Dev tooling modules (gengrammar, modgraph, errscan, affected, zever-lsp, zever-mcp) plus scripts such as the tag-release.sh lockstep tagger no
docs/ Starlight site (npm, not Go) no
examples/ Runnable skeletons with schema, server, worker, seed reference

Batteries under core/: agent, ai, analytics, auth, authz, billing, cache, crypto, db, document, eval, eventbus, flag, geo, i18n, idempotency, job, lock, log, mailer, media, notification, observability, outbox, password, payment, permission, queue, rag, ratelimit, resilience, scheduler, search, secrets, session, storage, tenant, vectorstore, webhook, workflow. core/middleware and core/router are HTTP plumbing.

container/ is the only resolver. Application code never constructs adapters directly:

main.go
package main
import (
"fmt"
"github.com/zenta-dev/zever/adapters/db/sqlite"
"github.com/zenta-dev/zever/config"
"github.com/zenta-dev/zever/container"
)
func main() {
sqlite.Register()
c := container.New(config.Default())
db, err := c.DB()
if err != nil {
panic(err)
}
fmt.Println("db:", db.Dialect())
}

Expected output:

db: sqlite

The dialect comes per call from conn.Dialect(), so the same query code prints postgres in production.

  • No globals and no init() wiring. ctx is the first argument of IO functions and is never stored in a struct.
  • Exported identifiers need a doc comment starting with the name. goimports local prefix is github.com/zenta-dev/zever; depguard denies github.com/pkg/errors and io/ioutil.
  • Do not add methods to a public service interface: it breaks every implementer. Add a new interface instead.
  • New service shape: interface plus Register/Open registry in core/<b>, one module per adapter in adapters/<b>/<a> with a Register() call, shared SDK-free code in shared/*, and a README.md with an adapter table.
  • Timeouts and intervals are time.Duration (cookie MaxAge int seconds excepted); pool options use the MaxConn* prefix order. File-decoded Options need snake_case json/toml/yaml tags.
  • Tests stay deterministic: no time.Sleep sync, no network, no unseeded randomness. File suffixes (cover, live, bench, internal, race, closure) encode purpose; helpers use stub*, must*, freshAdapter.
  • Shutdown is a deploy contract: one container per process, closed in dependency order with a timeout parent (see Lifecycle).
A service package imports dsl

Cause: the compiler frontend leaked into runtime. Fix: remove the import and consume generated output (ORM, routes, stubs). See compiler boundary.

A new interface method breaks every adapter

Cause: a public interface grew a method. Fix: revert it and add a new interface.

go build ./... passes but the docs site fails

Cause: docs/ is npm, not Go. Fix: run npm run dev under docs/ with Node 22.12+.

A new service has no adapter table

Cause: scaffolding skipped the package README. Fix: add the interface, per-adapter subdirectories, registration, and a README.md with the adapter table.