Make sequence diagrams from text

Treasure Hunt AppUserWebAppTreasureAPIGeoServiceMapDBSearch nearby lootGET /treasures?nearbyresolve locationlat/longFind within 5nm3 resultslocationsShow treasure mapcheck locationrank by distanceTierClientServiceData
sequence Treasure Hunt App

tag Tier as t
  Client green
  Service blue
  Data red

User
WebApp t: Client
TreasureAPI t: Service
GeoService t: Service
MapDB t: Data

User -Search nearby loot-> WebApp
WebApp -GET /treasures?nearby-> TreasureAPI
TreasureAPI -resolve location-> GeoService
GeoService -lat/long-> TreasureAPI
note
  - check location
  - rank by distance
TreasureAPI -Find within 5nm-> MapDB
MapDB -3 results-> TreasureAPI
TreasureAPI -locations-> WebApp
WebApp -Show treasure map-> User

Two things are happening here. Shapes are inferred from namesUser becomes a stick figure and MapDB a cylinder, while WebApp, TreasureAPI, and GeoService fall through to the default rectangle. And the Tier tag group adds color — each participant is shaded by layer (client, service, data), so a request’s path through the stack reads at a glance. The human User stays neutral, outside the system tiers.

Overview

A sequence diagram shows how participants exchange messages over time, ordered top to bottom — the standard way to trace a request, a protocol, or an interaction between services or actors. Reach for it when the point is which system is talking to which, and in what order.

When to use

  • sequence — the boxes are parties sending messages to each other, and the order of the exchange is the story.
  • flowchart — the boxes are actions rather than parties, and who performs them doesn’t matter.
  • swimlane — you’re showing work handed off down a chain of teams rather than a back-and-forth conversation.
  • infra — you’re modelling sustained traffic volume across components rather than tracing one request.
  • version-control — the lines are branches splitting and merging in a commit history, not messages between parties.

The sequence diagram uses an inference-driven syntax. Just write messages between participants and Diagrammo automatically:

  • Creates participants from their first mention — no declarations needed
  • Infers participant shapes from naming conventions — User gets a stick figure, OrderDB gets a cylinder, Kafka gets a horizontal pipe
  • Tracks activation bars from call stacks

No end keywords are needed — blocks are scoped by indentation.

Syntax

sequence Diagram Title
autonumber
no-activations

== Section Label ==

A -message-> B
A ~async message~> B

if condition
  A -message-> B
else
  A -alternative-> C

loop description
  A -retry-> B

Settings

KeyDescriptionDefault
chartsequence (inferred from -> content)Optional
autonumberPrefix authored messages with stable source-order numbersoff
no-activationsHide activation bars (on by default)off
active-tagGroup to color by (first declared is active by default; none suppresses)first group

Participants

Automatic Type Inference

Participants are created automatically when first mentioned in a message. Their shape is inferred from the name — just use descriptive names and Diagrammo does the rest:

User -createOrder-> OrderService
OrderService -save-> OrderDB
OrderService -cache result-> Redis
OrderService ~publish event~> EventBus

This creates five participants, each with a different shape — no declarations needed.

The inference rules are checked in priority order (first match wins). An explicit declaration overrides them; automatic matches then run database → cache → queue → actor, so a name such as AdminDB is a database rather than an actor:

TypeShapeNaming Patterns
databaseCylinderNames ending in DB; Database, Store, Storage, Repo, Postgres, MySQL, Mongo, Dynamo
cacheDashed cylinderCache, Redis, Memcache, KeyDB, Dragonfly, Hazelcast, Valkey
queueHorizontal cylinderQueue, Kafka, RabbitMQ, EventBus, SQS, SNS, PubSub, Topic, Stream, Broker
actorStick figureUser, Customer, Admin, Guest, Visitor, Operator, Alice, Bob, Charlie
defaultRectangleAnything unrecognized

Inference is intentionally narrow — only names whose role is unambiguous at a glance get a distinctive shape. Anything else (services, gateways, UI, third-party providers) falls through to the default rectangle.

Explicit Declarations (Optional)

You only need explicit declarations when you want to override the inferred type, set a display alias, or control position:

// Override type when the name doesn't match conventions
Vault is a database

// Multi-word names are accepted directly — no aliasing needed
"Order History" is a database

// Control left-to-right ordering
OrderDB position: -1

Quote a participant name that contains spaces. Messages then refer to it by the same quoted name:

Order HistoryUserOrderHistoryServicefetch past orders
sequence Order History

"Order History Service" is a database

User -fetch past orders-> "Order History Service"

as <alias> needs same-line metadata to take effect. The alias is only peeled off when the declaration also carries key: value metadata — Svc as s env: Prod works, but a bare Svc as s is discarded with an Unexpected line warning and creates no participant. Until that is fixed, quote the full name instead of aliasing it.

The old keywords service, frontend, networking, gateway, and external are no longer participant types. A line such as Vault is a service is accepted without a diagnostic but does not declare the intended typed participant. Drop the is a clause and let the name render as the default rectangle.

Participant Ordering

Participants are laid out left-to-right based on first appearance in messages — the first participant mentioned gets the leftmost column.

Position values:

  • 0 = leftmost, 1 = second from left, etc.
  • -1 = rightmost, -2 = second from right
  • If two participants target the same slot, the later one shifts to the nearest free position

Groups affect ordering: members of the same group always stay adjacent (see Groups below). The group is placed where its first member would naturally appear.

Priority (highest wins):

  1. Explicit position: N
  2. Group adjacency
  3. First appearance in messages
// Example: force the database to the far right
sequence
User -placeOrder-> OrderService
OrderService -save-> OrderDB
OrderDB position: -1

Messages

Call Arrows

A solid arrow from one participant to another:

User -login-> API

Return Arrows

Return arrows are generated automatically from the call stack. When A calls B, a dashed return arrow from B back to A appears once B’s work is done:

User -login-> API
API -query-> UserDB
// Auto-return: UserDB → API (dashed)
// Auto-return: API → User (dashed)

The response heuristic also restyles an authored message that closes the active call as a dashed, muted return arrow. The source arrow remains an authored, numbered message even though it looks like an automatic return.

Async / Fire-and-Forget

No return arrow, no activation on the target — use the ~ arrow:

API ~sendWelcomeEmail~> EmailService
API ~logEvent~> LogService

Self-Calls

A participant calling itself renders as a loopback arrow:

OrderService -validate-> OrderService

Message Numbers

Add autonumber before the first participant or message when people need to refer to individual interactions in a review or discussion:

Sign InBrowserAppIdentityProvider1. submit credentials2. verify3. accepted4. signed in
sequence Sign In
autonumber

Browser -submit credentials-> App
App -verify-> IdentityProvider
IdentityProvider -accepted-> App
App -signed in-> Browser

Every message written in the source gets its source-order number. A message without a label shows the number by itself. Returns that Diagrammo infers automatically are not numbered because there is no source line to refer to.

Numbers identify the authored message rather than its current visible position. If folding a participant group hides an internal message, the remaining numbers can skip; they do not change underneath a discussion that already refers to “message 6.”

Blocks

Blocks use indentation for scoping — no end keyword needed.

If / Else

if user authenticated
  API -getOrders-> OrderService
  OrderService -query-> OrderDB
else
  API -401 Unauthorized-> User

Renders as a dashed frame with an if label and an optional else divider.

Add else if <condition> for additional branches. Each one gets its own labeled divider, and a bare else may close the chain:

PaymentUserAPIPaymentGatewayif card acceptedelse if card expiredelseSubmit paymentchargeAsk for a new cardPayment declined
sequence Payment

User -Submit payment-> API

if card accepted
  API -charge-> PaymentGateway
else if card expired
  API -Ask for a new card-> User
else
  API -Payment declined-> User

else never takes a label of its own — write else if <condition> instead. elif is not a keyword.

Loop

loop retry up to 3 times
  OrderService -request-> ExternalAPI

Parallel

parallel send notifications
  API ~email~> EmailService
  API ~text~> SMSService

Blocks can nest inside each other. Unindent to end a block.

Notes

Add context between messages with note:

User -POST /login-> API
note Validates credentials against LDAP
API -query-> UserDB

The note appears between the two surrounding messages, attached to the sender of the message above it.

Positioning a note

Add left of or right of plus a participant name to attach the note to a specific lifeline:

LoginUserAPIUserDBPOST /loginqueryValidates credentialsagainst LDAPWaits for the redirect
sequence Login

User -POST /login-> API
note right of API Validates credentials against LDAP
API -query-> UserDB
note left of User Waits for the redirect

left and right may also be written without of (note right API ...). With neither, the note attaches to the sender of the preceding message and sits on its right.

Multi-line notes

Leave the text off the note line and indent the body underneath. Every indented line belongs to the note, including bulleted lists:

Treasure LookupTreasureAPIGeoServiceMapDBresolve locationlat/longFind within 5nmcheck locationrank by distance
sequence Treasure Lookup

TreasureAPI -resolve location-> GeoService
GeoService -lat/long-> TreasureAPI
note
  - check location
  - rank by distance
TreasureAPI -Find within 5nm-> MapDB

The positioning keywords work on a multi-line head too — note right of API on its own line, body indented below.

Sections

Full-width horizontal dividers to organize phases. In the app each section is a fold button. Folding it replaces the messages with a capsule labelled Name (N messages), a dashed reach line, and per-participant traffic marks:

== Authentication ==

User -login-> API

== Data Fetch ==

API -query-> OrderDB

== Response ==

API -results-> User

Groups

Organize participants into labeled boxes in the header:

[Backend]
  OrderService
  PaymentService
  OrderDB

[Frontend]
  WebApp
  MobileApp
  • [Name] declares a named group
  • Indented names belong to the group
  • Grouped participants stay adjacent in the layout
  • Groups can carry tag metadata: [Backend] team: Product

Add the bare collapsed flag to start a group folded — its members render as one column and their messages re-target it:

CheckoutUserSubmit paymentchargerecord
sequence Checkout

[Backend] collapsed
  OrderService
  PaymentGateway
  OrderDB

User -Submit payment-> OrderService
OrderService -charge-> PaymentGateway
OrderService -record-> OrderDB

Collapsed groups also remove member names from the drawing. Messages between two members become labelled self-call loopbacks on the folded group, which gains a collapse bar and toggle.

Participant labels wrap at camelCase boundaries. Cards cap at 225px wide and ellipsize text that still does not fit.

Activation Bars

Thin vertical rectangles on lifelines show when a participant has an active call. They are computed automatically from the call stack:

  • Appear from call arrow to auto-generated return
  • Nested calls show overlapping bars
  • Self-calls show offset overlapping bars
  • Disabled with no-activations

Comments

// This is a comment
// Use // for all comments

Lines starting with // are ignored by the parser.

Tags

Tags add color-coded metadata dimensions to sequence diagrams. Define a tag group, list its values with colors, then attach values to participants, messages, and groups with same-line key: value metadata.

Defining Tag Groups

tag Concern as c
  Caching blue
  Auth green
  BusinessLogic purple default
  • tag Name declares a tag group; alias x adds a shorthand
  • Each entry: Value color — named color trails the value (lowercase)
  • default on an entry applies it to untagged elements when the group is active

Attaching Tags

Use key: value after participant declarations, message lines, or group headers:

API concern: Caching
User -login-> API concern: Auth
[Backend] concern: BusinessLogic
  OrderAPI
  DB
  • Multiple tags are allowed only for declared tag-group names (or their aliases). Arbitrary keys such as team: Platform warn as unknown metadata unless a Team tag group was declared.
  • Aliases work: c: Caching (if tag Concern as c was declared)

Tag Resolution

When a tag group is active, colors are resolved in priority order:

  1. Explicit metadata on the element
  2. Group propagation (participant inherits from its group)
  3. Receiver inheritance (all incoming tagged messages agree on the same value)
  4. default entry value
  5. Neutral (no color)

Legend

A legend is rendered automatically above participants when tag groups exist. The active group expands to show colored entry dots. In the desktop app, click a group pill to activate it — participants and messages recolor to show that dimension.

The first declared group is active by default. Set active-tag GroupName to activate a different group on load, or active-tag none to suppress coloring.

Complete Example

E-Commerce CheckoutBackendUserWebAppOrderServicePaymentGatewayOrderDBEmailServiceif payment successfulelseloop expire stale carts1. Add items to cart2. validateCart3. Submit payment4. createOrder5. charge(amount)6. saveOrder7. sendReceipt8. Order confirmed9. Payment declined10. purgeExpiredLayerFrontendBackendStorage
sequence E-Commerce Checkout
autonumber

tag Layer as l
  Frontend teal
  Backend blue
  Storage purple

[Backend]
  OrderService
  PaymentGateway
  OrderDB

== Browse & Select ==

User -Add items to cart-> WebApp
WebApp -validateCart-> OrderService

== Payment ==

User -Submit payment-> WebApp
WebApp -createOrder-> OrderService
OrderService -charge(amount)-> PaymentGateway

if payment successful
  OrderService -saveOrder-> OrderDB
  OrderService ~sendReceipt~> EmailService
  WebApp -Order confirmed-> User
else
  WebApp -Payment declined-> User

== Cleanup ==

loop expire stale carts
  OrderService -purgeExpired-> OrderDB

Appearance

Every chart accepts the universal appearance directives:

DirectiveEffect
fill-tintSoft tinted fills (default).
fill-solidSaturated solid fills.
fill-outlineOutline only, no fill.
no-titleHide the title line.
no-legendHide the legend.

Colors come from the active palette — see Colors. Set the palette and light/dark theme at render time with --palette <name> and --theme light|dark|transparent.

Common mistakes

  • elif is not a keyword, and else never takes a label of its own — the surrounding sections of this guide cover the shapes that do work.
  • A <- B is not a distinct arrow. Write the message in the direction it travels: B -> A.
  • Indentation inside a block is structural, not cosmetic. Adding a level to make something line up moves it into a different block.
  • Anything that renders but looks wrong: Troubleshooting is organised by symptom.

Next