Skip to content

Anatomy of an artifact

A template artifact is a directory published to object storage under {name}/{version}/. Once published, that prefix is immutable; the platform caches artifacts aggressively (in-memory and at the CDN) precisely because a version can never change underneath anyone.

{name}/{version}/
├── manifest.json # REQUIRED: identity, format, what you support
├── layout.liquid # OPTIONAL: the page chrome, when supports.layout is true
├── sections/ # REQUIRED: one {type}.liquid per supported section type
│ └── *.liquid
├── pages/ # OPTIONAL: display bodies for pages in supports.pageTemplates
│ └── *.liquid
└── assets/
└── theme.css # REQUIRED: the template's entire look

The manifest declares what your template is and what it supports. It’s validated against a JSON Schema at publish time; the important fields:

Field What it means
name Permanent identity. Lowercase, hyphenated, stable across every version.
version Semver. Immutable once published, a fix is a new version.
format The contract major you’re written against, currently port60-liquid@1.
supports.pages Section based page bodies you render: currently home and about.
supports.sections Which section types you ship renderers for.
supports.islands Every island your renderers place.
supports.layout True when you ship layout.liquid and own the chrome, see Layouts.
supports.pageTemplates Route specific data views you render. Listings are events and articles; details are course and article. See Page templates.
compositions Your preferred composition per page: the ordered section types the design is built around, each with a role. core carries the design (an organisation removing one is warned, never stopped), recommended is on by default, optional is offered. A page an organisation never edited renders this composition, the kit preview renders it, and the Pages editor offers it as the order to reset to. Every type must be in supports.sections and belong to that page.
requiresCapabilities Capabilities the design needs to work as intended. This is checked against the artifact and used for catalogue matching. It never grants an entitlement.
suitsProfiles Organisation profiles the design was composed for. This improves recommendations but never hides or unlocks a feature.
fonts Webfont stylesheet URLs the platform loads in <head>.
settings.schema Your own theming knobs (colour schemes etc.), see Theming.

Two support rules matter:

  1. Sections you don’t support are omitted, never an error. If a charity authors a section your template has no renderer for, that section silently doesn’t render. Support the catalogue broadly, but you’ll never crash for missing one.
  2. Every island you place must be declared in supports.islands; the validator enforces placed ⊆ declared ⊆ platform registry.
  3. Every required capability needs a visible surface. The validator rejects a capability claim that has no matching section, page template, island or context declaration in the artifact.

One file per supported section type, named exactly after it (hero.liquid renders hero sections). Each is a self-contained fragment written in the Port60 dialect, there is no include mechanism and no partials in contract v1, and sections never contain chrome (that’s the layout’s job).

Each renderer receives the render context: the section object (typed per the section catalogue) and brand.

Renderers must survive the minimal fixture of every type they support, the least content a charity can author. The validator renders both fixtures; if your hero falls over when eyebrow is absent, you don’t publish.

Your whole look, one file. It layers on top of the platform base stylesheet, which owns mechanics (layout plumbing, form controls, island internals) and exposes CSS tokens for everything brandable. Your CSS:

  • overrides tokens under :root:root (doubled specificity so the theme wins),
  • styles your own section markup (class names are yours, the starter uses an lq- prefix),
  • may restyle islands only through their published styling API.
  • No JavaScript. Behaviour is platform-owned; templates place islands.
  • No network calls, no data fetching. The platform feeds renderers everything they get.
  • No unsanitised HTML output. | raw is for the contract’s richtext fields only.
  • No file inclusion, include/render/layout are excluded from the dialect and fail at parse time.