Extension Schema Specification
Quarto extensions can provide a _schema.yml file alongside their _extension.yml manifest. This file declares every configurable option, shortcode parameter, format key, element attribute, and CSS class the extension accepts.
A single schema serves two consumers:
- Lua runtime validates options when Quarto renders, catching configuration errors early with clear messages.
- IDE tooling (Quarto Wizard) reads the same file to provide autocompletion, hover documentation, and diagnostics in
_quarto.yml,_metadata.yml, and document YAML front matter.
Schema specification support in Quarto Wizard may evolve over time. Quarto CLI may use, modify, or discard this schema behaviour in future releases. No guarantees are provided regarding Quarto CLI native support.
File Location
Place _schema.yml (or _schema.yaml) in the same directory as _extension.yml. A _schema.json file is also supported alongside or instead of the YAML variants.
Tree
_extensions/
└── my-extension/
├── _extension.yml
├── _schema.yml
└── my-extension.luaWhen both a JSON and a YAML schema exist in the same directory, the JSON file takes precedence. JSON files use camelCase keys natively (e.g., enumCaseInsensitive, patternExact, minLength), whereas YAML files use kebab-case (e.g., enum-case-insensitive, pattern-exact, min-length).
Quarto Wizard discovers schema files automatically when scanning installed extensions.
Schema Version ($schema)
Schema files may include a $schema key at the top level to declare the schema format version. This is optional but recommended for forward-compatibility.
yaml
$schema: https://m.canouil.dev/quarto-wizard/assets/schema/v1/extension-schema.json
options:
threshold:
type: numberThe currently supported URI is:
https://m.canouil.dev/quarto-wizard/assets/schema/v1/extension-schema.json
When an unrecognised version URI is encountered, Quarto Wizard emits a warning but does not reject the schema. This allows older tooling to gracefully handle schemas written for newer versions.
Top-level Structure
The schema has six optional top-level sections. An extension may define any combination of these.
yaml
# Extension-level metadata options (all extension types).
# Configured under the extension name in YAML metadata.
options:
<option-name>: <field-descriptor>
# Per-shortcode schemas (one entry per contributed shortcode).
shortcodes:
<shortcode-name>:
description: <string>
arguments:
- name: <string>
<field-descriptor properties>
attributes:
<attribute-name>: <field-descriptor>
# Per-format schemas (one entry per contributed format).
# Configured under format: <format-name>: in YAML metadata.
formats:
<format-name>:
<option-name>: <field-descriptor>
# Project types contributed by the extension.
# Suggested for project.type in _quarto.yml.
projects:
- <project-type>
# Element attributes accepted by filters on Div/Span/CodeBlock elements.
# Used in: [text]{.class attr=value} or ::: {.class attr=value}
# These are Pandoc AST element attributes, not metadata options.
attributes:
<class-or-context>:
<attribute-name>: <field-descriptor>
# CSS classes contributed by filters, with descriptions.
# Used in: [text]{.class} or ::: {.class}
classes:
<class-name>:
description: <string>options
Extension-level configuration options. Users set these values in _quarto.yml, _metadata.yml, or document front matter, scoped under the extension name inside an extensions key.
Given a _schema.yml for an extension called spotlight:
_extensions/spotlight/_schema.yml
options:
size:
type: number
default: 60
description: "Radius of the spotlight circle in pixels."
lockPointerInsideCanvas:
type: boolean
default: false
description: "Whether to lock the mouse pointer inside the canvas."The corresponding user configuration in _quarto.yml would be:
_quarto.yml
extensions:
spotlight:
size: 80
lockPointerInsideCanvas: trueThe same structure works in _metadata.yml or document front matter:
presentation.qmd
---
title: "My Presentation"
extensions:
spotlight:
size: 80
---shortcodes
Per-shortcode schemas, keyed by shortcode name. Each shortcode entry can specify a description, positional arguments (as an ordered array), and named attributes (as a map).
yaml
shortcodes:
modal:
description: "Generate a Bootstrap modal toggle or dismiss button."
arguments:
- name: type
type: string
default: "toggle"
enum: [toggle, dismiss]
description: "Button type: toggle to open, dismiss to close."
attributes:
target:
type: string
description: "ID of the modal to target (without the # prefix)."
label:
type: string
description: "Button label text."Shortcode arguments use the same field descriptor properties as options, plus a required name field that identifies the positional argument.
formats
Per-format options, keyed by the format name as it appears in YAML metadata (e.g., letter-pdf, invoice-pdf).
yaml
formats:
letter-pdf:
address:
type: array
required: true
description: "Recipient address lines."
items:
type: string
subject:
type: string
description: "Letter subject line."projects
An array of project type strings contributed by the extension. These values are suggested for project.type in _quarto.yml.
yaml
projects:
- my-websiteattributes
Attributes accepted by filter extensions on Pandoc Div, Span, CodeBlock, and Header elements. Groups are matched against the current element using five strategies:
_any: matches any element regardless of class, ID, or type.- CSS class name (e.g.
panel,highlight): matches elements that carry that class. - ID prefix (e.g.
modalmatches#modal-example): matches elements whose ID starts with that prefix followed by a hyphen. - Pandoc element type (
Div,Span,Code,CodeBlock,Header): matches based on the structural context (fenced div:::, bracketed span], backtick code`, or ATX heading#).
Group key matching is case-insensitive: div matches Div, codeblock matches CodeBlock, header matches Header, and so on.
Use _any for attributes accepted on any element regardless of class.
yaml
attributes:
_any:
colour:
type: string
aliases: [color, ink, fg]
description: "Text (foreground) colour."
completion:
type: color
bg-colour:
type: string
aliases: [bg-color, bg, paper]
description: "Background colour."
completion:
type: color
Header:
toc-depth:
type: number
min: 1
max: 6
description: "Override table-of-contents depth for this heading."
CodeBlock:
filename:
type: string
description: "Display filename label for the code block."classes
CSS classes contributed by the extension’s filters. Each entry maps a class name to a descriptor containing a description. Quarto Wizard uses this information to provide class name completion and hover documentation in fenced divs (:::), bracketed spans ([]), and code block attributes.
yaml
classes:
panel:
description: "Wraps content in a styled panel box."
highlight:
description: "Applies highlight styling to the element."
callout-note:
description: "Renders a note-style callout block."Field Descriptor Properties
Every option, argument, or attribute is described by the same set of properties. All properties are optional.
Type and Value Constraints
| Property | Type | Description |
|---|---|---|
type |
string |
Expected value type: string, number, integer, boolean, array, object, or content. |
required |
boolean |
Whether the field must be present. Default: false. |
default |
any | Default value applied when not provided. |
const |
any | Fixed value the field must equal. |
enum |
array | List of allowed values. |
enum-case-insensitive |
boolean |
Case-insensitive enum matching. Default: false. |
pattern |
string |
Regular expression the value must match (JS regex syntax). |
pattern-exact |
boolean |
Anchor the pattern to match the entire value (wraps in ^...$). Default: false. |
min |
number |
Minimum value (inclusive, for type: number or type: integer). |
max |
number |
Maximum value (inclusive, for type: number or type: integer). |
minimum |
number |
Alias for min. |
maximum |
number |
Alias for max. |
exclusive-minimum |
number |
Exclusive minimum (value must be strictly greater). |
exclusive-maximum |
number |
Exclusive maximum (value must be strictly less). |
min-length |
integer |
Minimum string length (for type: string). |
max-length |
integer |
Maximum string length (for type: string). |
min-items |
integer |
Minimum number of items (for type: array). |
max-items |
integer |
Maximum number of items (for type: array). |
The integer type validates that the value is a whole number. It supports the same numeric constraints as number (min, max, exclusive-minimum, exclusive-maximum).
The content type is specific to shortcode arguments and accepts any Pandoc Inlines, Blocks, or string value. Validation only checks presence (for required); no further type or pattern checking applies.
In JSON schema files, the properties above use camelCase equivalents: enumCaseInsensitive, patternExact, minLength, maxLength, minItems, maxItems, exclusiveMinimum, and exclusiveMaximum.
Metadata Properties
| Property | Type | Description |
|---|---|---|
description |
string |
Human-readable description shown in hover tooltips and completion detail. |
aliases |
array<string> |
Alternative accepted names (e.g., [color] alongside colour). |
deprecated |
boolean, string, or object |
Mark the field as deprecated (see Deprecation). |
Nested Type Properties
| Property | Type | Description |
|---|---|---|
items |
field descriptor | Schema for array elements (when type: array). |
properties |
map<string, field descriptor> |
Schema for object keys (when type: object). |
Completion
The completion object controls IDE autocomplete behaviour. When omitted, Quarto Wizard infers completion from other properties (e.g., enum values become suggestions, type: boolean suggests true/false).
| Property | Type | Description |
|---|---|---|
type |
string |
Completion strategy (see Completion types). |
extensions |
array<string> |
File extension filter for type: file (e.g., [.csv, .xlsx]). |
placeholder |
string |
Hint text for type: freeform. |
values |
array |
Override values for type: enum (when different from validation enum). |
dynamic |
boolean |
Values come from external sources (brand colours, filesystem). Default: false. |
source |
string |
Hint for dynamic value source (e.g., "brand-colors", "git-remote"). |
Completion Types
| Type | IDE Behaviour |
|---|---|
enum |
Suggests values from the enum or values property. |
file |
Opens a file picker filtered by extensions. |
color |
Shows a colour picker. |
boolean |
Suggests true and false. |
freeform |
Shows a text input with placeholder as hint. |
size |
Suggests common CSS size values. |
none |
Disables autocompletion for this field. |
Features
Alias Resolution
Alternative field names allow extensions to accept multiple spellings. The IDE suggests all names; the Lua validator resolves aliases to the primary key.
yaml
colour:
type: string
aliases: [color, ink, fg]
description: "Text colour."If a user provides color: red, validation and merging resolve it to colour = "red".
Deprecation
The deprecated property supports three forms:
deprecated: truemarks the field as deprecated with a generic warning.deprecated: "Use X instead"uses the string as the warning message.- Object form with
replace-withenables automatic value forwarding.
yaml
old_colour:
type: string
deprecated:
since: "1.2"
message: "Use colour instead."
replace-with: colour
colour:
type: stringWhen replace-with is specified, the deprecated key’s value is forwarded to the replacement key automatically. The IDE shows a diagnostic on deprecated fields.
Boolean Coercion
YAML parsers accept true, True, yes, on (and their negatives) as boolean values. Pandoc metadata may deliver these as native booleans or as the strings "true"/"false".
For type: boolean fields, string representations are normalised to native booleans before validation.
Nested Validation
When type: array with an items descriptor, each array element is validated against the items schema. When type: object with a properties descriptor, the object value is validated recursively.
yaml
badge:
type: array
description: "Array of badge configuration objects."
items:
type: object
properties:
key:
type: string
required: true
description: "Unique identifier for the badge."
colour:
type: string
aliases: [color]
description: "Background colour for the badge."
completion:
type: colorCommon Patterns
Filter with options
A filter extension that reads configuration from YAML metadata.
_schema.yml
options:
enabled:
type: boolean
default: true
description: "Enable or disable the extension."
threshold:
type: number
min: 0
max: 1
default: 0.5
description: "Detection threshold value."Shortcode with arguments and attributes
A shortcode extension with positional arguments and named attributes.
_schema.yml
shortcodes:
iconify:
description: "Renders an Iconify icon."
arguments:
- name: set-or-icon
type: string
required: true
description: "Icon set name, or 'set:icon' combined format."
- name: icon
type: string
description: "Icon name when the first argument is the set name."
attributes:
size:
type: string
description: "Icon size as a keyword or CSS value."
flip:
type: string
enum: [horizontal, vertical, "horizontal,vertical"]
description: "Flip transformation for the icon."Format extension
A format extension with format-specific options.
_schema.yml
formats:
letter-pdf:
address:
type: array
required: true
description: "Recipient address lines."
items:
type: string
opening:
type: string
description: "Opening salutation."
closing:
type: string
description: "Closing salutation."Element attributes with colour picker
A filter extension that processes element attributes with IDE colour picker support.
_schema.yml
attributes:
_any:
colour:
type: string
aliases: [color, ink, fg]
description: "Text (foreground) colour."
completion:
type: color
bg-colour:
type: string
aliases: [bg-color, bg, paper]
description: "Background colour."
completion:
type: color
border-colour:
type: string
aliases: [border-color, bc]
description: "Border colour."
completion:
type: colorCombined extension
An extension that defines options, shortcodes, and attributes together.
_schema.yml
options:
size:
type: string
default: ""
enum: ["", sm, lg, xl]
enum-case-insensitive: true
description: "Default modal dialog size."
fade:
type: boolean
default: false
description: "Apply a fade transition."
shortcodes:
modal:
description: "Generate a Bootstrap modal button."
arguments:
- name: type
type: string
default: "toggle"
enum: [toggle, dismiss]
description: "Button type."
attributes:
target:
type: string
description: "ID of the modal to target."
label:
type: string
description: "Button label text."
attributes:
modal:
size:
type: string
enum: ["", sm, lg, xl]
enum-case-insensitive: true
description: "Modal dialog size override."
fade:
type: boolean
description: "Apply a fade transition for this modal."Reference Schema Files
The JSON Schema meta-schema that formally describes the structure of _schema.yml and _schema.json files is published at:
extension-schema.json(JSON Schema draft 2020-12).
This is the same schema referenced by the $schema key at the top of schema definition files. It can be used by any JSON Schema-aware tool for validation and autocompletion.
Example instances showing every supported property are also available:
extension-schema-example.yml(YAML example, kebab-case keys).extension-schema-example.json(JSON example, camelCase keys).
Generating a Schema with AI
The prompt below can be used with an AI assistant to generate a _schema.yml for an existing extension. Copy the prompt, attach your extension’s _extension.yml and Lua source files, and the assistant will produce a schema that matches your extension’s actual behaviour.
_schema.yml
markdown
Generate a `_schema.yml` file for the attached Quarto extension.
Read the attached `_extension.yml` to identify the extension name and
contribution types (filters, shortcodes, formats, projects).
Then read every Lua source file to discover:
1. **Options** read from `meta` or `meta['extensions']` tables.
Record each key, its expected type, any default value, and whether
it is required.
2. **Shortcode arguments and attributes** parsed in shortcode handler
functions. Record positional arguments (in order) and named
attributes with their types, defaults, and allowed values.
3. **Format-specific options** read under a format name in metadata.
4. **Attributes** read from `el.attributes` in Div, Span, or
CodeBlock filter functions. Group them by CSS class (use `_any` when
the attribute applies regardless of class).
5. **Classes** contributed by the extension's filters. List each CSS
class name the extension handles, with a short description.
Look for patterns such as `el.classes:includes("name")`,
`el.classes:find("name")`, or class-based conditionals.
6. **Project types** declared or contributed by the extension. If the
extension provides a project type, list it under the `projects`
top-level key.
For every field use the following properties where applicable:
- `type`: `string`, `number`, `integer`, `boolean`, `array`, `object`,
or `content` (for shortcode arguments that receive Pandoc content).
Use `integer` when only whole numbers are valid.
When a field accepts multiple types, use an array
(e.g., `type: [string, number]`).
- `required`: set to `true` only when the code raises an error or
returns early for missing values.
- `default`: the fallback value used in the code.
- `const`: a fixed value the field must equal, when the code expects
exactly one value.
- `enum`: list of allowed values when the code checks against a
fixed set.
- `enum-case-insensitive`: `true` when the code lowercases or
case-folds before comparing.
- `pattern`: regular expression the value must match (JS syntax).
- `pattern-exact`: `true` to anchor the pattern with `^...$`.
- `min` / `max`: inclusive numeric bounds
(`minimum` and `maximum` are accepted as aliases).
- `exclusive-minimum` / `exclusive-maximum`: exclusive numeric bounds
(value must be strictly greater / strictly less).
- `min-length` / `max-length`: string length constraints.
- `min-items` / `max-items`: array item count constraints.
- `aliases`: alternative key names accepted by the code.
- `deprecated`: `true`, a message string, or an object with `since`,
`message`, and `replace-with` keys.
- `description`: one sentence in British English explaining the option.
- `completion`: controls IDE autocompletion behaviour. Sub-properties:
`type` (`color` for CSS colour values, `file` for file paths,
`freeform` for text input, `none` to disable), `extensions`
(file extensions to filter when `type: file`), `placeholder`
(hint text for `freeform`), `values` (static suggestion list),
`dynamic` and `source` (for runtime-resolved values).
Omit `completion` to let the IDE infer from `enum` and `type`.
- `items`: schema for elements of an `array` type. Use `items` to
describe what each array element looks like (its type, enum, etc.).
- `properties`: schema for keys of an `object` type. Use `properties`
to describe each expected key and its constraints.
Output only the YAML content of `_schema.yml`, nothing else.
Use kebab-case for multi-word property names (`enum-case-insensitive`,
not `enumCaseInsensitive`).
Add a one-line comment header: `# Schema for the <name> extension`.
Optionally include `$schema: https://m.canouil.dev/quarto-wizard/assets/schema/v1/extension-schema.json`
at the top level.