Skip to main content

Get started

Working with AI

What an AI coding agent can read, how to check what it wrote, and the accessibility reviewer you can give it.

Give your agent LUZ

LUZ is plain HTML and CSS, so an AI coding agent can write it when it knows which class names exist. Paste this prompt into your agent.

It points the agent at the files below and asks it to run the checker on what it wrote. What the checker does not do is in What this does not do.

Prompt
Use LUZ for the markup. Read https://nandovejer.github.io/luz/llms.txt first and use only the classes in each package's classes.json. After you write HTML or CSS, run `npx @luz-ds/check@0.3.0` on the files and fix every finding before you answer.

Start a site

For a new site, or to move one to LUZ, give an LLM the longer prompt. It asks you about the project in short rounds, shows you the plan, and writes nothing until you say "go".

Open the prompt

For one kind of site, its page has a prompt made for it and the recipes of its parts: a landing page, a blog or a newspaper, a web application or a documentation site.

What an agent can read

Every file below is written by the build of this site from the pages you are reading, so an agent and a person get the same facts. Give an agent the URL of llms.txt: it lists the rest.

Files an agent can read
FileURLWhat it isMade by
llms.txt
https://nandovejer.github.io/luz/llms.txt
The index of the documentation for an agent: every page with its description, in reading order.
scripts/docs-site/ai.js, in the pages build
llms-full.txt
https://nandovejer.github.io/luz/llms-full.txt
The same pages as plain text: the markup, the variants, when to use and the keyboard of each one.
scripts/docs-site/ai.js, in the pages build
prompts/start.txt
https://nandovejer.github.io/luz/prompts/start.txt
The general prompt: paste it into any LLM to start a site or move one to LUZ; it asks about the project in rounds before it writes anything.
scripts/docs-site/prompts.js, in the pages build
prompts/landing.txt
https://nandovejer.github.io/luz/prompts/landing.txt
The prompt for a landing page: the general one, with the parts and classes of a landing page.
scripts/docs-site/prompts.js, in the pages build
prompts/blog.txt
https://nandovejer.github.io/luz/prompts/blog.txt
The prompt for a blog or a newspaper, on any CMS: the general one, with the parts and classes of a blog.
scripts/docs-site/prompts.js, in the pages build
prompts/app.txt
https://nandovejer.github.io/luz/prompts/app.txt
The prompt for a web application: the general one, with the parts and classes of an app.
scripts/docs-site/prompts.js, in the pages build
prompts/docs.txt
https://nandovejer.github.io/luz/prompts/docs.txt
The prompt for a documentation site: the general one, with the parts and classes of a documentation site.
scripts/docs-site/prompts.js, in the pages build
examples/<area>/<slug>.html
https://nandovejer.github.io/luz/examples/components/button.html
The markup of one component or pattern page, styled by LUZ; every page that has a markup section has its own under /examples/.
scripts/docs-site/ai.js, in the pages build
manifests/tokens/classes.json
https://nandovejer.github.io/luz/manifests/tokens/classes.json
Every class, custom property and attribute hook of the package: the names an agent may use. Package: @luz-ds/tokens.
scripts/ai-manifests.js, in the build of each package
manifests/core/classes.json
https://nandovejer.github.io/luz/manifests/core/classes.json
Every class, custom property and attribute hook of the package: the names an agent may use. Package: @luz-ds/core.
scripts/ai-manifests.js, in the build of each package
manifests/core/custom-elements.json
https://nandovejer.github.io/luz/manifests/core/custom-elements.json
The custom elements the package defines or declares, with the attributes each one reads. Package: @luz-ds/core.
scripts/ai-manifests.js, in the build of each package
manifests/catalog/classes.json
https://nandovejer.github.io/luz/manifests/catalog/classes.json
Every class, custom property and attribute hook of the package: the names an agent may use. Package: @luz-ds/catalog.
scripts/ai-manifests.js, in the build of each package
manifests/catalog/custom-elements.json
https://nandovejer.github.io/luz/manifests/catalog/custom-elements.json
The custom elements the package defines or declares, with the attributes each one reads. Package: @luz-ds/catalog.
scripts/ai-manifests.js, in the build of each package

Check what an agent wrote

npx @luz-ds/check@0.3.0 reads the HTML and CSS of a project, offline, and says which LUZ classes, elements, load order and color tokens are wrong. It reads files and writes nothing.

It needs Node 20 or later.

Shell
npx @luz-ds/check@0.3.0
npx @luz-ds/check@0.3.0 index.html css/site.css
npx @luz-ds/check@0.3.0 src --json

Say npx @luz-ds/check@0.3.0, with the scope. A path is a file, a folder (read recursively: .html, .htm and .css) or a quoted glob such as "src/**/*.html".

With no path it reads the current folder.

The options of the command
OptionWhat it does
--json
Prints the report as JSON
--strict
Fails on a warning as well as on a finding that blocks
--config <file>
Reads this configuration instead of luz-check.json
--theme <file.css>
Names a stylesheet that sets color tokens, whose colors are measured; repeat it for each file, in the order the page loads them
--ext <list>
Also reads these extensions as HTML, such as .astro,.vue
--version
Prints the version
--help
Shows the options and the limits of the command

A luz-check.json in the folder you run it from sets ignore, rules, themes and strict. A rule that warns can be switched off there; a rule that blocks is silenced only with ignore, and the summary says how many findings were ignored and how many rules are off.

Exit codes

The exit codes of the command
CodeMeaning
0
Nothing blocks. Warnings may still have been printed
1
At least one finding blocks, or, with --strict, a warning was found
2
The command was used wrongly, a configuration cannot be read, or there is nothing to read

What it prints

One line for each finding, in the order of the files and lines: a mark (✗ blocks, ! warns), the place, the rule and one sentence that says what is wrong and what to do. A color token finding is followed by the lines where the colors were set.

The last line counts what it found in the files it read.

Output
✗ index.html:14:8 class/unknown  .luz-btn-primary is not a LUZ class; the closest is .luz-btn--primary
✗ index.html:22:5 load/package-missing  <luz-announcement> is in @luz-ds/catalog/components/announcement.css; add it after core
! site.css:8:3 css/literal-colour  color is set to #1a5fb4; use a token, such as var(--luz-brand-fill)
✗ theme.css:3:3 theme/contrast  light: --luz-text-secondary on surface-page is 2.8:1, needs 4.5:1 (text); change one of the two
    --luz-text-secondary: #999999 is set in theme.css:3
✗ 3 blocking and 1 warning in 3 files (manifests: @luz-ds/core 0.1.0 from node_modules)

The (manifests: …) part says which LUZ version the names were checked against, and from where: your node_modules or the copy that ships with the command.

The JSON report

--json prints one object with these fields. A field that is not in this table is not part of the report.

The fields of the JSON report
FieldTypeWhat it is
tool
string
Always @luz-ds/check
version
string
The version of the checker
ok
boolean
True when nothing blocks and, with --strict, nothing warns. It is not an accessibility result
files
list of strings
The files it read, sorted
manifests
list of objects
The LUZ data it checked against, one entry for each package
manifests[].package
string
The package, such as @luz-ds/core
manifests[].version
string
The version of that package's data
manifests[].source
string
node_modules when your project has the package, bundled when the command's own copy was used
summary
object
The counts of the run
summary.files
number
How many files it read
summary.blocking
number
How many findings block
summary.warnings
number
How many findings warn
summary.skipped
number
How many paths it did not read
summary.ignored
number
How many findings the configuration's ignore removed
summary.off
number
How many rules the configuration switched off
summary.truncated
boolean
True when the list of findings was cut; the counts above are complete
config
object
The configuration that was read
config.file
string or null
The configuration file, or null when there was none
config.off
list of strings
The rules the configuration switched off
findings
list of objects
What it found, in the order of files and lines
findings[].rule
string
The rule, such as class/unknown
findings[].severity
string
block or warn
findings[].file
string
The path, relative to where you ran the command
findings[].line
number or null
The line, when the finding has a place in the file
findings[].column
number or null
The column, when the finding has a place in the file
findings[].message
string
The sentence that says what is wrong and what to do, in English
findings[].suggestion
string or null
The closest LUZ name, when there is one close enough
findings[].docs
string
The URL of the page that explains the rule
findings[].details
object
Only on some findings. A color token finding names the mode, the colors, the ratio and the places where the colors were set
skipped
list of objects
The paths it did not read
skipped[].file
string
The path
skipped[].reason
string
Why: a link, a file that is not a regular file, a file over 1 MiB, one it could not open, or a limit of the run

The same two things hold for the text and for the JSON: a path or a name that is not made of ordinary characters is written escaped, and the command never quotes the text of your files.

What check blocks and what it warns about

Each rule has an id such as class/unknown, shown in every finding. A rule that blocks makes the exit code 1.

A rule that warns does not, unless you pass --strict. The two tables are written from the list of rules the command has.

Catalog 0.3 renamed its classes, elements, files and chunks, and the old names do nothing. names/renamed finds an old class, an old tag, a link to an old component file or an old chunk, and gives the new name. It says nothing on a page that links catalog 0.0 to 0.2, where the old names are the right ones.

Rules that block
RuleWhat it findsSeverity
a11y/slider-no-name
A <luz-theme-time variant="bar"> with no data-luz-label-scrub on it or an ancestor, so its slider has no accessible name: the script writes no English text.
block
class/unknown
A class starting with luz- that no classes.json lists, or an o- or u- class a typo away from one LUZ has.
block
element/unknown
A <luz-*> tag that no custom-elements.json declares and that is not the block of a class.
block
element/unknown-attribute
An attribute on a LUZ element that its custom-elements.json does not declare; global, aria-*, data-* and framework attributes are left alone.
block
load/layer-statement
A <style> that declares the layers after the first LUZ stylesheet, when the order of the layers is already fixed.
block
load/package-missing
A class or tag from a package whose stylesheet the page does not load, such as a site class with no site stylesheet.
block
load/tokens-missing
A page that links core, catalog or a package for one kind of site and does not link @luz-ds/tokens.
block
misuse/host-element
A class on an element it is not made for, such as a button class on a <div>; classes.json lists each class's elements.
block
misuse/modifier-alone
A modifier such as luz-btn--primary on an element that does not also have the class it modifies.
block
names/renamed
A class, element or file of catalog that has its old name from before 0.3 (luz-landing-hero, <luz-mode>, <luz-color-mode>, luz-mode-btn, landing-hero.css): the finding gives the new name.
block
parse/error
A file that ends inside a comment, tag, string or brace, so the rest of it cannot be read.
block
theme/contrast
A foreground and background pair in your colour token files that is under its WCAG contrast minimum in light, dark or high contrast.
block
theme/unreadable
A LUZ colour token, in a file that sets colour tokens, whose value cannot be read as an sRGB colour, so its contrast cannot be measured.
block
Rules that warn
RuleWhat it findsSeverity
a11y/link-no-href
An <a> that has a class made for links and no href, so it is not a link and a keyboard cannot reach it.
warn
a11y/role-on-generic
A widget role, or onclick, on a <div> or <span> where a native element such as <button> does the same with the keyboard.
warn
attr/unknown-hook
A data-luz-* attribute on an element that no package reads: usually a misspelling of one it does.
warn
class/reserved-prefix
A stylesheet of yours that defines a class starting with luz-, the prefix LUZ keeps for itself.
warn
class/unknown-in-css
A selector in your stylesheet that names a .luz-* class no classes.json lists.
warn
css/important
!important in a declaration, in a custom property too; a rule outside the layers already wins over LUZ.
warn
css/knob-in-px
--luz-type-base or --luz-space-unit set in px, which ignores the text size the reader chose.
warn
css/literal-colour
A colour written out in a declaration (hex, rgb, hsl and the other functions) instead of a token.
warn
css/literal-size
A px or rem length in font-size, margin, padding, gap or border-radius instead of a space, text or radius token.
warn
css/private-token
A --luz-* property that one component sets for itself, set or read outside that component.
warn
css/unknown-token
A --luz-* property that no package declares, set or read: usually a misspelling.
warn
file/skipped
A path the check did not read, such as a symlink or a file that is too large; the finding says why.
warn
load/no-stylesheet
Checked files that load no LUZ stylesheet at all, so a class can only be told from your own by its name.
warn
load/order
LUZ stylesheets linked out of order; the order is tokens, core, catalog, then the package for your kind of site.
warn
misuse/part-orphan
A part such as luz-card__title with no element of its block around it.
warn
misuse/state-class
An is-* class that LUZ's own script sets, written in the markup.
warn
theme/advisory
A note on how the colour check ran: the file order it used, a token no colour mode can place, a wide-gamut colour it does not measure, or sets of colour tokens past its limit.
warn

The accessibility reviewer

The same package prints an agent definition for an AI coding assistant: a reviewer that reads the source of a page and gives advice on accessibility. Copy it into your project.

Shell
npx @luz-ds/check@0.3.0 agent > .claude/agents/luz-accessibility-reviewer.md
  • It overwrites. The > replaces a file that is already there. Use another path, or put your copy under version control first, if you edited it.
  • It is read-only. It has three tools, Read, Grep and Glob: it reads, searches and lists files, and writes nothing. Read-only does not mean harmless, because Read has no path limit. Read the file before you use it, and review any change to it as you would code.
  • It gives advice. It reviews source against WCAG 2.2 level AA and EN 301 549, and labels each finding as confirmed in the source or as one that needs a browser or assistive technology. Its findings are suggestions from reading code, not test results.
  • It does not use assistive technology. It does not open a page or run a script, and it does not look at how a page renders, so it does not replace a test with a keyboard and a screen reader.

The file is also in the package as @luz-ds/check/agents/accessibility.md, for a build step that copies it.

What this does not do

A run with no findings says what the checker did not find in the files it read. It is not a test of the page.

  • It does not run a browser. It reads files, so anything that depends on how a page renders, such as layout, focus order or the colors a browser works out, is not seen.
  • Contrast is measured for your tokens only. It measures the --luz-* colors you set in your own color tokens file. A color written straight into a rule is not measured against anything. How the pairs are read is on Contrast check.
  • A class built at run time is not seen. A name put together in a script, such as "luz-" + name, or written by a template, is not in the file, so it is not checked.
  • It does not check names, labels, alt text, headings and language. Whether a button has a name, an image a useful alternative, the headings an order and the page a language is not read, and a run with no findings says nothing about them.
  • It does not replace testing with a screen reader. No assistive technology is used, by the command or by the reviewer. What has not been tested is listed in the accessibility statement.
  • It does not call a network. It runs offline, with the data in your node_modules or in its own package.
  • Discovery by llms.txt is by link. This site is not at the root of a host, so an agent does not find the file by itself: give it the URL, as the prompt above does.
  • Exit code 0 is not an accessibility result. It says that no rule above blocks in the files that were read.
  • The messages are in English. They are not translated, whatever the language of the page.