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 schema.ts 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. |
no-client-directive-in-contract |
eslint | No “use client” in a section’s four contract files. |
props-from-schema |
eslint | A Renderer’s Props type must be derived from schema.ts, not hand-written. |
no-inline-style |
eslint | No inline style= in server-rendered JSX. Islands are exempt. |
no-raw-element |
eslint | No raw <section>, <img> or <video> — use <Section>, <Image> and <Video>. |
image-bare-needs-reason |
eslint | <Image bare> needs a // bare: comment saying why it skips the frame. |
slot-marker-literal |
eslint | A slot-marker key must be a string literal, not an expression. |
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 four required 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. |
manifest-invalid |
check | A template’s manifest.json is missing, unparseable, or violates the manifest contract. |
missing-slot-marker |
check | An editable slot in schema.ts has no marker in the section’s JSX. |
slot-group-marker |
check | A group with two or more members has no <SlotGroup> wrapper. |
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. |
sidebar-order |
check | Schema slot order must match the order the page renders them in. |
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, or src-less <img>. |
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. |
license-denied |
check | A production dependency’s license is not on the allowlist. |
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 section’s static assets exceed their byte budget. |
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.
- Check — running
template-kit check, its flags, output shape, and exit code.