- Docs
- Start
- Project layout
Project layout
Find any Zever package fast: core interfaces, adapter modules, shared helpers, container, ORM, compiler, and CLI.
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/.
The four roles
Section titled “The four roles”core/<b> battery interface + Register/Open registry (container resolves)adapters/<b>/<a> one Go module per adapter; Register() wires it into its core registryshared/* SDK-free helpers (codec, redisclient, s3opts, retry, ...)wiring config/ container/ layered config + lazy resolverlanguage dsl/ .zen compiler frontend (compile time only)surface orm/ cmd/zever/ typed queries, CLIgo.workat the repo root resolves every workspace module locally (176useentries;examples/external-smsanddocs/examplesstay outside by design), sogo build/test ./...from the root works. CI runs per-module commands withGOWORK=off.- Releases are lockstep: one version, with per-module tags
<path>/vX.Y.Zmade bytools/tag-release.sh. config/owns decoding (defaults < file < env, strict snake_case keys,RedactedServices);container/owns construction, caching, retry, and close. Load errors belong toconfig/, resolution errors tocontainer/.
Package map
Section titled “Package map”| 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.
Resolve a service from the container
Section titled “Resolve a service from the container”container/ is the only resolver. Application code never constructs adapters directly:
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: sqliteThe dialect comes per call from conn.Dialect(), so the same query code prints postgres in production.
Conventions for contributors
Section titled “Conventions for contributors”- No globals and no
init()wiring.ctxis the first argument of IO functions and is never stored in a struct. - Exported identifiers need a doc comment starting with the name.
goimportslocal prefix isgithub.com/zenta-dev/zever;depguarddeniesgithub.com/pkg/errorsandio/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/Openregistry incore/<b>, one module per adapter inadapters/<b>/<a>with aRegister()call, shared SDK-free code inshared/*, and aREADME.mdwith an adapter table. - Timeouts and intervals are
time.Duration(cookieMaxAgeint seconds excepted); pool options use theMaxConn*prefix order. File-decoded Options need snake_casejson/toml/yamltags. - Tests stay deterministic: no
time.Sleepsync, no network, no unseeded randomness. File suffixes (cover,live,bench,internal,race,closure) encode purpose; helpers usestub*,must*,freshAdapter. - Shutdown is a deploy contract: one container per process, closed in dependency order with a timeout parent (see Lifecycle).
Troubleshooting
Section titled “Troubleshooting”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.