termaid
Render Mermaid diagrams in your terminal or Python app.
Features
- 18 diagram types: flowcharts, sequence, class, ER, state, block, git, gantt, architecture, pie, treemap, mindmap, timeline, kanban, quadrant, XY chart, user journey, and packet
- No dependencies. The core is pure Python
- Fits the terminal width: it tightens spacing first, then wraps labels at word boundaries
- Colored output with Rich and a TUI widget for Textual, as optional extras, with 11 themes
--asciifor terminals without box-drawing characters- Reads from a file or stdin:
cat diagram.mmd | termaid - Draws the Mermaid blocks in a Markdown file, or in Claude Code's replies, in place
Why?
Mermaid is great for documentation, but rendering it usually means spinning up a browser or calling an external service. termaid lets you render diagrams over SSH, in CI logs, inside TUI apps, or anywhere you have a Python environment. I built it because the existing tools in this space, like mermaid-ascii (Go) and beautiful-mermaid (TypeScript), don't offer a native Python library you can import and call directly.
Install
Pip
pip install termaid
Homebrew
brew install termaid
Or try it without installing:
uvx termaid diagram.mmd
Quick start
CLI
termaid diagram.mmd
echo "graph LR; A-->B-->C" | termaid
termaid diagram.mmd --theme neon
termaid diagram.mmd --ascii
termaid --markdown README.md # draw everymermaid block in a document
gh pr view 42 | termaid --markdown
### Pythonpython
from termaid import render
print(render("graph LR\n A --> B --> C"))
python
Colored output (requires: pip install termaid[rich])
from termaid import render_rich from rich import print as rprintrprint(render_rich("graph LR\n A --> B", theme="terra"))
python
Textual TUI widget (requires: pip install termaid[textual])
from termaid import MermaidWidgetwidget = MermaidWidget("graph LR\n A --> B")
## Supported diagram types
Flowcharts
All directions supported: LR, RL, TD/TB, BT.
mermaid
graph TD
A[Start] --> B{Is valid?}
B -->|Yes| C(Process)
C --> D([Done])
B -->|No| E[Error]
┌─────────────┐
│ │
│ Start │
│ │
└──────┬──────┘
│
│
▼
┌──────◇──────┐
│ │
│ Is valid? │
│ │
└──────◇──────┘
│
│
╰──────────────────╮
Yes│ │No
▼ ▼
╭─────────────╮ ┌─────────────┐
│ │ │ │
│ Process │ │ Error │
│ │ │ │
╰──────┬──────╯ └─────────────┘
│
│
▼
╭─────────────╮
( )
( Done )
( )
╰─────────────╯
Node shapes: rectangle [text], rounded (text), diamond {text}, stadium ([text]), subroutine [[text]], circle ((text)), double circle (((text))), hexagon {{text}}, cylinder [(text)], asymmetric >text], parallelogram [/text/], trapezoid [/text\], and @{shape} syntax
Edge styles: solid -->, dotted -.->, thick ==>, bidirectional <-->, circle endpoint --o, cross endpoint --x, labeled -->|text|, variable length --->, ---->
Styling: classDef, style, linkStyle directives, :::className suffix
Subgraphs: nesting, cross-boundary edges, per-subgraph direction override
Other: %% comments, ; line separators, Markdown labels ` "bold italic" , & operator (A & B --> C), entity codes (#quot;, #amp;, #9829;)
Sequence diagrams
mermaid
sequenceDiagram
Alice->>Bob: Hello Bob
Bob-->>Alice: Hi Alice
Alice->>Bob: How are you?
Bob-->>Alice: Great!
┌──────────┐ ┌──────────┐
│ Alice │ │ Bob │
└──────────┘ └──────────┘
┆ Hello Bob ┆
──────────────────►
┆ Hi Alice ┆
◄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄
┆ How are you? ┆
──────────────────►
┆ Great! ┆
◄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄
┆ ┆
mermaid classDiagram class Animal { +String name +int age +makeSound() } class Dog { +String breed +fetch() } Animal <|-- DogMessage types: solid arrow->>, dashed arrow-->>, solid line->, dashed line-->participantParticipants:
,actor, aliasesClass diagrams
┌──────────────┐
│ Animal │
├──────────────┤
│ +String name │
│ +int age │
├──────────────┤
│ +makeSound() │
└──────────────┘
△
│
│
│
┌───────────────┐
│ Dog │
├───────────────┤
│ +String breed │
├───────────────┤
│ +fetch() │
└───────────────┘
mermaid erDiagram CUSTOMER ||--o{ ORDER : places ORDER ||--|{ LINE-ITEM : containsRelationships: inheritance<|--, composition*--, aggregationo--, association--, dependency..>, realization..|>+Members: attributes and methods with visibility (
public,-private,#protected,~package)ER diagrams
┌──────────────┐
│ CUSTOMER │
└──────────────┘
│1
│ places
│
│0..*
┌──────────────┐
│ ORDER │
└──────────────┘
│1
│ contains
│
│1..*
┌──────────────┐
│ LINE-ITEM │
└──────────────┘
mermaid stateDiagram-v2 [*] --> Idle Idle --> Processing : start Processing --> Done : complete Done --> [*]Cardinality:||(exactly one),o|(zero or one),}|(one or more),o{(zero or more)--Line styles: solid
, dashed..PKAttributes: type, name, keys (
,FK,UK), commentsState diagrams
╭───────◯──────╮
│ │
│ ● │
│ │
╰───────◯──────╯
│
│
▼
╭──────────────╮
│ │
│ Idle │
│ │
╰───────┬──────╯
│
start│
▼
╭──────────────╮
│ │
│ Processing │
│ │
╰───────┬──────╯
│
complete│
▼
╭──────────────╮
│ │
│ Done │
│ │
╰───────┬──────╯
│
│
▼
╭───────◯──────╮
│ │
│ ◉ │
│ │
╰───────◯──────╯
mermaid block-beta columns 3 A["Frontend"] B["API"] C["Database"]Features:[*]start/end states, transition labels,state "name" as alias, composite states (state Parent { }), stereotypes (<<choice>>,<<fork>>,<<join>>)Block diagrams
┌──────────┐ ┌──────────┐ ┌──────────┐
│ │ │ │ │ │
│ Frontend │ │ API │ │ Database │
│ │ │ │ │ │
└──────────┘ └──────────┘ └──────────┘
mermaid gitGraph commit id: "init" commit id: "feat" branch develop commit id: "dev-1" commit id: "dev-2" checkout main commit id: "fix" merge develop id: "merge"Features:columns N, column spanning (blockname:N), links between blocks, nested blocksGit graphs
main ───●─────●──────┼──────────────●──────●─
init feat │ fix merge
│ │
develop ●───────●─────────────┼
dev-1 dev-2
mermaid gantt title Project Plan dateFormat YYYY-MM-DD section Design Wireframes :done, des1, 2024-01-01, 2024-01-14 Prototypes :active, des2, 2024-01-08, 2024-01-21 section Development Frontend :dev1, after des2, 30d Backend :crit, dev2, 2024-01-15, 2024-03-01Directions:LR(default),TB,BTcommitCommands:
(withid:,type:,tag:),branch(withorder:),checkout/switch,merge,cherry-pickNORMALCommit types:
(●),REVERSE(✖),HIGHLIGHT(■)%%{init: {"gitGraph": {"mainBranchName": "master"}}}%%Config:
Gantt charts
Project Plan
Design │ Wireframes │░░░░░░░░░░░░░ Prototypes │ ▓▓▓▓▓▓▓▓▓▓▓▓▓ Development │ Frontend │ ██████████████████████████████ Backend │ ███████████████████████████████████████████████ └┬─────────┬─────────┬─────────┬─────────┬─────────┬─────────┬ Jan 01 Jan 11 Jan 21 Jan 31 Feb 10 Feb 20 Mar 01
mermaid pie title Pets adopted by volunteers "Dogs" : 386 "Cats" : 85 "Rats" : 15Tasks:done,active,crit,milestonetags,after iddependencies, durations in Mermaid's units (30d,2w,3M,1.5h,45m,1.2s,406ms)dateFormat YYYY-MM-DD HH:mmTime scales: any span from years to milliseconds.
keeps the time of day,dateFormat xandXread Unix milliseconds and seconds,axisFormat %H:%M(or%S.%L) labels the axis, andtickInterval 6hourplaces the tickspiePie charts
Yes, the syntax says
. No, we don't draw a circle. I know. Have you ever tried to read a pie chart made of█and▓? Exactly. We render them as horizontal bar charts instead.
Dogs┃████████████████████████████████ 79.4%
Cats┃▓▓▓▓▓▓▓ 17.5%
Rats┃░ 3.1%
mermaid treemap-beta "Frontend" "React": 40 "CSS": 15 "Backend" "API": 35 "Auth": 10Features:title,showData(display raw values),%%commentsTreemaps
┌┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┐ ┌┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┐
┆ Frontend ┆ ┆ Backend ┆
┆┌───────────────────────┐ ┌───────┐┆ ┆┌───────────────────┐ ┌────┐┆
┆│ React │ │ CSS │┆ ┆│ API │ │Auth│┆
┆│ 40 │ │ 15 │┆ ┆│ 35 │ │ 10 │┆
┆│ │ │ │┆ ┆│ │ │ │┆
┆└───────────────────────┘ └───────┘┆ ┆└───────────────────┘ └────┘┆
└┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┘ └┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┘
mermaid mindmap Project Design Wireframes Mockups Development Frontend Backend TestingFeatures: nested sections via indentation,"label": valuesyntax, proportional sizing,%%commentsMindmaps
╭─ Design ──╭─ Wireframes
│ ╰─ Mockups
Project ──├─ Development ──╭─ Frontend
│ ╰─ Backend
╰─ Testing
mermaid xychart-beta title "Monthly Revenue" x-axis [Jan, Feb, Mar, Apr, May, Jun] bar [12, 18, 25, 20, 30, 35]Features: indentation-based nesting, automatic overflow to the left when many children, rounded/sharp/ASCII branch characters, Mermaid shape markers stripped ((round),[square],{{hexagon}},)cloud()XY charts
Monthly Revenue
35 │ ████ │ ████ │ ▄▄▄▄ ████ 28 │ ████ ████ │ ▄▄▄▄ ████ ████ │ ████ ████ ████ 21 │ ████ ▄▄▄▄ ████ ████ │ ▄▄▄▄ ████ ████ ████ ████ │ ████ ████ ████ ████ ████ 14 │ ████ ████ ████ ████ ████ │████ ████ ████ ████ ████ ████ │████ ████ ████ ████ ████ ████ 7 │████ ████ ████ ████ ████ ████ │████ ████ ████ ████ ████ ████ │████ ████ ████ ████ ████ ████ 0 └──┬─────┬─────┬─────┬─────┬─────┬─ Jan Feb Mar Apr May Jun
mermaid journey title My working day section Go to work Make tea: 5: Me Go upstairs: 3: Me Do work: 1: Me, Cat section Go home Go downstairs: 5: Me Sit down: 5: MeFeatures: bar charts, line charts, bar+line combos, horizontal orientation (xychart horizontal), axis labels,xychartandxychart-betakeywords, rounded/sharp line corners, JSON ingestUser journeys
My working day
● Cat ◆ Me
╭───────────── Go to work ──────────────╮ ╭───────── Go home ───────────╮
╭◆─────────╮ ╭◆────────────╮ ╭●◆───────╮ ╭◆──────────────╮ ╭◆─────────╮ ─│ Make tea │─│ Go upstairs │─│ Do work │────│ Go downstairs │─│ Sit down │────► ╰──────────╯ ╰─────────────╯ ╰─────────╯ ╰───────────────╯ ╰──────────╯ 😄 😐 😞 😄 😄
Features: sections, satisfaction scores (😞-😄), multi-actor support with distinct symbols (●◆■▲), rounded/sharp/ASCII corners
Packet diagrams
mermaid
packet
0-15: "Source Port"
16-31: "Destination Port"
32-63: "Sequence Number"
64-95: "Acknowledgment Number"
0 15 16 31
╭───────────────────────────────────────────────┬───────────────────────────────────────────────╮
│ Source Port │ Destination Port │
╰───────────────────────────────────────────────┴───────────────────────────────────────────────╯
32 63
╭───────────────────────────────────────────────────────────────────────────────────────────────╮
│ Sequence Number │
╰───────────────────────────────────────────────────────────────────────────────────────────────╯
64 95
╭───────────────────────────────────────────────────────────────────────────────────────────────╮
│ Acknowledgment Number │
╰───────────────────────────────────────────────────────────────────────────────────────────────╯
python from termaid import MermaidWidgetFeatures: bit-aligned field layouts, boundary numbers, auto-increment (+N) syntax, separated boxes per row, truncated label legend with bit ranges,packetandpacket-betakeywords--asciiCLI options
| Flag | Description | |------|-------------| |
| ASCII-only output (no Unicode box-drawing) | |--theme NAME| Color theme (requirespip install termaid[rich]). Use--themesto list | |--themes| List all available color themes | |--demo [TYPE]| Render sample diagrams (all,flowchart,sequence,mindmap, etc.) | |--padding-x N| Horizontal padding inside boxes (default: 4) | |--padding-y N| Vertical padding inside boxes (default: 2) | |--gap N| Space between nodes (default: 4). Use1or2for compact diagrams | |--inline-edge-labels| Attach flowchart labels directly to their edges | |--width N| Max output width. Re-renders with smaller gap/padding, then wraps labels, if exceeded | |--strict-width| Exit with status 2 instead of a warning when the output is still wider than--width| |--max-height ROWS| Exit with status 2 when the output has more thanROWSlines (a check, not a fitting target) | |--no-auto-fit| Disable automatic compaction when diagram exceeds terminal width | |--sharp-edges| Sharp corners on edge turns instead of rounded | |-o FILE| Write output to file instead of stdout | |--show-ids| Show node IDs alongside labels for debugging (e.g.myId: My Label) | |--json TYPE| Pipe JSON/tabular data and render astreemap,pie,mindmap,flowchart, orxychart| |--markdown| Read a Markdown document and draw eachmermaidcode block in place; other text passes through. A block that cannot be drawn is kept as source, with a warning | |--claude-hook| Run as a Claude CodeMessageDisplayhook: read one batch of a reply as JSON on stdin and draw itsmermaidblocks in place (see Claude Code) | |--tui| Interactive TUI viewer (requirespip install termaid[tui]) | |--format FORMAT|text(default) orstyled-json: one JSON document of text chunks tagged with style keys (see Editor and tool integration) | |--diagnostics-format FORMAT|text(default) orjson: print each error and warning on stderr as one JSON line |render(source, ...) -> strPython API
render_rich(source, ..., theme="default") -> rich.text.TextRender a Mermaid diagram as a plain text string. Auto-detects diagram type.
TextRender as a Rich
object with colors. Requirespip install termaid[rich].render_styled(source, ...) -> dict--format styled-jsonRender as theme-independent styled chunks, the same document that
prints (see Editor and tool integration).MermaidWidgetsourceA Textual widget with a reactive
attribute. Requirespip install termaid[textual]. Updates live when you change thesourceproperty.
class MyApp(App): def compose(self): yield MermaidWidget("graph LR\n A --> B")
bash pip install termaid[rich] # Colored terminal output pip install termaid[textual] # Textual TUI widget## Themes--theme11 built-in themes for
/render_rich(). Runtermaid --themesto list them.defaultText themes (foreground colors only):
| Theme | Colors | Description | |-------|--------|-------------| |
| !#00FFFF !#FFFF00 !#FFFFFF | Cyan nodes, yellow arrows, white labels | |terra| !#D4845A !#E8A87C !#F5E6D3 | Warm earth tones (browns, oranges) | |neon| !#FF00FF !#00FF00 !#00FFFF | Magenta nodes, green arrows, cyan edges | |mono| !#FFFFFF !#AAAAAA !#666666 | White/gray monochrome | |amber| !#FFB000 !#FFD080 !#FFD580 | Amber/gold CRT-style | |phosphor| !#33FF33 !#66FF66 !#AAFFAA | Green phosphor terminal-style |gruvboxSolid themes (filled backgrounds with foreground colors):
| Theme | Colors | Description | |-------|--------|-------------| |
| !#282828 !#FABD2F !#FE8019 | Gruvbox dark palette | |monokai| !#272822 !#F92672 !#A6E22E | Monokai dark with pink/green accents | |dracula| !#282A36 !#BD93F9 !#50FA7B | Dracula purple/pink/green palette | |nord| !#2E3440 !#88C0D0 !#A3BE8C | Nord muted blue/cyan arctic palette | |solarized| !#002B36 !#268BD2 !#B58900 | Solarized dark blue/yellow/cyan |Optional extras
## Claude Code
Claude draws Mermaid diagrams all the time. With the termaid plugin they show up
in the terminal as diagrams instead of code fences, while Claude keeps seeing the
Mermaid source. One command on Claude Code 2.1.275 or later:
/plugin install termaid --marketplace fasouto/termaid
json { "hooks": { "MessageDisplay": [ { "hooks": [ { "type": "command", "command": "termaid --claude-hook", "timeout": 10 } ] } ] } }On older versions, add the marketplace first with/plugin marketplace add fasouto/termaidand then/plugin install termaid@termaid. The plugin needs thetermaidcommand on your PATH (brew install termaidoruv tool install termaid). It adds:MessageDisplay
- a
hook that runstermaid --claude-hookon each reply and draws its mermaid blocks in place. It only changes what you see. The transcript keeps the source, and if termaid is missing or fails, Claude Code shows the original text./termaid:mermaid
- a
skill for explicit requests, such as rendering a file or the diagrams in a PR description..claude/settings.jsonWithout the plugin, the same hook works from
:
claude -p "draw the login flow as a mermaid sequence diagram" | termaid --markdownFor headless use, pipe the reply throughtermaid --markdown:
{"version":1,"lines":[[{"text":"┌───┐","style":"node"},{"text":" ","style":"default"},{"text":"┌───┐","style":"node"}], [{"text":"│","style":"node"},{"text":" ","style":"default"},{"text":"A","style":"label"},{"text":" ","style":"default"},{"text":"├","style":"node"},{"text":"───","style":"edge"},{"text":"►","style":"arrow"},{"text":"│","style":"node"},{"text":" ","style":"default"},{"text":"B","style":"label"},{"text":" ","style":"default"},{"text":"│","style":"node"}], [{"text":"└───┘","style":"node"},{"text":" ","style":"default"},{"text":"└───┘","style":"node"}]]}## Editor and tool integration--format styled-jsonEditor plugins and other tools that run termaid as a subprocess can ask for structured output instead of terminal text.
prints the diagram as one line of JSON. Each line of the diagram is a list of chunks, and each chunk is a run of text with one style key. Forgraph LR; A-->Bwith--padding-x 1 --padding-y 0, wrapped here at each diagram line:
$ termaid --diagnostics-format json --width 0 diagram.mmd {"version": 1, "severity": "error", "code": "invalid_arguments", "message": "--width must be positive.", "details": {}, "exit_code": 2} `Joining the chunk texts of each line gives exactly the text output, fitted to--widththe same way. The tool picks the colors. Style keys name the role of the cells (node,edge,arrow,label,edge_label,subgraph,section:N, and so on). Flowcharts also carryclass:<name>,nodestyle:<id>andlinkstyle:<index>, so a tool can apply the diagram's ownclassDef,styleandlinkStylecolors. termaid ignores--themehere and rejects--tui,--markdownand--claude-hooktogether with this format.--diagnostics-format jsonprints each error and warning on stderr as one JSON line, with a stablecodeto branch on:
Codes:
input_missing, input_empty, invalid_arguments,
input_conversion_failed, dependency_missing, render_failed,
render_empty, output_write_failed, width_exceeded, height_exceeded.
With --width alone, width_exceeded is a warning with status 0 and the
actual and target widths in details. With --strict-width it is an error.
Limitations
- Layout engine is approximate. Node positioning uses a grid-based barycenter heuristic. Very dense graphs may still produce some edge crossings.
- Grid edge routing. Edges are horizontal and vertical segments found by A* search on a grid. Two edges share a line only when they share a node. Otherwise they cross, and the gap between layers grows to keep them apart, which can leave tall empty gaps in dense diagrams.
- Wide diagrams. The CLI auto-compacts when the diagram exceeds terminal width, and wraps labels at word boundaries when spacing alone cannot fit it. For very wide LR chains, use
--width N, --gap 1, or pipe through less -S`.
Gallery
See the examples page for rendered examples of all 18 supported diagram types.
Acknowledgements
Inspired by mermaid-ascii by Alexander Grooff and beautiful-mermaid by Lukilabs.
License
MIT