Your documentation has a schema.
Plain Markdown with typed YAML blocks for diagrams, ERDs, API docs, and ADRs. Your AI agent writes them, a strict schema validates like code (avo check fails CI), and one command exports themed HTML, slides, or a PDF — your .md files stay the single source of truth.
npm i -g @avodado/cli
+ avodado.config.json+ docs/getting-started.md+ docs/tutorial.md+ .avodado/skill/SKILL.md… 26 more filesCreated 30 file(s), skipped 0. (theme: textbook)OK: 2 files checked, no diagnosticsPressing the whole grove into a site…✓ 3 page(s) + 2 deck(s) → dist/ (751738 bytes)One file
Left is what you write. Right is what ships.
Pick a block type: the same fenced YAML, twice — as it sits in your Markdown, and as the output the render pipeline produces from it. No runtime, no drawing tool.
title: Checkout
actors:
- { id: client, name: Client }
- { id: api, name: Orders API }
- { id: db, name: Postgres }
messages:
- { from: client, to: api, label: POST /orders, kind: sync }
- { from: api, to: db, label: INSERT order, kind: sync }
- { from: api, to: client, label: 201 Created, kind: response }title: Order data
entities:
- name: users
columns:
- { name: id, type: uuid, pk: true }
- { name: email, type: text }
- name: orders
columns:
- { name: id, type: uuid, pk: true }
- { name: user_id, type: uuid, fk: true }
- { name: status, type: text }
- name: order_items
columns:
- { name: id, type: uuid, pk: true }
- { name: order_id, type: uuid, fk: true }
- { name: qty, type: int }
relations:
- { from: users, to: orders, card: "1:N" }
- { from: orders, to: order_items, card: "1:N" }title: System context
level: context
nodes:
- { id: user, col: 1, row: 1, kind: person, name: Shopper, desc: A customer placing an order. }
- { id: app, col: 2, row: 1, kind: system, name: ShopCo, desc: The retail platform. }
- { id: pay, col: 3, row: 1, kind: external, name: Payment GW, desc: Stripe authorisation. }
edges:
- { from: user, to: app, label: places order }
- { from: app, to: pay, label: authorises }title: p95 latency by week
kind: line
unit: ms
labels: [W1, W2, W3, W4]
series:
- { label: /orders, accent: navy, values: [240, 220, 185, 150] }
- { label: /search, accent: teal, values: [310, 285, 260, 230] }title: Checkout launch
columns: [Workstream, Latest update]
statuses:
- { label: on track, color: green }
- { label: at risk, color: amber }
- { label: blocked, color: red }
rows:
- { cells: [Payment provider migration, Adapter live behind a feature flag], status: on track }
- cells: [Fraud review queue, Model handoff slipped a week]
status: at risk
subtasks:
- { cells: [Rule-based fallback, Serving 10% of traffic today], status: on track }
- { cells: [Tax calculation, Vendor contract still in legal review], status: blocked }Or see whole documents built this way in the live demo
Work with AI
Your AI writes the docs. The schema keeps it honest.
Ask your agent for a sequence diagram and get a typed block, not a screenshot. It learns the grammar from your repo, works through MCP tools — and when it makes something up, avo check says so before the PR does.
Teach it once
avo install claudedrops the authoring skill into your repo — the block grammar, the reference scheme, every field contract. Claude Code, Cursor, Copilot, and Windsurf all read it.Tools, not guesswork
The MCP server gives agents seven tools —
get_block_schema,check_document,render_document… — so they look the schema up instead of inventing fields.A safety net for AI edits
Every block validates against a strict schema. An invented field, a dangling reference, a malformed diagram —
avo checkfails it on the spot, and in CI.Review it like code
The output is a Markdown diff, not an exported canvas. AI-written docs go through the same pull-request review as AI-written code — because they validate the same way.
● Edited docs/webhooks.md — added a ```sequence blockdocs/webhooks.md:18 E_SCHEMA unknown field 'retries'● not in the schema — fixed: retry loop as explicit messagesOK: 4 files checked, no diagnosticsdocs that survive their own review — commit itPipeline
One source of truth, every output
Markdown files go in. One pure core parses, validates, and resolves cross-references — then the same parsed document renders to a site, slides, PDF, the visual studio, or an MCP server for AI agents.
What you get
Structure without leaving Markdown
Every feature below is the library talking about itself — block counts, diagnostics, themes, and tool names come straight from the packages.
76 typed blocks
Sequence diagrams, ERDs, C4, kanban boards, charts, user stories — every block has a strict schema and a ready template.
Strict validation
avo check names the file, line, and offending value — and exits non-zero. Gate CI on it.
Cross-references
Give a block an id, reference it as doc#id from anywhere. Duplicate ids and dangling refs are caught repo-wide.
6 themes
Rendered pages and decks pick up any of the built-in themes — same content, different paper.
Slides from the same file
One slide per heading, keyboard navigation, print-to-PDF ready. A {split} marker gives message-left, exhibit-right.
AI-native
An authoring skill plus an MCP server — agents write, check, and render the same files you do, through seven tools.
avo studio
The grove goes visual
Click a block to select it, edit it as a form or as YAML, and watch the preview update — the .md files on disk stay the source of truth.

avo studio — the visual editor over a local file bridge. Your repo, your files, no cloud.
The catalog
A block for every shape of thought
Each miniature below is a real render of that block's built-in template — the same starting point avo gives you.
Browse all 76 block types
0
block types
0
families
0
themes
0
tests
The gallery
All of this is plain text.
Nine documents, six themes, zero screenshots — every sheet below is a fenced YAML block rendered at build time by the same pipeline avo build runs. Open devtools: it's live SVG.
Your docs are already Markdown. Give them types.
Install the CLI, run avo init, and write your first block — avo check keeps it honest.
npm i -g @avodado/cli