Skip to content

Agentflow (v12.0.0+) ​

WARNING

Agentflow is in beta. Diagrams start with the agentflow-beta keyword, and the syntax may still change in a backwards-incompatible way before it is declared stable.

An agentflow diagram describes an agentic workflow: the agents that do the work, the flows they run, the tasks and tools inside those flows, and how control and data move between them.

Introduction ​

A flowchart tells you what happens next. An agentflow tells you who is doing it, with which tool, and what contract holds at each step. It keeps the familiar flowchart feel — nodes, arrows, containers — but adds a small vocabulary aimed at describing systems built out of language-model agents:

  • Containers (flow … end) group work and nest to any depth.
  • Shapes carry meaning: a task is not a tool is not a decision.
  • Edges carry meaning: sequence, reference, and failure are three different arrows.
  • Metadata (@{ … }) attaches the non-visual detail — the model, the instruction, the parameter and return types, the connector a tool is bound to.

Basic example ​

Code:
mermaid
agentflow-beta TB
  flow reviewer["Review Agent"]
    changes["Gather changes"]@{ shape: input }
    analyse["Analyse diff"]@{ shape: task }
    lint["run_linter"]@{ shape: tool }
    ok["Clean?"]@{ shape: decision }

    changes --> analyse --> lint --> ok
  end
Ctrl + Enter|

Default theme, look and layout (v12.0.0+) ​

Agentflow diagrams use the redux-color theme and the neo look by default, and are laid out by ELK rather than Dagre. Not every diagram type does — see Per-diagram defaults for the list and for the order in which Mermaid decides.

The same diagram, drawn both ways:

With the defaults ​

Code:
mermaid
agentflow-beta TB
  brief["Release brief"]@{ shape: input }
  flow writer["Drafting Agent"]
    draft["Draft the notes"]@{ shape: task }
    lookup["changelog_search"]@{ shape: tool }
    guide["Tone of voice"]@{ shape: refdoc }
    draft --> lookup
    draft -.- guide
  end
  flow reviewer["Review Agent"]
    check["Check the claims"]@{ shape: task }
    ok["Accurate?"]@{ shape: decision }
    check --> ok
  end
  publish["Publish"]@{ shape: action }
  brief --> writer
  writer --> reviewer
  ok --> publish
Ctrl + Enter|

The previous appearance ​

Both are only defaults, so anything you set yourself wins. Naming the previous theme and look in a diagram's front matter draws it the way Mermaid did before:

Code:
mermaid
---
config:
  theme: default
  look: classic
  layout: dagre
---
agentflow-beta TB
  brief["Release brief"]@{ shape: input }
  flow writer["Drafting Agent"]
    draft["Draft the notes"]@{ shape: task }
    lookup["changelog_search"]@{ shape: tool }
    guide["Tone of voice"]@{ shape: refdoc }
    draft --> lookup
    draft -.- guide
  end
  flow reviewer["Review Agent"]
    check["Check the claims"]@{ shape: task }
    ok["Accurate?"]@{ shape: decision }
    check --> ok
  end
  publish["Publish"]@{ shape: action }
  brief --> writer
  writer --> reviewer
  ok --> publish
Ctrl + Enter|

Passing the same three keys to mermaid.initialize() does it for every diagram on the page, and scoping the theme and look to one diagram type — mermaid.initialize({ layout: 'dagre', agentflow: { theme: 'default', look: 'classic' } }) — does it for that type alone. layout is a top-level option, so it applies to every diagram.

Declaring a diagram ​

Every diagram starts with the agentflow-beta keyword, optionally followed by a direction — TB, TD, BT, LR, or RL.

txt
agentflow-beta LR

Nodes and shapes ​

Nodes are declared exactly as in a flowchart: an id, optionally followed by a label in brackets.

txt
research["Research the topic"]

The shape is chosen with the shape key in an @{ … } block. Agentflow provides domain-facing aliases on top of the standard Mermaid shape names:

AliasMeaningUnderlying shape
taskA unit of work an agent performsroundedRect
toolA callable capability — a function, an API, a subroutinesubroutine
inputData entering the workflowlean-right
decisionA branch pointdiamond
refdocReference material an agent consultslin-doc
actionA side-effecting step — sending, writing, publishinghexagon

Any canonical Mermaid shape name also works, so the aliases are a convenience rather than a restriction.

Code:
mermaid
agentflow-beta LR
  brief["Brief"]@{ shape: input }
  draft["Draft copy"]@{ shape: task }
  spellcheck["spell_check"]@{ shape: tool }
  guide["Style guide"]@{ shape: refdoc }
  publish["Publish"]@{ shape: action }

  brief --> draft --> spellcheck --> publish
  draft -.- guide
Ctrl + Enter|

Edges ​

Agentflow uses three edge operators, each with a distinct meaning:

OperatorSemanticReads as
-->sequenceControl or data flows from source to target
-.-referenceThe source consults the target; no control passes
--xfailureThe failure path out of the source

Labels are written in the middle of the arrow, as in a flowchart:

Code:
mermaid
agentflow-beta TB
  check["Tests pass?"]@{ shape: decision }
  ship["Ship it"]@{ shape: action }
  fix["Fix the build"]@{ shape: task }
  logs["Build logs"]@{ shape: refdoc }

  check -- yes --> ship
  check -- no --> fix
  fix --x check
  fix -.- logs
Ctrl + Enter|

Chained edges work too: a --> b --> c.

Containers ​

A flow … end block groups nodes into a container. Containers nest, and a node referenced inside a container belongs to it.

Code:
mermaid
agentflow-beta TB
  flow team["Content Team"]
    flow researcher["Researcher"]
      gather["Gather sources"]@{ shape: task }
    end

    flow writer["Writer"]
      compose["Compose draft"]@{ shape: task }
    end

    researcher --> writer
  end
Ctrl + Enter|

The global block ​

Sometimes a node is shared by several flows and should not be pulled into whichever one happens to mention it first. Declare it inside a global … end block and it stays at the top level no matter where it is referenced:

Code:
mermaid
agentflow-beta TB
  global
    corpus["Shared corpus"]@{ shape: refdoc }
  end

  flow summariser["Summariser"]
    summarise["Summarise"]@{ shape: task }
    summarise -.- corpus
  end

  flow indexer["Indexer"]
    index["Build index"]@{ shape: task }
    index -.- corpus
  end
Ctrl + Enter|

global takes no id, label, or metadata, renders nothing itself, and may appear anywhere in the diagram — including nested inside a flow, as an escape hatch.

Collapsing a container ​

@{ view: collapsed } folds a container down to a single summary node while keeping its edges. Edges that crossed the boundary terminate at the collapsed node instead of disappearing.

Code:
mermaid
agentflow-beta TB
  flow intake["Intake"]
    receive["Receive request"]@{ shape: input }
  end

  flow processing["Processing"]
    validate["Validate"]@{ shape: task }
    enrich["Enrich"]@{ shape: task }
    validate --> enrich
  end
  processing@{ view: "collapsed" }

  flow output["Output"]
    publish["Publish"]@{ shape: action }
  end

  receive --> validate
  enrich --> publish
Ctrl + Enter|

Metadata ​

Any node, edge, or container can carry an @{ … } block. The contents are YAML, so both the single-line form and a multi-line block work:

txt
researcher@{ model: "claude-sonnet-4-20250514", instruction: "Research and cite sources." }
txt
fetch@{
  shape: tool
  params: "city :: String"
  returns: "Report"
  retry: 2
}

Mermaid itself acts on a small, fixed set of keys:

KeyApplies toEffect
shapenodesSelects the node shape (see the table above)
label, labelTypenodesOverrides the node's label and how it is parsed
viewcontainerscollapsed folds the container down to a summary node
algorithmcontainersPer-container ELK algorithm
curve, animate, animationedgesEdge interpolation and animation

Everything else is carried through untouched and surfaced to consumers, so the vocabulary below is a convention rather than a closed list — an unknown key is preserved, never rejected.

The one exception is prototype-shaped keys: __proto__, constructor, and prototype are stripped from parsed metadata, at every level of nesting. They are dropped rather than carried so that a consumer merging node.metadata into its own object cannot be made to pollute a prototype.

KeyApplies toPurpose
descriptionanythingFree-text description
instructionagents, flowsThe system prompt or standing instruction
modelagents, flowsThe model the agent runs on
paramstools, containersInput contract, e.g. "city :: String"
returnstools, containersOutput contract
valueinput nodesA concrete value
exampleinput nodesAn example value
connectorReftools, actionsThe connector capability this node is bound to

Connectors ​

A connector describes an external system a tool talks to. Declare it with the connector keyword and configure it with metadata; tools then point at one of its capabilities with connectorRef.

Code:
mermaid
agentflow-beta LR
  connector github["GitHub API"]
  github@{ protocol: "http", endpoint: "https://api.github.com" }

  title["Issue title"]@{ shape: input }
  create["create_issue"]@{ shape: tool, connectorRef: "github.create_issue" }

  title --> create
Ctrl + Enter|

A connectorRef value may be a bare node id, a dotted connector.capability form, or a URL. The dotted and URL forms are treated as opaque.

A worked example ​

Code:
mermaid
agentflow-beta TB
  connector llm["LLM API"]
  llm@{ protocol: "http", endpoint: "https://api.example.com/chat" }

  flow coffee_team["Coffee Team"]
    city["city"]@{ shape: input, value: "Stockholm" }

    flow researcher["Researcher"]
      research["research_location"]@{ shape: tool, params: "city :: String", returns: "Report" }
      write["write_copy"]@{ shape: tool, connectorRef: "llm.chat", returns: "CoffeeCopy" }
      city --> research --> write
    end
    researcher@{ instruction: "Research the city and draft English coffee copy citing sources." }

    flow designer["Designer"]
      render["generate_html"]@{ shape: tool, connectorRef: "llm.chat", returns: "String" }
      brand["Nordic Brand Guide"]@{ shape: refdoc }
      render -.- brand
    end

    researcher --> designer
  end
Ctrl + Enter|

Configuration ​

Agentflow has its own config namespace, so it can be tuned without moving flowcharts on the same page.

OptionDescriptionDefault
titleTopMarginMargin above the diagram title25
diagramPaddingPadding around the diagram as a whole, in pixels8
nodeSpacingSpacing between nodes on the same level50
rankSpacingSpacing between nodes on different levels50
useMaxWidthScale the diagram to the available widthtrue
Code:
mermaid
---
config:
  agentflow:
    nodeSpacing: 70
    rankSpacing: 70
---
agentflow-beta TB
  a["A"] --> b["B"]
Ctrl + Enter|

Theme variables ​

Containers are themed with flowContainerStroke, defined by every theme mermaid registers; it falls back to secondaryBorderColor when unset. Everything else on an agentflow diagram uses the standard node, edge, and cluster theme variables.

Layout ​

Agentflow renders through the unified renderer, so it works with any registered layout engine. ELK is the default, and an individual container can also select its own ELK algorithm:

Code:
mermaid
---
config:
  layout: elk
---
agentflow-beta TB
  flow tools["Tools"]
    a["a"]@{ shape: tool }
    b["b"]@{ shape: tool }
  end
  tools@{ algorithm: "elk.rectpacking" }
Ctrl + Enter|

For tool builders ​

Two accessors on the diagram DB are meant for programs rather than people:

  • getSemanticModel() returns the diagram with presentation-only controls (view, class, style, icon, img, w, h) stripped, so downstream consumers get a stable semantic view that does not shift when someone restyles the diagram.
  • getDiagnostics() returns structured warnings — unresolved references, misapplied metadata keys, containment violations, unsatisfied capability requirements — each with a source position. Diagnostics are warnings; they never block a render.
Opens in mermaid.ai