Rules
Router for the rule corpus — every `template-kit/<id>` an author can hit, and the page that explains it.
Every authoring rule the kit enforces is printed under one namespace, template-kit/<id>,
and resolves to exactly one page here: guide/rules/<id>.md.
One namespace, two venues. Some rules are properties of one file (a Date.now()
in a Renderer) and are enforced by the ESLint preset, which ships as its
own package, @homepages/eslint-plugin-template. Others are properties of the
tree (a slot declared in the schema but never marked in the JSX, a stylesheet, a
dependency, a byte budget) and cannot be expressed one file at a time; those are enforced
by template-kit check. You never need to know which engine produced a
violation — only the id, which names its page either way.
Read server vs client first if you are here for any rule that mentions “server-rendered code” or an island. It is the one concept those rules assume, and it is explained there rather than on each of them.
| Rule | Venue | What it enforces |
|---|---|---|
no-nondeterminism |
eslint | No clock or randomness reads in server-rendered code. |
no-client-runtime-in-server |
eslint | No effects, state, event handlers, network, or browser globals in server-rendered code. |
serializable-island-props |
eslint | Props handed to an island must be JSON-serializable. |
require-island-editor |
eslint | Every island must declare whether it is live in the editor canvas. |
require-editor-reason |
eslint | Every fork on inCanvas must carry an editor-reason: comment naming what it protects. |
no-editor-globals |
eslint | No reads of the platform’s internal __tr* canvas globals — useEditor() is the contract. |
no-client-directive-in-contract |
eslint | No “use client” in a section’s contract files. |
no-node-builtins-in-contract |
eslint | No Node built-in imports in a section’s contract files. |
props-from-schema |
eslint | A Renderer’s Props type must be derived from schema.ts, not hand-written. |
no-slot-marker-literal |
eslint | No hand-written data-slot-* attributes or string literals — markers come from the Slot primitives. |
no-raw-slot-values |
eslint | Read slot values through bindSlots/bindItems, never off the raw slots prop. |
no-inline-style |
eslint | No inline style= in server-rendered JSX. Islands are exempt. |
no-hex |
eslint | No hard-coded colours — the one legal colour function is a color-mix() over theme-derived arguments. Islands are NOT exempt. |
no-css-import-from-render-path |
eslint | No relative/absolute .css import from a section’s render path — a package’s is the sanctioned channel. |
bundle-incomplete |
check | A section folder is missing one of its contract files. |
bundle-binary-asset |
check | An unreferenced binary asset sits in a section folder. |
schema-invalid |
check | A section’s schema.ts or fill-spec.ts fails a contract assertion, or cannot be loaded. |
fixtures-invalid |
check | A section’s fixtures.ts does not satisfy the fixture-module shape. |
template-invalid |
check | A template’s template.ts is missing, unloadable, or violates the composition contract. |
theme-invalid |
check | A template’s theme.ts is missing, does not export theme, or exports one that is not a valid TokenTheme. |
missing-slot-marker |
check | Every editable slot, every per-item collection row, and every declared row field must reach the rendered DOM with a selectable marker. |
unit-collection-item-marker |
check | A collection edited as one unit must not render data-slot-item row markers. |
group-ancestry |
check | A grouped slot must be marked inside its group’s data-slot-group element. |
section-unrenderable |
check | A section that fails to load renders no fixture, so none of its markers can be proven. |
island-server-frame |
check | An island’s serverFrame declaration must match what it actually server-renders. |
css-reason |
check | A hand-written CSS file must open with a css-reason: comment. |
no-bare-css-import |
check | No @import in hand-written CSS — the browser drops it silently. |
unlayered-fence |
check | An /* unlayered: */ escape hatch must be balanced and give a reason. |
section-root-margin |
check | No margin utilities on the section root — margin opens gaps between sections. |
frame-aspect-conflict |
check | No aspect utilities on a framed element — the slot’s declared frame owns its aspect. |
sidebar-order |
check | Schema slot order must match the order the page renders them in. |
rendered-class-conflict |
check | A section must not be composed by both a website template and a rendered-class one. |
rendered-no-motion |
check | No animation or transition in an image or document class — a still frame never plays them. |
rendered-no-fixed |
check | No position: fixed or sticky in a rendered class — both bind wrongly in the stacked print document. |
unknown-format-variant |
check | A format-variant prefix must name a declared format of a template composing the section. |
typecheck |
check | The template must compile under TypeScript. |
parse-error |
check | A file could not be parsed at all — a syntax error, not a rule violation. |
determinism-drift |
check | Rendering the same fixture twice must produce byte-identical HTML. |
render-invariant |
check | Rendered output must carry no [object Object], bare null/undefined/NaN leaf, src-less <img>, or dev-media URL naming no file in the pack. |
lockfile-missing |
check | The workspace has no package-lock.json. |
lockfile-stale |
check | The lockfile does not satisfy package.json — an npm ci would fail. |
single-react |
check | The installed tree carries more than one copy of react or react-dom. |
audit-severity |
check | A dependency carries a high or critical security advisory. |
size-renderer-bundle |
check | A section’s renderer bundle exceeds its byte budget. |
size-section-css |
check | A section’s compiled CSS exceeds its byte budget. |
size-island-bundle |
check | A section’s island (browser) bundle exceeds its byte budget. |
size-assets |
check | A single static asset is heavier than the guideline. Warning only. |
no-templates |
check | The workspace has no template to check at all. |
See also
Section titled “See also”- Server vs client — how a file is scoped, and which rules stop at the hydration boundary.
- ESLint preset — setting the preset up in a template workspace.
- Run
check— running the gate and reading what it reports. checkreference — its flags, stages, thresholds and exit codes.