Skip to content

sheldonj/zenstack-docs-plugin

Repository files navigation

zenstack-docs-plugin

npm version CI License: MIT

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.

Why

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)

Installation

pnpm add -D zenstack-docs-plugin

Requires ZenStack v3 (@zenstackhq/language and @zenstackhq/sdk >= 3.0.0).

Quick Start

1. Register the plugin in your schema.zmodel:

plugin documentation {
    provider = 'zenstack-docs-plugin'
    output   = './docs/schema'
}

2. Generate:

pnpm exec zenstack generate

3. Browse your docs in ./docs/schema/.

That's it. Every entity in your schema now has its own documentation page.

Example Output

Generated documentation from the showcase schema is committed to this repo — browse it to see exactly what you get:

A second example using a larger multi-file schema is in preview-output/verbose/.

Output structure

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

An index page with everything at a glance

The index lists every model, view, type, enum, and procedure with inline description excerpts, artifact counts, and links to the relationships diagram.

Model pages packed with context

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 @@allow and @@deny rule in a readable table
  • Validation rules@email, @length, @regex, and all other validation attributes
  • Indexes@@index and @@unique constraints
  • 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.

Mermaid diagrams everywhere

  • 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

Rich cross-linking

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

Configuration

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)

ERD SVG Export

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 Mermaid
  • schema-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.

Themes

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.

Per-Page SVG Diagrams

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'
}

Diagram format

Value Behavior
"mermaid" Inline ```mermaid code blocks (default, requires a Mermaid-capable viewer)
"svg" Companion .svg files referenced via ![Entity diagram](./Entity-diagram.svg) — works everywhere
"both" SVG image reference with the Mermaid source in a collapsible <details> block

Embed mode

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".

Additional features

  • 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.

Enriching Your Documentation

Triple-slash comments become descriptions

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
}

Documentation metadata with @@meta / @meta

Use @@meta (model-level) and @meta (field-level) with doc: prefixed keys to add structured metadata that the plugin renders into the generated pages.

Model-level attributes (@@meta)

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')

Field-level attributes (@meta)

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')

Custom keys

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.

Everything else is automatic

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, @computed attributes
  • 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 @@validate rules
  • @@allow / @@deny access policies (including auth() expressions)
  • @@index and @@unique constraints
  • @@map (table name) and @@schema (database schema)
  • @@auth and @@delegate model 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

Multi-File Schema Support

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.

Recipes

Commit generated docs to version control

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"

Serve as a static site

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

Minimal output for simpler schemas

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.

AI Agent Integration (SKILL.md)

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.md

To 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.

Compatibility

  • Renders on any Markdown viewer (GitHub, GitLab, Bitbucket, Obsidian, VS Code, etc.)
  • Mermaid diagrams require a renderer that supports fenced mermaid code blocks (GitHub, GitLab, Docusaurus, VitePress, Obsidian all do natively)
  • GitHub Flavored Markdown alerts (> [!CAUTION], > [!IMPORTANT]) render on GitHub; other viewers show them as blockquotes

License

MIT

About

ZenStack community plugin that generates rich, browsable Markdown documentation from ZModel schemas

Topics

Resources

License

Contributing

Stars

Watchers

Forks

Packages

 
 
 

Contributors