Skip to main content

AI authoring

Documents are plain markdown, so anything that writes markdown can write them: notes fields, generated reports, agent output. The one dialect worth teaching a generator is diagrams.

Emit skeletons

Generators should write ```diagram blocks: a coordinate-free skeleton with boxes, connectors and palette colour names. The editor lays it out on import and stores the result as a concrete ```drawing block. Use ```drawing (format version 2) only to edit an existing concrete payload or when exact positions matter.

```diagram
{"direction":"right","boxes":[
{"id":"web","label":"CLIENT","text":"Web App","color":"blue"},
{"id":"api","label":"SERVICE","text":"API","color":"green"},
{"id":"db","type":"cylinder","text":"Postgres","color":"purple"}
],"connectors":[
{"from":"web","to":"api","text":"REST"},
{"from":"api","to":"db","routing":"elbow"}
]}
```

The complete rules for both payloads are in Diagrams and, authoritatively, in DRAWING_FORMAT.md, which ships in the npm package next to the README and is written to be pasted into a prompt.

What a generated skeleton becomes once the editor opens it (the Markdown view shows the expanded ```drawing block it stores):

Loading editor

Validate with the JSON Schemas

DRAWING_SKELETON_JSON_SCHEMA and DRAWING_DATA_JSON_SCHEMA (JSON Schema draft-07) are the same contracts as the spec. Use them to validate generated payloads, or as structured-output / tool schemas so a model can only produce valid diagrams:

import { DRAWING_SKELETON_JSON_SCHEMA } from '@zuilib/text-editor'

const tool = {
name: 'draw_diagram',
description: 'Add an architecture diagram to the document',
input_schema: DRAWING_SKELETON_JSON_SCHEMA,
}

Work with payloads in code

FunctionPurpose
parseDrawingSkeleton(json)Parse a skeleton string / object; throws on a malformed one
isDrawingSkeleton(value)Type guard
expandSkeleton(skeleton)Lay out and expand to DrawingData (what the editor does on import)
parseDrawingData(json)The editor's lenient parser for concrete payloads: invalid shapes drop out, never throws
serializeDrawingData(data)Inverse of the above
normalizeDrawingData(data)Re-anchor bound connector endpoints
drawingToMermaid(data, options?)Export a Mermaid flowchart

Everything above runs without a DOM (the router, bindings and skeleton expansion are pure), so it works in Node, workers and tests.

Generation checklist

  1. Prefer a ```diagram skeleton. Fall back to ```drawing only to edit an existing concrete payload or when you need exact positions.
  2. One JSON object per fence, no comments or trailing commas.
  3. Every id unique; every connector references an existing box id.
  4. Put box text in label / text / footer, not in floating text shapes. actor only has text.
  5. Pick the attach edge with {"id":"…","side":"bottom"} only when it matters (a decision's "yes" / "no"); omit it otherwise.
  6. Use "routing":"elbow" for flowcharts.
  7. For concrete payloads: boxes at least 120 × 70 when they carry text (use the default sizes), about 60px between cards, canvasHeight large enough for every shape plus ~20px, shapes within x ∈ [0, 700] unless canvasWidth is set.

Tables and settings

Write GFM pipe tables. Add a settings comment on the line directly above only when you want a non-default width or density:

<!-- width: content; density: compact -->
| Key | Value |
| --- | --- |
| Region | eu-west-1 |

Claude Code skill

The monorepo ships a ready-made Claude Code skill (.claude/skills/text-editor-documents/) that teaches an agent this dialect: markdown conventions, the skeleton format, and when to use drawings. Copy it into consuming repositories so agents there author documents the editor renders correctly.