Skip to content

Manifest schema

Every artifact ships a manifest.json validated against a JSON Schema at publish time. Required fields: name, version, format, supports.

Field Type Description
name string The template’s identity, lowercase, hyphenated, stable across versions.
version string Semver. Stable versions are immutable once submitted. Owner-only development versions use x.y.z-dev.N, remain non-promotable, and may be replaced before creating a stable release.
format port60-liquid@1 The dialect/contract major this template is written against.
label string Human-readable name shown in pickers.
description string
requiresCapabilities array Platform capabilities this design needs in order to work as intended. This is a catalogue matching signal, never an entitlement grant. The validator checks that each declared capability has a corresponding section, page template, island or context surface.
suitsProfiles array Organisation profiles this design was composed for. An empty list means the template is general purpose. Profiles improve catalogue recommendations but do not hide or unlock features.
changelog string One human line describing what THIS version changed, shown on the Appearance update nudge.
supports object
supports.pages array Section based page bodies this template renders from sections/{type}.liquid. Contract v1 supports home and about. This is independent of layout chrome and route-specific pageTemplates.
supports.sections array Section types this template ships renderers for (sections/{type}.liquid). Unsupported types are omitted at render, never an error.
supports.islands array Islands this template places. Every {% island %} name must be listed here AND exist in the platform island registry.
supports.layout boolean True when the template ships layout.liquid and owns the page chrome (header/nav/footer). The platform still owns , consent, and identity, see the layouts guide.
supports.pageTemplates array Route-specific data views rendered from pages/{page}.liquid with documented context. Events and articles own listings; course and article own detail presentation. Event transactions, course enrolment, article engagement, comments, identity and consent stay platform-owned islands. Requires supports.layout; without an entry the platform body renders inside the template chrome.
supports.worship boolean True when the layout renders the worship context (the prayer/service-times rail). Declared honesty: the choosers badge worship-enabled tenants toward looks that show their times, and warn on looks that don’t. Requires supports.layout; the layout must actually branch on worship.
supports.heroImagery boolean True when the homeHero renderer displays the tenant’s hero photographs (homeHero.images, legacy imageUrl), always under a TREATMENT built from the template’s own palette variables (scrim/tint/blend), never raw. Declared honesty, proven behaviourally at validation: the choosers badge photo-led tenants toward templates that show their images and warn on ones that won’t. Requires the homeHero section among supports.sections.
supports.behaviors array Engine-attached behaviours this template’s markup opts into via data-p60-* attributes (see the behaviour catalogue). Templates never ship JavaScript; declaring here is what makes the engine wire the markup, and the validator proves declaration and usage agree in both directions.
supports.focus array The site-focus kinds this template can LEAD with (docs/volunteering.md). Declaring ‘volunteer’ means the home hero places the primary_action_widget island (the widget that becomes the donation widget or the volunteer sign-up as the charity chooses) or branches on section.primary.kind, so the volunteer sign-up can take the widget slot; the picker marks templates that cannot lead with volunteering. Templates that predate the setting keep rendering the donation widget, since donate is the default.
imagery object The template’s OWN image advice, surfaced beside uploads in the charity’s editor, a design statement (what shape suits THIS composition), advisory only, never enforced. Entity images (events, courses, articles) are platform-scoped instead: see the contract’s imagery.json envelopes.
imagery.hero object
imagery.hero.idealAspect string The aspect this hero composes best with, e.g. “16:9”.
imagery.hero.minWidth integer Below this pixel width the photo may look soft full-bleed.
imagery.hero.note string One human line of advice, e.g. how panoramas or portraits behave in this hero.
fonts array Webfont stylesheet URLs the platform loads in (with preconnects, never a CSS @import). Google Fonts css2 URLs only.
looks array One-click LOOKS: author-named bundles of knob values (scheme + fonts + width…) applied together. Everything remains individually adjustable afterwards.
looks[].name string The look’s evocative, author-chosen name, shown as a one-click chip in Appearance.
looks[].values object Knob key → value. Every key must be a declared settings knob; select values must be listed options; font values must be catalogue families.
compositions object The template’s preferred composition per supported page (site editor stage 4): the ordered section types it designs the page around, each with a role. core sections carry the design (removing one warns, never locks), recommended ones are on by default, optional ones are offered. A page a tenant never edited renders this composition; the Pages editor offers it as the order to reset to.
settings object
settings.schema array The template’s own theming knobs (colour schemes etc.), rendered as an editor in Appearance/get-started; values land in site-config config.theme.
settings.schema[].key string
settings.schema[].kind color | select | toggle | font
settings.schema[].label string
settings.schema[].default
settings.schema[].options array
settings.schema[].group typography | looks Where the admin surfaces this knob: ‘typography’ → the Typography section beside the font slots; ‘looks’ → the Looks section with the one-click bundles (colour schemes and accent dials belong there, and ungrouped color knobs plus a knob keyed ‘scheme’ default there anyway); other ungrouped knobs render under Template options.
settings.schema[].weights array FONT knobs only: the weights this template’s typographic system uses for the slot. The host requests these for the tenant’s chosen family (clamped to the family’s real weights). The tenant picks the FAMILY; weights, sizes and tracking stay template-owned.

Worked example, the starter template’s manifest

Section titled “Worked example, the starter template’s manifest”
{
"name": "starter",
"version": "1.13.0",
"format": "port60-liquid@1",
"label": "Starter",
"description": "The reference template for the Port60 dialect, the developer docs' worked example and the base to copy when building your own. 1.1.0 adds the layout slot: the template owns the header, navigation and footer chrome.",
"supports": {
"pages": [
"home",
"about"
],
"sections": [
"homeHero",
"hero",
"values",
"cta",
"people",
"campaigns",
"impactMap"
],
"islands": [
"donation_widget",
"member_menu",
"hero_carousel",
"map",
"primary_action_widget",
"search"
],
"layout": true,
"heroImagery": true,
"behaviors": [
"reveal",
"carousel"
],
"focus": [
"donate",
"volunteer"
]
},
"compositions": {
"home": [
{
"type": "homeHero",
"role": "core"
},
{
"type": "campaigns",
"role": "recommended"
},
{
"type": "impactMap",
"role": "optional"
},
{
"type": "cta",
"role": "recommended"
}
],
"about": [
{
"type": "hero",
"role": "core"
},
{
"type": "values",
"role": "recommended"
},
{
"type": "people",
"role": "optional"
},
{
"type": "cta",
"role": "recommended"
}
]
},
"settings": {
"schema": [
{
"key": "siteFont",
"kind": "font",
"label": "Site font",
"default": "Inter",
"weights": [
400,
500,
600,
700,
800
]
}
]
},
"changelog": "Places the site search box in the header: a typeahead across events, articles, services, campaigns, appeals, volunteering and documents, with the results page at /search.",
"imagery": {
"hero": {
"idealAspect": "16:9",
"minWidth": 1600,
"note": "Landscape around 16:9 fills the hero cleanly; panoramas suit the whole-photo framing."
}
}
}