The diagram language: write what connects to what and Kribble draws it. Flowcharts, architecture, activity, use case, sequence and class diagrams
A diagram is a drawing you write as text. You say what connects to what, one fact per line, and Kribble lays it out and draws it in the same hand-drawn style as a drawing. There are no coordinates in the text: Kribble does the layout, and you can still drag things around afterwards.
To add one, type /diagram in a note, or write a fenced block with the diagram language in markdown. The block has two views, switched at its top:
Text shows the text next to the live drawing, beside it or above it, whichever shows the drawing bigger. Every change you type redraws it. Drag the bar between the two to give either more room; Kribble remembers this per browser, and double-clicking the bar puts it back.
Draw is the drawing. Shapes and arrows you add, delete, rename or restyle there are written back into the text.
There are three kinds of diagram. The kind goes after diagram in the fence, or in the block's menu:
Fence | For |
|---|---|
| flowcharts, architecture, activity and use case diagrams |
| sequence diagrams |
| class diagrams |
These rules hold in every kind of diagram.
One line, one fact. A -> B connects A to B. A line with just a name adds that box on its own.
Names are the boxes. A name is any text up to an arrow, a comma, a colon or a bracket. Spaces are fine and need no quotes: Notes service -> Search index. Extra spaces inside a name don't count, and capitals do: api and API are two boxes. To use a comma, colon or bracket in a name, put the name in double quotes: "Sales, EMEA".
Chains and fan-out. A -> B -> C is two arrows. Queue -> Mailer, Billing is an arrow to each, and Web, Mobile -> API is an arrow from each.
Labels. Text after a colon labels the last arrow on the line: API -> Postgres: reads and writes. In a fan-out, every arrow of the last step gets the label.
Comments. A # followed by a space starts a comment, at the start of a line or after a space: # the read path. A # directly followed by text is a colour (see below), or part of a label.
Indentation makes blocks: groups, lanes, class members and the bodies of alt and loop. A block holds the lines indented more than the line that opens it. Two spaces per level is the convention.
Settings go on lines of their own, usually at the top:
direction: down, right, up or left: which way arrows flow. The default is down.
look: hand-drawn or look: clean: the hand-drawn style (the default) or straight lines.
Write | Draws |
|---|---|
| an arrow |
| a dashed arrow |
| an arrow with an open head (in sequence diagrams, an async message) |
| a line |
| a dashed line |
| an arrow both ways |
| an arrow from B to A |
| a thick arrow |
| inheritance: a hollow triangle at B |
| realization: dashed, a hollow triangle at B |
| composition: a filled diamond at the |
| aggregation: a hollow diamond at the |
| dependency: dashed with an open head |
| a dashed arrow labelled «include» |
| a dashed arrow labelled «extend» |
In class diagrams, extends and implements put the parent above the child, the way class diagrams are usually drawn.
End labels (multiplicities and roles) are quoted text right next to the arrow: Order "1" *-- "1..*" Line item writes 1 at the Order end and 1..* at the Line item end. Either one can be left out.
Square brackets after a name set its shape and style. They can follow the name anywhere it appears, or stand on a line with the name alone. Separate several with commas or spaces: Postgres [cylinder, blue].
Shape | Looks like |
|---|---|
| a rectangle with rounded corners (the default) |
| a rectangle with square corners |
| an ellipse |
| a diamond |
| a database cylinder |
| a cylinder lying on its side |
| a cloud |
| a page with a wavy bottom edge |
| a stick figure with the name below |
| a note with a folded corner |
| a UML component |
| a UML package (a box with a tab) |
| just the text, no border |
| a use case (an ellipse) |
| activity start, end and flow-end nodes |
| an activity action (rounded box) |
| a decision diamond |
| a fork/join bar |
| an object node (a rectangle) |
Colours are red, orange, yellow, green, teal, blue, purple, pink and gray, or a hex colour like #0ea5e9. They colour the border and text and give a light fill. A colour can also be written straight after a name as #red. The styles dashed, dotted and thick change the border.
An unknown shape or colour is reported on its line, with the nearest known name, and the box is drawn as a plain box.
A name followed by a colon opens a group, and the indented lines below it are its contents. A box belongs to the group where it starts an arrow or stands on a line of its own. A box that's only ever at the end of arrows belongs to the first group that mentions it. So Web app -> API gateway inside Frontend can point at a box that belongs to Backend. Groups can nest, take a style in brackets before the colon, and have arrows of their own.
A short group fits on one line: Workers: Mailer, Indexer is a group with two boxes in it. Shop [boundary]: draws a use case system boundary, and Geometry [package]: a UML package.
Activity diagrams are flowcharts with a few special names:
start and end are the start and end nodes. Write them in lowercase.
A name ending in ? is a decision diamond: In stock?.
fork and join are bars where the flow splits and joins. Number them when there are several: fork 2, join 2.
Labels on arrows out of a decision are its guards: In stock? -> Ship: [yes].
Swimlanes: lane Name: followed by indented lines puts those boxes in a lane, and lane Name: A, B is the short form. Boxes join lanes the way they join groups. All lanes of a diagram form one pool, side by side, and the flow goes down. A box that isn't in any lane joins the lane of the first box it connects to. Swimlanes can't be combined with groups.
Actors, use cases and a system boundary:
Start the fence with ```diagram sequence. Each line is a message, top to bottom. Participants appear left to right in the order they're first mentioned. To fix the order, or to draw a participant as a stick figure, declare it first: participant API, actor User.
Write | Draws |
|---|---|
| a call: a solid line with a filled head |
| an async message: an open head |
| a return: dashed with an open head |
| a message to itself, looping back |
| creates B: B's box appears at this message |
| a note over A (or |
A call that is answered by a later return from the same participant gets an activation bar between the two. Calls inside it nest.
Fragments group messages: alt condition, then else condition for each other case, opt condition, loop condition, par and and, break condition and critical. The messages inside are indented. An end line is accepted but not needed.
Start the fence with ```diagram class. A class name on its own line, followed by indented members, is a class: one member per line, written however you like. Members with parentheses go in the methods compartment and the others in the attributes compartment. After the name, (abstract) sets the name in italics, (interface) adds «interface», and (enum) adds «enumeration».
Relationships use the arrows above: extends, implements, *--, o--, ..>, -- and ->. Quoted end labels give multiplicities, and the text after the colon names the relationship. package Name: with indented classes draws a package around them.
Writing a class's name again later (Circle above) adds to it: members are collected from every block.
The text never holds coordinates. When you drag a box in Draw, Kribble remembers where you put it. When you change the text later, boxes you didn't touch stay where they are, and new ones are placed around them. Tidy up in the block's menu lays everything out afresh and forgets the positions. Swimlane and sequence diagrams always follow the text exactly, so dragging there doesn't stick: change the order in the text instead.
Things the language can't describe, like freehand strokes, images or a text note, stay in the drawing next to the generated parts. They're kept when you edit the text, but they don't appear in it, so a diagram written into a note from markdown doesn't have them.
Convert to diagram in a drawing's menu turns a drawing of boxes and arrows into a diagram. Labelled shapes become names, arrows between them become lines of text, and everything keeps its place.
In markdown, kribble read and the API, a diagram is the fenced block with its text, exactly as you write it. The positions you dragged things to are kept with the note. Edits through kribble edit, kribble push or an AI agent keep them as long as the block is still there. Exports, PDFs and published sites draw diagrams the way the editor does, and a site's markdown copy for AI agents has the text.
kribble check reports diagram problems with their line numbers, and AI agents get the same warnings when they write a note.
The text editor helps without getting in the way:
Tab and Shift+Tab indent and outdent the line, or every selected line, by two spaces. Focus always stays in the editor.
Enter keeps the indentation, and indents one more level after a line that opens a block, like Backend: or alt ok. Backspace in the indentation removes a whole level.
Suggestions pop up as you type: arrows after a name, shapes and colours inside [, names already in the diagram, and keywords. They never change your text on their own. Press ↓ or ↑ to pick one, then Enter to insert it, or click it. Typing on, or pressing Enter without picking, works as if the popup weren't there. Esc closes it, and the switch at its bottom turns suggestions off (or on again from the block's menu). Kribble remembers this per browser.
Mistakes are underlined with a wavy line, and the message shows when you hover over it. The rest of the diagram still draws.
Long lines wrap instead of running off the edge. The wrapped part is indented under its line, so it doesn't read as a line of its own.