Skip to content

CLI reference

diago is one binary with four verbs. Every verb reads a spec and writes its result to stdout; warnings and errors go to stderr. Getting started shows them in use.

Verb Does
diago render [flags] [SPEC] Draws one spec in the chosen format.
diago diff [flags] PATH Draws the latest change of a file kept in git.
diago diff [flags] OLD NEW Draws one picture of what changed between two specs.
diago check [-strict] [-json] [SPEC] Prints advisories without laying anything out.
diago import [SPEC] Translates a Mermaid source into a diago JSON spec.
diago help [verb] Prints the usage, or a verb’s usage and flags.
diago --version Prints the installed version: a release tag such as v0.5.0, the commit it was built from, or (devel) when the binary carries no version.

Every call names its verb. diago spec.json and diago -format text spec.json are errors that print the usage (exit 2), with a did you mean: diago render … hint when the word looks like a spec. Help you ask for goes to stdout with exit 0: diago -h, --help or help print the usage, and diago help <verb> or -h/--help on a verb print that verb’s usage and flags. A bad flag prints its error and the verb’s usage on stderr, exit 2. diago --version (or diago version) prints diago <version>.

A SPEC is a path, - or nothing (stdin, for render, check and import; diff reads files only), or REV:PATH: the file as it was at a git revision, such as HEAD~1:arch.json, v1.2:arch.json or a commit hash. PATH is relative to the current directory, and the repository is the one that contains it; a name that exists on disk is always read as a file. Reading a revision needs git on PATH, and a symbolic link at that revision is refused: git keeps the link’s text, not the spec it points to. With one PATH, diff draws that file’s latest change: the newest version committed along first parents from HEAD, following renames, whose content differs from the file on disk, against the file on disk.

A Mermaid file renders as it is: diago render diagram.mmd. Mermaid sources are accepted wherever a spec is. A path ending in .mmd or .mermaid, or a body whose first meaningful line is flowchart, graph, sequenceDiagram or classDiagram, is translated before parsing. This holds for render, check, both arguments of diff and the -previous argument. Constructs diago cannot carry are translated to their nearest form and reported on stderr; statements with no meaning in diago fail with a line number. The mapping is under diago import.

Flags may come before, between or after the paths, on every verb: diago render spec.json -format text and diago render -format text spec.json are the same call. A -- ends the flags.

Flag Default Notes
-format svg svg, png, text (alias txt), drawio, excalidraw (the last two in beta). An unknown value is an error, never a silent fallback.
-theme the spec’s theme, else default default, dark, midnight, sketch, or a theme file in DIAGO_THEME_DIR. Overrides the spec’s field. Text art takes no theme, but the name must still load. An unknown name is an error.
-scale 2.0 PNG only. Ignored when -width is set.
-width none PNG width in pixels. Overrides -scale.
-previous none Anchors the layout on an earlier render, so the nodes that survive an edit stay close to where they were. Flow and class only. See Anchoring on a previous render.
-debug off Writes one JSON line per layout decision to stderr. See Debug logging.
Flag Default Notes
-format svg svg, png, text (alias txt). drawio and excalidraw are not available for a diff.
-theme the new spec’s theme, else default The old spec’s theme field is not read.
-scale 2.0 PNG only. Ignored when -width is set.
-width none PNG width in pixels. Overrides -scale.
-debug off JSON Lines layout decisions on stderr.

diff has no -previous: for a flow or class diagram it always anchors the union of the two specs on the old layout. A sequence diff is not anchored.

Flag Default Notes
-strict off Exit 1 when any finding remains after the spec’s ignore list.
-json off Print {"warnings": [...]} instead of one line per finding.

check validates the spec as render does, the theme it names included, and exits 1 on an error. It never lays a diagram out, so three findings appear only on render and diff: text-label-dropped and flat-edge-ranked, which come from the layout, and edge-without-id, which only render -previous and diff report, since only they match elements by id. The advisories page lists every rule.

import takes no flags, only an optional path. It writes the JSON spec to stdout and report lines to stderr.

Format render diff Types
svg yes (default) yes (default) flow, sequence, class
png yes yes flow, sequence, class
text or txt yes yes flow, sequence, class
drawio beta yes no flow only
excalidraw beta yes no flow only

PNG is the SVG rasterized by resvg, which must be installed (see Environment variables). Without it -format png fails with an install hint and the other formats still work. A PNG is 2.0 times the SVG’s size unless -scale or -width says otherwise.

draw.io and Excalidraw output is in beta, not fully tested yet: check the file before relying on it. It is derived from the laid-out flow model, never from the SVG. Asking for either on a sequence or class spec is an error: error: render: drawio format is not supported for sequence diagrams, exit 2.

Text art lays the diagram out under its own profile: every position snaps to a character cell, so node positions differ from the SVG’s even though both are orthogonal. An edge label sits on the row next to a wire that runs along its row, and may be written over a group frame’s left or right side when nothing nearer is free. A label that cannot be placed without overwriting other ink is dropped and reported as the text-label-dropped advisory.

-previous keeps the nodes that survive an edit close to where they were, instead of laying the whole diagram out from scratch. It takes any of:

  • an SVG that diago rendered: it carries its layout in a <metadata id="diago-layout"> element, which is the exact anchor;
  • that layout carrier as a JSON file on its own;
  • the previous spec, which is laid out fresh the way the new render is (under the text profile for -format text, else under the theme’s screen profile), so anchoring on an unchanged spec draws what a fresh render draws.

An SVG from an older diago anchors as a best effort. The carrier lists ids only, never labels. -previous anchors flow and class specs, and a previous spec’s type must match the spec being rendered. A sequence diagram has no layout to anchor: its render checks that the file is an SVG, a carrier or a sequence spec, ignores it and warns -previous ignored.

Each version anchored on the render before it:

Terminal window
diago render hello.v1.json > v1.svg
diago render -previous v1.svg hello.v2.json > v2.svg

When a flat edge falls back to an ordinary edge, the carrier records it, and every render anchored on that carrier keeps the edge ordinary: its flat-edge-ranked warning then says it was kept, not that no side route exists. A render without -previous tries the side route again and decides fresh.

A render or diff that has not finished its layout and drawing after 10 seconds is cancelled and fails. The limit applies to every invocation, and check and import do not lay anything out. Each git call made to read a REV:PATH has its own 10 seconds. It prints error: the render took longer than 10s and was stopped: split the diagram or simplify it and exits 2.

Code Meaning
0 Success. Advisories and import reports do not change it.
1 The spec is invalid: not JSON, a missing or unknown type, a field of the wrong JSON type, a validation error, a rejected Mermaid line, or, for check -strict, a finding that survived the ignore list.
2 A usage or internal error: an unknown verb or format, a missing file, a git failure reading REV:PATH, a render that fails or runs past 10 seconds, output that cannot be written to stdout.

A validation error is structured JSON on stderr with a field that names the path into the spec. This is diago render on a spec whose node has the shape oval:

{
"error": {
"type": "validation_error",
"errors": [
{
"field": "nodes[1].shape",
"message": "unknown shape \"oval\""
}
]
}
}

A spec that is not JSON at all has the field "" (in a diff, before or after). Several errors are collected and returned together. For diff, a field is prefixed before. or after.. For check -strict, exit 1 means findings survived the ignore list; the output is the findings, not a JSON error.

  • Advisories, on render and diff: warning: <rule> <field>: <message>, or warning: <rule>: <message> for a finding about the whole diagram. check prints the same lines without the warning: prefix, on stdout.
  • Import reports: warning: import line <n>: <message>. With two inputs the line names the side: warning: import (before) line <n>: <message>, (after) or (previous).
  • A rejected Mermaid line: diago <verb>: line <n>: <message>, exit 1.
  • Anything else that fails: error: <message>, exit 2.
  • With -debug, JSON Lines on stderr as well.

Without -debug, stderr stays empty on a clean render.

Terminal window
diago import diagram.mmd > spec.json # JSON on stdout, report lines on stderr
diago import < diagram.mmd | diago check

The dialect is sniffed from the header. The output is the JSON an agent would have written: two-space indent, edge ids left out for diago to derive, rect left out. Exit 1 on a rejected line (plain text, with the line number) or on a non-Mermaid input; exit 0 otherwise, even with report lines.

Flowchart (graph or flowchart, with TD, TB, LR, BT or RL):

  • Every node bracket form; the links -->, ---, -.->, -.-, ==>, === and <-->, with |label| or -- label -->; a trailing ;; & fan-out; chains; nested subgraph … end (a fourth level is flattened into its depth-3 ancestor and reported); a title: frontmatter.
  • Translated and reported: stadium and subroutine shapes become rounded and rect, doublecircle and trapezoid become circle and parallelogram.
  • Rejected: classDef, class, style, linkStyle, click, accTitle, accDescr, direction, and an edge whose endpoint is a subgraph.

Sequence (sequenceDiagram):

  • participant and actor with as, implicit declaration on first use; the arrows ->>, -->>, -) and --); loop, opt, alt/else, par/and and break blocks, nested, become fragments over interaction ranges.
  • Translated and reported: actor renders as a participant; + and - marks and activate/deactivate lines are ignored, because diago computes the activation bars; a Note is folded into the label of the nearest preceding message in its block, and dropped when there is none; an empty branch or block is dropped.
  • Rejected: critical, autonumber, create, destroy, rect, box, link, links, properties, details, and lost-message arrows (-x).

Class (classDiagram):

  • class X~T~ { … } blocks and bare declarations, <<stereotype>> inside a block or on its own, X : +member inline members, visibility prefixes, * abstract and $ static suffixes, ~T~ generics, all twelve relation operators with cardinalities and labels (the JSON is written with from as the subtype, implementer, owner or dependent), and direction TB|LR|BT|RL.
  • Rejected: <-->, ()--, note, namespace, cssClass and click.
Variable Description
DIAGO_RESVG_PATH Path to the resvg binary, overriding the PATH lookup. PNG only.
DIAGO_THEME_DIR Directory searched for theme files whose name is not built in. A theme name is a plain file name, never a path. Built-in themes always win. See Theme file.

These are the only two.