Skip to content

Using TopoKit with an AI Agent

Instructions for an LLM with web-fetch and HTTP tools. Follow each step in order. Do not skip the schema fetch.

Goal

Turn the user's data into a TopoKit topo and return a https://topokit.io/t/<hash> URL they can share.

Steps

1. Read the JSON schema

Fetch https://topokit.io/docs/data-format. This is the canonical reference for the topo JSON format — the full list of layouts, themes, UI flags, node shapes, edge types, and per-field types lives there. Do not rely on memory; the SDK gains options over time.

2. Look at a real sample

Fetch one of the samples to copy the shape from:

3. Convert the user's data into a TopoKit config

Required fields:

  • nodes: array of { id, data, style }. Always set style.label.text so the node has a human-readable label. Put domain metadata in data (e.g. data.type, data.role) — that powers tooltips and conditional styling.
  • edges: array of { id, source, target, data }. source and target must reference node ids that exist in nodes.

Optional fields (pick from the lists in /docs/data-format):

  • layout — pick by graph shape. DAG / hierarchy → "dagre" or "hierarchical". Tree from a root → "radial". Unstructured network → "force". Small graph (≤ 20 nodes) → "circular" or "concentric". When unsure → "auto".
  • theme — default is "dark". Use "light" only if the user explicitly wants a light look.
  • UI flag booleans: search, minimap, toolbar, tooltip, contextMenu, infoPanel, hoverFocus, layoutSelector, themeSelector. Pass true to enable with defaults. Disable minimap for graphs with ≤ 25 nodes — it adds clutter.
  • legend: use the object form legend: { groupBy: 'data.type' } (substitute whatever meaningful field your nodes share — data.category, data.role, etc.). Do NOT pass legend: true without groupBy — it falls back to grouping by node fill color and shows hex codes (#6B7280, …) as labels. See /docs/components/legend for the full option table.

4. POST the config

http
POST https://topokit.io/api/topos
Content-Type: application/json
Body: 

Response (201): {"hash":""}

Rate limit is roughly 30 writes/minute per IP. Body limit is the Cloudflare ceiling (~100 MB) — fine for any human-scale graph.

5. Return the URL

Build the share URL as https://topokit.io/t/<hash> and return it to the user. That URL renders the topo view-only. If the user wants to edit, send them to /play?from=<hash>.

6. (Optional) Static thumbnail PNG

Every /t/<hash> URL has a matching /t/<hash>.png that serves a 1200×630 render of the topo. By default it returns the static Open Graph fallback on the first request (so social-media unfurlers never wait on the headless browser) and the real chromedp render lands in the cache a few seconds later; subsequent requests get the real PNG with year-long immutable caching.

For build-pipeline use cases — embedding the PNG as a static thumbnail, generating preview cards in a generator, etc. — append ?wait=1: https://topokit.io/t/<hash>.png?wait=1. The request blocks until the render lands (up to ~10 s) and returns the real PNG, or 503 with Retry-After if the render fails. Never returns the fallback.

Minimal example

bash
curl -X POST https://topokit.io/api/topos \
  -H 'Content-Type: application/json' \
  -d '{
    "nodes": [
      {"id":"a","data":{},"style":{"label":{"text":"A"}}},
      {"id":"b","data":{},"style":{"label":{"text":"B"}}}
    ],
    "edges": [{"id":"e1","source":"a","target":"b","data":{}}],
    "layout":"force",
    "theme":"dark"
  }'

# {"hash":"x7Qp"}
# → https://topokit.io/t/x7Qp

Common mistakes to avoid

  • Edge source / target referencing a missing node id. Validate before POSTing — the server will accept the topo but it will render with a broken edge.
  • Forgetting style.label.text. Nodes without a label show only the bare id. Always synthesize a readable label from the data.
  • Guessing layout / theme / UI flag names from memory. The valid sets are defined at /docs/data-format. Re-fetch it if unsure.
  • Embedding non-JSON-serializable values (functions, Dates, undefined). Pre-stringify or drop them.
  • Enabling legend without groupBy. Bare legend: true falls back to grouping by node fill color, producing a legend of hex codes (#6B7280, #3B82F6, …). Always pass legend: { groupBy: 'data.type' } — or whichever field has meaningful category values.

Component options

For the legend, tooltip, badges, minimap, and other UI components, each has its own options page under /docs/components/. Fetch the page for any component you enable beyond bare-default:

See also