A ZenStack community plugin that automatically generates rich, browsable Markdown documentation from your ZModel schema — every time you run zenstack generate.
ℹ️ This project is not affiliated with or endorsed by the ZenStack team.
Your ZModel schema is already the single source of truth for your data layer: models, relationships, enums, access policies, validation rules, computed fields, procedures. But that knowledge is locked inside .zmodel files that non-engineers can't easily read, and manually-maintained wiki pages inevitably drift.
This plugin turns your schema into a documentation site that:
- Stays in sync — regenerated on every
zenstack generate, so docs never go stale - Surfaces hidden knowledge — access policies, validation constraints, and indexes are documented automatically, not just fields and types
- Onboards new engineers — a browsable reference with cross-links, ER diagrams, and field descriptions means less time asking "what does this model do?"
- Works with your tools — outputs standard Markdown with Mermaid diagrams, compatible with GitHub, GitLab, Obsidian, Docusaurus, VitePress, and any Markdown renderer that supports fenced Mermaid blocks (Notion renders plain Markdown but not Mermaid natively)
pnpm add -D zenstack-docs-pluginRequires ZenStack v3 (@zenstackhq/language and @zenstackhq/sdk >= 3.0.0).
1. Register the plugin in your schema.zmodel:
plugin documentation {
provider = 'zenstack-docs-plugin'
output = './docs/schema'
}2. Generate:
pnpm exec zenstack generate3. Browse your docs in ./docs/schema/.
That's it. Every entity in your schema now has its own documentation page.
Generated documentation from the showcase schema is committed to this repo — browse it to see exactly what you get:
- Index page — overview with counts, descriptions, navigation, and embedded ERD
- Model page (User) — fields, relationships, ER diagram, policies, procedures
- Model page (Task) — computed fields, validation rules, indexes
- Relationships page — cross-reference table + full ER diagram
- Enum page (Role) — values, used-by section, usage diagram
- Procedure page (signUp) — parameters, return type, flowchart
- ERD (Mermaid source) — complete entity relationship diagram
- ERD (SVG) — rendered SVG via
beautiful-mermaid - SKILL.md — AI agent skill file
- Theme gallery — the same ERD rendered in all 15
beautiful-mermaidthemes
A second example using a larger multi-file schema is in preview-output/verbose/.
docs/schema/
├── index.md # Overview with counts, descriptions, and navigation
├── relationships.md # Full ER diagram + cross-reference table
├── schema-erd.mmd # Complete Mermaid ERD source (when generateErd = true)
├── schema-erd.svg # Rendered SVG ERD (when generateErd = true)
├── models/
│ ├── User.md
│ └── Post.md
├── views/
│ └── UserProfile.md
├── types/
│ └── Timestamps.md
├── enums/
│ └── Role.md
└── procedures/
└── signUp.md
The index lists every model, view, type, enum, and procedure with inline description excerpts, artifact counts, and links to the relationships diagram.
Each model page includes (when applicable):
- Fields table — name, type, required/optional, default value, attributes, description
- Relationships — related models with cardinality and a Mermaid ER diagram
- Access policies — every
@@allowand@@denyrule in a readable table - Validation rules —
@email,@length,@regex, and all other validation attributes - Indexes —
@@indexand@@uniqueconstraints - Computed fields — clearly badged so readers know they're derived
- Mixins — which types are mixed in, with links to their definitions
- Procedures — which procedures reference this model
- Declaration — the raw ZModel source in a collapsible block
Sections are only shown when they have content, so simple models get clean, short pages.
- Relationship pages get a full-schema ER diagram
- Model pages get a focused ER diagram showing that model's relationships and a field-level entity diagram with PK/FK/UK annotations
- Enum pages get a class diagram showing which models use them
- Type pages get a class diagram showing mixin relationships
- Procedure pages get a flowchart showing input → procedure → output
Every reference is a working link:
- Field types link to their model, enum, or type page
- "Used By" sections on enums and types deep-link to the exact field on the model page
- Procedures link to return types and parameter types
- Models link back to procedures that reference them
- Prev/next navigation between entities of the same kind
- Breadcrumbs on every page back to the index
All options go inside the plugin block:
plugin documentation {
provider = 'zenstack-docs-plugin'
output = './docs/schema'
title = 'Acme API Schema'
fieldOrder = 'alphabetical'
includeInternalModels = true
includeRelationships = true
includePolicies = true
includeValidation = true
includeIndexes = true
generateSkill = true
generateErd = true
erdTheme = 'github-light'
diagramFormat = 'svg'
diagramEmbed = 'inline'
}| Option | Type | Default | Description |
|---|---|---|---|
output |
string |
ZenStack default output path | Directory to write generated docs |
title |
string |
"Schema Documentation" |
Heading on the index page |
fieldOrder |
"declaration" or "alphabetical" |
"declaration" |
How fields are ordered in tables |
includeInternalModels |
boolean |
false |
Include models marked @@ignore in output |
includeRelationships |
boolean |
true |
Generate relationship sections and relationships.md |
includePolicies |
boolean |
true |
Generate access policy tables |
includeValidation |
boolean |
true |
Generate validation rule tables |
includeIndexes |
boolean |
true |
Generate index/constraint tables |
generateSkill |
boolean |
false |
Generate a SKILL.md file for AI agent consumption |
generateErd |
boolean |
false |
Generate a complete ERD as .mmd and .svg files |
erdFormat |
"svg", "mmd", or "both" |
"both" |
Which ERD output format(s) to produce |
erdTheme |
string |
default | beautiful-mermaid theme name for SVG rendering |
diagramFormat |
"mermaid", "svg", or "both" |
"mermaid" |
How per-page Mermaid diagrams are rendered (see Per-Page SVG Diagrams) |
diagramEmbed |
"file" or "inline" |
"file" |
Whether SVGs are written as companion files or embedded directly in the markdown (see Per-Page SVG Diagrams) |
Set generateErd = true to produce a complete Entity Relationship Diagram covering all models, scalar fields (with PK/FK/UK annotations), and relationship connectors.
plugin documentation {
provider = 'zenstack-docs-plugin'
output = './docs/schema'
generateErd = true
erdTheme = 'github-light'
}This produces:
schema-erd.mmd— the raw Mermaid ER diagram source, usable anywhere that renders Mermaidschema-erd.svg— a rendered SVG via beautiful-mermaid, a pure-TypeScript Mermaid renderer with zero DOM dependencies
The SVG is embedded directly in the index page so it's visible when browsing the docs.
The erdTheme option accepts any built-in beautiful-mermaid theme: zinc-dark, tokyo-night, tokyo-night-storm, tokyo-night-light, catppuccin-mocha, catppuccin-latte, nord, nord-light, dracula, github-light, github-dark, solarized-light, solarized-dark, one-dark.
See all 15 themes rendered against the showcase schema in the theme gallery.
By default, diagrams on model, view, enum, type, procedure, relationship, and SKILL pages are rendered as inline Mermaid code blocks. Set diagramFormat to render them as SVG images instead:
plugin documentation {
provider = 'zenstack-docs-plugin'
output = './docs/schema'
diagramFormat = 'svg'
erdTheme = 'github-light'
}| Value | Behavior |
|---|---|
"mermaid" |
Inline ```mermaid code blocks (default, requires a Mermaid-capable viewer) |
"svg" |
Companion .svg files referenced via  — works everywhere |
"both" |
SVG image reference with the Mermaid source in a collapsible <details> block |
Control whether SVGs are written as separate files or embedded directly in the markdown:
plugin documentation {
provider = 'zenstack-docs-plugin'
output = './docs/schema'
diagramFormat = 'svg'
diagramEmbed = 'inline'
}| Value | Behavior |
|---|---|
"file" |
SVG written as companion files next to each .md page (default) |
"inline" |
Raw <svg> XML embedded directly in the markdown — fully self-contained, no separate files |
The diagramEmbed option only takes effect when diagramFormat is "svg" or "both".
- Descriptive alt text — image references use the entity name (e.g.
![User diagram]) for accessibility and hover tooltips - Responsive wrapper — all SVG outputs (file references and inline) are wrapped in
<div style="max-width:100%;overflow-x:auto">so large diagrams scroll horizontally instead of overflowing the page
The erdTheme option applies to all per-page SVGs as well as the standalone ERD.
Add /// comments to any model, field, enum value, or procedure. They become the description in the generated docs:
/// A registered user in the platform.
/// Users can have multiple posts and belong to organizations.
model User {
id String @id @default(cuid())
/// User's primary email address. Must be unique.
email String @unique @email
}Use @@meta (model-level) and @meta (field-level) with doc: prefixed keys to add structured metadata that the plugin renders into the generated pages.
These are placed inside the model body alongside @@allow, @@index, etc.
model User {
id String @id @default(cuid())
email String @unique
@@meta('doc:category', 'Identity')
@@meta('doc:since', '1.0')
@@meta('doc:deprecated', 'Use Account model instead')
}| Key | Value | Where it appears | Example |
|---|---|---|---|
doc:category |
Free-text category label | Metadata line at the top of the model page, next to Category: | @@meta('doc:category', 'Billing') |
doc:since |
Version string | Metadata line at the top of the model page, next to Since: | @@meta('doc:since', '2.0') |
doc:deprecated |
Deprecation reason or migration note | Strikes through the model name, adds a Deprecated badge, shows the message in the metadata line |
@@meta('doc:deprecated', 'Use Account model instead') |
These are placed on individual fields alongside @id, @default, etc.
model User {
id String @id @default(cuid())
/// User's primary email address.
email String @unique @email @meta('doc:example', 'jane@acme.com')
/// URL-safe profile handle.
handle String @unique @meta('doc:example', 'alex-chen')
}| Key | Value | Where it appears | Example |
|---|---|---|---|
doc:example |
A representative value for the field | Prepended to the field's description column as Example: \value`` |
@meta('doc:example', 'jane@acme.com') |
Any @@meta or @meta key that does not start with doc: is ignored by the documentation plugin. You can use non-doc: keys for other purposes without affecting generated output.
You don't need to annotate anything for the plugin to work. It automatically documents:
- All field types, optionality, and default values
@id,@unique,@map,@updatedAt,@json,@ignore,@computedattributes- All default-value functions:
cuid(),uuid(),nanoid(),ulid(),now(),autoincrement(),dbgenerated() - All validation attributes:
@email,@url,@datetime,@length,@regex,@startsWith,@endsWith,@contains,@gt,@gte,@lt,@lte,@trim,@lower,@upper - Model-level
@@validaterules @@allow/@@denyaccess policies (includingauth()expressions)@@indexand@@uniqueconstraints@@map(table name) and@@schema(database schema)@@authand@@delegatemodel attributes- Inherited fields from
extends(with source links) - Mixin fields from
with(with source links) - All relationships with cardinality
- Procedure parameters, return types, and mutation/query distinction
If your schema uses import to split across files:
// schema.zmodel
import './models'
import './enums'
import './mixins'The plugin resolves each entity to its originating file. The Defined in metadata and declaration blocks show the correct source filename (e.g. models.zmodel, enums.zmodel), not just the entry point.
Add the zenstack generate step to your CI pipeline and commit the output. This way docs stay in sync and are reviewable in PRs:
pnpm exec zenstack generate
git add docs/schema/
git diff --cached --quiet || git commit -m "docs: regenerate schema documentation"The generated Markdown works with any static site generator that supports Markdown + Mermaid:
- Docusaurus — drop the output into
docs/and add a sidebar entry - VitePress — use the output directory as a docs section
- GitHub Pages — push to a
docs/folder and enable Pages
Turn off sections you don't need:
plugin documentation {
provider = 'zenstack-docs-plugin'
output = './docs/schema'
includeRelationships = false
includePolicies = false
includeValidation = false
includeIndexes = false
}This gives you clean model/enum/type pages with just fields, descriptions, and declarations.
Set generateSkill = true to produce a SKILL.md alongside the human-readable docs. This file gives AI coding agents (Cursor, Claude Code, Windsurf, and others) instant, project-specific context about your data layer.
plugin documentation {
provider = 'zenstack-docs-plugin'
output = './docs/schema'
generateSkill = true
}The generated SKILL.md includes:
- YAML frontmatter with name and description, compatible with the skills.sh ecosystem
- Schema overview — entity counts at a glance
- Compact entity catalog — every model, enum, type, and view with fields, types, and attributes in a dense, machine-readable format
- Relationship map — flat listing of every model-to-model relationship with cardinality
- Access policies — allow/deny rules per model
- Procedure signatures — params, return types, mutation vs query
- Validation constraints — per-field validation rules
- Links to full docs — each entity links to its full documentation page for deeper context
The SKILL.md format is optimized for LLM consumption: information-dense, no visual formatting, consistent structure. When an agent needs to understand your data layer — to generate a query, build a form, write a migration, or reason about access control — it can read this single file instead of parsing .zmodel schemas.
To make the generated skill discoverable by AI agents, place it in a named subdirectory:
mkdir -p .agents/skills/my-project
cp docs/schema/SKILL.md .agents/skills/my-project/SKILL.mdTo share it with your team, commit the skill directory and have teammates install it via:
npx skills add <owner>/<repo>See the skills.sh documentation for details.
- Renders on any Markdown viewer (GitHub, GitLab, Bitbucket, Obsidian, VS Code, etc.)
- Mermaid diagrams require a renderer that supports fenced
mermaidcode blocks (GitHub, GitLab, Docusaurus, VitePress, Obsidian all do natively) - GitHub Flavored Markdown alerts (
> [!CAUTION],> [!IMPORTANT]) render on GitHub; other viewers show them as blockquotes
MIT