Machine-readable JSON Schema (Draft-07) for JSONHTL documents. The linter reads this note and extracts the schema from the codeblock below to validate documents dynamically.
Human-readable linter specification: gdata-server/linter. Base format: JSONHTL_SPEC. Extensions: README/format.
This note and gdata-server/linter must be kept in sync for structural changes. Semantic-only changes (e.g. updating a description field) do not require updates to the other. When in doubt, update both and note what changed.
The linter fetches this note by key JSONHTL_SCHEMA and uses the first codeblock with lang: json as the schema.
{
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "JSONHTL Document",
"description": "Machine-readable schema for JSONHTL documents. Canonical note: JSONHTL_SCHEMA. Text spec: gdata-server/linter.",
"type": "object",
"required": ["content"],
"additionalProperties": true,
"properties": {
"title": {"type": "string"},
"version": {"type": "integer"},
"updated": {"type": "string", "pattern": "^\\d{4}-\\d{2}-\\d{2}$"},
"created": {"type": "string", "pattern": "^\\d{4}-\\d{2}-\\d{2}$"},
"tags": {"type": "array", "items": {"type": "string"}},
"runnable": {"type": "boolean"},
"content": {
"oneOf": [
{"type": "string"},
{"type": "array", "items": {"$ref": "#/definitions/block"}}
]
}
},
"definitions": {
"inline_link": {
"type": "object", "required": ["link"], "additionalProperties": false,
"properties": {
"link": {
"type": "object", "required": ["href", "text"], "additionalProperties": false,
"properties": {
"href": {"type": "string"},
"text": {"type": "string"}
}
}
}
},
"inline_code": {
"type": "object", "required": ["code"], "additionalProperties": false,
"properties": {"code": {"type": "string"}}
},
"inline_bold": {
"type": "object", "required": ["bold"], "additionalProperties": false,
"description": "Registered extension. Both renderers support it; not in JSONHTL_SPEC base.",
"properties": {"bold": {"type": "string"}}
},
"inline_element": {
"oneOf": [
{"type": "string"},
{"$ref": "#/definitions/inline_link"},
{"$ref": "#/definitions/inline_code"},
{"$ref": "#/definitions/inline_bold"}
]
},
"para_content": {
"oneOf": [
{"type": "string"},
{"type": "array", "items": {"$ref": "#/definitions/inline_element"}}
]
},
"table_cell": {
"description": "A table cell is a string or an inline-element list (same content model as para), so links and other inline objects are valid in cells.",
"oneOf": [
{"type": "string"},
{"type": "array", "items": {"$ref": "#/definitions/inline_element"}}
]
},
"block_para": {
"type": "object", "required": ["para"], "additionalProperties": false,
"properties": {"para": {"$ref": "#/definitions/para_content"}}
},
"block_heading": {
"type": "object", "required": ["heading"], "additionalProperties": false,
"properties": {
"heading": {
"type": "object", "required": ["level", "text"], "additionalProperties": false,
"properties": {
"level": {"type": "integer", "minimum": 1, "maximum": 6},
"text": {"type": "string"}
}
}
}
},
"block_codeblock": {
"type": "object", "required": ["codeblock"], "additionalProperties": false,
"properties": {
"codeblock": {
"type": "object", "required": ["lang", "body"], "additionalProperties": false,
"properties": {
"lang": {"type": "string"},
"body": {"type": "string"},
"exec": {"type": "boolean", "description": "Runnable extension. Only valid when document has runnable: true."},
"name": {"type": "string", "description": "Runnable extension. Must be unique within document. Only valid when runnable: true."}
}
}
}
},
"block_list": {
"type": "object", "required": ["list"], "additionalProperties": false,
"properties": {
"list": {
"type": "object", "required": ["items"], "additionalProperties": false,
"properties": {
"label": {"type": "string"},
"ordered": {"type": "boolean"},
"items": {"type": "array"}
}
}
}
},
"block_table": {
"type": "object", "required": ["table"], "additionalProperties": false,
"properties": {
"table": {
"type": "object", "required": ["columns", "rows"], "additionalProperties": false,
"properties": {
"columns": {"type": "array", "items": {"type": "string"}},
"rows": {"type": "array", "items": {"type": "array", "items": {"$ref": "#/definitions/table_cell"}}}
}
}
}
},
"block_image": {
"type": "object", "required": ["image"], "additionalProperties": false,
"description": "Spec-base block (JSONHTL_SPEC, added 2026-07-17). Raster image; data is base64.",
"properties": {
"image": {
"type": "object", "required": ["format", "data"], "additionalProperties": false,
"properties": {
"format": {"type": "string"},
"data": {"type": "string"},
"alt": {"type": "string"},
"caption": {"type": "string"}
}
}
}
},
"block_svg": {
"type": "object", "required": ["svg"], "additionalProperties": false,
"description": "Spec-base block (JSONHTL_SPEC, added 2026-07-17). Inline vector diagram; body is raw SVG XML (text, not base64).",
"properties": {
"svg": {
"type": "object", "required": ["body"], "additionalProperties": false,
"properties": {
"body": {"type": "string"},
"alt": {"type": "string"},
"caption": {"type": "string"}
}
}
}
},
"block_details": {
"type": "object", "required": ["details"], "additionalProperties": false,
"description": "Spec-base block (JSONHTL_SPEC, added 2026-07-17). Collapsible section; content is nested blocks.",
"properties": {
"details": {
"type": "object", "required": ["summary", "content"], "additionalProperties": false,
"properties": {
"summary": {"type": "string"},
"content": {"type": "array", "items": {"$ref": "#/definitions/block"}}
}
}
}
},
"block_section": {
"type": "object", "required": ["section"], "additionalProperties": false,
"description": "Nested section container (proposal: proposals/section-editing). title is the heading text; level is optional (defaults to nesting depth); content is a recursive block list. Coexists with the legacy flat heading block during migration.",
"properties": {
"section": {
"type": "object", "required": ["title", "content"], "additionalProperties": false,
"properties": {
"title": {"type": "string"},
"level": {"type": "integer", "minimum": 1, "maximum": 6},
"content": {"type": "array", "items": {"$ref": "#/definitions/block"}}
}
}
}
},
"block": {
"oneOf": [
{"$ref": "#/definitions/block_para"},
{"$ref": "#/definitions/block_heading"},
{"$ref": "#/definitions/block_codeblock"},
{"$ref": "#/definitions/block_list"},
{"$ref": "#/definitions/block_table"},
{"$ref": "#/definitions/block_image"},
{"$ref": "#/definitions/block_svg"},
{"$ref": "#/definitions/block_details"},
{"$ref": "#/definitions/block_section"}
]
}
}
}
These are not in the JSONHTL_SPEC base but are registered here as supported extensions:
These appear in renderer code but are not registered. The linter should flag them as unknown block types: