Doc formats: rich content for humans + agents
Doc bodies in Dock accept the full friendly format set: diagrams, math, callouts, custom SVG, toggles, cross-references, embeds. Every format is markdown-fenced-block addressable so agents emit them natively, and every format round-trips losslessly through get_doc. Bundle weight is paid only on docs that actually use a format (lazy-loaded on first encounter, cached for the session).
The format catalog
| Format | Markdown | Per-doc cap | Per-source cap |
|---|---|---|---|
| Mermaid diagrams | ```mermaid | 50 diagrams | 30 KB source |
| Math (KaTeX) | $inline$ / $$block$$ | 500 expressions | 8 KB source |
| Callouts | > [!NOTE|TIP|IMPORTANT|WARNING|CAUTION] | (global doc cap) | (global) |
| SVG (sanitized) | ```svg | 50 blocks | 100 KB post-sanitize |
| Toggle / details | <details><summary>X</summary>...</details> | (global) | (global) |
| Cross-refs | [[slug]] / [[slug#tab]] | 200 refs | n/a |
| Embeds (oEmbed) | Lone URL on its own line (safelisted provider) | 20 embeds | 2 KB URL |
Mermaid diagrams
Drop a ```mermaid fenced block. 15 sub-types covered by one library: flowchart, sequence, gantt, ER, state, class, mindmap, timeline, pie, quadrant, sankey, XY-chart, packet, block, journey.
# Auth flow
```mermaid
sequenceDiagram
Agent->>Server: POST /upgrade
Server-->>Agent: 402 payment_required
Agent->>User: surface payment URL
```Diagrams render as SVG (zoom-friendly on mobile, indexable for search). Bad syntax surfaces as an error tile with the source visible — your content is never lost. The library is async-loaded on first encounter and cached for the session.
Math (KaTeX)
Inline with $x$, block with $$x$$ on its own lines. LaTeX, KaTeX-rendered with trust: false — no \\href, \\input, or \\includegraphics. ARIA + MathML output by default for screen readers.
The latency budget is $L < 200ms$ at p99.
Cost model:
$$
C = N \cdot \frac{r}{1000}
$$Callouts
GFM-standard. Five variants: NOTE (info), TIP (helpful), IMPORTANT (call attention), WARNING (heads-up), CAUTION (danger).
> [!IMPORTANT]
> Tokens expire 60 seconds after mint.
> [!CAUTION]
> Production data; review before shipping.SVG (the universal escape hatch)
For diagrams Mermaid doesn't model: geometry, custom layouts, decorative figures. Drop a ```svg fenced block with raw SVG markup. The sanitizer strips <script>, <foreignObject>, every on* event handler, and javascript: URLs at write time AND render time.
```svg
<svg viewBox="0 0 100 100">
<title>Right triangle</title>
<polygon points="10,90 90,90 10,10" fill="none" stroke="#0A84FF" stroke-width="2"/>
<text x="50" y="100" text-anchor="middle">a</text>
<text x="0" y="55">b</text>
<text x="55" y="50" transform="rotate(-45 55 50)">c</text>
</svg>
```Always include a <title> element for screen readers — the parser pulls it into the node's alt attr. SVG renders to a centered figure with overflow-auto for mobile zoom.
Toggle / details
Native <details> disclosure widget. Useful for FAQ-style content, long appendices, rare-path branches.
<details>
<summary>Risks + mitigations</summary>
- Risk A: handle via retry with exponential backoff
- Risk B: fall back to cached value, log degraded state
- Risk C: page on-call
</details>Cross-references
Inline links to other workspaces, surfaces, or rows. Five forms:
[[my-workspace]]— bare workspace slug[[my-org/my-workspace]]— org-prefixed[[my-workspace#brief]]— specific surface (tab)[[my-workspace#row-cuid42]]— specific row[[my-workspace|My Label]]— custom display text
Every cross-ref creates a Backlink row. The target's "Referenced from" sidebar widget lists every doc that points at it (Roam-style backlinks but typed: workspace, surface, or row). Targets the reader can't see render as plain text — no info leak about existence.
Slug renames are handled automatically: the cross-ref's stored slug stays as the original spelling for round-trip readability, but resolution chases through WorkspaceSlugAlias.
External embeds
Paste a URL on its own paragraph from a safelisted provider; it becomes a sandboxed iframe. URLs not on the safelist stay as plain links — no auto-promotion outside the explicit list.
Supported providers (v1):
- YouTube (
youtube.com/watch?v=+youtu.be) - Vimeo
- Loom (share URLs)
- Figma (file / design / board / proto)
- CodePen
- GitHub gists
Watch the demo:
https://www.loom.com/share/abc123def456789
Design system spec:
https://www.figma.com/file/abcXYZ/design-systemPer-provider sandbox attrs are tuned for each service's needs. allow-top-navigation and allow-forms are NEVER enabled. referrerpolicy="no-referrer" on every iframe so the embed can't see the source workspace URL.
For agents: validate before writing
The validate_doc_markdown MCP tool parses your markdown and returns counts per format type, structured cap-breach errors, and warnings — without writing anything. Use this when iterating on rich-format markdown to catch problems before burning a real update_doc or append_doc_section call.
{
"ok": true,
"errors": [],
"warnings": [
{
"code": "cross_ref_unresolved",
"message": "Cross-ref [[old-slug]] doesn't resolve to an accessible workspace.",
"details": { "payload": "old-slug" }
}
],
"parsed": {
"byteSize": 4280,
"nodeCount": 87,
"depth": 4,
"headingCount": 3,
"paragraphCount": 12,
"mermaidCount": 1,
"mathCount": 4,
"svgCount": 0,
"calloutCount": 2,
"crossRefCount": 5,
"embedCount": 1,
"detailsCount": 1
}
}Round-trip guarantee
Every format in this catalog round-trips losslessly through get_doc → markdown → update_doc. Source is preserved verbatim for code-shaped formats (Mermaid, math, SVG); the syntactic form is preserved for cross-refs (so a renamed target's original spelling survives in your prose). This means an agent can round-trip any doc body through markdown without losing fidelity.
Cap behavior
Cap breaches return a DocGuardError with a structured limit field (e.g. mermaid_count, math_source_bytes). Agents can branch on the limit name to decide whether to retry with smaller content, split across multiple docs, or surface the issue to their user. The full set of limit names is in src/lib/doc-guard.ts.
Related
- Doc body API — pass
markdownon PUT / POST sections; server converts to TipTap. - Doc mode — UI for the same surfaces (slash menu, image upload, shortcuts).
- MCP tool catalog —
update_doc/append_doc_section/validate_doc_markdown.