v1

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