v1yUML AI spec
A compact DSL reference, designed to be pasted into an LLM system prompt. If you're building an AI agent, Claude/ChatGPT custom GPT, or an MCP tool that emits yUML, include this as context and the model will produce valid DSL.
Use it
Fetch the plain-text version:
curl https://app.yuml.me/dsl/v1/spec.txt
Then prepend it to your prompt as the system message. Ask the model for DSL for any of the 9 diagram types listed below, and render the result via /diagram/v1/{type}/{style}/{dsl}.svg.
Spec
# yUML DSL Reference (v1)
yUML is a text-based diagramming language. Each diagram type has its own
syntax. Metadata lines (`@heading`, `@caption`, `@legend`, `@direction`,
`@style`) can appear anywhere in any diagram type.
This file is the **canonical source of truth** for the AI-friendly DSL
reference. It is read by:
- `/dsl/v1/spec` and `/dsl/v1/spec.txt` (public docs endpoint on app.yuml.me)
- `Ai::FixDsl` service (Fix-with-AI system prompt in the Rails web app)
- The MCP server's `render_diagram` / `render_story` tool descriptions
Formal grammars live in `renderer/src/*.pegjs` and are the ultimate
authority on what parses. This file is the human-and-LLM-friendly
narrative — keep it in sync when grammar changes.
Public URL: https://app.yuml.me/dsl/v1/spec.txt
## Styles
Available styles: `clean`, `plain`, `boring`, `sketch`, `scruffy`,
`napkin`, `midnight`, `blueprint`. Set via `@style <name>` in stories
or as a render option.
## Layout direction
Most diagram types lay out top-to-bottom by default. The **use case**
diagram is the exception — it goes left-to-right. Override with
`@direction` in the DSL:
```
@direction LR — left-to-right
@direction TB — top-to-bottom (alias: TD, DOWN)
[A]->[B]
[B]->[C]
```
Accepted values (case-insensitive): `LR` / `RIGHT`, `TB` / `TD` / `DOWN`.
Direction has no effect on types whose layout is intrinsic to the type
— sequence, journey flow, timeline, roadmap, and the chart family
(bar, column, line, pie).
When rendering via the URL API you can also pass direction as a modifier
on the style segment instead of editing the DSL:
```
/diagram/v1/class/clean;dir=LR/[A]->[B],[B]->[C].svg
```
`@direction` and `;dir=…` are equivalent. If both are present, the URL
modifier wins.
## Forced line breaks
A literal `\n` (backslash + the letter n) in the DSL becomes a forced line
break in the rendered text. Soft-wrapping still applies to each segment,
so `\n` is a *guaranteed* break, not a substitute for wrapping.
Supported in:
- `@heading` and `@caption` (any diagram type)
- Class-diagram labels and notes — e.g. `[note: First line\nSecond line]`
- Canvas titles, sub-titles, `>` help text, prose, and bullets
Example:
```
@heading Quarterly Review\nSWOT
[note: Recalculated\non every change]-[Order]
```
## Class Diagrams
```
[ClassName] — class
[ClassName|attr1;attr2] — with attributes
[ClassName|attr1;attr2|method()] — with methods
[<<Interface>>;Name] — stereotype
[note: text{bg:wheat}] — note
[A]->[B] — directed association
[A]<->[B] — bidirectional
[Parent]^[Child] — inheritance — the side adjacent to ^ is the PARENT
[A]<>[B] — aggregation
[A]++->[B] — composition
[A]-.->[B] — dependency (dashed)
[A]^-.-[B] — implements (dashed inheritance)
[A]label->[B] — labelled
[A]1-0..*>[B] — cardinality
// comment
```
Example:
```
[Customer|name;email]-orders>*[Order|date;total]
[Order]->*[LineItem|qty;price]
[LineItem]->[Product|name;sku;price]
```
Inheritance direction — the parent is on the **left** of `^`. So
`[Animal]^[Duck]` means Duck inherits from Animal. Mirror this when
translating from Mermaid (`Animal <|-- Duck` becomes `[Animal]^[Duck]`)
or PlantUML (`Animal <|-- Duck` becomes `[Animal]^[Duck]`).
```
[Animal|age;gender|isMammal();mate()]
[Animal]^[Duck|beakColor|swim();quack()]
[Animal]^[Fish|sizeInFeet|canEat()]
[Animal]^[Zebra|isWild|run()]
```
## Sequence Diagrams
```
[Object] — participant (box) — on its own line declares; in a message it references
(Actor) — participant (stick figure) — on its own line declares; in a message it references
[A]message->[B] — sync message
[A]message-->[B] — return message (dashed)
[A]message->>[B] — async message
{alt condition} ... {else} ... {end} — alt fragment
{loop condition} ... {end} — loop fragment
{opt condition} ... {end} — optional fragment
[note: text]->[A] — note on participant
```
Example:
```
(User)Login->[Auth]
[Auth]validate->[Auth]
[Auth]checkCredentials->[DB]
[DB]result-->[Auth]
{alt valid}
[Auth]token-->(User)
{else}
[Auth]error-->(User)
{end}
```
## Activity Diagrams
```
(Activity Name) — activity (rounded box)
(start) — start node
(end) — end node
<Decision> — decision diamond
|Fork| — fork/join bar
(A)->(B) — flow
(A)label->(B) — labelled flow
(A)[guard]->(B) — guarded flow
(note: text) — note
```
Example:
```
(start)->(Receive Order)
(Receive Order)-><Valid?>
<Valid?>[yes]->(Process)
<Valid?>[no]->(Reject)
(Process)->(end)
(Reject)->(end)
```
## Use Case Diagrams
```
[Actor Name] — actor (stick figure)
(Use Case Name) — use case (ellipse)
[A]-(B) — association
(A)<(B) — extends
(A)>(B) — includes
(A)^(B) — inheritance
```
Example:
```
[Customer]-(Place Order)
[Customer]-(Track Order)
(Place Order)>(Validate Payment)
(Track Order)<(Cancel Order)
[Admin]-(Manage Inventory)
```
## State Diagrams
```
[State Name] — state (rounded rect)
(start) — initial state
(end) — final state
<Choice> — choice diamond
[A]->[B] — transition
[A]-event->[B] — event transition
[A]-event[guard]->[B] — guarded transition
[A]-event[guard]/action->[B] — with action
[note: text] — note
```
Example:
```
(start)->[Idle]
[Idle]-login->[Active]
[Active]-logout->[Idle]
[Active]-timeout[inactive > 30m]->[Expired]
[Expired]->[Idle]
```
## C4 Architecture Diagrams
A single `c4` diagram type covers Context, Container, Component and
System Landscape views — they use the same notation.
```
[Name|Type|Description] — element with type + description
[Name|Type] — element with type, no description
[Name] — untyped element
```
Recognised element types (case-insensitive, with common aliases):
- `Person` — also `User`, `Actor`, `Role`, `Customer`, `Admin`
- `System` — also `Software System`, `Platform`
- `Container` — also `Application`, `Web App`, `Service`, `Microservice`,
`API`, `Database`, `Queue`, `Message Bus`, `Worker`, `Function`
- `Component` — also `Module`, `Package`, `Library`, `Subsystem`
- `External` — also `External System`, `External Service`, `Third Party`,
`Vendor`, `SaaS`
Edges:
```
[A]->[B] — solid arrow
[A]-.->[B] — dashed arrow (any `.` in the dash run → dashed)
[A]-Uses->[B] — middle label (solid)
[A]-Sends mail via-.->[B] — middle label (dashed)
[A]<->[B] — bidirectional
[A]->[B] : Uses — colon label (alternative)
```
Boundaries group elements inside a dashed frame:
```
{Banking System
[Web App|Container|Browser UI]
[API|Container|REST endpoints]
[DB|Container|Data store :database:]
}
```
Decorator shortcodes inside descriptions trigger strip visuals on the
card (database cylinder, browser chrome, mobile status bar, etc.):
`:database:`, `:browser:`, `:mobile:`, `:queue:`, `:folder:`,
`:document:`, `:console:`.
Metadata:
```
@heading My Banking Architecture
@caption System Context view
@legend true
@direction LR
```
Example:
```
@heading Banking System Context
@legend true
[Customer|Person|A user of the bank]
[Banking System|System|Core system for accounts and payments]
[Email Service|External|Third-party transactional email]
[Customer]-Uses->[Banking System]
[Banking System]-Sends mail via-.->[Email Service]
```
## Journey Flow Diagrams
Uses activity diagram syntax with emotions for customer journey mapping.
```
(Phase Name) — journey phase/section header
[:emotion: Action text] — step with emotion
[:emotion: "Quote text"] — speech bubble with emotion
[Action text] — step without emotion
-> — flow arrow (optional)
```
Emotions: `:elated:` `:happy:` `:relieved:` `:neutral:` `:uncertain:`
`:frustrated:` `:angry:`
Example:
```
(Discover)->
[:happy: Finds product online]->
[:happy: "This looks promising"]->
(Evaluate)->
[:neutral: Reads reviews]->
[:uncertain: "Is it worth the price?"]->
(Purchase)->
[:frustrated: Complex checkout form]->
[:elated: Order confirmed]
```
## Timeline Diagrams
Uses activity diagram syntax for milestones.
```
(Title|Subtitle|Details) — major milestone (3 parts)
(Title|Subtitle) — major milestone (2 parts)
(Title) — major milestone (title only)
[Event text] — minor milestone
-> — flow arrow (optional)
```
Example:
```
(Q1|Research|Interviewed 50 users)->
[Team assembled]->
(Q2|Beta launch)->
[First paying customer]->
(Q3|Public release)
```
## Roadmap Diagrams
```
(Horizon Name) — horizon/column header
[Card Title|Description] — feature card
[Card Title] — card without description
[Card{bg:color}] — coloured card
```
Example:
```
(Now)
[Search improvements|Full-text search]
[Bug fixes|Top 10 issues]
(Next)
[Mobile app|iOS and Android]
[API v2|REST and GraphQL]
(Future)
[AI features{bg:green}]
[Enterprise SSO]
```
## Canvas Diagrams
Canvases are structured 2D thinking grids — Strategy Choice Cascade, SWOT,
retros, OKRs, post-mortems, or any custom frame. The DSL is markdown-
flavoured.
```
@type canvas — required type metadata
@cols N — top-level grid width (optional)
# Region Title — top-level region
## Sub Region — sub-region of the most recent #
> Custom help text — blockquote overrides canonical help
Prose body… — body lines (prose or bullets)
- bullet — `* ` or `- ` starts a bullet
# Region {cols: 2} — sub-grid layout override
# Region {span: 2} — width weight within its row
# Region {bg: cream} — fill that cell
# Region {!} — accent: tint title + body
```
A `#` section with at least one `##` child renders as a group containing
sub-boxes; otherwise it renders as a single box with its body content.
Bullets are content, not regions. Decorators chain with `;` —
`{cols: 2; bg: cream; !}`.
A literal `\n` forces a break inside any title, sub-title, `>` help line,
prose paragraph, or bullet — see [Forced line breaks](#forced-line-breaks).
### Auto-detected templates
When section names match a known framework, the renderer applies the
template automatically: canonical help text appears under each heading
(muted subtitle), missing canonical sections are inserted as dashed-
inset placeholders, and the layout shape is hinted (e.g. SWOT → 2×2).
Detection is fuzzy and case-insensitive. Aliases:
```
Strategy Choice Cascade — vertical stack of regions
Aspiration / Winning Aspiration
Where to Play — 4 sub-regions:
Geography
Customer / Customer Segments
Channels
Offering / Products
How to Win
Capabilities / Must-Have Capabilities
Management Systems / Systems
SWOT Analysis — 2×2 quadrant
Strengths
Weaknesses
Opportunities
Threats
```
### Layout
- `@cols N` (canvas-level): how many top-level cells per row. Default 1
(vertical stack), or template default, or heuristic (even-and-≥4 → N/2).
- `{cols: N}` (on a heading with sub-regions): sub-grid width inside
that group.
- `{span: N}` (on any heading): weight within its row. Default 1; `{span: 2}`
is twice as wide as a default sibling.
- Empty cells (no body, no children) render as dashed-inset placeholders —
same treatment whether auto-inserted or written empty by the user.
### Examples
Strategy Choice Cascade — auto-detected, canonical help text supplied:
```
@type canvas
# Aspiration
Launch a successful startup that helps people build their face-to-face
network and relationships without compromising privacy.
# Where to Play
## Geography
Initially focus on saturating specific events in a single town, then
global product.
## Customer
Anyone doing networking — hobbyist artists to business folks.
## Channels
Organic makes most sense.
## Offering
Privacy-first way of sharing always-up-to-date contact details at
networking events.
# How to Win
???
# Capabilities
- Privacy-by-design contact format
- Event partnerships
# Management Systems
- KPI: subscription revenue to £30K ARR
- KPI: k-factor for card shares
- KPI: after-event conversations
```
SWOT — 2×2 layout from the template:
```
@type canvas
# Strengths
Deep ML expertise; existing customer base of 200 SMBs.
# Weaknesses
- Limited marketing budget
- Single-region presence
# Opportunities
> Where could we grow? (overrides canonical help)
Enterprise demand for privacy-first tools is accelerating.
# Threats
Big-tech entrants with bundled offerings.
```
Custom canvas without a template — author supplies help via blockquote:
```
@type canvas
@cols 2
# What worked
> Highlights from this sprint
- Shipped onboarding redesign
- Cut p95 latency by 40%
# What didn't
> Rough edges
- Demo broke in staging twice
- Search relevance regression
# Surprises
- 3 enterprise leads from a tweet
# Next sprint
- Re-run onboarding A/B
- Latency budgets per service
```
Guidelines for AI canvas generation:
- Prefer canonical section names so templates auto-apply (Aspiration,
Where to Play, Strengths, etc.) — gets help text and layout for free.
- Use `>` blockquote help text only for *non-template* sections, or to
override the canonical when a domain-specific framing is needed.
- Reach for `{bg}` sparingly — it draws the eye; one or two cells max.
- Use `{!}` to mark a single most-important region.
- Leave a region empty (just heading + optional `>` help) when the user
is mid-thinking — the dashed placeholder invites filling-in.
## Causal Loop Diagrams
Causal loop diagrams (CLDs) show how variables in a system reinforce or
balance one another. Polarity lives in the arrow.
```
@type causal-loop — required type metadata
A -+> B — A increases B (positive / same-direction)
A --> B — A increases B's *opposite* (negative)
A -+> B --> C — chain: two links sharing node B
Name (bad) — flag an undesirable variable
Name (good) — default; rarely needed explicitly
{Zone Name — group related variables
Member 1
Member 2
}
// comment
```
Conventions:
- **Spaces around the operator are required**: write `A -+> B`, not
`A-+>B`. Multi-word names with internal hyphens (`Tech-debt`) stay
unambiguous because of the surrounding whitespace.
- **`-+>` vs `-->`**: `-+>` means "as A goes up, B goes up" (or both
down). `-->` means "as A goes up, B goes *down*". Never use a bare
`->` — that is a syntax error.
- **Value tags** `(good)` / `(bad)` are optional after any node name.
`(good)` is the implicit default — only flag `(bad)` when a variable
represents something undesirable (Burnout, Bugs shipped, Tech debt).
- **Bare lines** declare or retag a variable without creating a link:
`Churn (bad)` on its own line just marks Churn as bad.
- **Zones** are visual groupings; a zone is opened with `{Name` on its
own line and closed with `}`. Members listed on their own lines (or
declared via links inside the zone) become part of it.
- **Loop type is derived** at layout time from the parity of negative
links around a cycle and any `(bad)` tags — you don't tag loops as
reinforcing/balancing yourself.
Example — burnout cycle:
```
@type causal-loop
@heading Burnout cycle
{People
Burnout (bad)
Decision quality
Hours worked
}
{Output
Bugs shipped (bad)
Customer complaints (bad)
}
Hours worked -+> Burnout --> Decision quality --> Bugs shipped -+> Customer complaints -+> Hours worked
```
Example — SaaS referral with saturation:
```
@type causal-loop
Happy customers -+> Referrals -+> New signups -+> Happy customers
New signups -+> Market saturation --> New signups
```
Guidelines for AI causal-loop generation:
- Aim for 4–8 variables and 1–3 loops. CLDs become unreadable past
~10 variables.
- Name variables as nouns or short noun phrases ("Customer complaints",
not "Customers complain").
- Mark only the genuinely undesirable variables with `(bad)`. Don't
tag everything.
- Use chains (`A -+> B --> C`) to keep loops on one line — easier to
read than three separate `A -+> B` / `B --> C` / `C -+> A` lines.
- Use zones when the user describes distinct sub-systems (People vs
Output, Customer vs Internal, etc.).
## Chart Diagrams
Charts render numeric data as visualisations. Five types share the
same syntax shape: `bar`, `column`, `line`, `pie`, and `chart`
(auto-pick — the renderer picks the best fit from the data).
```
@heading <title> — optional title
@caption <subtitle> — optional caption
Label: value — value can be number, tally, or percentage
Label: 100 — number
Label: ||||| — tally marks (count = number of bars)
Label: 72% — percentage
Label{!}: value — accent / highlight
Label{bg:wheat}: value — custom bar background tint
// comment
```
Charts ignore `@direction` — bar is horizontal, column is vertical,
line is left-to-right time series, pie is radial.
### Bar — horizontal bars
Best for tally counts, survey responses, votes. Tally marks (`|||`)
or numbers both work. Tally marks render as a count of glyphs.
```
@heading Fruit bowl census
Apples: |||||
Pears: |||||||
Bananas: |||
Plums: ||||||||||
```
### Column — vertical bars
Best for category comparisons (quarters, months, products).
```
@heading Quarterly revenue
Q1: 100
Q2: 120
Q3: 140{!}
Q4: 160
```
### Line — time series
Best for trends over time. Labels typically dates or sequential
periods; values are numbers.
```
@heading Monthly active users
2025-01: 120
2025-02: 135
2025-03: 128
2025-04: 142
2025-05: 155
2025-06: 170
```
### Pie — proportions
Best for parts-of-a-whole. Values can be percentages (must sum to
~100) or raw numbers (renderer normalises).
```
@heading Sprint status
Done: 72%
In progress: 18%
Blocked: 10%
```
### Chart — auto-picked type
When the diagram type isn't specified, the renderer picks from the
data shape: dated labels → line, percentages → pie, short numeric
labels (Q1, Jan) → column, tally marks → bar.
```
// no @type — yUML picks bar/column/line/pie from the data shape
Q1: 100
Q2: 120
Q3: 140
Q4: 160
```
Guidelines for AI chart generation:
- Pick a specific type (`bar`/`column`/`line`/`pie`) when the user's
intent is clear; reach for `chart` only when ambiguous.
- Tally marks suit small whole-number counts (≤ 12-ish). Use numbers
for larger values.
- Percentages should sum to ~100 in pies. If the user gives raw
counts, leave them — the renderer handles the maths.
- Use `{!}` on a single most-important bar/column to draw attention.
## Story Format
Stories are markdown documents with embedded yUML diagrams.
````
@style blueprint — global style (applies to all diagrams)
@direction LR — global direction
# Slide Title — starts a section
Prose text in **markdown**. — rendered as styled text
```yuml class — diagram block (type after "yuml")
@heading Diagram Title — optional heading
@caption Description — optional caption
[A]->[B]
```
--- — slide separator
# Next Slide
...
````
Guidelines for AI story generation:
- Start with a high-level overview, then progressively reveal detail
- Each slide should have a heading, 1-2 sentences of prose, and one diagram
- Use different diagram types to show different perspectives
(class for structure, sequence for behaviour, journey for UX, c4 for systems)
- Keep individual diagrams focused — 3-7 elements each, not comprehensive
- Use `@heading` on diagrams to label what aspect they show
## Common mistakes to avoid
- Missing closing `]` or `)` on the last element
- Unbalanced `{ }` boundary braces
- Wrong arrow for the diagram type — respect the target type's arrow set
- Extra or missing pipes in `[Name|Type|Desc]` (c4) or `[Name|attrs|methods]` (class)
- Quoting names that don't need quotes — the grammar is liberal about names
Versioning
This spec describes DSL grammar v1, matching
/diagram/v1/{type}/{style}/{dsl}.svg. If the grammar ever breaks
backwards compatibility, a new spec will ship at /dsl/v2/spec
and the v1 URL will remain stable for agents already referencing it.