Guide

Doc formats: rich content for humans + agents

Doc bodies in Dock accept the full friendly format set: diagrams, math, callouts, custom SVG, sandboxed HTML, 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
Inline images![alt](https://…)200 imagesn/a (URL reference)
Native videosLone URL on its own line (.mp4 / .webm / .mov / .mkv / .m4v)20 videos5 GB per file (upload time)
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
HTML (sandboxed)```html5 blocks50 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

Inline images

Standard CommonMark ![alt](url) syntax. The URL is referenced directly: no server-side reupload, no resizing, no compression. Any publicly-reachable HTTPS URL works. The alt text is the accessible label and shows in place of the image if the URL fails to load, always include it.

Inline imagemarkdown
Here's the proposed login flow:

![Login flow mockup](https://cdn.dock.ai/login-flow-v3.png)

The agent step lands between magic-link click and dashboard paint.

Renders as a block-feeling figure (full width up to 100%, rounded corners, drop shadow) even though the underlying TipTap node is inline-grouped, that's what makes markdown round-trip cleanly. The allowBase64: false setting rejects data: URIs to keep doc bodies small and crawlable; upload first, then reference.

To attach a user-uploaded file, the human-side UI hits POST /api/workspaces/:slug/upload (10 MB cap) for images or POST /api/workspaces/:slug/upload-media (5 GB cap, client-side multipart) for anything larger. Both return a Vercel Blob URL; reference it from markdown.

Native videos

A lone URL on its own paragraph with a video file extension (.mp4, .m4v, .webm, .mov, .mkv) becomes a native HTML5 <video controls preload="metadata"> player. No iframe, no provider wrapper, no transcoding. The source file's quality is the rendered quality, 4K masters at H.264/H.265 stream cleanly via HTTP range requests.

Video by lone URLmarkdown
# Launch walkthrough

Recording from yesterday's rehearsal:

https://cdn.dock.ai/launch-rehearsal-4k.mp4

The intro hits the founding story; jump to 1:42 for the demo segment.

Signed-param + timestamp fragments are tolerated (?token=…&Expires=… from S3-style signed URLs, #t=01:42 for a deep-link starting position). Mid- paragraph URLs stay as plain links, the auto-promote only fires when the entire paragraph is the URL.

For user-uploaded files, the slash menu "Video" item or drag-drop of a video file pushes the upload through @vercel/blob/client direct-multipart so the file bypasses the Vercel function body cap (4.5 MB) and streams in parallel chunks straight to Blob. 5 GB hard ceiling per file (Vercel Blob's platform max); longer recordings split into clips.

Why not iframe through an oEmbed provider: YouTube / Vimeo / Loom all apply their own per-tier bitrate caps and compression pipelines. For source-quality playback (design reviews, raw camera footage, screen recordings agents need to inspect frame- by-frame), reference the file directly with a video node.

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.

HTML (sandboxed)

For embedded mockups, landing-page snippets, design previews, anything an agent would render as HTML in a brief. Drop a ```html fenced block. The body is sanitized (no <script>, no on* handlers, no javascript: URLs, no data:text/html) and rendered in a sandboxed iframe. Scripts are disabled by default; data:image/* URIs are allowed for inline images.

Inline mockupmarkdown
```html
<style>
  .card { padding: 16px; border: 1px solid #ddd; border-radius: 8px; }
  .card h2 { margin: 0 0 8px; }
</style>
<div class="card">
  <h2>Welcome to Dock</h2>
  <p>The AI workspace for you, your team, and every agent you run.</p>
  <a href="https://trydock.ai">Get started</a>
</div>
```

For full-page mockups beyond the 50 KB block cap, graduate to a dedicated HTML surface. The same sanitizer + sandbox primitive renders both.

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,
    "imageCount": 3,
    "videoCount": 1,
    "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.
Updated