Mermaid Formatter
Streaming formatter that renders Mermaid diagrams inline in the terminal using the best available graphics protocol, with a Unicode half-block fallback that works everywhere.
| Name | mermaid_formatter |
| Type | Formatter Pipeline Plugin |
| Priority | 28 (structural formatting range) |
| Dependencies | Pillow (required), mmdc (optional, recommended) |
Features
- Auto-detection: Picks the best graphics protocol for your terminal
- 4 rendering backends: Kitty, iTerm2, Sixel, Unicode half-blocks
- Streaming: Detects mermaid blocks incrementally across chunks
- Artifact saving: PNG files saved for vision capture feedback
- Graceful degradation: Falls back to syntax-highlighted code when no renderer is installed
Model output containing a mermaid block:
"Here's the architecture:
```mermaid
graph TD
A[Client] -->|HTTP| B[Server]
B --> C[Database]
B --> D[Cache]
```
As shown above..."
The formatter:
1. Yields "Here's the architecture:" immediately
2. Buffers the mermaid source
3. Renders to PNG via mmdc
4. Displays inline using terminal protocol
5. Saves artifact to /tmp/jaato_vision/
6. Yields "As shown above..."
# Gold standard renderer (requires Node.js)
npm install -g @mermaid-js/mermaid-cli
# Verify installation
mmdc --version
Terminal Graphics Backends
The plugin auto-selects the best rendering backend based on your terminal.
Detection uses shared/terminal_caps.py, which reads
TERM_PROGRAM and TERM environment variables
and caches the result process-wide.
| Backend | Protocol | Supported Terminals |
|---|---|---|
kitty |
Kitty graphics protocol | Kitty, Ghostty |
iterm |
iTerm2 inline images | iTerm2, WezTerm, Mintty |
sixel |
Sixel bitmap | foot, mlterm |
rich_pixels |
Unicode half-blocks (▀) | All terminals |
rich_pixels when a
multiplexer is detected. Override with
JAATO_MERMAID_BACKEND=kitty if you have tmux
passthrough enabled.
# 1. Explicit override (always wins)
os.environ["JAATO_MERMAID_BACKEND"] = "kitty"
# 2. Global graphics override
os.environ["JAATO_GRAPHICS_PROTOCOL"] = "sixel"
# 3. Auto-detection from TERM_PROGRAM
# kitty/ghostty → Kitty protocol
# iTerm.app/WezTerm → iTerm2 protocol
# foot/mlterm → Sixel protocol
# 4. Universal fallback
# Everything else → Unicode half-blocks
# Kitty: sends PNG via escape sequences
ESC_Gf=100,a=T,m=1;base64data...ESC\
ESC_Gm=0;base64data...ESC\
# iTerm2: single OSC escape sequence
ESC]1337;File=inline=1;size=N:base64...BEL
# Sixel: DCS with color palette + bitmap
ESC P0;1;0q"1;1;W;H #0;2;R;G;B ...data... ESC\
# rich_pixels: Unicode half-block characters
▀▀▀▀▀▀▀▀▀ (with ANSI fg/bg colors)
▀▀▀▀▀▀▀▀▀ (2 pixels per cell height)
Mermaid Rendering
Diagrams are converted from Mermaid source text to PNG using the first available renderer. The rendering step is separate from the terminal display step, allowing different combinations.
mmdc (mermaid-cli)
The official Mermaid CLI tool. Uses Puppeteer to render diagrams in a headless browser. Supports all Mermaid diagram types and themes.
| Install | npm install -g @mermaid-js/mermaid-cli |
| Requires | Node.js |
| Detection | shutil.which("mmdc") |
| Timeout | 30 seconds |
mermaid-py (Python fallback)
Python package that produces SVG, converted to PNG via cairosvg. Used when mmdc is not available.
| Install | pip install mermaid cairosvg |
| Optional extra | pip install jaato[mermaid] |
Passthrough (no renderer)
When neither renderer is available, the source is emitted as a
```mermaid code block with a dim install hint. The
downstream code_block_formatter applies syntax highlighting.
```mermaid source
│
├── mmdc available?
│ └── YES → subprocess mmdc → PNG bytes
│
├── mermaid-py available?
│ └── YES → mermaid.Graph → SVG → cairosvg → PNG bytes
│
└── Neither available
└── Pass through as ```mermaid code block
+ hint: "npm install -g @mermaid-js/mermaid-cli"
graph TD/LR Flowcharts
sequenceDiagram Sequence diagrams
classDiagram Class diagrams
stateDiagram State diagrams
erDiagram Entity relationship
gantt Gantt charts
pie Pie charts
gitgraph Git branch diagrams
mindmap Mind maps
timeline Timelines
quadrantChart Quadrant charts
sankey Sankey diagrams
Configuration
JAATO_MERMAID_BACKEND
Force a specific graphics backend, overriding auto-detection.
| Type | string |
| Values | kitty, iterm, sixel, ascii, off |
| Default | Auto-detect |
Setting off disables diagram rendering entirely.
JAATO_MERMAID_THEME
Mermaid rendering theme.
| Type | string |
| Values | default, dark, forest, neutral |
| Default | default |
JAATO_MERMAID_SCALE
Rasterization scale factor. Higher values produce sharper images on retina/HiDPI displays but use more memory.
| Type | int |
| Default | 2 |
JAATO_GRAPHICS_PROTOCOL
Global terminal graphics protocol override. Affects all plugins
that use shared/terminal_caps.py, not just the
mermaid formatter.
| Type | string |
| Values | kitty, iterm, sixel, none |
| Default | Auto-detect |
# Force Kitty protocol (e.g., inside tmux with passthrough)
export JAATO_MERMAID_BACKEND=kitty
# Use dark theme for diagrams
export JAATO_MERMAID_THEME=dark
# Higher resolution for retina displays
export JAATO_MERMAID_SCALE=3
# Disable diagram rendering entirely
export JAATO_MERMAID_BACKEND=off
# Save artifacts to custom directory
export JAATO_VISION_DIR=~/diagrams
{
"formatters": [
{"name": "hidden_content_filter", "enabled": true},
{"name": "diff_formatter", "enabled": true},
{"name": "table_formatter", "enabled": true},
{"name": "mermaid_formatter", "enabled": true, "config": {
"theme": "dark",
"scale": 2,
"background": "transparent"
}},
{"name": "code_block_formatter", "enabled": true,
"config": {"line_numbers": true}}
]
}
from shared.plugins.mermaid_formatter import create_plugin
formatter = create_plugin()
formatter.initialize({
"theme": "dark",
"scale": 2,
"background": "white",
"console_width": 120,
})
formatter.set_console_width(terminal_width)
Artifact Output
Every rendered diagram is saved as a PNG file in the artifact directory
(JAATO_VISION_DIR, default /tmp/jaato_vision).
This integrates with the vision capture system, enabling:
- Model feedback loop: The model can "see" its own diagrams and iterate
- Export: Users can open/share the high-fidelity PNG files
- Documentation: Artifacts persist across turns for reference
Files are named sequentially: mermaid_001.png,
mermaid_002.png, etc. The counter resets when the
plugin is re-initialized.
# After rendering a diagram, the output includes:
[rendered diagram inline]
[saved: /tmp/jaato_vision/mermaid_001.png]
# Multiple diagrams in one turn:
[first diagram]
[saved: /tmp/jaato_vision/mermaid_001.png]
[second diagram]
[saved: /tmp/jaato_vision/mermaid_002.png]
Pipeline flow:
mermaid_formatter (priority 28)
│
├── Renders diagram inline
├── Saves PNG to JAATO_VISION_DIR
│
▼
vision_capture_formatter (priority 95)
│
└── Observes rendered output
for model feedback loop
Dependencies
Required
| Package | Purpose |
|---|---|
Pillow>=10.0.0 |
Image processing for all graphics backends |
Optional
| Package | Purpose | Install |
|---|---|---|
@mermaid-js/mermaid-cli |
High-fidelity Mermaid rendering | npm install -g @mermaid-js/mermaid-cli |
cairosvg>=2.7.0 |
SVG to PNG conversion | pip install jaato[mermaid] |
# Minimal (Unicode half-block rendering only)
pip install jaato
# With mermaid-cli (recommended)
pip install jaato
npm install -g @mermaid-js/mermaid-cli
# Full setup (all optional deps)
pip install jaato[mermaid]
npm install -g @mermaid-js/mermaid-cli
from shared.plugins.mermaid_formatter.renderer import (
is_renderer_available
)
from shared.terminal_caps import detect
# Check if rendering will work
print(is_renderer_available()) # True/False
# Check which graphics backend will be used
caps = detect()
print(caps["graphics"]) # "kitty"/"iterm"/"sixel"/None