Rendered with NanoMD
Last updated
Since v1.2.2 the browser dashboard renders agent replies and Markdown files with NanoMD, so charts, diagrams and formulas show up as figures instead of source.
What renders
| Markdown | Result |
|---|---|
```chartjs with {"type": ..., "data": {...}} | Chart: bar, line, pie, doughnut, radar, polarArea, scatter, bubble |
```mermaid | Diagram: flowchart, sequenceDiagram, stateDiagram-v2, classDiagram, erDiagram, gantt, timeline |
```math or inline $...$ | KaTeX formula |
| Any other fenced code | Syntax highlighting with a copy button |
GFM tables, task lists, footnotes, ==highlight==, > [!NOTE] callouts | Styled Markdown |
A block that fails to parse (invalid JSON, unknown chart type, broken Mermaid syntax) shows its source instead. This page is rendered by NanoMD as well; see "Full rendering test" below for every case.
Full rendering test
The test document below exercises every syntax the dashboard declares, and this page renders it with the same NanoMD build. This document tests the CommonMark, GFM and custom extensions the interface declares as supported. All chart values are test data; whether external images and media load depends on the network and interface limits. The document provides test cases; it does not mean every case has been visually verified.
Basic formatting
Plain text, bold, italic, bold italic,
inline code.Subscript: H2O. Superscript: x2.
This is the first paragraph.
This is the second paragraph. The next line uses two trailing spaces to force a line break. This line should break within the same paragraph.
Heading levels
Fourth-level heading
Fifth-level heading
Sixth-level heading
Alternate heading
Lists and quotes
- Unordered list
- Nested list
- One level deeper
- Nested list
- Bold list item
- Ordered item A
- Ordered item B
- Unordered item inside an ordered list
- Completed task
- Pending task
A plain quote.
Second paragraph of the quote.
Nested quote.
NoteSupplementary information.
TipA suggestion for how to proceed.
ImportantImportant information.
WarningA warning.
CautionSomething to handle with care.
Tables
| Left | Center | Right |
|---|---|---|
| Bold | code | Plain text |
| Escaped pipe | | highlight |
Links, escapes and footnotes
Inline link: CommonMark
<https://commonmark.org/>
Reference link
Escapes: *not italic*, #not a heading, [not a link], $not a math delimiter.
This sentence has a numbered footnote.1 This sentence has a named footnote.2
Code
- const message = "Code block test";
- console.log(message);
- def greet(name):
- return f"Hello, {name}!"
Indented code:
const indented = true; console.log(indented);
An outer fence of four backticks should keep the inner three-backtick fence intact:
- **This should show as source, not bold**
- ```javascript
- console.log("Nested code fence");
- ```
Math
Inline formula: a^2+b^2=c^2.
Display formulas:
\int_a^b f(x)\,dx = F(b)-F(a)
- \int_a^b f(x)\,dx = F(b)-F(a)
\mathbf{A}=\begin{pmatrix}a&b\\c&d\end{pmatrix}
- \mathbf{A}=\begin{pmatrix}a&b\\c&d\end{pmatrix}
The block below uses the
latex tag and should show only its source, not a rendered formula:- E=mc^2
Chart.js charts
All values below are unitless test data, not real statistics.
Bar chart
| Category | Value |
|---|---|
| A | 12 |
| B | 19 |
| C | 7 |
- {"type":"bar","data":{"labels":["A","B","C"],"datasets":[{"label":"Value","data":[12,19,7]}]}}
Line chart
- {"type":"line","data":{"labels":["A","B","C"],"datasets":[{"label":"Trend","data":[12,19,7]}]}}
Pie chart
- {"type":"pie","data":{"labels":["A","B","C"],"datasets":[{"label":"Share","data":[12,19,7]}]}}
Doughnut chart
- {"type":"doughnut","data":{"labels":["A","B","C"],"datasets":[{"label":"Share","data":[12,19,7]}]}}
Radar chart
- {"type":"radar","data":{"labels":["A","B","C"],"datasets":[{"label":"Profile","data":[12,19,7]}]}}
Polar area chart
- {"type":"polarArea","data":{"labels":["A","B","C"],"datasets":[{"label":"Distribution","data":[12,19,7]}]}}
Scatter chart
- {"type":"scatter","data":{"datasets":[{"label":"Points","data":[{"x":1,"y":12},{"x":2,"y":19},{"x":3,"y":7}]}]}}
Bubble chart
- {"type":"bubble","data":{"datasets":[{"label":"Bubbles","data":[{"x":1,"y":12,"r":6},{"x":2,"y":19,"r":10},{"x":3,"y":7,"r":8}]}]}}
Mermaid diagrams
Flowchart
flowchart LR
A[Input] --> B{Check}
B -->|Pass| C[Render]
B -->|Fail| D[Show source]- flowchart LR
- A[Input] --> B{Check}
- B -->|Pass| C[Render]
- B -->|Fail| D[Show source]
Sequence diagram
sequenceDiagram
participant U as User
participant R as Renderer
U->>R: Submit Markdown
R-->>U: Show content- sequenceDiagram
- participant U as User
- participant R as Renderer
- U->>R: Submit Markdown
- R-->>U: Show content
State diagram
stateDiagram-v2
[*] --> Pending
Pending --> Rendering
Rendering --> Done
Done --> [*]- stateDiagram-v2
- [*] --> Pending
- Pending --> Rendering
- Rendering --> Done
- Done --> [*]
Class diagram
classDiagram
class Document {
+String title
+render()
}
class Renderer {
+parse()
}
Document --> Renderer : uses- classDiagram
- class Document {
- +String title
- +render()
- }
- class Renderer {
- +parse()
- }
- Document --> Renderer : uses
Entity relationship diagram
erDiagram
AUTHOR ||--o{ DOCUMENT : writes
AUTHOR {
string name
}
DOCUMENT {
string title
}- erDiagram
- AUTHOR ||--o{ DOCUMENT : writes
- AUTHOR {
- string name
- }
- DOCUMENT {
- string title
- }
Gantt chart
gantt
title Rendering test schedule (illustrative)
dateFormat YYYY-MM-DD
section Test
Prepare cases :a, 2026-11-08, 1d
Review output :b, after a, 1d- gantt
- title Rendering test schedule (illustrative)
- dateFormat YYYY-MM-DD
- section Test
- Prepare cases :a, 2026-11-08, 1d
- Review output :b, after a, 1d
Timeline
timeline
title Test stages
Prepare : Write content
Render : Show content
Review : Manual check- timeline
- title Test stages
- Prepare : Write content
- Render : Show content
- Review : Manual check
Images and media
This section tests embedding external resources; the URLs are not guaranteed to load in every environment.
Plain image
Fixed width and height
Percentage width
Fixed height
MP4 player
MOV player syntax
This case deliberately uses a reserved domain: it tests whether the syntax is recognized as a player, but there is no actual video to play.
Bare YouTube URL
https://www.youtube.com/watch?v=aqz-KE-bpKQ
Vimeo link
Vimeo embed test
Cases expected to fall back to source
The blocks below are deliberately invalid or unsupported; they should show their source without affecting the sections after them.
Invalid Chart.js JSON:
- {"type":"bar","data": }
Missing
data:- {"type":"bar"}
Unsupported chart type:
- {"type":"unsupported","data":{"labels":[],"datasets":[]}}
Invalid Mermaid syntax:
this is not a valid diagram
- this is not a valid diagram
Test boundaries
- Raw HTML, CSS, JavaScript execution, collapsible blocks and other undeclared syntax are not guaranteed to be supported.
- External media that fails to load because of anti-tracking, content security policy, network or source-site limits does not necessarily mean the Markdown syntax failed.
- This is a test document; it has not been checked by screenshot or item by item in a browser.
Where it renders
| Surface | Behavior |
|---|---|
Web chat replies and reasoning (chat- sessions) | Rendered while streaming; figures in older messages render as they scroll into view |
.md, .markdown, .txt file links in a reply | Open in the side panel, rendered with NanoMD; local images resolve through /v1/file/open |
| TUI, Telegram, Discord | Show the Markdown source |
How the agent uses it
The system prompt tells the agent where figures render. In
chat- sessions it adds them to both chat replies and .md files; in every other session it puts them only in .md files, because those chat surfaces would show the raw block. When content holds numbers across three or more items or time points, a process or a formula, the agent adds the matching chart, diagram or formula next to the table or text it summarizes, without being asked. It skips the figure when it would only restate a single number or a two-item comparison.About NanoMD
NanoMD is a TypeScript Markdown parser that turns Markdown into sanitized HTML and a JSON AST, loading Mermaid, KaTeX and Chart.js only when a page uses them. Agenvoy pins its parser and stylesheet in
page/vendor.json (2.0.10 in v1.2.2); the daemon downloads them once into ~/.config/agenvoy/vendor/nanomd/ and serves them locally, so rendering works offline. Syntax reference and playground: nanomd.pardn.io.See also: Browser Dashboard.
- Numbered footnote content; it should appear in the footnote area with navigation.
- A named footnote that supports bold and links.