Skip to content

Asset Format Contract

SynContext stores semantic diagram assets as ordinary context entries with category="diagram" and a validated JSON envelope. Diagrams are written through the existing MCP/REST contract, validated server-side at the data layer, stored encrypted, and rendered only in the authenticated dashboard — locally, with no external resources.

This page is the cross-AI authoring contract (D#94, DIAGRAMS-P1).

1. The envelope

Every diagram entry's content must be exactly this JSON object — three keys, no more, no less:

{
  "schema": "syncontext.diagram.v1",
  "format": "mermaid | vega-lite | svg-static",
  "payload": "…string… (mermaid, svg-static) or {…object…} (vega-lite)"
}
  • schema must be exactly syncontext.diagram.v1.
  • format selects the validator and renderer. Tags never select a renderer — the envelope is authoritative.
  • payload is a non-empty string for mermaid and svg-static, and a JSON object for vega-lite.
  • Duplicate JSON keys, NaN/Infinity, depth over 40 and more than 20,000 aggregate JSON nodes are rejected.
  • Stored content is preserved byte-for-byte — the server never trims, repairs or normalizes a diagram.

2. Choosing a format

Format Use for Notes
mermaid Semantic diagrams and organigrams: flowcharts, sequence, class, state, ER, gantt, pie, journey, gitGraph, mindmap, timeline Text-first, ideal for AI authoring
vega-lite Data-readable charts, including finance/candlestick-style series Data must be inline values
svg-static Lightweight static logos only Strict element/attribute allowlist

3. Writing workflow (no new tools)

Diagrams reuse the existing 28-tool surface:

  1. hub_store_context with category="diagram", content=<envelope>.
  2. hub_update_context to change a diagram — the new content must be a complete valid envelope (partial edits are validated against the full effective state).
  3. fetch(id, offset, max_chars) to read back; page beyond ~22 KB with offsets.

The server derives exactly one format:<format> tag per diagram. Caller supplied format:* tags are rejected in any category. Rollback re-validates the historical envelope under your current tier; an invalid legacy version is never written.

No new MCP tools, no ImageContent, no raster ingest in P1 (see §8).

4. Limits

Tier Max payload Diagrams per project
Free 10,000 bytes 5
Pro 100,000 bytes unlimited
Team 256,000 bytes unlimited
  • Sizes are measured in UTF-8 bytes, not characters.
  • The whole envelope is capped at 500,000 bytes (the general content cap).
  • Reads beyond ~22 KB use fetch pagination (offset / max_chars).

5. Security rules (what is rejected)

Mermaid — allowed diagram families are listed in §2; graph/flowchart require a direction (TD, TB, BT, RL, LR). SynContext accepts the documented edge syntax for the pinned Mermaid 11.16.0 grammar, including arrows, length-extensible flow links bounded by the service validator, stateDiagram-v2, and classDiagram-v2. Edge syntax is allowlisted per diagram family. Rejected: unsupported -v2 declarations, residual angle brackets, angle brackets inside quoted labels, backtick markdown strings, click directives, %%{ init/config directives, http:/https:/data:/javascript:/file:/protocol-relative // references, image/icon resources, more than 1,000 lines, or more than 500 parsed edges. Plain full-line %% comments are fine.

Safe example:

{"schema":"syncontext.diagram.v1","format":"mermaid","payload":"graph TD\n  A[Ingest] --> B[Validate]\n  B --> C[Store]"}

Rejected (network reference): A[see https://example] --> B.

Vega-Lite — data must be inline ("data": {"values": [...]}). Rejected at any depth: url, href, loader, usermeta keys (case-insensitive), __proto__/prototype/constructor, image marks, named or remote data loading, non-finite numbers, more than 10,000 inline rows, width/height outside 1–4,000, and any $schema other than https://vega.github.io/schema/vega-lite/v6.json.

Safe example:

{"schema":"syncontext.diagram.v1","format":"vega-lite","payload":{"mark":"bar","data":{"values":[{"x":"a","y":3},{"x":"b","y":7}]},"encoding":{"x":{"field":"x","type":"nominal"},"y":{"field":"y","type":"quantitative"}}}}

Rejected: {"data": {"url": "https://example.com/data.csv"}} — remote data never loads.

SVG (static) — allowed elements: svg, g, defs, symbol, use, path, rect, circle, ellipse, line, polyline, polygon, text, tspan, textPath, style, clipPath, mask, pattern, marker, title, desc, linearGradient, radialGradient, stop. Everything else is rejected — including script, foreignObject, image, a, animation and filter elements, DTD/entity declarations and processing instructions (no <?xml …?> prolog). Attributes are allowlisted; anything starting with on, plus src and xml:base, is rejected. href/xlink:href only on use/textPath and only as #fragment. Paint references only as url(#internal-id). CSS may not contain url(, @import, expression(, javascript:, behavior:, -moz-binding or @font-face.

6. Privacy

  • Storage is unchanged: tenant-scoped and encrypted at rest like every other entry.
  • Rendering happens locally in your browser in the authenticated dashboard, with libraries bundled into the app — no CDN, no external fonts/configs/schemas, no telemetry, no editor hand-off, no external data loading.
  • PNG/SVG export is generated locally; filenames are diagram-<id>.png/svg and never contain titles, project names or content.

7. Errors and fail-closed rendering

Invalid envelopes are rejected on write with a ValueError-style message (HTTP 400 on REST, a bounded {"error": …} on MCP) that never echoes your payload. On read, a malformed or legacy category="diagram" entry renders as escaped plain text with a generic notice — the dashboard never guesses a renderer from tags or content sniffing.

8. Deferred to D-P2

Raster PNG ingest, MCP ImageContent results, and any schema v20 changes are explicitly out of P1 scope and gated by the D#94 triggers.

9. Accessibility

  • Mermaid: add a short title-style first node label or accompanying entry text describing the diagram.
  • Vega-Lite: use "description" in the spec so assistive technologies can announce the chart.
  • SVG logos: include <title> and <desc> children on the root svg.

10. Static logo guidance (size/quality)

  • Prefer plain paths and basic shapes; keep logos under a few kilobytes — they must fit the Free 10 KB payload cap to be portable across tiers.
  • Set a viewBox and omit fixed pixel width/height so the logo scales.
  • Use internal gradients (url(#id)) instead of raster effects; filters, fonts and images are rejected.