From e8ead934c92bcd7009e7aa01a20d0c47bd17240e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micka=C3=ABl=20Canouil?= <8896044+mcanouil@users.noreply.github.com> Date: Mon, 9 Mar 2026 21:24:05 +0100 Subject: [PATCH 01/17] feat(quarto): add quarto-lua skill for Lua shortcodes and filters Add a new skill for writing Lua shortcodes and filters in Quarto. Covers handler patterns, Lua style conventions, Quarto-specific APIs, and delegates to Quarto's .llms.md pages for detailed API reference. --- .claude-plugin/marketplace.json | 3 +- README.md | 1 + quarto/README.md | 32 ++++--- quarto/quarto-lua/SKILL.md | 164 ++++++++++++++++++++++++++++++++ 4 files changed, 188 insertions(+), 12 deletions(-) create mode 100644 quarto/quarto-lua/SKILL.md diff --git a/.claude-plugin/marketplace.json b/.claude-plugin/marketplace.json index 4edc581..8bb7ca4 100644 --- a/.claude-plugin/marketplace.json +++ b/.claude-plugin/marketplace.json @@ -74,7 +74,8 @@ "skills": [ "./brand-yml", "./quarto/quarto-authoring", - "./quarto/quarto-alt-text" + "./quarto/quarto-alt-text", + "./quarto/quarto-lua" ] } ] diff --git a/README.md b/README.md index f882fac..ba7558d 100644 --- a/README.md +++ b/README.md @@ -54,6 +54,7 @@ Skills for Quarto document creation and publishing. - **[brand-yml](./brand-yml/)** - Create and apply brand.yml files for consistent styling across Quarto projects, supporting HTML documents, dashboards, RevealJS presentations, Typst PDFs, and websites with automatic brand discovery and theme layering - **[authoring](quarto/README.md#quarto-authoring-skill)** - Comprehensive guidance for Quarto document authoring and R Markdown migration. Write new Quarto documents with best practices, convert R Markdown files, migrate bookdown/blogdown/xaringan/distill projects, and use Quarto-specific features like hashpipe syntax, cross-references, callouts, and extensions - **[quarto-alt-text](./quarto/quarto-alt-text/)** - Generate accessible alt text for figures in Quarto documents using Amy Cesal's three-part formula (chart type, data description, key insight). Supports code-generated plots and static images +- **[quarto-lua](./quarto/quarto-lua/)** - Write Lua shortcodes and filters for Quarto, with runtime access to Quarto's LLM-optimised API documentation ## Installation diff --git a/quarto/README.md b/quarto/README.md index 61a853e..9cc15c5 100644 --- a/quarto/README.md +++ b/quarto/README.md @@ -76,10 +76,11 @@ Comprehensive guidance for Quarto document authoring and R Markdown migration. W Create and use `_brand.yml` files for consistent branding across Quarto documents and Shiny applications. Use when working with brand styling, corporate identity, colors, fonts, or logos in Quarto projects. **Organization**: Main skill file includes workflows and decision tree. Reference files provide framework-specific integration guides: -- `brand-yml-spec.md` - Complete brand.yml specification -- `shiny-r.md` - Shiny for R integration with bslib -- `shiny-python.md` - Shiny for Python integration with ui.Theme -- `quarto.md` - Quarto integration for all formats (HTML, dashboards, RevealJS presentations, Typst PDFs, websites) + +- `brand-yml-spec.md` - Complete brand.yml specification. +- `shiny-r.md` - Shiny for R integration with bslib. +- `shiny-python.md` - Shiny for Python integration with ui.Theme. +- `quarto.md` - Quarto integration for all formats (HTML, dashboards, RevealJS presentations, Typst PDFs, websites). **Note**: This skill is also registered in the shiny category since brand.yml works across both Shiny and Quarto projects. @@ -92,6 +93,16 @@ Create and use `_brand.yml` files for consistent branding across Quarto document --- +### `lua` + +Write Lua shortcodes and filters for Quarto. Covers shortcode handlers, Pandoc AST filters, Lua coding conventions, Quarto-specific Lua APIs, and common patterns. Includes runtime access to Quarto's LLM-optimised documentation (`.llms.md` pages) for detailed API reference. + +#### Authors + +- [Mickaël CANOUIL](https://github.com/mcanouil) + +--- + ### `quarto-alt-text` Generate accessible alt text for data visualizations in Quarto documents. Use when adding, improving, or reviewing `fig-alt` for figures in `.qmd` files, or when making documents more accessible for screen readers. @@ -106,13 +117,12 @@ Generate accessible alt text for data visualizations in Quarto documents. Use wh This category could include skills for: -- Publishing workflows -- Extension development -- Template creation -- Multi-format output -- Parameterized reports -- Website and book publishing -- Presentation design +- Publishing workflows. +- Template creation. +- Multi-format output. +- Parameterized reports. +- Website and book publishing. +- Presentation design. ## Contributing diff --git a/quarto/quarto-lua/SKILL.md b/quarto/quarto-lua/SKILL.md new file mode 100644 index 0000000..e212f74 --- /dev/null +++ b/quarto/quarto-lua/SKILL.md @@ -0,0 +1,164 @@ +--- +name: quarto-lua +description: > + Write Lua shortcodes and filters for Quarto. + Use when creating, debugging, or modifying Lua code that runs inside + Quarto, including shortcode handlers, Quarto Lua filters, and + Quarto-specific Lua APIs. +metadata: + author: Mickaël Canouil (@mcanouil) + version: "1.0" +license: MIT +--- + +# Quarto Lua + +Write Lua shortcodes and filters for Quarto. + +> This skill is based on Quarto CLI v1.8.26. + +## When to Use What + +Task: Write a shortcode -> "Writing a Shortcode" below +Task: Write a filter -> "Writing a Filter" below +Task: Pandoc Lua API (constructors, types, methods) -> WebFetch `https://quarto.org/docs/extensions/lua-api.llms.md` +Task: Debug Lua / tooling -> WebFetch `https://quarto.org/docs/extensions/lua.llms.md` +Task: Shortcode details (args, raw output) -> WebFetch `https://quarto.org/docs/extensions/shortcodes.llms.md` +Task: Filter details (AST traversal, multi-pass) -> WebFetch `https://quarto.org/docs/extensions/filters.llms.md` +Task: Metadata / project filters -> WebFetch `https://quarto.org/docs/extensions/metadata.llms.md` + +Fetch only pages relevant to the current task. +The fetched `.llms.md` pages may contain `.llms.md` URLs for external sites (e.g., `lua.org`, `pandoc.org`). +These are broken links. Only `https://quarto.org` URLs have valid `.llms.md` pages; replace with `.html` for any other domain. + +## Writing a Shortcode + +A shortcode exports a function called whenever `{{< name ... >}}` appears in `.qmd`. +Register under `shortcodes:` in `_extension.yml` or document YAML. +Add a file header (see "Lua File Header Convention"), then: + +```lua +return function(args, kwargs, meta, raw_args) + local name = pandoc.utils.stringify(args[1] or "world") + return pandoc.Str("Hello, " .. name .. "!") +end +``` + +Parameters: `args` (positional, 1-indexed), `kwargs` (named), `meta` (document metadata), `raw_args` (unparsed strings). +Both `args` and `kwargs` contain `pandoc.Inlines`; use `pandoc.utils.stringify()` to get strings. +Return `pandoc.Inlines` or `pandoc.Blocks`. Use `pandoc.RawInline`/`pandoc.RawBlock` for format-specific output. +Verify the exact handler signature against the shortcodes `.llms.md` page when targeting a specific Quarto version. + +## Writing a Filter + +A filter returns a list of handler tables mapping AST element types to transform functions. +Register under `filters:` in `_extension.yml` or document YAML. +Add a file header (see "Lua File Header Convention"), then: + +```lua +local function convert_emph(el) + return pandoc.SmallCaps(el.content) +end + +return { + { Emph = convert_emph } +} +``` + +Each table is a separate traversal pass. Handlers return a replacement element, a list, or `nil` (or nothing) to skip. +Use a `Pandoc(doc)` handler to process the entire document, or `Meta(meta)` to read/modify metadata. +Multiple passes: `return { { Header = fix_headers }, { Link = fix_links } }`. + +## Lua File Header Convention + +Every `.lua` file must start with: + +```lua +--- name - Short description +--- @module name.lua +--- @license MIT +--- @copyright 2026 Author Name +--- @author Author Name +--- @version 0.1.0 +--- @brief One-line summary. +--- @description Longer explanation of purpose and behaviour. +--- Wrap at ~72 chars, indent continuation with two spaces. +``` + +Fields: `@module` (filename), `@license`, `@copyright`, `@author`, `@version` (semver), `@brief` (one-liner), `@description` (multi-line). +Always generate for new files. Update `@version`/`@description` when modifying. + +## Lua Style and Conventions + +- **Naming**: `snake_case` for variables/functions, `PascalCase` for module-level tables only. +- **Indentation**: 2 spaces. +- **Strings**: double quotes for user-facing text, single quotes for identifiers/keys. +- **Scoping**: always `local` unless intentionally global. +- **Errors**: fail fast with `error("context: what went wrong")`. +- **Docs**: `---` comment blocks above functions (LDoc-compatible): + +```lua +--- Convert a Pandoc inline element to plain text. +--- @param el pandoc.Inline The inline element to convert. +--- @return string The plain text representation. +local function stringify_inline(el) + return pandoc.utils.stringify(el) +end +``` + +## Common Patterns + +### `pandoc.utils.stringify()` + +Converts any AST element to plain text. Use for shortcode arguments and metadata fields. + +### Format Detection + +Check the output format before emitting format-specific content: + +```lua +if quarto.doc.is_format("html") then + -- HTML-only logic +end +``` + +### Quarto Document APIs + +```lua +-- HTML only; no-op for PDF/Typst +quarto.doc.add_html_dependency({ + name = "my-dep", version = "0.1.0", + stylesheets = { "style.css" }, scripts = { "script.js" } +}) + +-- Works for all formats (HTML, LaTeX/PDF, Typst) +quarto.doc.include_text("in-header", "...") +-- Positions: "in-header", "before-body", "after-body" +``` + +### Debugging + +```lua +quarto.log.output("my-var:", my_var) +``` + +### Multi-file Modules + +```lua +local utils = require("utils") +``` + +Quarto resolves `require` paths relative to the calling script's directory. + +### Testing + +```bash +quarto render example.qmd +``` + +## Resources + +- [Quarto Lua API](https://quarto.org/docs/extensions/lua-api.html) +- [Pandoc Lua Filters reference](https://pandoc.org/lua-filters.html) +- [Pandoc community Lua filters](https://github.com/pandoc/lua-filters) +- [LuaRocks style guide](https://github.com/luarocks/lua-style-guide) From 564f18ceb64a32cc1d0cb265dadc543c0cb5394e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micka=C3=ABl=20Canouil?= <8896044+mcanouil@users.noreply.github.com> Date: Mon, 9 Mar 2026 21:26:20 +0100 Subject: [PATCH 02/17] fix(quarto-lua): remove broken links note to external .llms.md pages --- quarto/quarto-lua/SKILL.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/quarto/quarto-lua/SKILL.md b/quarto/quarto-lua/SKILL.md index e212f74..d4c6cd7 100644 --- a/quarto/quarto-lua/SKILL.md +++ b/quarto/quarto-lua/SKILL.md @@ -28,8 +28,6 @@ Task: Filter details (AST traversal, multi-pass) -> WebFetch `https://quarto.org Task: Metadata / project filters -> WebFetch `https://quarto.org/docs/extensions/metadata.llms.md` Fetch only pages relevant to the current task. -The fetched `.llms.md` pages may contain `.llms.md` URLs for external sites (e.g., `lua.org`, `pandoc.org`). -These are broken links. Only `https://quarto.org` URLs have valid `.llms.md` pages; replace with `.html` for any other domain. ## Writing a Shortcode From d28f2b10c7ce5b91e872cef4b498d9846532261e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micka=C3=ABl=20Canouil?= <8896044+mcanouil@users.noreply.github.com> Date: Mon, 9 Mar 2026 21:43:24 +0100 Subject: [PATCH 03/17] chore: update Quarto CLI version in SKILL.md --- quarto/quarto-lua/SKILL.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/quarto/quarto-lua/SKILL.md b/quarto/quarto-lua/SKILL.md index d4c6cd7..7e88ee3 100644 --- a/quarto/quarto-lua/SKILL.md +++ b/quarto/quarto-lua/SKILL.md @@ -15,7 +15,7 @@ license: MIT Write Lua shortcodes and filters for Quarto. -> This skill is based on Quarto CLI v1.8.26. +> This skill is based on Quarto CLI v1.9.30. ## When to Use What From 0d275b8b4b9e5637cd45f3db0c8a739079918246 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micka=C3=ABl=20Canouil?= <8896044+mcanouil@users.noreply.github.com> Date: Mon, 9 Mar 2026 21:55:51 +0100 Subject: [PATCH 04/17] chore: add date of last check --- quarto/quarto-lua/SKILL.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/quarto/quarto-lua/SKILL.md b/quarto/quarto-lua/SKILL.md index 7e88ee3..d00aef1 100644 --- a/quarto/quarto-lua/SKILL.md +++ b/quarto/quarto-lua/SKILL.md @@ -15,7 +15,7 @@ license: MIT Write Lua shortcodes and filters for Quarto. -> This skill is based on Quarto CLI v1.9.30. +> This skill is based on Quarto CLI v1.9.30 (2026-03-09). ## When to Use What From ce6bdca9807e8765e504a5b518a480ab38fef58a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micka=C3=ABl=20Canouil?= <8896044+mcanouil@users.noreply.github.com> Date: Mon, 9 Mar 2026 23:17:38 +0100 Subject: [PATCH 05/17] feat(quarto-lua): add custom AST nodes section and references Include details on custom AST nodes and filter timing in the documentation. This enhances the understanding of Quarto's capabilities for users working with Lua shortcodes and filters. --- quarto/quarto-lua/SKILL.md | 19 +++++ .../quarto-lua/references/custom-ast-nodes.md | 84 +++++++++++++++++++ 2 files changed, 103 insertions(+) create mode 100644 quarto/quarto-lua/references/custom-ast-nodes.md diff --git a/quarto/quarto-lua/SKILL.md b/quarto/quarto-lua/SKILL.md index d00aef1..7cd7d5a 100644 --- a/quarto/quarto-lua/SKILL.md +++ b/quarto/quarto-lua/SKILL.md @@ -26,6 +26,7 @@ Task: Debug Lua / tooling -> WebFetch `https://quarto.org/docs/extensions/lua.ll Task: Shortcode details (args, raw output) -> WebFetch `https://quarto.org/docs/extensions/shortcodes.llms.md` Task: Filter details (AST traversal, multi-pass) -> WebFetch `https://quarto.org/docs/extensions/filters.llms.md` Task: Metadata / project filters -> WebFetch `https://quarto.org/docs/extensions/metadata.llms.md` +Task: Custom AST nodes / filter timing -> Read `references/custom-ast-nodes.md` in this skill directory Fetch only pages relevant to the current task. @@ -154,6 +155,24 @@ Quarto resolves `require` paths relative to the calling script's directory. quarto render example.qmd ``` +## Custom AST Nodes + +Quarto extends Pandoc's AST with custom node types that filters can match by name. + +**Block-level:** Callout, ConditionalBlock, Tabset, PanelLayout, FloatRefTarget, DecoratedCodeBlock, Theorem, Proof. + +**Inline-level:** Shortcode. + +**Other:** LatexEnvironment, LatexInlineCommand, HtmlTag. + +Constructors exist for: `quarto.Callout(tbl)`, `quarto.ConditionalBlock(tbl)`, `quarto.Tabset(tbl)`, `quarto.Tab(tbl)`. + +Cross-referenceable elements (figures, tables, listings) are represented as `FloatRefTarget` nodes. + +Filter timing supports eight phases (`pre-ast` through `post-finalize`) via the `at` property in `_extension.yml`. + +For full constructor signatures and filter timing details, read `references/custom-ast-nodes.md`. + ## Resources - [Quarto Lua API](https://quarto.org/docs/extensions/lua-api.html) diff --git a/quarto/quarto-lua/references/custom-ast-nodes.md b/quarto/quarto-lua/references/custom-ast-nodes.md new file mode 100644 index 0000000..92dbc01 --- /dev/null +++ b/quarto/quarto-lua/references/custom-ast-nodes.md @@ -0,0 +1,84 @@ +# Custom AST Nodes + +Quarto extends Pandoc's AST with custom node types. +Filters match these by name in handler tables (e.g., `{ Callout = handle_callout }`). + +## Available Node Types + +**Block-level:** Callout, ConditionalBlock, Tabset, PanelLayout, FloatRefTarget, DecoratedCodeBlock, Theorem, Proof. + +**Inline-level:** Shortcode. + +**Other:** LatexEnvironment, LatexInlineCommand, HtmlTag. + +Note: `_quarto.ast.add_handler()` is internal to Quarto. +Extension authors interact via standard filter handlers. + +## Constructor Signatures + +### `quarto.Callout(tbl)` + +- `type`: `string` - callout type (note, caution, warning, tip, important). +- `title`: `pandoc.Inlines` or `string` (optional). +- `icon`: `boolean` or `string` (optional, defaults based on type). +- `appearance`: `string` - "minimal", "simple", or "default" (optional). +- `collapse`: collapse state (optional). +- `content`: `pandoc.Blocks` or list (optional, defaults to empty Blocks). +- `attr`: `pandoc.Attr` (optional, defaults to empty Attr). + +### `quarto.ConditionalBlock(tbl)` + +- `node`: `pandoc.Div` - the div holding the content. +- `behavior`: `string` - "content-visible" or "content-hidden". +- `condition`: list of 2-element lists (optional, defaults to `{}`). + Each sublist: `{"when-format"|"unless-format"|"when-profile"|"unless-profile", value}`. + +### `quarto.Tabset(tbl)` + +- `tabs`: list of `quarto.Tab` objects (optional, defaults to empty list). +- `level`: `number` - heading level for tabs (optional, default `2`). +- `attr`: `pandoc.Attr` (optional, defaults to `pandoc.Attr("", {"panel-tabset"})`). + +### `quarto.Tab(tbl)` + +- `title`: `pandoc.Inlines` or `string` (required). +- `content`: `pandoc.Blocks` or `string` (optional, string parsed as markdown). +- `active`: `boolean` (optional, default `false`). + +## Filter Timing + +Eight phases available via the `at` property in `_extension.yml` or document YAML: + +1. `pre-ast` +2. `post-ast` +3. `pre-quarto` +4. `post-quarto` +5. `pre-render` +6. `post-render` +7. `pre-finalize` +8. `post-finalize` + +Syntax in `_extension.yml` or document YAML: + +```yaml +filters: + - path: my-filter.lua + at: pre-quarto +``` + +Default (no `at`): filters listed before a "quarto" marker get `pre-quarto`, filters listed after get `post-render`. + +## FloatRefTarget + +Cross-referenceable elements (figures, tables, listings) are represented as `FloatRefTarget` custom AST nodes. +Filters operating on these should use the `FloatRefTarget` handler: + +```lua +return { + { FloatRefTarget = function(el) + -- el.caption, el.content, el.identifier, etc. + return el + end + } +} +``` From 5fcf9fe5bdc7872cc16fe61073fe6f3f02593d5c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micka=C3=ABl=20Canouil?= <8896044+mcanouil@users.noreply.github.com> Date: Tue, 24 Mar 2026 00:27:29 +0100 Subject: [PATCH 06/17] chore: update Quarto CLI version in SKILL.md --- quarto/quarto-lua/SKILL.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/quarto/quarto-lua/SKILL.md b/quarto/quarto-lua/SKILL.md index 7cd7d5a..9466b91 100644 --- a/quarto/quarto-lua/SKILL.md +++ b/quarto/quarto-lua/SKILL.md @@ -15,7 +15,7 @@ license: MIT Write Lua shortcodes and filters for Quarto. -> This skill is based on Quarto CLI v1.9.30 (2026-03-09). +> This skill is based on Quarto CLI v1.9.36 (2026-03-24). ## When to Use What From 80252697acf545de31e72d3dd00847899a0cbf98 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micka=C3=ABl=20Canouil?= <8896044+mcanouil@users.noreply.github.com> Date: Wed, 1 Apr 2026 10:59:24 +0200 Subject: [PATCH 07/17] fix: update with clearer YAML registration details Clarified registration instructions for shortcodes and filters in YAML. --- quarto/quarto-lua/SKILL.md | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/quarto/quarto-lua/SKILL.md b/quarto/quarto-lua/SKILL.md index 9466b91..1cd26bc 100644 --- a/quarto/quarto-lua/SKILL.md +++ b/quarto/quarto-lua/SKILL.md @@ -33,7 +33,13 @@ Fetch only pages relevant to the current task. ## Writing a Shortcode A shortcode exports a function called whenever `{{< name ... >}}` appears in `.qmd`. -Register under `shortcodes:` in `_extension.yml` or document YAML. +Register under `shortcodes:` in the document YAML header or projec YAML (`_quarto.yml`). + +```yaml +shortcodes: + - my-shortcode.lua +``` + Add a file header (see "Lua File Header Convention"), then: ```lua @@ -51,7 +57,13 @@ Verify the exact handler signature against the shortcodes `.llms.md` page when t ## Writing a Filter A filter returns a list of handler tables mapping AST element types to transform functions. -Register under `filters:` in `_extension.yml` or document YAML. +Register under `filters:` in the document YAML header or projec YAML (`_quarto.yml`). + +```yaml +filters: + - my-filter.lua +``` + Add a file header (see "Lua File Header Convention"), then: ```lua From 2044e4e13459ff82ae0389ad129fb36e88197178 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micka=C3=ABl=20Canouil?= <8896044+mcanouil@users.noreply.github.com> Date: Wed, 1 Apr 2026 20:52:02 +0200 Subject: [PATCH 08/17] fix: relax luadocs header requirement --- quarto/quarto-lua/SKILL.md | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/quarto/quarto-lua/SKILL.md b/quarto/quarto-lua/SKILL.md index 1cd26bc..0b3d218 100644 --- a/quarto/quarto-lua/SKILL.md +++ b/quarto/quarto-lua/SKILL.md @@ -87,17 +87,13 @@ Every `.lua` file must start with: ```lua --- name - Short description --- @module name.lua ---- @license MIT ---- @copyright 2026 Author Name --- @author Author Name ---- @version 0.1.0 ---- @brief One-line summary. --- @description Longer explanation of purpose and behaviour. --- Wrap at ~72 chars, indent continuation with two spaces. ``` -Fields: `@module` (filename), `@license`, `@copyright`, `@author`, `@version` (semver), `@brief` (one-liner), `@description` (multi-line). -Always generate for new files. Update `@version`/`@description` when modifying. +Fields: `@module` (filename), `@author`, and `@description` (multi-line). +Always generate for new files. Update `@description` when modifying. ## Lua Style and Conventions From 8c40b520aae0ffdcb2ef2553eeefc6c935a54728 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micka=C3=ABl=20Canouil?= <8896044+mcanouil@users.noreply.github.com> Date: Wed, 1 Apr 2026 20:53:25 +0200 Subject: [PATCH 09/17] fix: typo --- quarto/quarto-lua/SKILL.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/quarto/quarto-lua/SKILL.md b/quarto/quarto-lua/SKILL.md index 0b3d218..855ba68 100644 --- a/quarto/quarto-lua/SKILL.md +++ b/quarto/quarto-lua/SKILL.md @@ -33,7 +33,7 @@ Fetch only pages relevant to the current task. ## Writing a Shortcode A shortcode exports a function called whenever `{{< name ... >}}` appears in `.qmd`. -Register under `shortcodes:` in the document YAML header or projec YAML (`_quarto.yml`). +Register under `shortcodes:` in the document YAML header or project YAML (`_quarto.yml`). ```yaml shortcodes: @@ -57,7 +57,7 @@ Verify the exact handler signature against the shortcodes `.llms.md` page when t ## Writing a Filter A filter returns a list of handler tables mapping AST element types to transform functions. -Register under `filters:` in the document YAML header or projec YAML (`_quarto.yml`). +Register under `filters:` in the document YAML header or project YAML (`_quarto.yml`). ```yaml filters: From fc59a3f599b6eb40ec60429f7475f273925146ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micka=C3=ABl=20Canouil?= <8896044+mcanouil@users.noreply.github.com> Date: Wed, 1 Apr 2026 21:13:38 +0200 Subject: [PATCH 10/17] feat: make extension an alternative to standalone with starting question --- quarto/quarto-lua/SKILL.md | 42 ++++++++++++++++++++++++++++++++------ 1 file changed, 36 insertions(+), 6 deletions(-) diff --git a/quarto/quarto-lua/SKILL.md b/quarto/quarto-lua/SKILL.md index 855ba68..fc9aa22 100644 --- a/quarto/quarto-lua/SKILL.md +++ b/quarto/quarto-lua/SKILL.md @@ -1,10 +1,6 @@ --- name: quarto-lua -description: > - Write Lua shortcodes and filters for Quarto. - Use when creating, debugging, or modifying Lua code that runs inside - Quarto, including shortcode handlers, Quarto Lua filters, and - Quarto-specific Lua APIs. +description: Write Lua shortcodes and filters for Quarto. Use when creating, debugging, or modifying Lua code that runs inside Quarto, including shortcode handlers, Quarto Lua filters, and Quarto-specific Lua APIs. metadata: author: Mickaël Canouil (@mcanouil) version: "1.0" @@ -19,6 +15,8 @@ Write Lua shortcodes and filters for Quarto. ## When to Use What +**First question**: When asked to create a new shortcode or filter, ask the user whether it should be a standalone file (registered in `_quarto.yml` or document YAML) or packaged as a Quarto extension (with `_extension.yml`). + Task: Write a shortcode -> "Writing a Shortcode" below Task: Write a filter -> "Writing a Filter" below Task: Pandoc Lua API (constructors, types, methods) -> WebFetch `https://quarto.org/docs/extensions/lua-api.llms.md` @@ -30,6 +28,34 @@ Task: Custom AST nodes / filter timing -> Read `references/custom-ast-nodes.md` Fetch only pages relevant to the current task. +## Quarto Extension Structure + +A Quarto extension lives in `_extensions//` with an `_extension.yml` manifest and one or more `.lua` files alongside it. + +``` +_extensions/ + my-extension/ + _extension.yml + my-extension.lua +``` + +Extension manifest (`_extension.yml`): + +```yaml +title: My Extension +author: Firstname Lastname +version: X.Y.Z +quarto-required: ">=1.6.0" +contributes: + shortcodes: # for shortcode extensions + - my-shortcode.lua + filters: # for filter extensions + - my-filter.lua +``` + +Fields: `title` (display name), `author`, `version` (semver), `quarto-required` (optional minimum Quarto version), `contributes` (what the extension provides). +List only the relevant key under `contributes` (shortcodes, filters, or both). + ## Writing a Shortcode A shortcode exports a function called whenever `{{< name ... >}}` appears in `.qmd`. @@ -40,6 +66,8 @@ shortcodes: - my-shortcode.lua ``` +For extension packaging, register in `_extension.yml` instead (see "Quarto Extension Structure" above). + Add a file header (see "Lua File Header Convention"), then: ```lua @@ -64,6 +92,8 @@ filters: - my-filter.lua ``` +For extension packaging, register in `_extension.yml` instead (see "Quarto Extension Structure" above). + Add a file header (see "Lua File Header Convention"), then: ```lua @@ -183,7 +213,7 @@ For full constructor signatures and filter timing details, read `references/cust ## Resources -- [Quarto Lua API](https://quarto.org/docs/extensions/lua-api.html) +- [Quarto Lua API](https://quarto.org/docs/extensions/lua-api.llms.md) - [Pandoc Lua Filters reference](https://pandoc.org/lua-filters.html) - [Pandoc community Lua filters](https://github.com/pandoc/lua-filters) - [LuaRocks style guide](https://github.com/luarocks/lua-style-guide) From 8be24d3691fa4f31b2199dda6ec4b2dd63fb1272 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micka=C3=ABl=20Canouil?= <8896044+mcanouil@users.noreply.github.com> Date: Wed, 1 Apr 2026 21:22:39 +0200 Subject: [PATCH 11/17] fix: don't mention "WebFetch" to not enforce a retrieval method --- quarto/quarto-lua/SKILL.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/quarto/quarto-lua/SKILL.md b/quarto/quarto-lua/SKILL.md index fc9aa22..8d627d9 100644 --- a/quarto/quarto-lua/SKILL.md +++ b/quarto/quarto-lua/SKILL.md @@ -19,12 +19,12 @@ Write Lua shortcodes and filters for Quarto. Task: Write a shortcode -> "Writing a Shortcode" below Task: Write a filter -> "Writing a Filter" below -Task: Pandoc Lua API (constructors, types, methods) -> WebFetch `https://quarto.org/docs/extensions/lua-api.llms.md` -Task: Debug Lua / tooling -> WebFetch `https://quarto.org/docs/extensions/lua.llms.md` -Task: Shortcode details (args, raw output) -> WebFetch `https://quarto.org/docs/extensions/shortcodes.llms.md` -Task: Filter details (AST traversal, multi-pass) -> WebFetch `https://quarto.org/docs/extensions/filters.llms.md` -Task: Metadata / project filters -> WebFetch `https://quarto.org/docs/extensions/metadata.llms.md` -Task: Custom AST nodes / filter timing -> Read `references/custom-ast-nodes.md` in this skill directory +Task: Pandoc Lua API (constructors, types, methods) -> Fetch `https://quarto.org/docs/extensions/lua-api.llms.md` +Task: Debug Lua / tooling -> Fetch `https://quarto.org/docs/extensions/lua.llms.md` +Task: Shortcode details (args, raw output) -> Fetch `https://quarto.org/docs/extensions/shortcodes.llms.md` +Task: Filter details (AST traversal, multi-pass) -> Fetch `https://quarto.org/docs/extensions/filters.llms.md` +Task: Metadata / project filters -> Fetch `https://quarto.org/docs/extensions/metadata.llms.md` +Task: Custom AST nodes / filter timing -> Read the file `references/custom-ast-nodes.md` in this skill directory Fetch only pages relevant to the current task. From e76d6315c426fa0a8232c9a86f38b95e53b9cb8c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micka=C3=ABl=20Canouil?= <8896044+mcanouil@users.noreply.github.com> Date: Wed, 1 Apr 2026 21:24:26 +0200 Subject: [PATCH 12/17] docs: rename section from 'lua' to 'quarto-lua' --- quarto/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/quarto/README.md b/quarto/README.md index 9cc15c5..8acd2e7 100644 --- a/quarto/README.md +++ b/quarto/README.md @@ -93,7 +93,7 @@ Create and use `_brand.yml` files for consistent branding across Quarto document --- -### `lua` +### `quarto-lua` Write Lua shortcodes and filters for Quarto. Covers shortcode handlers, Pandoc AST filters, Lua coding conventions, Quarto-specific Lua APIs, and common patterns. Includes runtime access to Quarto's LLM-optimised documentation (`.llms.md` pages) for detailed API reference. From df3b61a7b17e70089f32aa3d90abb76f2ad10f62 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micka=C3=ABl=20Canouil?= <8896044+mcanouil@users.noreply.github.com> Date: Wed, 1 Apr 2026 21:31:11 +0200 Subject: [PATCH 13/17] fix: update task descriptions to use 'Read' instead of 'Fetch' and to mention "quarto" for Lua API --- quarto/quarto-lua/SKILL.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/quarto/quarto-lua/SKILL.md b/quarto/quarto-lua/SKILL.md index 8d627d9..63cb4ca 100644 --- a/quarto/quarto-lua/SKILL.md +++ b/quarto/quarto-lua/SKILL.md @@ -19,11 +19,11 @@ Write Lua shortcodes and filters for Quarto. Task: Write a shortcode -> "Writing a Shortcode" below Task: Write a filter -> "Writing a Filter" below -Task: Pandoc Lua API (constructors, types, methods) -> Fetch `https://quarto.org/docs/extensions/lua-api.llms.md` -Task: Debug Lua / tooling -> Fetch `https://quarto.org/docs/extensions/lua.llms.md` -Task: Shortcode details (args, raw output) -> Fetch `https://quarto.org/docs/extensions/shortcodes.llms.md` -Task: Filter details (AST traversal, multi-pass) -> Fetch `https://quarto.org/docs/extensions/filters.llms.md` -Task: Metadata / project filters -> Fetch `https://quarto.org/docs/extensions/metadata.llms.md` +Task: Quarto and Pandoc Lua API (constructors, types, methods) -> Read `https://quarto.org/docs/extensions/lua-api.llms.md` +Task: Debug Lua / tooling -> Read `https://quarto.org/docs/extensions/lua.llms.md` +Task: Shortcode details (args, raw output) -> Read `https://quarto.org/docs/extensions/shortcodes.llms.md` +Task: Filter details (AST traversal, multi-pass) -> Read `https://quarto.org/docs/extensions/filters.llms.md` +Task: Metadata / project filters -> Read `https://quarto.org/docs/extensions/metadata.llms.md` Task: Custom AST nodes / filter timing -> Read the file `references/custom-ast-nodes.md` in this skill directory Fetch only pages relevant to the current task. From 91b1ada0b176f8e8b37a6d345c40dff3db817a43 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micka=C3=ABl=20Canouil?= <8896044+mcanouil@users.noreply.github.com> Date: Wed, 1 Apr 2026 21:43:09 +0200 Subject: [PATCH 14/17] fix: strenghen logic to ensure resources and files are read before using other online resources. --- quarto/quarto-lua/SKILL.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/quarto/quarto-lua/SKILL.md b/quarto/quarto-lua/SKILL.md index 63cb4ca..44e8373 100644 --- a/quarto/quarto-lua/SKILL.md +++ b/quarto/quarto-lua/SKILL.md @@ -11,6 +11,8 @@ license: MIT Write Lua shortcodes and filters for Quarto. +**Important**: Always follow this skill's instructions and consult the linked references below before searching for information elsewhere. + > This skill is based on Quarto CLI v1.9.36 (2026-03-24). ## When to Use What From cb325310723e948eb2fce7691dd2029d80e08545 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micka=C3=ABl=20Canouil?= <8896044+mcanouil@users.noreply.github.com> Date: Wed, 1 Apr 2026 21:47:26 +0200 Subject: [PATCH 15/17] fix: rewrite description to improve trigger of the skill It appears, the skill was not triggered when asking for information or trying to extend lua filter with custom callouts, etc. --- quarto/quarto-lua/SKILL.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/quarto/quarto-lua/SKILL.md b/quarto/quarto-lua/SKILL.md index 44e8373..682534e 100644 --- a/quarto/quarto-lua/SKILL.md +++ b/quarto/quarto-lua/SKILL.md @@ -1,6 +1,6 @@ --- name: quarto-lua -description: Write Lua shortcodes and filters for Quarto. Use when creating, debugging, or modifying Lua code that runs inside Quarto, including shortcode handlers, Quarto Lua filters, and Quarto-specific Lua APIs. +description: "Write Lua shortcodes and filters for Quarto. TRIGGER when: code involves `.lua` files in a Quarto project, `_extension.yml` manifests, Pandoc Lua filters, shortcode handlers, `quarto.doc.*` or `quarto.log.*` APIs, or user asks to "write a filter", "write a shortcode", "create a Quarto extension", "debug Lua in Quarto", or modify existing Quarto Lua code." metadata: author: Mickaël Canouil (@mcanouil) version: "1.0" From 18d33b7b05f6e242e566409d4841c09ce65eea2a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micka=C3=ABl=20Canouil?= <8896044+mcanouil@users.noreply.github.com> Date: Wed, 1 Apr 2026 22:00:58 +0200 Subject: [PATCH 16/17] fix: improve access to crustom AST node reference using plain english --- quarto/quarto-lua/SKILL.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/quarto/quarto-lua/SKILL.md b/quarto/quarto-lua/SKILL.md index 682534e..7462c8b 100644 --- a/quarto/quarto-lua/SKILL.md +++ b/quarto/quarto-lua/SKILL.md @@ -26,7 +26,7 @@ Task: Debug Lua / tooling -> Read `https://quarto.org/docs/extensions/lua.llms.m Task: Shortcode details (args, raw output) -> Read `https://quarto.org/docs/extensions/shortcodes.llms.md` Task: Filter details (AST traversal, multi-pass) -> Read `https://quarto.org/docs/extensions/filters.llms.md` Task: Metadata / project filters -> Read `https://quarto.org/docs/extensions/metadata.llms.md` -Task: Custom AST nodes / filter timing -> Read the file `references/custom-ast-nodes.md` in this skill directory +Task: Custom AST nodes (callout, conditional block, tabset, panel layout, cross-reference, decorated code block, theorem, proof) / filter timing -> Read the file `references/custom-ast-nodes.md` in this skill directory Fetch only pages relevant to the current task. From 7199586d8c0e4063f16eec65ca1d344d2ea0c352 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micka=C3=ABl=20Canouil?= <8896044+mcanouil@users.noreply.github.com> Date: Wed, 1 Apr 2026 22:02:50 +0200 Subject: [PATCH 17/17] fix: use single quote --- quarto/quarto-lua/SKILL.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/quarto/quarto-lua/SKILL.md b/quarto/quarto-lua/SKILL.md index 7462c8b..4f7cc54 100644 --- a/quarto/quarto-lua/SKILL.md +++ b/quarto/quarto-lua/SKILL.md @@ -1,6 +1,6 @@ --- name: quarto-lua -description: "Write Lua shortcodes and filters for Quarto. TRIGGER when: code involves `.lua` files in a Quarto project, `_extension.yml` manifests, Pandoc Lua filters, shortcode handlers, `quarto.doc.*` or `quarto.log.*` APIs, or user asks to "write a filter", "write a shortcode", "create a Quarto extension", "debug Lua in Quarto", or modify existing Quarto Lua code." +description: 'Write Lua shortcodes and filters for Quarto. TRIGGER when: code involves `.lua` files in a Quarto project, `_extension.yml` manifests, Pandoc Lua filters, shortcode handlers, `quarto.doc.*` or `quarto.log.*` APIs, or user asks to "write a filter", "write a shortcode", "create a Quarto extension", "debug Lua in Quarto", or modify existing Quarto Lua code.' metadata: author: Mickaël Canouil (@mcanouil) version: "1.0"