# Rendered with NanoMD

Since v1.2.2 the browser dashboard renders agent replies and Markdown files with [NanoMD](https://nanomd.pardn.io), 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***, ~~strikethrough~~, ==highlight==, `inline code`.

Subscript: H~2~O. Superscript: x^2^.

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
- **Bold list item**

1. Ordered item A
2. Ordered item B
   - Unordered item inside an ordered list

- [x] Completed task
- [ ] Pending task

> A plain quote.
>
> Second paragraph of the quote.
>
> > Nested quote.

> [!NOTE]
> Supplementary information.

> [!TIP]
> A suggestion for how to proceed.

> [!IMPORTANT]
> Important information.

> [!WARNING]
> A warning.

> [!CAUTION]
> Something to handle with care.

### Tables

| Left | Center | Right |
| :--- | :---: | ---: |
| **Bold** | `code` | Plain text |
| Escaped pipe \| | ==highlight== | ~~deleted~~ |

### Links, escapes and footnotes

[Inline link: CommonMark](https://commonmark.org/)

<https://commonmark.org/>

[Reference link][commonmark]

[commonmark]: https://commonmark.org/ "CommonMark official site"

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.[^note]

### Code

```javascript
const message = "Code block test";
console.log(message);
```

```python
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:

````markdown
**This should show as source, not bold**

```javascript
console.log("Nested code fence");
```
````

### Math

Inline formula: $a^2+b^2=c^2$.

Display formulas:

```math
\int_a^b f(x)\,dx = F(b)-F(a)
```

```math
\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:

```latex
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 |

```chartjs
{"type":"bar","data":{"labels":["A","B","C"],"datasets":[{"label":"Value","data":[12,19,7]}]}}
```

#### Line chart

```chartjs
{"type":"line","data":{"labels":["A","B","C"],"datasets":[{"label":"Trend","data":[12,19,7]}]}}
```

#### Pie chart

```chartjs
{"type":"pie","data":{"labels":["A","B","C"],"datasets":[{"label":"Share","data":[12,19,7]}]}}
```

#### Doughnut chart

```chartjs
{"type":"doughnut","data":{"labels":["A","B","C"],"datasets":[{"label":"Share","data":[12,19,7]}]}}
```

#### Radar chart

```chartjs
{"type":"radar","data":{"labels":["A","B","C"],"datasets":[{"label":"Profile","data":[12,19,7]}]}}
```

#### Polar area chart

```chartjs
{"type":"polarArea","data":{"labels":["A","B","C"],"datasets":[{"label":"Distribution","data":[12,19,7]}]}}
```

#### Scatter chart

```chartjs
{"type":"scatter","data":{"datasets":[{"label":"Points","data":[{"x":1,"y":12},{"x":2,"y":19},{"x":3,"y":7}]}]}}
```

#### Bubble chart

```chartjs
{"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

```mermaid
flowchart LR
    A[Input] --> B{Check}
    B -->|Pass| C[Render]
    B -->|Fail| D[Show source]
```

#### Sequence diagram

```mermaid
sequenceDiagram
    participant U as User
    participant R as Renderer
    U->>R: Submit Markdown
    R-->>U: Show content
```

#### State diagram

```mermaid
stateDiagram-v2
    [*] --> Pending
    Pending --> Rendering
    Rendering --> Done
    Done --> [*]
```

#### Class diagram

```mermaid
classDiagram
    class Document {
        +String title
        +render()
    }
    class Renderer {
        +parse()
    }
    Document --> Renderer : uses
```

#### Entity relationship diagram

```mermaid
erDiagram
    AUTHOR ||--o{ DOCUMENT : writes
    AUTHOR {
        string name
    }
    DOCUMENT {
        string title
    }
```

#### Gantt chart

```mermaid
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

```mermaid
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

![External test image](https://placehold.co/600x200/png?text=Markdown)

#### Fixed width and height

![Fixed size test](https://placehold.co/600x200/png?text=Fixed)(320x240)

#### Percentage width

![Percentage width test](https://placehold.co/600x200/png?text=Width)(50%x)

#### Fixed height

![Fixed height test](https://placehold.co/600x200/png?text=Height)(x120)

#### MP4 player

![MP4 test video](https://interactive-examples.mdn.mozilla.net/media/cc0-videos/flower.mp4)

#### 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.

![MOV syntax test, no real media](https://example.com/test.mov)

#### Bare YouTube URL

https://www.youtube.com/watch?v=aqz-KE-bpKQ

#### Vimeo link

[Vimeo embed test](https://vimeo.com/76979871)

### 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:

```chartjs
{"type":"bar","data": }
```

Missing `data`:

```chartjs
{"type":"bar"}
```

Unsupported chart type:

```chartjs
{"type":"unsupported","data":{"labels":[],"datasets":[]}}
```

Invalid Mermaid syntax:

```mermaid
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.

[^1]: Numbered footnote content; it should appear in the footnote area with navigation.
[^note]: A named footnote that supports **bold** and [links](https://commonmark.org/).

## 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](https://nanomd.pardn.io).

See also: [Browser Dashboard](/getting-started-browser).
