Skip to content

feat(quarto): add quarto-lua skill for Lua shortcodes and filters - #39

Open
mcanouil wants to merge 25 commits into
posit-dev:mainfrom
mcanouil:feat/quarto-lua
Open

feat(quarto): add quarto-lua skill for Lua shortcodes and filters#39
mcanouil wants to merge 25 commits into
posit-dev:mainfrom
mcanouil:feat/quarto-lua

Conversation

@mcanouil

@mcanouil mcanouil commented Mar 9, 2026

Copy link
Copy Markdown
Contributor

Add a new quarto-lua skill for writing Lua shortcodes and filters in Quarto.

It covers shortcode handlers, AST filters, Lua conventions, an index of the quarto.* API surface, and a decision tree that sends detailed questions to Quarto's .llms.md pages.

references/custom-ast-nodes.md holds the custom AST node constructors and the eight filter timing phases. It stays in the skill because the .llms.md page drops the constructor table (quarto-dev/quarto-cli#14806) and the AST page documents only six of the phases.

Evaluation

File Lines ~Tokens
SKILL.md 284 2,907
references/custom-ast-nodes.md 94 820
Total 378 3,727
Description - 84

mcanouil added 2 commits March 9, 2026 21:24
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.
@mcanouil

This comment was marked as resolved.

@mcanouil
mcanouil marked this pull request as draft March 9, 2026 22:13
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.
@mcanouil
mcanouil marked this pull request as ready for review March 9, 2026 22:19
@mcanouil
mcanouil marked this pull request as draft March 9, 2026 22:40
@mcanouil
mcanouil marked this pull request as ready for review March 23, 2026 23:27
@mcanouil

Copy link
Copy Markdown
Contributor Author

First version of this lua skill for Quarto ready with Quarto CLI v1.9.36 now released.

Comment thread quarto/quarto-lua/SKILL.md Outdated
Comment thread quarto/quarto-lua/SKILL.md Outdated
Comment thread quarto/quarto-lua/SKILL.md Outdated
Clarified registration instructions for shortcodes and filters in YAML.

@cderv cderv left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for this addition !

Something that makes me wonder: Lua filter can be used without Quarto Extensions. Shortcodes can't. Is this skill made for Lua inside quarto extension ? Or just any Quarto Lua writing ?

I wonder if the skill should be more clear on this to help Claude know when this is in Extensions context or just Lua filter context. 🤷‍♂️

Also, this is a good opportunity to better document the Lua API so I'll add something in the doc with all the feature. (like quarto.format endpoint).

Comment thread quarto/quarto-lua/SKILL.md Outdated
Comment thread quarto/quarto-lua/SKILL.md Outdated
Comment thread quarto/quarto-lua/SKILL.md
Comment thread quarto/README.md Outdated
@mcanouil

mcanouil commented Apr 1, 2026

Copy link
Copy Markdown
Contributor Author

@cderv "Something that makes me wonder: Lua filter can be used without Quarto Extensions. Shortcodes can't. "

This is not true.
They 100% can.

screenshot showing definition and usage of shortcode without Quarto extension, as a plain YAML inline setting

@cderv

cderv commented Apr 1, 2026

Copy link
Copy Markdown
Member

Oh cool ! I thought they couldn't !

I guess I forgot this shortcodes configuration can also work in single documents !! Awesome !

@mcanouil

mcanouil commented Apr 1, 2026

Copy link
Copy Markdown
Contributor Author

I believe most if not all users don't know about this because that's not documented.
Discovered this few years ago when "shortcodes" was autocompleted in my header, then I tried it and it worked🤯
Edit: it's "documented"-ish in the schema thus in reference pages obviously

@cderv

cderv commented Apr 1, 2026

Copy link
Copy Markdown
Member

Possibly not documented because not expected initially but side effect 🤷‍♂️

it seems useful to avoid setting a full extension to add shortcode explicitly to a single project without intent of sharing

@mcanouil

mcanouil commented Apr 1, 2026

Copy link
Copy Markdown
Contributor Author

it seems useful to avoid setting a full extension to add shortcode explicitly to a single project without intent of sharing

and quick development/debugging ;) (that's how I use it)

# Conflicts:
#	.claude-plugin/marketplace.json
#	README.md
#	quarto/README.md
The shortcode example returned a bare function. Quarto iterates the
value that a shortcode file returns with pairs(), so that form stops
the render with "bad argument posit-dev#1 to 'for iterator'". A shortcode file
must return a table keyed by shortcode name.

A filter extension is not active on its own. The document or project
must still name the extension under filters:. Only shortcodes from an
installed extension register automatically.

Module paths now use the relative form that Quarto documents. A bare
require("utils") resolves to a global module name, so a second filter
that ships its own utils.lua silently receives the module of the first
one.

Also refresh the skill for Quarto CLI v1.10.18: add an index of the
quarto.* API surface, link the Quarto AST page, and record why the
constructor signatures stay in references/custom-ast-nodes.md.
The multi-file module example used require("../shared"). That resolves
while the extension sits in its source project, but quarto add copies
only _extensions/<name>/, so the parent module is absent after
installation and the render stops with "cannot open
.../_extensions/shared.lua".

Show a subdirectory module instead, and state that a bare require name
is global across separate installed extensions, not only across filters
in one project.
A relative path resolves against the file that calls it, so it works
inside a module that another module requires.

A bare name does not. Quarto puts only the directory of the top-level
filter or shortcode file on package.path, so a module cannot load a
file beside it by bare name and the render stops with
"module 'b' not found".
The style rule asked for single quotes around identifiers and keys, but
every example in the skill uses double quotes, and Quarto's own filter
sources prefer them by roughly three to one. Follow the examples.

The standalone or extension question was unconditional. An
_extension.yml beside the target path, or a path already inside
_extensions/, answers it without asking, and a headless run cannot ask
at all.

Keep the node type list in one place. The reference file repeated it
and then the skill told the reader to open the reference for the list
they had just read.

Show the "quarto" marker that the filter timing default refers to,
since neither file explained what it was.
@mcanouil

Copy link
Copy Markdown
Contributor Author

I updated this to 1.10 and few adjustments.

I believe this is ready as a first version.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants