This is the internal, portable format for custom webs. External sources are converted into this.
A self-contained knowledge web.
Required:
id (string, stable)title (string)createdAt (ISO string)updatedAt (ISO string)Optional:
description (string)settings (object)A thing in the web: person, place, event, object, concept.
Required:
id (string, stable)title (string)kind (string, e.g. person, place, event, concept)summary (string, short)Optional:
body (rich text blocks, see below)time (object)location (object)media (array)tags (array of strings)sources (array)A relationship between two nodes.
Required:
id (string, stable)from (node id)to (node id)type (string, controlled vocabulary per web)label (string, short)Optional:
description (string)time (object)weight (number)sources (array)A recorded journey.
Required:
idtitlesteps (array of node ids)createdAtOptional:
descriptiontagsTime is modeled as a flexible range:
{
"start": "1800-01-01",
"end": "1899-12-31",
"label": "19th century",
"precision": "year|month|day|range|circa"
}
For “century” nodes, time can be the century span.
{
"lat": 57.7089,
"lon": 11.9746,
"label": "Göteborg, Sweden"
}
Avoid raw HTML in the stored model. Use blocks:
paragraphheadingimagequotelistlink (internal node refs and external URLs)Example:
{
"type": "paragraph",
"text": "This connects to [[node:abc123]] and also to https://example.com"
}
The renderer turns [[node:...]] into internal links.
A “web package” is a folder or zip containing:
web.json (the full web)media/ (optional)meta.json (optional, versioning)See ./persistence.md for details.
{
"version": 1,
"web": {
"id": "demo",
"title": "Demo Web",
"createdAt": "2026-01-01T00:00:00Z",
"updatedAt": "2026-01-01T00:00:00Z"
},
"nodes": [
{ "id": "a", "title": "Node A", "kind": "concept", "summary": "A thing." },
{ "id": "b", "title": "Node B", "kind": "concept", "summary": "Another thing." }
],
"links": [
{ "id": "l1", "from": "a", "to": "b", "type": "relates-to", "label": "relates to" }
],
"trails": []
}