Array [[array: SyntaxConcept]]SyntaxConcept
Description [[description: text]]textTable In Array ValidationError 80%Extra Table In Array ValidationError 78%Common Errors NarrativeDoc 77%
Arrays of primitives and objects. QMD.md supports two syntaxes for primitive arrays: YAML notation (compact inline [a, b, c]) and Markdown lists (expanded via subheading). Object arrays are created via subheadings where each child heading becomes an array element. Tables provide a compact alternative for homogeneous object arrays.
Syntax [[syntax: text]]text
YAML inline notation:
- tags: [react, typescript, nodejs]
- ports: [8080, 8081, 8082]
- enabled: [true, false, true]
- mixed: [1, "two", true, null]
Values are wrapped in [...], elements separated by commas. Strings with spaces, commas, or special characters require quotes: "hello world". A quoted element ends at the next occurrence of its own quote character and there is no escape, so an element that contains " is quoted with ': ['say "hi"', x]. Quote true, false, null and numbers to keep them strings: ["42", "true"]. The __syntax field records yaml_array.
YAML multiline notation (for long values):
## Result [[result: TaskResult]]
- files_changed: [
qmdc-rs/src/parser.rs,
qmdc-py/qmdc/parser.py,
qmdc-ts/src/parser.ts
]
- status: done
Opening bracket [ on the same line as the field name, each element on its own line with 4-space indent, closing bracket ] on a separate line with 2-space indent. The __syntax field records yaml_multiline_array (preserves formatting on round-trip).
Markdown lists via subheading:
## Team [[team]]
### Members [[members]]
- Alice
- Bob
- Charlie
A subheading with [[field_id]] followed by a bullet list without colons (- value, not - key: value). Each list item is an array element. Supports multiline elements. The __syntax field records markdown_list.
Explicit type annotation: [[field_id: [type]]] where type is [string], [number], [boolean], or a user-defined type.
Comma-separated references (no outer brackets):
- deps: [[#auth]], [[#db]], [[#cache]]
Object arrays via subheadings with [[field: [Kind]]]:
## My Scenario [[my_scenario]]
- name: Zoe
### Stages [[stages: [Stage]]]
#### After Class [[after_class]]
- duration: 10
#### Sketch [[sketch]]
- duration: 15
Each child heading at the next level becomes a separate object in the array. The parent gets stages: ["[[#after_class]]", "[[#sketch]]"], and each child gets __parent and __parent_field auto-links.
Variants for the section heading:
[[field_id]]— array without type (auto-detection)[[field_id: [Kind]]]— typed array (strict validation)[[field_id: array]]— explicit array (strict validation)
Table syntax as compact alternative:
## Team [[team]]
### Members [[members: [User]]]
| name | role | email |
| ------- | --------- | -------------- |
| Alice | admin | alice@ex.com |
| Bob | developer | bob@ex.com |
| Charlie | designer | charlie@ex.com |
First row = field names, each data row = one object. Supports primitives and references in cells. The __syntax field records table.
The table must be the array container's own content — directly under the array heading, as above. A table written inside one of the array's ELEMENTS is that element's content, not more rows for the array:
### Members [[members: [User]]]
#### Alice [[alice]]
- role: admin
| col_a | col_b |
| ----- | ----- |
| r1 | v1 |
Here the table belongs to alice and is carried as its comment content; members keeps exactly
one element.
Only the FIRST table under an array heading feeds the array. A second table under the same heading
describes nothing — its rows cannot extend the array, since they would collide on the generated
positional ids — so it produces an extra_table_in_array error. Its content is still preserved
verbatim in the container's __comments.
An array is written in ONE form, not both. Once it has been fed by a table, a following element
heading cannot join it and produces a mixed_array error — it would otherwise become a plain field
on the parent with its Kind silently dropped. To attach a table to an element deliberately and have it land in a named field,
declare a text field for it (#### Details [[details: text]]) — text fields are covered in
docs/format/fields.qmd.md.
A PRIMITIVE array, [[field: array]], holds list items, so a deeper heading inside it cannot be an
element — and it does not become an object either, because a declared field kind decides what the
section is (see docs/format/headings.qmd.md). Such a heading produces a mixed_array error at its
own line and closes the array's content, exactly as prose between two lists does.
Examples [[examples: text]]textMixed Array ValidationError 79%Syntax Syntax 77%Table In Array ValidationError 76%
Primitive arrays — strings:
## Config [[config]]
- tags: [react, typescript, nodejs]
[
{
"__id": "config",
"__label": "Config",
"__syntax": { "tags": "yaml_array" },
"tags": ["react", "typescript", "nodejs"]
}
]
Primitive arrays — numbers:
## Config [[config]]
### Ports [[ports]]
- 8080
- 8081
- 8082
[
{
"__id": "config",
"__label": "Config",
"__syntax": { "ports": "markdown_list" },
"ports": [8080, 8081, 8082]
}
]
Primitive arrays — mixed types:
- values: [null, 42, "hello world"]
Multiline elements:
## Documentation [[documentation]]
### Notes [[notes]]
- First note with
multiple lines
of text
- Second note
- Third note
[
{
"__id": "documentation",
"__label": "Documentation",
"notes": [
"First note with\nmultiple lines\nof text",
"Second note",
"Third note"
]
}
]
Object arrays with parent-child links:
## Company [[acme]]
- name: Acme Corporation
### Teams [[teams: [Team]]]
#### Engineering [[team_eng]]
- members: 45
#### Marketing [[team_marketing]]
- members: 25
[
{
"__id": "acme",
"__label": "Company",
"name": "Acme Corporation",
"teams": ["[[#team_eng]]", "[[#team_marketing]]"]
},
{
"__id": "team_eng",
"__label": "Engineering",
"__kind": "Team",
"__parent": "[[#acme]]",
"__parent_field": "teams",
"members": 45
},
{
"__id": "team_marketing",
"__label": "Marketing",
"__kind": "Team",
"__parent": "[[#acme]]",
"__parent_field": "teams",
"members": 25
}
]
Table syntax with references in cells:
## Organization [[org]]
### Team Members [[members: [Member]]]
| name | role | manager |
| ------- | ---------------- | ---------- |
| Alice | [[#admin_role]] | [[#bob]] |
| Bob | [[#dev_role]] | null |
| Charlie | [[#design_role]] | [[#alice]] |
Rules [[rules: text]]textTable In Array ValidationError 79%Mixed Array ValidationError 78%Validation Validation 76%
- Only bullet lists are allowed in heading-syntax primitive arrays. Numbered lists (
1. item) produce anordered_list_in_arrayerror. - A Markdown table is not allowed under a primitive array field either — a primitive array holds scalars and a table has columns, so there is no mapping. It produces a
table_in_arrayerror. Tables ARE valid under an object array ([[field: [Kind]]]), where one row becomes one object. - Parent-child auto-links: objects inside array sections (
[[field: [Kind]]]or[[field: array]]) automatically receive__parent(reference to the parent object) and__parent_field(field name in the parent). Independent objects outside array sections do not get__parent. - Syntax choice is preserved in
__syntaxfor lossless round-trip:yaml_array,yaml_multiline_array,markdown_list,headers,table. - Table syntax is equivalent to subheading syntax but more compact. The same data can be expressed either way.
- Tables support only primitives and references in cells — nested objects are not supported.
- In table syntax, objects receive auto-generated
__idvalues (e.g.user_0,user_1) unless an explicit ID column is present. - Text around tables (before or after) is captured in
__comments.