Getting started
Run the platform locally, create a design on the site, or lint one from your own repository.
There are three ways in, and they do not depend on each other. Pick the one that matches what you want today.
Run the platform locally
Everything is in one repository and the web app needs nothing installed. Without a
DATABASE_URL it runs an embedded Postgres under apps/web/.pglite, so there is no database to
set up.
pnpm install pnpm validate # the repository gate: catalogue and designs pnpm test # every package's tests pnpm dev # http://localhost:3000
There is no local-account sign-in: GitHub is the only identity provider, so signing in locally
needs a GitHub OAuth app and GITHUB_CLIENT_ID, GITHUB_CLIENT_SECRET and CANVAS_URL in
apps/web/.env.local. Reading and linting never need an account; creating a design does.
For the real thing — Postgres, GitHub OAuth, Prometheus and Grafana — the supported way is the compose stack at the repository root:
cp .env.example .env # then fill in the four secrets docker compose up -d --build
First boot seeds the curated designs, which takes a minute or two. See Deployment for the service list and every environment variable.
Create your first design on the site
- New design. The button is in the site header. A new design is private and parked at a
temporary address of the form
draft-a1b2c3until you give it a name. - Draw it. The canvas has the catalogue in its palette. Drop components, join them with edges, nest them in groups. Findings update as you work: structural problems block the save, rule findings do not.
- Name it. Click the title. The address follows the title the first time you publish, so
Order processingbecomes/d/<you>/order-processing. - Publish. Publishing moves the release pointer to what you have saved. Until then, your edits are the head and readers keep seeing the last release. Making a design public with nothing released yet releases the head at that moment, so a public page is never empty.
Lint a design in your own repository
The command line tool works on any repository. It needs no account and no network.
npx zeema init # starter design, config, editor schema mapping, CI workflow npx zeema lint # exit 1 on a structural error or a rule of severity error
init writes four things and never overwrites an existing file:
| File | What it is |
|---|---|
architecture/checkout.zeema.yaml | A starter design you can edit down to nothing |
zeema.config.json | Which paths to lint, the failing severity, disabled rules |
.github/workflows/zeema.yml | A pull-request check that also uploads SARIF |
.vscode/settings.json | Maps *.zeema.yaml and design.yaml to the design schema |
With the YAML extension installed, your editor now validates the design against the schema and completes enum values as you type. In a repository that is not this one, the first line of the file does the same job:
# yaml-language-server: $schema=https://zeema.dev/schema/design.schema.jsonzeema validate is a different thing from zeema lint: it runs the whole-repository gate over a
catalogue — every kind, component, rule, locale entry and reference design — and is what you
run when contributing to the vocabulary rather than describing a system. See
Command line for every command and its exit codes.
The shape of a design
The smallest true statement, and then grow it:
schemaVersion: "1" type: "design" id: "checkout" nodes: - { id: "api", component: "aws-api-gateway" } - { id: "checkout-service", component: "container-service" } - { id: "orders-db", component: "postgres" } edges: - { from: "api", to: "checkout-service", protocol: "http", mode: "sync" } - { from: "checkout-service", to: "orders-db", protocol: "postgres", mode: "sync" }
Add requirements, then groups, then props, then per-node NFRs — in that order, because each step unlocks rules that the previous one could not answer. Writing a design walks through all of it.