Skip to content

Graph file schema

A Nesso graph file is a single JSON document. The envelope — versioning, the concept and relation arrays — is owned by @nesso-how/schema and is vocabulary-agnostic; the meaning of the content is owned by the vocabulary declared in vocabulary. The app exports exactly this shape, the @nesso-how/graph embed renders it, and the MCP server’s validate_graph and build_graph tools check and produce it.

FieldTypeDescription
version1Envelope format version. Older released formats upgrade on load; a newer unsupported version is rejected so its data is not misinterpreted.
namestringGraph name.
vocabulary{ id, version }The vocabulary the graph was built with, e.g. { "id": "@nesso-how/vocab-learning", "version": "0.2.0" }. Files missing it, or declaring a foreign id or unsupported version, are rejected on import.
idstring (optional)Internal graph id used by desktop project sync; omitted in manual exports.
updatedAtnumber (optional)Last save time as Unix milliseconds; desktop sync metadata.
conceptsConcept[]The nodes (see below).
relationsRelation[]The edges (see below).
metaobject (optional)App metadata. The app stores the graph’s display settings under meta.display. Opaque to the schema.
{
"id": "n1",
"label": "Sunlight",
"x": 120,
"y": 80,
"data": { "elaboration": { "definition": "Light energy from the sun." } }
}
  • id: opaque string, unique within the file.
  • label: the concept title shown on the canvas.
  • x, y: canvas position.
  • data.elaboration (optional): definition, a short explanation in your own words that feeds Review and the AI mentor, and notes, an optional bounded rich-text document ({ "type": "doc", "content": [...] }, at most 8 levels deep and 100,000 serialized characters). Blocks an app version does not know load as their plain text. See How notes are stored.
{ "id": "e1", "source": "n1", "target": "n2", "type": "enables" }
  • source, target: ids of concepts in the same file; validate_graph reports a dangling endpoint as an error.
  • type: a relation type id from the relation types reference. A missing type is reported as a warning by validate_graph (the app falls back to causes at render time); an unknown type is an error.
  • data (optional): curveFlip and curveFlipPinned, the manual curve bend controls from Display options.
{
"version": 1,
"vocabulary": { "id": "@nesso-how/vocab-learning", "version": "0.2.0" },
"name": "Photosynthesis",
"concepts": [
{ "id": "n1", "label": "Sunlight", "x": 120, "y": 80 },
{
"id": "n2",
"label": "Glucose",
"x": 320,
"y": 80,
"data": { "elaboration": { "definition": "A sugar plants produce." } }
}
],
"relations": [{ "id": "e1", "source": "n1", "target": "n2", "type": "enables" }]
}

The MCP server can build a complete document for you: its build_graph tool assigns ids, vocabulary metadata, and layout positions, and accepts notes as plain text (capped at 20,000 characters).

  • FSRS review progress (stability, difficulty, due dates): stored separately and never exported, so sharing a file never carries recall history. See Export and import.
  • Runtime render state: React Flow internals and selection live only in the app.

Envelope and vocabulary versions are independent axes with sequential migration ladders. See File compatibility for the policy and the supported baselines.