Kits

A kit is one selected presentation package. It supplies a site design, while the site root continues to own content, configuration, data, deployment files, and local adaptations. A kit is not a generic theme that Heine can safely swap between arbitrary sites. Its required reference site shows the structure and conventions it expects.

Start with a kit when its reference site is a useful starting point. Keep an ordinary site when you want to own every template and presentation resource.

Install a kit and copy its reference site

Heine does not download or resolve kits. Install one below kits/<name>/, then copy its site/ directory into the project root. The copied configuration selects the installed kit.

my-site/
├── heine.toml
├── content/
├── templates/
└── kits/
    └── paper/
        ├── kit.toml
        ├── templates/
        ├── assets/
        ├── locales/
        ├── LICENSES/
        └── site/

The copied site/ directory is an ordinary site root. It may contain heine.toml, content/, data/, templates/, locales/, deploy/, and LICENSES/. It does not participate in a build after copying. Heine checks only that every selected kit has a regular site/heine.toml file that selects the kit containing it.

# heine.toml
[kit]
name = "paper"
version = "^1.0"

name is required. version is optional, but it gives the site an additional check against an unintended installed kit release. Heine also checks the kit's declared compatible Heine-version range before it reads the kit's templates, assets, messages, or license texts.

Only one kit may be selected. Removing [kit] restores an ordinary site, but any root template that extends a kit template then fails at that reference.

Describe a kit

Each kit has a kit.toml manifest beside its runtime directories. It identifies the package, states which Heine releases may load it, reserves its Fluent message prefix, and declares its public integration surface.

# kits/paper/kit.toml
name = "paper"
version = "1.0.0"
heine = ">=0.8.0, <0.9.0"
message_prefix = "paper-"

[public]
templates = ["base.tera", "post.tera"]
assets = ["assets/css/paper.css"]
components = ["paper.card"]

name must match the kit directory. version is the kit's semantic version, and heine is the semantic-version requirement for the Heine binary that loads it. message_prefix is non-empty and namespaces every Kit Fluent message and term. The [public] lists are exact: a root site may extend only listed templates, resolve only listed kit assets through ordinary asset() calls, and invoke only listed components. The reference defines the root-owned [kit] selection and settings; the design record explains the compatibility contract.

The package directory, its manifest, and its runtime directories must be ordinary paths, not symbolic links. This keeps the selected package's source ownership visible while Heine loads it.

Adapt public templates

The kit owns its original templates below kits/paper/templates/. Their names always begin with kit/paper/; root template names never fall back to them. The kit manifest declares which originals are public. A copied root adapter can extend one of those public templates and override its Tera blocks.

{# templates/post.tera #}
{% extends "kit/paper/post.tera" %}

{% block content %}
  <p>Published by the site.</p>
{% endblock content %}

This keeps the customization boundary visible. A root template cannot extend a private kit partial, and a kit template cannot reach into a root template. When a kit does not expose a block or public component for the change you need, override the relevant public template or change the kit itself.

The kit/ template namespace is reserved even without a selected kit. Do not create root templates below templates/kit/.

Use kit settings

A kit can declare a small schema of presentation settings in its manifest. The site may override only those declared keys through [kit.extra]. Tables merge into declared tables; scalar values and arrays replace their defaults.

# kits/paper/kit.toml
[extra]
accent = "violet"

[extra.navigation]
compact = false
# heine.toml
[kit]
name = "paper"

[kit.extra]
accent = "indigo"

[kit.extra.navigation]
compact = true

Kit templates receive the resolved value as kit.extra:

{% if kit.extra.navigation.compact %}
  <nav class="compact">…</nav>
{% endif %}

Heine rejects an undeclared key or a value whose type differs from the kit's default. This preserves a small, checked customization contract rather than merging arbitrary site configuration into a kit.

Assets, messages, and components

The manifest's [public] table states a kit's supported integration surface. It can declare templates, copied assets, and Tera components.

[public]
templates = ["base.tera", "post.tera"]
assets = ["assets/css/paper.css"]
components = ["paper.card"]

A declared public asset has its ordinary shared assets/… ID. A root shared asset at the same ID overlays it, and a locale-local root asset continues to use the normal locale lookup. Private kit assets use kit/paper/assets/… and remain available only to kit templates. They are still published, so their output URLs intentionally show that kit-owned namespace.

Kit Fluent messages and terms use the manifest's prefix, such as paper-. Root Fluent files may replace existing prefixed entries, which lets a site adjust kit interface wording without editing the kit. Root templates may call only components declared public by the kit. Components remain kit-owned and cannot be replaced from the root.

Root LICENSES/ files and licensing declarations work across root and kit assets. A root license text with the same logical path replaces the kit text. See asset licensing for the copied-asset rules.

Develop and update a kit

Develop kit runtime resources in their final kits/<name>/ locations. Use the surrounding ordinary root as an integration site: its root templates extend public kit originals, and its content and data exercise the design as a user would.

When preparing a release, copy the root's Heine inputs into kits/<name>/site/. Copy heine.toml, content/, data/, templates/, locales/, deploy/, LICENSES/, and other applicable input directories. Do not copy kits/, generated output, VCS data, or unrelated workspace files. The reference site is a release snapshot, so update it whenever the kit's expected root structure or example changes.

Kit runtime inputs follow the same rebuild rules as their root counterparts. A selected kit template, Fluent resource, or license-input change needs a full build. A selected present asset change can participate in the existing quick asset update. Changes below kits/<name>/site/ and changes in non-selected kits do not trigger a build because they are not runtime inputs.

The kit design record explains the compatibility and ownership decisions behind this contract.