The template kit
@port60/template-kit is the local half of the platform: the same contract, dialect,
validator and preview renderer the engine runs in production, packaged as a CLI. If it validates
on your machine, it validates at upload, the two cannot drift.
Commands
Section titled “Commands”p60-template-kit create <dir>A working template from the platform starter: renders immediately, validates clean, and comes
briefed for AI agents (AGENTS.md/CLAUDE.md) with npm scripts wired. The folder name becomes
the template name and the label derives from it; --name/--label override the identity when it
should differ from the folder.
p60-template-kit dev [dir] [--port 4400]Live preview over the contract’s kind fixtures with realistic, non-interactive island skeletons for worship rails, events, donation widgets and other platform features. The skeletons use each island’s stable styling API, so theme CSS can be judged without a platform account. Files are re-read per request, so refresh is the reload; validation re-runs in the terminal on save.
What the preview is, precisely, so nothing surprises you at upload:
- Two compositions, as the platform composes them. When your manifest declares
compositions,/and/aboutrender your composition for that page, in your order, with theoptionalentries left out, against the catalogue’s sample content. Without one,/renders the sections you declare that the catalogue assigns to the home page and/aboutthe ones it assigns to about, each in manifest order. A template that does not declareaboutinsupports.pagessees the platform’s own About body there, as it would live. Your own compositions and copy come from thepagesblock ofpreview-content.json(below). - Routed platform surfaces. The bar at the top links to
/about,/events,/services,/donate,/articles,/campaignsand/courses, each wearing your chrome and, where you ship one, your page template. - What leads is switchable. The bar’s Leads with links (or
?focus=donate|volunteer|noneon any URL) set the site focus: theprimary_action_widgetisland in your hero becomes the donation widget, the volunteer sign-up, or nothing, andsite.focus,site.actions, the header button and the hero’ssection.actionfollow. The studio renders the default, giving. - Behaviours run. The platform’s behaviour runtime is inlined, so reveals, carousels,
accordions, tabs, and menus built on the
navbehaviour work as in production. Only the older chrome hooks (data-nav-burger,data-nav-drop) stay inert in the preview; they work on a live site and on a development version of your own site. - Knobs and Looks switch. Knobs render at their defaults; the bar’s Looks links (or
?look=Nameon any URL) apply one of yourmanifest.looks, and?p60s-<key>=<value>sets a single knob, exactly as Appearance does for a charity. Values are checked the way production checks them: a select value outside the knob’s options and an unknown font family fall back to the default. - Webfonts load. The dev preview loads your
manifest.fontsand your font knobs’ families from the platform’s provider mirror, so type is judged for real. The studio review render stays network-dead and shows the fallback stacks. - Icons resolve.
item.iconSvgis supplied for a Lucide icon name, as live; renderitem.iconas the fallback for anything else.
Photographic fixtures: set P60_FIXTURE_IMAGES=https://your-image-host before dev and the
built-in fixture image references load <kind>-<seed>.jpg from that one origin instead of the
sealed inline art; the preview admits exactly that host. Your own photographs go in a preview/
folder beside the template: the dev server serves them at /preview/<file> (images only), so a
preview-content.json can point imageUrl values at /preview/hero.jpg. Unset and without the
folder, the preview stays fully network-dead. Images you place next to the template are never
packaged, see what the zip contains.
p60-template-kit validate [dir] [--json]The conformance checks the platform runs at upload, manifest schema, dialect, fixture renders,
island discipline, the two-way supports honesty, render budgets. --json emits
{ok, errors, warnings, manifest, provenSupports}: supports as an output, a clean pass is
what turns your declarations into proven capability, and it’s the feedback loop AI agents iterate
against.
p60-template-kit package [dir]Validates, then produces dist/<name>-<version>.zip containing exactly the contract-shaped file set, the artifact your studio’s upload accepts as-is. dist/ is wiped and recreated on every run and is gitignored by the scaffold.
p60-template-kit model [--json]The content model in hand: every site.content.* collection with its
bound, onward link and fields. --json emits the registry verbatim for agents. The dev server
renders the same reference with live example data at /model.
p60-template-kit content [dir] [--out file]p60-template-kit dev [dir] --content my-org.jsonBring your own content and imagery. content EJECTS every collection plus the brand, the menu
(nav) and the home and about compositions (pages, each declared section with its sample copy),
fully populated with the canonical organisation, as one editable JSON file; edit the copy in
place, reorder or drop sections, swap imageUrl values for your own hosted images or a preview/
folder, and dev --content renders your data on every surface; the preview admits exactly the
image hosts your file names and nothing else. The shape stays the platform’s (schema-checked on
every read: a section type must be in the catalogue and its fields must be ones the section
declares), the data becomes yours; the file is hot-reloaded, never packaged, and refused at upload.
p60-template-kit loginp60-template-kit whoamip60-template-kit logoutSign in from the terminal. login runs the Keycloak device flow (the browser approves), stores an
offline token in ~/.port60, and discovers your studio workspace automatically; whoami shows who
is signed in and which workspace; logout signs this machine out and revokes its token. By default
the kit talks to Port60’s hosted stack; set P60_AUTH_BASE / P60_API_BASE / P60_REALM /
P60_CLIENT_ID to point it at a local or self-hosted environment.
p60-template-kit publish [dir] [--no-submit]Validate, package, upload to your studio and submit the version for review, in one command. The
dashboard upload in Publishing still works, this is
the same result from the terminal (--no-submit uploads without submitting).
p60-template-kit publish [dir] --ciThe same from a GitHub Actions workflow: no login, the run’s own OIDC token is the credential, and the repository must be trusted in Studio (once, for the whole studio). See Publish from GitHub Actions for the workflow.
Staying current
Section titled “Staying current”npx @port60/template-kit@latest upgradeYour scaffold pins the kit as a devDependency and every npm script runs that local copy, so the
whole enforcement surface, contract, content model, validator, fixtures, preview, behaviour
runtime, upgrades with one install. upgrade does it properly: it installs the latest kit into
your pin, regenerates AGENTS.md/CLAUDE.md (they are the kit’s generated briefing, stale the
moment the contract moves, your own notes belong in README.md), prints the kit, contract and
content-model versions now in force, and re-runs the full conformance check so you immediately
see what, if anything, the newer contract asks of your template.
Your template sources are never touched, and the contract is add-only within a major, an upgrade can inform you, it cannot break you. New collections, fields and behaviours simply become available; anything the validator newly asks for appears in the report, not in production. See Versioning for why published versions stay safe regardless.
From zip to a charity’s site
Section titled “From zip to a charity’s site”- Upload the zip in your studio (tenant admin → Studio → your template → Versions), the platform re-runs validation and stores the artifact in quarantine.
- Submit the validated version for review.
- A Port60 reviewer approves; the artifact is promoted to the live catalogue, privately delivered to your commissioning charity or listed on the marketplace at your price.
Versions are immutable once reviewed; ship fixes as a new semver. The name in your manifest is your claimed identity, it must match the template you created in the studio.

