Guide

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

FormatMarkdownPer-doc capPer-source cap
Mermaid diagrams```mermaid50 diagrams30 KB source
Math (KaTeX)$inline$ / $$block$$500 expressions8 KB source
Callouts> [!NOTE|TIP|IMPORTANT|WARNING|CAUTION](global doc cap)(global)
SVG (sanitized)```svg50 blocks100 KB post-sanitize
Toggle / details<details><summary>X</summary>...</details>(global)(global)
Cross-refs[[slug]] / [[slug#tab]]200 refsn/a
Embeds (oEmbed)Lone URL on its own line (safelisted provider)20 embeds2 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.

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

Inline + block mathmarkdown
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).

Calloutsmarkdown
> [!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.

Custom geometrymarkdown
```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.

Collapsible sectionmarkdown
<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
Embedding video + designmarkdown
Watch the demo:

https://www.loom.com/share/abc123def456789

Design system spec:

https://www.figma.com/file/abcXYZ/design-system

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

Sample validate_doc_markdown responsejson
{
  "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.

  • Doc body API — pass markdown on 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.