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": {
"oneOf": [
{
"type": "integer"
},
{
"type": "string"
}
]
},
"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"
},
{
"$ref": "#/definitions/inline_strong"
},
{
"$ref": "#/definitions/inline_em"
},
{
"$ref": "#/definitions/inline_italic"
}
]
},
"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",
"items": {
"oneOf": [
{
"type": "string"
},
{
"type": "array",
"items": {
"$ref": "#/definitions/inline_element"
}
},
{
"type": "object"
}
]
}
}
}
}
}
},
"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"
}
}
},
"caption": {
"type": "string"
}
}
}
}
},
"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"
}
]
},
"inline_strong": {
"type": "object",
"required": [
"strong"
],
"additionalProperties": false,
"properties": {
"strong": {
"type": "string"
}
}
},
"inline_em": {
"type": "object",
"required": [
"em"
],
"additionalProperties": false,
"properties": {
"em": {
"type": "string"
}
}
},
"inline_italic": {
"type": "object",
"required": [
"italic"
],
"additionalProperties": false,
"properties": {
"italic": {
"type": "string"
}
}
}
}
}
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:
Extension registry and consumer compatibility: README/jsonhtl-extensions. Reconciled 2026-10-06: optional table.caption; string or integer version metadata; list items typed as text, inline arrays or compatibility objects. Offline schema mirror: jsonhtl_schema.json in gdata-server.
strong is a registered alias of bold; em and italic are registered emphasis forms. All take string values and are valid in every inline context.