Migrating from Mermaid
How to move existing Mermaid diagrams to Plotwork with a converter that is deterministic, and how an AI agent finishes the job. It is written for the agent first: every step names the tool to call and what the result means. People can follow the same steps over the HTTP API.
TL;DR
| Question | Answer |
|---|---|
| What converts? | Flowcharts (flowchart, graph), sequenceDiagram, erDiagram, stateDiagram, classDiagram, gantt, gitGraph, timeline, journey, mindmap, treemap-beta (and treemap), pie, quadrantChart, C4Context, C4Container, C4Component, C4Dynamic, C4Deployment, sankey-beta (and sankey), xychart-beta (and xychart), and treeView-beta (and treeView). Each becomes the Plotwork kind of the same name: flow, sequence, schema, state, class, gantt, git, timeline, journey, mindmap, treemap, pie, quadrant, c4, sankey, xychart, or tree. |
| What does not? | Kanban, radar, and the other kinds in the list below. One diagnostic names the kind and says what to do instead. |
| One diagram | Call convert_mermaid with the Mermaid text. It returns the Plotwork source, the diagnostics, the validation, and an outline. |
| A whole document | Call sync_markdown with convertMermaid: true. It returns the rewritten document and the picture files to write. |
| HTTP API | POST /v1/diagrams/convert-mermaid for one diagram and POST /v1/markdown/sync for a document. Calling them directly needs the Pro plan and an API key. |
| What is lost? | Strokes, text colours, themes, links, tooltips, activations, and a few more. A fill that has a tone is kept as that tone. Every loss is reported with a diagnostic and a hint. Nothing is dropped silently. |
| Is it a model? | No. The converter is plain code. The same Mermaid always gives the same Plotwork. |
| What is left for the agent? | Read every diagnostic, give each node a type that means something, add a title and icons, then validate and render. |
Why migrate
GitHub already draws Mermaid fences in the page, so Mermaid works with no setup. Plotwork gives you these in return for the move:
| What you get | How |
|---|---|
| One look in light and dark | The theme owns every colour. There is no classDef, style, or %%{init}%% to vary from one diagram to the next. An author chooses a node type or a tone for meaning. |
| A static picture | The output is an SVG file in the repository. It needs no JavaScript, no browser, and no network to display. |
| Output that diffs cleanly | The same source gives the same bytes, so a change to a diagram shows as a small change in the diff. |
| Errors an agent can repair | Every mistake has a line, a column, and a hint, and all of them come back in one pass. |
| A closed icon vocabulary | An icon is set:name from a fixed list, and an unknown name is an error with a suggestion. |
| Text that never overflows | Boxes grow to fit their text, with the same padding on every side. |
When not to migrate
Keep the Mermaid fence when the diagram is one of the kinds in the next table. GitHub keeps drawing it. A fence that cannot be converted is left exactly as it was, so a document can hold both kinds.
Mermaid kinds Plotwork does not draw
| Mermaid diagram | Closest Plotwork kind | What to do |
|---|---|---|
| requirement diagram | flow | Redraw it as a flow diagram with one node per requirement and element, or keep it as Mermaid in its own mermaid fence. |
| block diagram | flow | Redraw it as a flow diagram with a group for each block that holds others, or keep it as Mermaid in its own mermaid fence. |
| packet diagram | schema | Redraw it as a schema diagram with one column per field, or keep it as Mermaid in its own mermaid fence. |
| kanban board | none | Keep it as Mermaid in its own mermaid fence; GitHub draws it. A Markdown task list per column is the plain alternative. |
| architecture diagram | flow | Redraw it as a flow diagram: a group for each Mermaid group and a node with a type and an icon for each service. Or keep it as Mermaid in its own mermaid fence. |
| ZenUML sequence diagram | sequence | Redraw it as a Plotwork sequence diagram (actors, messages, and alt, opt, loop, par blocks), or keep it as Mermaid in its own mermaid fence. |
| radar chart | none | Keep it as Mermaid in its own mermaid fence; GitHub draws it. |
These kinds used to be on this list and now convert to their own kinds: C4 diagrams, class diagrams, Gantt charts, git graphs, mind maps, pie charts, quadrant charts, Sankey diagrams, timelines, tree views, treemaps, user journeys, and XY charts. A state diagram is now a state diagram and no longer a flow diagram. Other Mermaid kinds that convert says where each one is explained.
The migration recipe for an agent
Follow these steps in order. Each one is a tool call or a decision.
- Convert. For one diagram, call
convert_mermaidwith the text inside the fence. For a document, callsync_markdownwithconvertMermaid: true. - Read every diagnostic. They are data:
code,severity,line,column,message, and ahintthat says what to do. Lines and columns point into the Mermaid you sent. A code that starts withM1is an error and nothing was converted. A code that starts withM2is a warning and the conversion went on. - Resolve each one with the guidance in what does not carry over and the diagnostic codes. Most need no action. Some need a choice, such as which node an edge into a subgraph should reach.
- Make it meaningful. The converter chooses a node type only when the shape or a short label says what the node is. Every other node is a plain
step. Choose a better type for each (see how a node type is chosen), give the diagram a title, and name the groups. Take the icon suggestions invalidation.warnings: each says whichicon=to write. Find others withsearch_iconsormap_icons. - Validate. Call
draw_diagramon the edited Plotwork source. It returns every error and warning, and draws nothing until the source is valid. - Render. Call
draw_diagramagain for the pictures, or put the source in adiagramfence and callsync_markdown. See Diagrams in Markdown and on GitHub.
Worked example: one call and its result
The call:
{ "tool": "convert_mermaid", "arguments": { "source": "flowchart TD\n user[User] --> db[(Orders DB)]\n classDef error fill:#f66\n class db error", "render": false }}The source argument, written out one line at a time:
flowchart TD user[User] --> db[(Orders DB)] classDef error fill:#f66 class db errorThe result, shortened to the fields an agent reads first:
{ "ok": true, "kind": "flow", "mermaidType": "flowchart", "source": "flow direction=down\n\nnode user person \"User\"\nnode db database \"Orders DB\" tone=red\n\nuser -> db", "diagnostics": [ { "code": "M214", "severity": "warning", "line": 1, "message": "The diagram has no title.", "hint": "Add a title to the header line of the Plotwork source, or a title: line in the Mermaid front matter." }, { "code": "M204", "severity": "warning", "line": 3, "message": "The fill #f66 of the class \"error\" became the tone red.", "hint": "Check that the tone says what it means. The theme draws it in light and dark." } ], "stats": { "nodes": 2, "edges": 1, "groups": 0, "dropped": 0, "renamed": 0 }, "validation": { "valid": true, "errors": [], "warnings": [] }, "outline": [ "Nodes:", "- User, person", "- Orders DB, database", "Connections:", "- User to Orders DB" ], "next": "Read the 2 diagnostics (they point into the Mermaid) and fix what the hints say. Then choose a meaningful type for every node left as step, add a title, and take the icon suggestions in validation.warnings. Call draw_diagram on the edited source to check and draw it, or sync_markdown to place it in a document."}The source of the result, written out one line at a time:
flow direction=down
node user person "User"node db database "Orders DB" tone=red
user -> dbThe field ok is true only when source passes the Plotwork parser. When it is false, source is empty and diagnostics holds the reason, so the converter never returns source that would fail validation.
Worked example: a whole document
Ask the agent: "Replace the Mermaid diagrams in README.md." The tool sequence is:
| Step | Call | What to do with the result |
|---|---|---|
| 1 | sync_markdown with markdown (the file text), documentPath: "README.md", convertMermaid: true, mode: "check" | A dry run. Read report: each Mermaid fence is converted or failed, with diagnostics. Nothing is rewritten. |
| 2 | Fix what the report says, or accept it | Fences that fail are left as Mermaid and reported. |
| 3 | sync_markdown again with mode: "sync" | The result has markdown (the rewritten document) and files (every SVG, light and dark). |
| 4 | Write markdown to README.md and each files entry to its path | The tool writes nothing itself; it has no file system. |
| 5 | Review the change in git | Read the diff before it is committed. |
The result, shortened:
{ "mode": "sync", "markdown": "<the whole document, rewritten>", "changed": true, "files": [ { "path": "assets/diagrams/readme-sign-in-flow.svg", "content": "<svg text>", "encoding": "utf8" }, { "path": "assets/diagrams/readme-sign-in-flow.dark.svg", "content": "<svg text>", "encoding": "utf8" } ], "report": [ { "id": "readme-sign-in-flow", "source": "mermaid", "kind": "flow", "line": 12, "status": "converted", "diagnostics": [], "message": null } ], "summary": { "diagrams": 1, "synced": 0, "converted": 1, "unchanged": 0, "skipped": 0, "failed": 0, "files": 2 }, "caps": { "hit": false, "messages": [] }}A call handles up to 30 diagrams and a document of up to 10 million characters. If a document has more, caps says which fences were skipped; send them in a second call. Nothing is cut silently.
Concept mapping
These tables are the converter's own data, so they cannot drift from what it does.
Flowchart shapes
| Mermaid shape | Example | Plotwork type | Why |
|---|---|---|---|
| Rectangle | A[Text] | step | The neutral shape. The label may suggest a type (see the keyword table). |
| Rounded rectangle | A(Text) | step | The same as a rectangle. |
| Stadium | A([Text]) | terminal | A start or an end of a flow, which is what a terminal is. |
| Subroutine | A[[Text]] | step | A plain step. Plotwork has no framed box. |
| Cylinder | A[(Text)] | database | A data store. A label such as Redis or Kafka picks the more exact cache or queue. |
| Circle | A((Text)) | terminal | Used for connectors and for starts and ends, so a terminal. |
| Double circle | A(((Text))) | terminal | An end of a flow, so a terminal. |
| Rhombus | A{Text} | decision | A question with branches, which is what a decision is. |
| Hexagon | A{{Text}} | step | A plain step. Plotwork has no hexagon. |
| Asymmetric | A>Text] | step | A plain step. |
| Parallelogram | A[/Text/] | step | A plain step. Input and output are not a separate type. |
| Parallelogram, leaning left | A[\Text\] | step | A plain step. |
| Trapezoid | A[/Text\] | step | A plain step. |
| Trapezoid, inverted | A[\Text/] | step | A plain step. |
Shapes written in the newer A@{ shape: name, label: "text" } form map the same way:
Shape names for @{ shape: name } | Plotwork type | Why |
|---|---|---|
lin-cyl, disk, h-cyl, das, horizontal-cylinder, bow-rect, stored-data | storage | Storage that is not a database. |
cloud | external | Something outside your system, which is what an external node is. |
doc, docs, documents, lin-doc, tag-doc, st-doc, flag, paper-tape | step | A plain step. |
sm-circ, small-circle, start | terminal | The start of a flow. |
fr-circ, framed-circle, stop | terminal | The end of a flow. |
st-rect, stacked-rectangle, lin-rect, lin-proc, lined-process, shaded-process, div-rect, div-proc, divided-process, divided-rectangle, notch-rect, card, notched-rectangle, sl-rect, manual-input, win-pane, internal-storage, curv-trap, display, delay, half-rounded-rectangle, tri, extract, flip-tri, manual-file, hourglass, collate, bolt, com-link, lightning-bolt, cross-circ, summary, f-circ, filled-circle, junction, text, brace, brace-r, braces, fork, join, bang, processes, procs, bow-tie-rectangle | step | A plain step with a warning, since the shape itself is lost. |
Edges
Edge text written as -->|text| or -- text --> becomes the edge label. A chain such as A --> B --> C and a fan such as A & B --> C & D become one edge for each pair. An edge animation, e1@{ animate: true }, is kept as animate=on on the line. The edge id and the speed are dropped and reported, and a link with no arrowhead stays still, because dashes travel toward an arrowhead.
| Mermaid link | Plotwork arrow | What changes |
|---|---|---|
A --> B | -> | Nothing. |
A --- B | -- | Nothing. |
A -.-> B | --> | Nothing. |
A -.- B | -- | Plotwork has no dashed line without an arrowhead, so the line is drawn solid. |
A ==> B | -> | Plotwork draws every edge with one stroke weight. |
A === B | -- | Plotwork draws every edge with one stroke weight. |
A --o B | -> | Plotwork has one arrowhead, so a circle or a cross at the end of a link becomes an arrowhead. |
A --x B | -> | Plotwork has one arrowhead, so a circle or a cross at the end of a link becomes an arrowhead. |
A <--> B | <-> | Nothing. |
A <-.-> B | <--> | Nothing. |
A <==> B | <-> | Plotwork draws every edge with one stroke weight. |
A o--o B | <-> | Plotwork has one arrowhead, so a circle or a cross at the end of a link becomes an arrowhead. |
A x--x B | <-> | Plotwork has one arrowhead, so a circle or a cross at the end of a link becomes an arrowhead. |
A ~~~ B | none | Dropped with a warning. It is a layout trick, and layout is done for you. |
Subgraphs
| Mermaid | Plotwork | Note |
|---|---|---|
subgraph id [Title] | group id "Title" {, its nodes, and } | The title is the label. A group has no direction of its own. |
subgraph Title with spaces | group Title_with_spaces "Title with spaces" { | The text is the label, and the id is made valid, with a warning. |
Nested subgraphs | Nested groups | Up to 24 levels deep. |
A node mentioned inside a subgraph | A node declared inside the group | A node belongs to the first subgraph it is mentioned in. A second subgraph that mentions it gets a warning. |
A --> subgraphId | An edge to a node inside the group | Plotwork edges connect nodes. An edge into a subgraph goes to its first node that nothing inside points at; an edge out of one comes from its last node that points at nothing inside. A warning names the node chosen. |
direction TB inside a subgraph | Dropped with a warning | Plotwork has one reading direction for the whole diagram. |
An empty subgraph | Dropped with a warning | A group with nothing in it draws nothing worth keeping. |
A subgraph with no end | Closed at the end of the diagram, with a warning | An extra end is ignored, with a warning. |
Sequence diagrams
Arrows:
| Mermaid arrow | Meaning | Plotwork arrow | What changes |
|---|---|---|---|
<<-->> | Dotted, arrowhead at both ends | <--> | Nothing. |
<<->> | Solid, arrowhead at both ends | <-> | Nothing. |
-->> | Dotted line with an arrowhead: a reply | --> | Nothing. |
->> | Solid line with an arrowhead: a call | -> | Nothing. |
--x | Dotted line ending in a cross | --> | Plotwork has one arrowhead, so a cross at the end of a message becomes an arrowhead. Say what failed in the label. |
--) | Dotted line with an open arrow: asynchronous | ..> | Plotwork draws an asynchronous message as a dotted line with an arrowhead. |
--> | Dotted line with no arrowhead | -- | Plotwork has no dashed line without an arrowhead, so the line is drawn solid. |
-x | Solid line ending in a cross | -> | Plotwork has one arrowhead, so a cross at the end of a message becomes an arrowhead. Say what failed in the label. |
-) | Solid line with an open arrow: asynchronous | ..> | Plotwork draws an asynchronous message as a dotted line with an arrowhead. |
-> | Solid line with no arrowhead | -- | Nothing. |
Blocks:
| Mermaid block | Plotwork block | Note |
|---|---|---|
loop | loop | The same. |
alt | alt | The same. |
opt | opt | The same. |
par | par | The same. |
critical | alt | Becomes an alt: the critical region is the first branch and each option is an else branch. |
break | opt | Becomes an opt, which is the nearest frame for steps that happen only on one path. |
rect | none | The coloured background is dropped and the messages inside are kept. |
Everything else:
| Mermaid | Plotwork | Note |
|---|---|---|
participant A as Alice | actor a step "Alice" | The neutral type step, unless the name says what it is, as Database or Browser do. Choose a type. |
actor A as Bob | actor a person "Bob" | The stick figure means a person. |
A messages B without declaring them | Actors declared in the order they first appear | Plotwork needs every actor declared; the converter adds them. |
Note over A,B: text | note over a, b : "text" | The same. |
Note left of A: text, Note right of A: text | note over a : "text" | Plotwork notes sit over a lifeline. A warning says the side was lost. |
A->>B: text with <br/> | A message label on one line | Plotwork wraps text itself. |
A->>A: text | a -> a : "text" | A message to oneself is kept. |
autonumber | numbered=on on the header | Each message gets a numbered badge. A message before the autonumber line, or after autonumber off, gets step=off. |
autonumber 10, autonumber 10 5 | numbered=on start=10, and step=15 on a message whose number the count would not give | The numbers Mermaid draws are the numbers Plotwork draws, up to 999. |
title Text | The diagram title | A front matter title wins when both are given. |
Entity relationship diagrams
A Mermaid relationship names two entities and no columns. A Plotwork relation joins one column to another, so the converter finds the key columns, and adds a column when it cannot. Each added column is reported.
| Meaning | Left marker | Right marker | Plotwork |
|---|---|---|---|
| Exactly one | || | || | The key it points at; the foreign key column is not nullable. |
| Zero or one | |o | o| | The foreign key column is nullable. |
| One or more | }| | |{ | A foreign key on this side (many to one). The "at least one" minimum is not drawn. |
| Zero or more | }o | o{ | A foreign key on this side (many to one). |
Whole relationships:
| Mermaid | Meaning | Plotwork |
|---|---|---|
A ||--o{ B : has | One A, zero or more B | B holds a foreign key to A. |
A ||--|| B : has | One A, exactly one B | B holds a unique foreign key to A, which draws one to one. |
A }o--o| B : has | Many A, zero or one B | A holds a nullable foreign key to B. |
A }o--o{ B : has | Many to many | A join table with a foreign key to each side. |
Lines and keys:
| Mermaid line | Meaning | Plotwork |
|---|---|---|
-- | Identifying | A normal relation. Plotwork draws one line style. |
.. | Non-identifying | A normal relation, with a warning that the dotted line is not drawn. |
| Mermaid key | Plotwork flag | Meaning |
|---|---|---|
PK | pk | Primary key |
FK | fk | Foreign key |
UK | unique | Unique key |
State diagrams
A state diagram becomes a Plotwork state diagram, which has its own kind: states are rounded cards, transitions are labelled lines, composite states are frames, and the start and end markers, choices, forks, joins and notes are drawn as such. Older versions of the converter turned a state diagram into a flow diagram of groups and terminal nodes, so a state diagram that was converted earlier reads differently when it is converted again. See State diagrams.
| Mermaid | Plotwork | Note |
|---|---|---|
A --> B : event | A transition a -> b : "event" | The label is kept as written, so event [guard] / action keeps its guard and its action. |
state A | state a "A" | A rounded card. Give it a tone= for a meaning such as an error or a success. |
state "Long name" as A | state a "Long name" | The id stays A. |
A : description | The state sub= text | Each description line stays its own line under the name. |
[*] --> A | start -> a | The start marker of the scope the line is in: the diagram, or the composite state. |
A --> [*] | a -> end | The end marker of the scope the line is in. |
state A { inner states } | A composite state state a "A" { with its states inside | Each composite state has its own start and end markers, and a transition may enter or leave the whole state. |
-- | region { blocks inside the composite state | The states before the first -- are the first region. A dashed line separates the regions. |
state A <<choice>> | choice a | A pill with a branch icon. Label the branches with their guards. |
state A <<fork>> or <<join>> | fork a or join a | A bar that splits or merges parallel paths. |
direction LR | direction=right in the header | Only at the top level. Inside a composite state it is dropped. |
note right of A : text | note a : "text" side=right | A note beside the state, across the reading direction. A note on a composite state sits inside its frame. |
classDef, class, :::name, style | Dropped with a warning | The theme owns colour. A class name such as error gives the state the tone red. |
Other Mermaid kinds that convert
More Mermaid kinds convert into a Plotwork kind of their own. Each has a guide that shows what is kept and what is dropped. The codes in the last column are the ones that only that kind raises, and the diagnostic codes table explains every code.
| Mermaid | Plotwork kind | Guide | Codes of its own |
|---|---|---|---|
classDiagram | class | Class diagrams | M240, M241, M242 |
gantt | gantt | Gantt charts | M130, M131, M132, M230 to M238 |
gitGraph | git | Git graphs | M120, M220, M221, M222 |
timeline | timeline | Timelines | M260 |
journey | journey | User journeys | M270, M271 |
mindmap | mindmap | Mind maps | M180, M280, M281, M282 |
stateDiagram | state | State diagrams | M250, M251 |
treemap-beta, treemap | treemap | Treemaps | None of its own |
pie | pie | Pie charts | None of its own |
quadrantChart | quadrant | Quadrant charts | None of its own |
C4Context, C4Container, C4Component, C4Dynamic, C4Deployment | c4 | C4 diagrams | None of its own |
sankey-beta, sankey | sankey | Sankey diagrams | None of its own |
xychart-beta, xychart | xychart | XY charts | None of its own |
treeView-beta, treeView | tree | Tree diagrams | None of its own |
Three kinds have no Mermaid type to read: Layered architecture, Matrices, and Swimlane diagrams. Each guide says how to move a Mermaid diagram or a Markdown table to it by hand.
How a node type is chosen
The converter is conservative. It picks a type in this order and stops at the first that applies:
- The construct itself decides, as for a flowchart rhombus (a
decision) or a stadium (aterminal). - A class name that carries meaning, such as
database,queue,external, orerror. The converter reports that it used the class. - The shape: a cylinder is a
database, a rhombus is adecision, a stadium or a circle is aterminal, a cloud isexternal. A label keyword may refine a cylinder to a cache, a queue, or storage. - A keyword in a short label of at most three words, and only when exactly one type matches. "Orders DB" is a
database; "Redis queue" matches two types and stays neutral; a sentence is never read. - Otherwise the neutral
step, which the converter lists in one warning so you choose a better one.
It writes an icon only when the label names a brand. "PostgreSQL", "Redis cache", or a second line such as "Stripe API" gets that brand's mark (icon=simple:postgresql). A decision, a start or end, and a plain step never get one, and a name that is only a word for a kind of thing ("Message Queue") keeps the icon of its type. The Plotwork validator suggests the other icons from the labels, and those suggestions come back in validation.warnings.
An HTTP status code at the start of a label sets a tone when the node has none: 200 and the other 2xx codes are green, and 4xx and 5xx codes are red. "Return 429 Too Many Requests" is red. A 3xx code gets no tone, because a redirect is neither good nor bad.
The words it looks for:
| Type | Whole label | Last word of a short label | Product names in a short label |
|---|---|---|---|
database | database, databases, db, datastore, data store, sql | database, db, datastore | postgres, postgresql, mysql, mariadb, sqlite, mongodb, mongo, dynamodb, cassandra, cockroachdb, oracle, mssql |
cache | cache, caches | cache | redis, memcached, valkey |
queue | queue, queues, topic, message bus, event bus | queue, topic, bus | kafka, rabbitmq, sqs, nats, pubsub, kinesis |
storage | storage, bucket, buckets, blob storage, file storage | bucket, storage | s3, gcs |
person | user, users, customer, customers, admin, administrator, developer, visitor, end user, operator, person, user request | none | none |
client | browser, client, clients, frontend, front end, web app, mobile app, ui, cli, spa, webapp, client request | browser | none |
gateway | gateway, api gateway, load balancer, reverse proxy, proxy, cdn, ingress | gateway, balancer, proxy | nginx, envoy, traefik, haproxy, kong |
service | api, service, backend, back end, server, microservice, rest api, web server, app server | service, api, server, microservice, backend | none |
function | worker, workers, worker pool, cron, cron job, scheduler, lambda, function, job, batch job | worker, cron, scheduler, lambda, function | lambda |
external | external, external system, third party, 3rd party, external api, partner, payment provider, email provider, sms provider, payment processor | none | stripe, sendgrid, twilio, paypal, mailgun, braintree |
identity | idp, identity provider, sso, auth server, authorization server, oauth, oidc | none | okta, auth0, keycloak |
secret | secret, secrets, vault, key vault, kms, secret store | none | none |
Class names that give a type or a tone:
| Class names | Becomes |
|---|---|
database, db, datastore, store | type database |
cache | type cache |
queue, topic, broker | type queue |
storage, bucket | type storage |
external, thirdparty, ext, vendor | type external |
user, person, actor | type person |
client, browser, frontend | type client |
service, api, backend | type service |
gateway, proxy | type gateway |
worker, job, function, lambda | type function |
decision | type decision |
start, end, terminal | type terminal |
error, danger, fail, failure, critical | tone red |
warning, warn, caution | tone amber |
success, ok, done, pass, passed | tone green |
Fills become tones
A style line, a classDef line, and a class or :::name that points at one can set a fill. The converter reads the fill and keeps it as the tone of the node (or the group) when the colour is clear: it works out the hue of the colour and takes the tone whose band holds it. Each one is reported with M204, the first few on their own and the rest in one summary, so a diagram painted by an agent is not buried in warnings. A tone is a meaning, and the theme draws it in light and dark.
| Hue of the fill | Tone | Colours that land there |
|---|---|---|
| 345 to 15 degrees | red | red, crimson, tomato |
| 15 to 38 degrees | orange | orange, salmon |
| 38 to 68 degrees | amber | yellow, gold, khaki |
| 68 to 160 degrees | green | lime, green, light green |
| 160 to 200 degrees | aqua | teal, cyan, turquoise |
| 200 to 255 degrees | blue | sky blue, blue, navy, a periwinkle such as #bbf |
| 255 to 320 degrees | violet | purple, violet, indigo, lavender, a pastel such as #f9f |
These fills become no tone, and are reported as dropped styling with M200 along with the strokes, text colours, and widths:
| Fill | Why it becomes no tone |
|---|---|
| Greys, such as #ddd and #333 | A grey is the page's own neutral, so there is nothing to keep. |
| Near white and near black, such as #fff and #111 | Neither says a hue; they are the surface and the ink. |
| Pink and magenta, from 320 to 345 degrees | Plotwork has no pink, and the nearest tone would be a guess. |
| A fill that is mostly transparent, or a colour that cannot be read | It is not a fill an agent chose to show. |
A fill set on the node itself wins over a tone a class name such as error suggests.
Edge labels that get a status icon
An edge label that states an outcome gets a status icon, written as icon=status:name on the line. The icon brings its own colour, so a branch such as "Rate limited" says what happened without a colour code to learn. A label matches only when all of it is one of the phrases below, in any case and with its punctuation ignored, so "Sends the order" and "Webhook" are never given an outcome they do not state. The labels yes, no, true, and false get their tick and cross from the language itself, so the converter writes nothing for them.
| Status icon | Edge labels that get it |
|---|---|
status:yes | y, ok, okay, pass, passed, valid, correct |
status:no | n, invalid, incorrect |
status:success | success, successful, succeeded, done, complete, completed, approved, accepted |
status:error | error, errors, failed, failure, fail, rejected, exception, crash, crashed |
status:verified | authenticated, verified, signed in, logged in |
status:allowed | allowed, authorized, authorised, permitted, granted, access granted |
status:denied | denied, forbidden, unauthorized, unauthorised, unauthenticated, not authenticated, not authorized, not allowed, access denied, permission denied |
status:blocked | blocked, banned, throttled, rate limited, rate limit exceeded, too many requests |
status:warning | warning, warn, degraded |
status:expired | expired, timeout, timed out |
status:retry | retry, retrying, try again |
status:pending | pending, waiting |
status:skipped | skip, skipped |
status:running | running, in progress, processing |
status:revoked | revoked |
What does not carry over and why
Plotwork owns colour, spacing, and layout, so a diagram cannot set them. The rule for every row is the same: choose a node type or a tone for meaning, and let the theme choose the colour.
| Mermaid | Applies to | Why it does not carry over | What to do instead |
|---|---|---|---|
classDef | flowchart, state | The theme owns every colour, in light and dark, so a diagram cannot set one. | Choose a node type or a tone for what the node means; the theme chooses the colour. |
class and :::name | flowchart, state | The theme owns every colour, in light and dark, so a diagram cannot set one. | Choose a node type or a tone for what the node means; the theme chooses the colour. |
style | flowchart, state | The theme owns every colour, in light and dark, so a diagram cannot set one. | Choose a node type or a tone for what the node means; the theme chooses the colour. |
What a style or classDef line sets besides a fill that has a tone | flowchart | The theme owns every colour, in light and dark, so a diagram cannot set one. A fill is kept as the nearest tone; strokes, text colours, widths, and a fill with no tone are left out. | Choose a node type or a tone for what the node means; the theme chooses the colour. |
linkStyle | flowchart | Plotwork draws every edge the same way. | Use an arrow form for meaning: -> for a call, --> for a reply or optional link, ..> for an asynchronous call. |
%%{init}%% directives, themes, themeVariables, curve | all | Theme and layout settings belong to Plotwork, not to a diagram. | Remove it. Use direction= in the header for the reading direction. |
Front matter config: | all | Theme and layout settings belong to Plotwork, not to a diagram. | Remove it. A title: is kept as the diagram title. |
click callbacks and links | flowchart, state | A Plotwork diagram is a static picture with no script and no links inside it. | Link to the page in the surrounding text, or put the name of the target in the node sub text. |
| Tooltips | flowchart | A static picture has no hover. | Put the detail in the node sub text or in the diagram desc=. |
Actor link and links | sequence | A static picture has no menus or links. | Link to the page in the surrounding text. |
direction inside a subgraph | flowchart | Plotwork has one reading direction for the whole diagram. | Set direction= on the header, or split the subgraph into its own diagram. |
Extra dashes in a link, as in ----> | flowchart | Layout places nodes; an author cannot ask for longer edges. | Nothing: the layout spaces nodes for you. |
Invisible link ~~~ | flowchart | It is a trick to move nodes, and layout does that for you. | Group the nodes with a group if they belong together. |
| Edge ids | flowchart | Plotwork names an edge by the two nodes it joins, so an id has nothing to refer to. | Nothing. An id that only animates the edge is not lost: e1@{ animate: true } becomes animate=on on the line. |
Animation speeds fast and slow | flowchart | Plotwork animates every line at one calm pace, so a speed has nothing to set. | The line is still animated with animate=on. Say in the label if a flow is meant to be fast. |
curve on an edge | flowchart | Layout routes every edge, with square bends and rounded corners, so a curve cannot be chosen. | Nothing: layout draws the edge for you. |
Activations +, -, activate, deactivate | sequence | Plotwork draws lifelines without activation bars. | Say who is busy in the message labels or a note over. |
create and destroy | sequence | Every Plotwork participant has a lifeline for the whole diagram. | Declare the participant at the top and say it is created or destroyed in a note over. |
box around participants | sequence | Plotwork has no frame around participants. | Put the grouping in the participant sub text, such as the name of the system. |
rect backgrounds | sequence | The theme owns every colour, in light and dark, so a diagram cannot set one. | The messages inside are kept. Use opt or loop if the highlighted part means something. |
State classDef, class, and style | state | The theme owns every colour, in light and dark, so a diagram cannot set one. | A tone= on a state is a meaning, not a colour. A class name such as error or success gives the state that tone, and the class itself is dropped. |
Entity style | ER | The theme owns every colour, in light and dark, so a diagram cannot set one. | A tone= on a table is a meaning, not a colour. |
Non-identifying relationships .. | ER | Plotwork draws one line style for a relation. | Mark an optional reference with nullable on the foreign key column. |
| "One or more" on the many side | ER | A relation draws many to one; a minimum count is a rule, not a shape. | Say it in the relation label if it matters. |
Other text is cleaned and the change is reported: HTML tags and Markdown marks are removed, <br/> and \n become a line break (a second line of a node label becomes its sub= text), entities such as #quot; and & are decoded, and Font Awesome tokens such as fa:fa-database are removed with the closest bundled icon named in the hint. Quotes and backslashes are escaped so every label keeps its exact text.
Ids that are not valid Plotwork ids (spaces, dots, accents, a leading digit) are renamed the same way every time, and each rename is reported. The label keeps the original text.
Diagnostic codes
| Code | Severity | What it means | What to do |
|---|---|---|---|
M100 | error | The text is empty or does not start with a Mermaid diagram type. | Check that the first line is a diagram type such as flowchart TD or sequenceDiagram. |
M101 | error | Plotwork does not draw this kind of Mermaid diagram. | Keep it as Mermaid in its own fence, or redraw it as the closest Plotwork kind, which the hint names. |
M102 | error | The diagram is over a size limit: too much text, too many nodes or edges, or nesting that is too deep. | Split it into several diagrams along a subgraph, then convert each. |
M103 | error | The diagram has a header but nothing to draw. | Add nodes or messages to the Mermaid, or delete the fence. |
M104 | error | The converter produced Plotwork that did not pass validation, so it returned nothing. | Report the Mermaid that caused it. Redraw the diagram by hand in the meantime. |
M110 | error | A statement could not be read as Mermaid, so nothing was converted. | Fix the line the diagnostic points at, or convert with lenient to skip unreadable lines and keep the rest. |
M200 | warning | Strokes, text colours, classes, themes, or other styling were dropped. A fill that has a tone is not here: it is kept as a tone (M204). | Choose a node type or a tone for what a node means. The theme chooses the colour. |
M201 | warning | A click action, link, or tooltip was dropped. | Link to the page in the surrounding text. A diagram is a static picture. |
M202 | warning | A hint about layout, such as a link length or a direction inside a subgraph, was dropped. | Nothing. Plotwork places nodes itself. Set direction= on the header if the reading direction matters. |
M203 | warning | Something that carried meaning has no Plotwork form and was dropped, such as activations or state notes. | Say it in a label, a sub= text, or a note over if the reader needs it. |
M204 | warning | A construct was replaced by the nearest Plotwork one, such as a cross end becoming an arrowhead or a fill becoming the nearest tone. | Read the message. Edit the Plotwork if the nearest form says the wrong thing. |
M205 | warning | Label text was cleaned: HTML tags, Markdown marks, or line breaks were removed or moved. | Compare the label in the Plotwork with the Mermaid. A second line became the sub= text of a node. |
M206 | warning | An id was not a valid Plotwork id and was renamed. | Nothing, unless you refer to the id elsewhere. The label keeps the original text. |
M207 | warning | A node type or tone was taken from a class name such as database or error. | Check that the type is right. The class itself was dropped. |
M208 | warning | Nodes got the neutral type step because nothing in the Mermaid says what they are. | Choose a type for each node that means something: database, service, queue, person, and so on. |
M209 | warning | An edge repeated an earlier one exactly and was dropped. | Nothing. Keep both only if they mean different things, and then give them different labels. |
M210 | warning | An edge pointed at a subgraph, and Plotwork edges connect nodes, so it was redrawn to a node inside. | Check that the node named in the message is the one the edge means. |
M211 | warning | A relationship names no columns, and Plotwork draws a relation between two columns, so one was added. | Rename the added column, or replace it with the real foreign key. |
M212 | warning | A many-to-many relationship was written as a join table with a foreign key to each side. | Rename the join table, and add the columns it holds. |
M213 | warning | A node appeared in more than one subgraph, and Plotwork puts a node in one group. | Check that the group the message names is the one you want. |
M214 | warning | The diagram has no title. A title names the picture, its file, and its alt text. | Add a title to the header line of the Plotwork source. |
M215 | warning | A Font Awesome icon in a label was removed. Plotwork icons are a closed set. | Set icon= on the node. The hint names the closest bundled icon. |
M216 | warning | An empty subgraph, state, or entity was dropped, or a label was empty and the id was used. | Add content to it in the Mermaid first if it should be drawn. |
M217 | warning | A subgraph or block was never closed, or an end had nothing to close, and the converter repaired it. | Check where the block should end. |
M218 | warning | A statement could not be read and was skipped because the conversion is lenient. | Fix the Mermaid line, or add the edge or node by hand in the Plotwork source. |
M250 | warning | A note on a composite state was drawn inside its frame, below the states it holds, because the frame has no free side. | Check that the note still reads well there. A note on a simple state keeps its side. |
M251 | warning | A state was named start or end, which Plotwork keeps for the start and end markers, so it was renamed. | Nothing, unless you refer to the id elsewhere. The label keeps the original name. |
M270 | warning | A journey task had a score outside 1 to 5, or a fraction, and Plotwork keeps whole scores from 1 to 5, so it was clamped or rounded. | Check that the task still reads as you meant. 1 is frustrated and 5 is delighted. |
M271 | warning | A journey task named an empty actor, or the same actor in two spellings that differ only in case or spacing, so the empty name was dropped or the spellings were merged. | Nothing, unless the two names were meant to be different people. Give them different words. |
M260 | warning | A timeline line had a # that is not part of an entity, and Mermaid reads everything after it as a comment, so the converter cut the line there as well. | Check that the text before the # says what you meant. Write the # as the entity #35; in the Mermaid if it was part of the text. |
M120 | error | A gitGraph statement names a branch or commit that does not exist, makes a branch that already exists, merges a branch into itself, or branches before the first commit, so the history cannot be replayed. | Fix the line the diagnostic points at, or convert with lenient to skip statements that cannot be replayed. |
M220 | warning | Mermaid draws a generated hash on a commit that has no id, and Plotwork draws a commit with no message as a bare dot. | Give the commit an id: in the Mermaid if the picture should say something next to it. |
M221 | warning | A cherry-pick named a parent:, and Plotwork has no choice of parent: a cherry-pick copies one commit. | Nothing, unless the picked commit is a merge and the parent mattered. Say which side in the commit message. |
M222 | warning | A commit had both an id: and a msg:, and Mermaid draws only the id, so the message was dropped. | Put the text the picture should show in the id:, or in the message of the Plotwork commit. |
M130 | error | A Gantt chart is scheduled in hours or minutes, or its dateFormat holds a time of day. Plotwork schedules in whole days, so nothing was converted. | Redraw the plan in days, or keep the chart as Mermaid in its own mermaid fence. |
M131 | error | A Gantt task comes after, or ends where, a task that is not in the chart, or waits for itself in a circle, so its dates cannot be worked out. | Fix the id the diagnostic names, or give the task a start date. Convert with lenient to skip tasks that cannot be placed. |
M132 | error | A Gantt dateFormat uses a token Plotwork does not read, such as a month name, so the dates cannot be read. | Write the dates as YYYY-MM-DD, DD/MM/YYYY, or another format of a year, a month, and a day in numbers. |
M230 | warning | A Gantt axisFormat was dropped. Plotwork writes the labels of the axis itself, from the step it draws. | Set unit= on the header to choose the step of the axis: day, week, month, quarter, or year. |
M231 | warning | A Gantt excludes or includes has no Plotwork form, apart from weekends and single days, which become weekends=skip and holidays=. | Use weekends=skip and holidays= on the header, and check that the lengths still add up. |
M232 | warning | A Gantt tickInterval was dropped because it is not one day, week, or month, which Plotwork writes as unit=. | Set unit= on the header, or leave it out so the step follows the span of the plan. |
M233 | warning | A Gantt todayMarker was dropped. Mermaid marks the day the chart is drawn, and Plotwork has no clock. | Add today=YYYY-MM-DD to the header to mark a day, and move it as the plan does. |
M234 | warning | A Gantt milestone had a length, and Mermaid draws it in the middle of it, so it sits on one day in Plotwork. | Check that the day is the one you mean, and set at= to change it. |
M235 | warning | A Gantt length changed: a fraction was rounded, a length of zero became one day, or a week was written in days because Mermaid counts it as seven working days. | Check the length in the Plotwork source, and write it as a whole number of days, weeks, or months. |
M236 | warning | A Gantt task tag such as vert has no Plotwork form and was dropped. The tags done, active, crit, and milestone are kept. | Use a milestone for a point in time, or today= for the current day. |
M237 | warning | A Gantt task ended where another task starts (until), and is written with the day that was, so it no longer moves with that task. | Check the date. Use after= on the other task if it should follow this one instead. |
M238 | warning | A Gantt layout setting (topAxis, weekday, weekend, displayMode) was dropped. Plotwork chooses the layout. | Nothing: the axis is above the chart, the week starts on Monday, and weekends are Saturday and Sunday. |
M240 | warning | A class member was written type first (String name, getName() String, List~int~ getIds()), and Plotwork writes a member name first, with the type after a colon, so it was turned round. | Check that the member reads as you meant. When neither word reads as a type, or both do, the text is kept as it was. |
M241 | warning | A class relation has no exact Plotwork form (a lollipop interface, a dashed line with no marker, or a marker at both ends), so the nearest of the eight relations was drawn. | Read the message for what was drawn. Edit the Plotwork if the nearest relation says the wrong thing. |
M242 | warning | A class had more than one annotation (<<interface>>, <<Service>>), and a Plotwork class has a type and one stereotype word, so the extra one was dropped. | Keep the annotation that matters, or say the other in a note on the class. |
M180 | error | A mind map has one root, and a later line is indented as far as it, or less, so it has no parent. Nothing was converted. | Indent the line under the node it belongs to, or move it into its own mindmap block. |
M280 | warning | A mind map node shape has no exact Plotwork form, such as a bang or a cloud, so the nearest shape was drawn. | Read the message for the shape that was drawn. Set shape= on the topic if another one reads better. |
M281 | warning | A mind map ::icon() line was dropped. Plotwork icons are a closed set. | Set icon= on the topic. The hint names the closest bundled icon. |
M282 | warning | A mind map node had text before its brackets. Mermaid reads that as an id and does not draw it, so only the text inside the brackets was kept. | Put all of the label inside the brackets if the text before them belongs in it. |
Diagnostics from the converter point into the Mermaid. The Plotwork validator's own warnings, such as an icon suggestion, point into the converted source, and they come back separately in validation.
Before and after
Each example shows the Mermaid source, the picture Mermaid draws from it, the Plotwork the converter produced, the picture Plotwork draws from that, and a table of what differs, with nothing edited by hand. After the conversion, an agent would still read the diagnostics, choose types for the nodes left as step, and take the icon suggestions.
The Mermaid pictures were drawn with Mermaid 12.1.0, in its default and dark themes, with Arial text. They are fixed pictures, drawn once from the source above them. They are not drawn by this page.
Some differences hold for every diagram:
| What | Mermaid | Plotwork |
|---|---|---|
| Meaning | The shape of a node, and a style you write for each color. | The type of a node, which sets its icon, tone, and shape. A color is never written. |
| Text for a reader who cannot see it | A role and the kind of diagram. A title and a description only when the source has accTitle and accDescr lines. | A title, a description, an outline of the nodes and connections, and the source the picture was drawn from, in every picture. |
| Text width | Measured in a browser when the diagram is drawn, so one source can give boxes of different sizes on different machines. | Measured with font metrics built into the renderer, so one source gives the same picture on every machine. |
| Light and dark | A theme chosen when the diagram is drawn. | A light picture and a dark picture of every diagram, chosen by the page. |
A flowchart with a subgraph and a decision
Mermaid:
---title: Sign-in flow---flowchart TD user[User] --> gw[API gateway] gw --> auth{Credentials valid?} auth -->|yes| session[Create session] auth -->|no| denied([Access denied]) subgraph store [Data] db[(Users DB)] audit[Audit log] end auth -.-> db session --> audit classDef database fill:#9cf class audit databaseMermaid draws it like this:
The converter reports the database type it took from the class of that name for the audit log, the class's blue fill kept as the tone blue, and the one node left as a plain step. The Plotwork:
flow "Sign-in flow" direction=down
node user person "User"node gw gateway "API gateway"node auth decision "Credentials valid?"node session step "Create session"node denied terminal "Access denied"group store "Data" { node db database "Users DB" node audit database "Audit log" tone=blue}
user -> gwgw -> authauth -> session : "yes"auth -> denied : "no"auth --> dbsession -> auditNodes:
- User, person
- API gateway, gateway
- Credentials valid?, decision
- Create session, step
- Access denied, terminal
- Data tier: Data
- Users DB, database
- Audit log, database
Connections:
- User to API gateway
- API gateway to Credentials valid?
- Credentials valid? to Create session: yes
- Credentials valid? to Access denied: no
- Credentials valid? to Users DB (dashed)
- Create session to Audit log
What differs between the two pictures:
| What | Mermaid | Plotwork |
|---|---|---|
| Title | Drawn above the diagram, from the front matter. | Not drawn. It names the picture for a screen reader. |
| What a node is | The shape: a box, a diamond for the decision, a rounded end, a cylinder for the database. Every shape has the same lavender fill unless a style says otherwise. | The type: an icon and a tone for each node, such as a person, a gateway, an amber decision, and a database. The end is a pill. |
| Color | classDef database fill:#9cf paints Audit log blue, and the subgraph has a pale yellow fill. | No color is written in the source. Audit log takes the type database from the class name, and the class's fill becomes tone=blue, which the theme draws in light and dark. |
| Edge labels | The words yes and no on the lines. | The same words, with a green tick and a red cross added, because those labels get a status icon. |
| The dotted link | A dotted line (-.->). | A dashed line (-->), which is the line for a link that is optional or indirect. |
| The group | A filled box with its name centered at the top. | A frame with a corner tab that holds the name. |
A sequence diagram with an alt block
Mermaid:
---title: Token refresh---sequenceDiagram autonumber actor U as User participant A as App participant I as Identity provider U->>A: Open the app A->>+I: Refresh token alt token valid I-->>-A: New access token else token revoked I-->>A: 401 sign in again A->>U: Ask to sign in end Note over A,I: Tokens last 15 minutesMermaid draws it like this:
The converter turns autonumber into numbered=on on the header, reports the dropped activation marks, and reports the participant App left as a plain step. The actor became a person, and the name Identity provider became an identity. The Plotwork:
sequence "Token refresh" numbered=on
actor U person "User"actor A step "App"actor I identity "Identity provider"
U -> A : "Open the app"A -> I : "Refresh token"alt "token valid" { I --> A : "New access token"} else "token revoked" { I --> A : "401 sign in again" A -> U : "Ask to sign in"}note over A, I : "Tokens last 15 minutes"Participants:
- User, person
- App, step
- Identity provider, identity
Steps:
-
- User to App: Open the app
-
- App to Identity provider: Refresh token
- alt: token valid
- 3. Identity provider to App (dashed): New access token
- else: token revoked
- 4. Identity provider to App (dashed): 401 sign in again
-
- App to User: Ask to sign in
- Note over App and Identity provider: Tokens last 15 minutes
What differs between the two pictures:
| What | Mermaid | Plotwork |
|---|---|---|
| Participants | A stick figure for the actor and a box for each participant, drawn at the top and again at the bottom. | A card for each, at the top only, with an icon from its type: a person, and an identity provider. App stays a plain card, because its type is step. |
| Numbers and activation | autonumber numbers each message, and activate draws a bar on the Identity provider. | The numbers carry over as numbered=on, so each message gets the same numbered badge. The activation bar is dropped and reported. |
| The alt block | A dotted frame with an alt tab. The conditions sit in brackets at the center, over the lifeline of App. | A rounded frame with an alt chip and an else chip, each beside its condition, at the left. |
| Replies | Dashed lines with filled arrowheads. | Dashed lines with open arrowheads. |
| The note | A yellow box. | A tinted box with an accent bar. |
An entity relationship diagram
Mermaid:
---title: Orders---erDiagram CUSTOMER ||--o{ ORDER : places ORDER ||--|{ LINE_ITEM : contains CUSTOMER { int id PK string email UK string name } ORDER { int id PK int customer_id FK date placed_at } LINE_ITEM { int order_id FK string sku int quantity }Mermaid draws it like this:
The many side of each relationship holds the foreign key, and the converter matched each one to a column that was already declared as FK, so it added none. It reports that the "one or more" minimum on contains is not drawn. The Plotwork:
schema "Orders"
table CUSTOMER { id int pk email string unique name string}
table ORDER { id int pk customer_id int fk placed_at date}
table LINE_ITEM { order_id int fk sku string quantity int}
ORDER.customer_id -> CUSTOMER.id : "places"LINE_ITEM.order_id -> ORDER.id : "contains"Tables:
- CUSTOMER
- id int (primary key)
- email string (unique)
- name string
- ORDER
- id int (primary key)
- customer_id int (foreign key)
- placed_at date
- LINE_ITEM
- order_id int (foreign key)
- sku string
- quantity int
Relations:
- ORDER.customer_id references CUSTOMER.id (many to one): places
- LINE_ITEM.order_id references ORDER.id (many to one): contains
What differs between the two pictures:
| What | Mermaid | Plotwork |
|---|---|---|
| A table | Three columns: the type, the name, and the key. | A card with an icon in its header. The key is a badge before the name, and the type sits at the right edge. |
| The unique key | Written UK in the source and drawn UK. | The converter turns UK into the flag unique, which is drawn as UQ. |
| The ends of a relationship | Each end says its minimum and its maximum: a double bar for exactly one, a circle and a crow's foot for zero or more. | A tick for the one side and a crow's foot for the many side. The "one or more" minimum on contains is not drawn, and the converter reports that. |
| The label | In a box on the line. | In a pill on the line. |
| Layout | The three tables stack in one column. | The three tables sit in a row. |
Converting a documentation folder safely
Go one file at a time, and read before you write. Ask your agent to run the steps, or make the calls yourself.
| Step | Call | Why |
|---|---|---|
| 1. Dry run | sync_markdown with the document, its path, convertMermaid: true, and mode: "check" | Reports each Mermaid fence and changes nothing. Repeat for every Markdown file. |
| 2. Read the report | Each fence has a status and its diagnostics. A failed fence could not be converted and is left exactly as it was. | |
| 3. Fix or accept | Fences that fail stay as Mermaid. To convert a diagram that has a line that cannot be read, call convert_mermaid on it with lenient: true, which skips the line with a warning. | |
| 4. Write | sync_markdown again, with mode: "sync" | Replaces each convertible fence with a diagram fence and returns the picture files and blocks. Everything else in the file is unchanged, byte for byte. Save the markdown over the file and each entry of files at its path. |
| 5. Review | git diff | Read every changed diagram before it is committed. |
To convert a whole folder, ask the agent to call sync_markdown on each file. Keep the dry run first for every file.
For a single diagram, call convert_mermaid with the Mermaid text. It returns the Plotwork source and the diagnostics as data, and you decide where to save the source.
FAQ
| Question | Answer |
|---|---|
| Does it handle my theme and colours? | Only as meaning. A class or style fill becomes the nearest tone, reported with M204, and the theme draws that tone in light and dark. Themes, strokes, text colours, and a fill with no tone are dropped with a diagnostic. |
| What about links and click actions? | Dropped with a diagnostic. A diagram is a static picture. Link to the page in the text around it. |
| Can I convert a whole repository? | Yes. Ask the agent to call sync_markdown on each Markdown file. Dry run first. |
| How do I review the result? | Read the diagnostics, then the outline (outline in the result), then the picture, then the git diff. |
| Why is a node a plain step? | Nothing in the Mermaid says what it is. Choose a type: database, service, queue, person, gateway, function, external. |
| Why did an edge move? | Plotwork edges connect nodes, so an edge into a subgraph goes to a node inside it. A diagnostic names the node. |
| What if one line cannot be read? | By default nothing is converted, so a diagram never loses a line unnoticed. The error names the line. Set lenient: true on convert_mermaid to skip such lines with a warning and convert the rest, then add what was skipped by hand. |
| Can I keep some diagrams as Mermaid? | Yes. A fence that is not converted stays as it was, and GitHub keeps drawing it. |
| Does the converter call a model or the network? | No. It is plain code. It does not fetch URLs, read files, or run anything from the diagram. |
| What are the size limits? | 50,000 characters, 300 nodes, 600 edges, and 24 levels of nesting for one diagram. Larger input comes back as an error that says to split it. |
See also
| Doc | Why |
|---|---|
| Writing diagrams | The Plotwork language by example |
| Writing diagrams with an agent | The validate and fix loop, and the one-call workflows |
| Diagrams in Markdown and on GitHub | How a fence becomes a picture |
| Tool reference | convert_mermaid, sync_markdown, and the other tools |
| Language reference | Every word the language accepts, and every diagnostic code |