Zenith

MCP serverDocs & knowledge

Author, validate, edit, and render deterministic .zen design docs to PNG/PDF.

Unavailable. This server has no hosted endpoint yet, so ahel can't serve it.

Connect ahel once, and every AI you use reads what you have installed.

From the project's README

As published by zenitheditor/zenith in README.md.

Every banner and diagram in this README is itself created using Zenith — source in assets/showcase/.


Zenith is a plain-text format and engine for design files — posters, decks, books, social graphics, diagrams, and more. The idea is simple: design should work the way code does. You should be able to read it, diff it, review it, test it, and let an agent safely edit it.

A .zen file is human-readable KDL text. The engine parses it, validates it against a large diagnostic set, compiles it to a backend-neutral scene, and renders the same file to the same pixels every time — as a PNG or a print-ready PDF.

The sections below are collapsed to keep this page skimmable — click any heading's ▸ to expand it. Install and Quick start are open by default.

Install

The recommended way to install the zenith CLI is the install script, which detects your platform and downloads the matching prebuilt binary from GitHub Releases.

Linux / macOS

curl -fsSL https://raw.githubusercontent.com/zenitheditor/zenith/main/scripts/install.sh | sh

Windows (PowerShell)

irm https://raw.githubusercontent.com/zenitheditor/zenith/main/scripts/install.ps1 | iex

Set ZENITH_INSTALL_DIR to change the install location (default ~/.local/bin):

ZENITH_INSTALL_DIR=/usr/local/bin \
  curl -fsSL https://raw.githubusercontent.com/zenitheditor/zenith/main/scripts/install.sh | sh

With cargo

cargo install zenith-tool    # from crates.io (installs the `zenith` binary)
cargo install --git https://github.com/zenitheditor/zenith zenith-tool   # from source

The library crates (zenith-core, zenith-layout, zenith-scene, zenith-render, zenith-tx, zenith-session) are published under their own names for Rust projects that want to build on the engine directly.

With npm

npm install -g @zenitheditor/zenith-mcp
npx -y @zenitheditor/zenith-mcp --help

The npm package installs the matching prebuilt zenith binary from GitHub Releases and is focused on the MCP Registry launch path. The unscoped zenith binary remains the Rust CLI.

GitHub Releases

Download directly from GitHub Releases:

PlatformArchitectureAsset
Linuxx86_64zenith-<version>-linux-x64.tar.gz
Linuxaarch64zenith-<version>-linux-arm64.tar.gz
macOSx86_64zenith-<version>-macos-x64.tar.gz
macOSApple Siliconzenith-<version>-macos-arm64.tar.gz
Windowsx86_64zenith-<version>-windows-x64.zip

Update

zenith update                   # latest stable release
zenith update --pre             # latest prerelease
zenith update --version <tag>   # a specific release tag, e.g. the ones on the Releases page

Verify with zenith --version.

Build from source

For local development or source installs:

git clone --recurse-submodules https://github.com/zenitheditor/zenith
cd zenith
cargo build --release
cargo install --path zenith-cli   # installs `zenith` to ~/.cargo/bin
./scripts/install.sh --local      # installs the local build to ~/.local/bin

The release binary lands at target/release/zenith. No C toolchain or system libraries are required — the dependency graph is C-free and unsafe is forbidden workspace-wide.

Quick start

zenith validate examples/hello.zen          # report diagnostics (add --json for machine output)
zenith fmt examples/hello.zen               # canonical, idempotent formatting
zenith tokens examples/hello.zen            # list design tokens and their resolved values
zenith inspect examples/hello.zen           # print the node tree (read-only)
zenith render examples/hello.zen --out .    # compile + render to PNG

zenith render examples/multipage.zen --all-pages out/     # one PNG per page
zenith render examples/hello.zen --pdf hello.pdf          # print-ready PDF
zenith render examples/hello.zen --scene scene.json       # dump the scene IR

The smallest valid document:

zenith version=1 {
  project id="proj.hello" name="Hello Zenith"
  tokens format="zenith-token-v1" {
    token id="color.bg" type="color" value="#f8fafc"
    token id="color.ink" type="color" value="#111827"
    token id="font.body" type="fontFamily" value="Noto Sans"
    token id="size.heading" type="dimension" value=(px)42
  }
  styles {}
  document id="doc.hello" title="Hello Zenith" {
    page id="page.hello" w=(px)480 h=(px)160 {
      rect id="rect.bg" x=(px)0 y=(px)0 w=(px)480 h=(px)160 fill=(token)"color.bg"
      text id="text.hello" x=(px)24 y=(px)24 w=(px)432 h=(px)112 fill=(token)"color.ink" font-family=(token)"font.body" font-size=(token)"size.heading" { span "Hello Zenith" }
    }
  }
}

See examples/ for runnable .zen files covering shapes, rich text, inline markdown (loaded from an external file), code blocks, images, frames/groups, multi-page documents and styles, plus the richer features — gradient, shadow, blur, filter, mask, table, flowchart (shapes + connectors), charts (bar/line/area/pie/donut/sparkline, with legends, value labels, and data binding), and anchors.

Why

Code got source control, types, tests, and pull requests. Design files got none of that. They're opaque blobs — you can't diff them, you can't review a change, and the same file can render differently on different machines.

That's a problem for people, and it's a bigger problem for AI. Agents can already write code and open pull requests, because code is text they can read and reason about. Drop them into a design tool and they go blind. Ask an agent to "make the heading brand red and tighten the layout" and there's nothing safe to grab onto — no stable target, no validation, no preview, no way to check the result.

Zenith fixes that. The goal is to make design files as safe to automate as code:

  • Plain text you own — readable, diffable, yours forever.
  • Stable IDs so every change is a reviewable patch, not a mouse drag.
  • Deterministic rendering — the same file always produces the same pixels.
  • Real validation — text fits, colors come from the design system, nothing falls off the page.
  • Safe edits — every change is a typed transaction, checked and previewable before it lands, with a source diff and an audit record.

It's not AI image generation

This is the most common mix-up, so it's worth being blunt: Zenith is the opposite of an image model like Nano Banana, ChatGPT image, or Grok Imagine.

An image generator gives you a flat picture. It's a bag of pixels — you can't open it up and move the logo, you can't force the headline to use your exact brand color, and asking for "the same thing but with a different date" gives you a different image. There's nothing to edit, review, or guarantee.

Zenith doesn't generate a picture. It generates the design itself — a structured, editable document where every element is real and addressable. An agent (or a person) can change one line, swap a color token, or regenerate a hundred on-brand variants, and every render is exact and repeatable. AI writes and edits the source; Zenith guarantees what it means and how it looks.

Agent-native first, not a tool with an API bolted on

Most design tools are built for a human dragging boxes, and an automation API gets added later as an afterthought — a thin, limited layer over a model that was never meant to be driven by software.

Zenith is built the other way around. The foundation is a programmatic, text-based, deterministic engine. Agents, scripts, and the command line drive it directly. So automation isn't a side door; it's the front door.

Where this is going. Today Zenith is the engine and the CLI — the surface an AI agent drives. The roadmap is a visual editor where humans and AI agents co-edit the same .zen documents: a designer nudges a box, an agent restyles a hundred variants, and both operate on the identical deterministic core with the same validation, transactions, and version history. The GUI is a client on top of the engine — not a separate product with automation bolted on. Agent-first now; agent + human, together, next.

How it works

A .zen document flows through a single deterministic pipeline. Each stage is a separate crate with a clean contract boundary, so a future GPU backend, SVG export, or visual editor consumes the same scene IR:

Rendered by Zenith — source: assets/showcase/pipeline.zen.

  design.zen  (KDL plain text)
       │  parse + validate           zenith-core   →  diagnostics (Error/Warning/Advisory)
       ▼
  Document AST  ──transaction ops──▶  Document AST'  zenith-tx  →  dry-run / apply + audit record
       │  compile                    zenith-scene + zenith-layout
       │    · resolve tokens, geometry, anchors
       │    · shape text (rustybuzz), wrap, hyphenate
       ▼
  Scene IR  (backend-neutral display list)
       │  render                     zenith-render
       ├─▶ PNG   (tiny-skia, byte-identical)
       └─▶ PDF   (vector, native CMYK, bleed / trim / crop)

  local history / undo / versions    zenith-session   (off the render path; never affects pixels)

Everything that touches the render path is deterministic and C-free: no time, no randomness, no HashMap, no unsafe, no C dependencies. The same bytes in always produce the same bytes out, on any machine.

What it does

  • Scaffold & identityzenith new creates a ready-to-edit document (minimal valid template, default .zen extension, parent dirs created) with a stable doc-id minted on first write; any .zen gains its identity and workspace store transparently on the first edit — no manual setup step.
  • Plain-text .zen format — KDL v2 source with project / tokens / styles / document / page structure; every node carries a stable id.
  • Design tokenscolor (sRGB and native CMYK), dimension, number, fontFamily, fontWeight, gradient (linear/radial), shadow, filter, and mask, with alias chains and cycle detection.
  • A full node setrect, ellipse, line, polygon, polyline, text, code, image, frame, group, pattern, shape, connector, chart, instance, field, footnote, toc, and table, plus lossless pass-through of unknown nodes for forward compatibility.
  • Real typographyrustybuzz shaping with bundled Noto Sans / Noto Sans Mono, font fallback, Knuth–Liang hyphenation, rich inline spans (bold/italic/underline/strikethrough/highlight/inline-code/link), threaded text flow (chains), drop-caps, tab-leaders, text runaround, and a font.glyph_missing diagnostic when a glyph is unavailable.
  • Lean long-form text — keep the .zen small by sourcing body copy from an external .md/.txt file (text src="copy/article.md") or a data field, and opt into markdown (format="markdown") for both inline marks (**bold**, *italic*, ==highlight==, ++underline++, ~~strike~~, `code`, [label](url)) and full block structure# headings (h1–h6), blank-line paragraphs, blockquotes, ordered/unordered lists, fenced code blocks, and --- rules. Per-role typography (font, size, weight, fill, spacing) is controlled by block role="h1" … declarations at document, page, or text scope (cascade: text > page > doc), so the .zen owns all layout and styling while the .md file stays pure prose. For long-form content that exceeds one box, link multiple text nodes with chain for manual pagination; a text.overflow warning fires when content doesn't fit.
  • Visual effects — linear & radial gradients, layered shadows, Gaussian blur, feathered masks, 12 Porter-Duff blend modes, opacity cascade, per-corner radius, and image fit / clip-shape / object-position.
  • Anchors — 9-point placement relative to the page, a safe-zone, the parent container, or a sibling node (precedence: zone > sibling > parent > page), all materializing to explicit, deterministic geometry (absent anchor = byte-identical to hand-placed coordinates).
  • Procedural recipes — a recipes provenance block records how a generated motif was made (kind, seed, generator, params, palette tokens, expanded node ids), inspectable and editable via typed recipe transactions, so procedural visuals stay reproducible and re-tunable.
  • Transaction engine — a typed op set (set fill/stroke/geometry, add/remove/reparent/group, align/distribute, page ops, token ops, find-replace, pattern detach, and more) applied as dry-run by default, with referential-integrity and id-uniqueness enforcement, a source diff, a scene diff, affected node ids, and an audit record.
  • Deterministic rendering — pixel-exact PNG via tiny-skia and print-ready PDF (native DeviceRGB/CMYK, MediaBox/TrimBox/BleedBox, no embedded timestamps), single page, all pages, or facing-page spreads. The scene IR can be dumped to JSON.
  • Real PDF text, not pictures — PDF output embeds genuine, selectable / searchable / indexable text (subsetted fonts + ToUnicode) and clickable hyperlinks by default; set selectable=#false on a text/code node to render it as outlines instead. --embed-full-fonts embeds whole faces in place of subsets.
  • Local history — per-document identity (ULID doc-id stamped in the file, ignored by the renderer), an ephemeral session DAG for undo/redo, and a durable content-addressed version store (SHA-256 + DEFLATE) with named versions and restore — entirely off the render path.
  • Workspace scratch candidates — content-addressed .zen snapshots for design exploration, stored alongside history: scratch new records a candidate, scratch list/show review them, candidate transitions their lifecycle (draft → selected | rejected), promote --into <page> merges a selected candidate into the deliverable, and finalize drops the rejected ones. bundle/unbundle pack the whole per-doc store (history + scratch) into a portable, deterministic .zenithbundle.
  • Library subsystem — embedded preset packs (@zenith/flowchart, @zenith/filters, @zenith/masks, @zenith/brand-kit); library add materializes an item into a self-contained document with libraries + provenance tracking. Inspect any item with zenith library show <pkg>#<item>.
  • AI-asset provenance — when an image/illustration from an image model is composed in as an asset, Zenith records how it was made: ai-prompt, ai-model, ai-provider, ai-seed, ai-license, ai-source-rights, ai-safety-status, ai-reuse-policy (alongside the sha256 content lock). Run zenith schema asset for the full field list.
  • Variable-data mergerole="data.<column>" bindings drive CSV mail-merge across text and image columns and multi-page templates, with a per-row JSON report and a byte-reproducible manifest.
  • Self-describing CLIzenith schema emits the authorable surface (every node kind + its attributes, the transaction op set, token types, and the page/asset/document/variant/diagnostics/brand surfaces) as human text or --json, so an agent discovers what it can author from the CLI itself rather than guessing — paired with zenith validate's actionable diagnostics for the fix loop.

Validation — the safety net

zenith validate file.zen is the step that makes design files safe to edit and trustworthy to ship. It's like a compiler's type-checker, but for a document: it reads the source and reports everything that is wrong, risky, or off-brand before you render or print — so an agent (or you) never has to "render it and eyeball it" to find out something broke.

It runs 70+ checks, each reported as a diagnostic with a stable code (e.g. text.overflow), a human message, the offending node id, and the source location. Every diagnostic has one of three severities:

SeverityMeaningEffect
ErrorA definite problem that would produce wrong outputBlocks renderingrender refuses and validate exits non-zero until it's fixed
WarningA likely problem or risky constructOutput still produced; worth a look
AdvisoryInformational noteNever blocks; just FYI

What it actually checks, in plain terms:

  • Structure & references resolve — every node id is unique and every reference points at something real: token refs, image assets, connector targets, fields, masters/sections (id.duplicate, token.unknown_reference, asset.unknown_reference, connector.missing_target). No dangling links, no typos that silently render nothing.
  • Design-system discipline — visual properties must come from tokens, not raw hex (token.raw_visual_literal), so a brand change is one edit; it also flags cyclic, mistyped, or unused tokens (token.cyclic_reference, token.type_mismatch, token.unused).
  • Nothing falls off or overflows — geometry is present and on-canvas, text actually fits its box, children stay inside their frame, and content respects page margins and safe zones (node.missing_geometry, text.overflow, text.fit_failed, frame.child_overflow, margin.violation, safe_zone.violation). Anchors must resolve to a real reference frame (anchor.unresolved_sibling, anchor.cycle).
  • Readable & print-ready — text/background contrast is checked against WCAG 3 (APCA) (contrast.low); colorspace, bleed, and page parity are validated so a PDF is actually printable (document.invalid_colorspace, page.invalid_bleed).
  • Model integrity — the newer variants, recipes, and provenance blocks are checked too, so generated/derived work stays consistent (variant.unknown_source, recipe.unknown_palette_token).

Why it matters:

  • For people — you catch "the headline ran off the page", "this grey-on-grey is unreadable", "that color isn't a brand token", or "the print file has the wrong colorspace" before exporting, not after.
  • For agentszenith validate --json is a precise, machine-readable contract. An agent edits the source, validates, and knows whether the change is sound — the safety net that makes hands-off editing trustworthy.

Rendered by Zenith — source: assets/showcase/loop.zen.

Variants

Two complementary ways to generate many outputs from one design — one varies size, the other varies content.

Rendered by Zenith — source: assets/showcase/variants.zen.

Size / format variants (zenith variant)

Declare a variants block and expand one canonical page into many named target sizes (square, story, banner, ad slots) — each written as a native .zen page plus a rendered PNG, with optional per-target overrides (hide/show a node, swap text, change a fill). Source token edits propagate to every variant automatically, and anchored nodes reflow to each size.

variants {
  variant id="square" source="page.main" w=(px)1080 h=(px)1080 {
    override node="qr" visible=#false
  }
  variant id="story" source="page.main" w=(px)1080 h=(px)1920 { }
}
zenith variant poster.zen --out-dir out/ --manifest manifest.json

Generation is deterministic (same source → byte-identical outputs + manifest, schema: zenith-variant-manifest-v1).

Data mail-merge (zenith merge)

One template plus a CSV becomes one rendered design per row — for localized posts, personalized graphics, certificates, or campaign variants. Mark the variable text/image nodes with role="data.<column>" (the columns are the CSV header), then merge:

Shortened here. Read the whole README on GitHub.

Signals

GitHub stars
22
Forks
4
Last commit
Jul 2026
Advanced
Delivery
zenith MCP server → your ahel gateway (mcp.ahel.ai) → every connected AI client.
Catalog kind
mcp-server
Gateway key
io-github-zenitheditor-zenith
Source
github.com/zenitheditor/zenith