Publishing & conformance
Publishing has four stages:
validate → package → upload to Studio → reviewValidate before packaging
Section titled “Validate before packaging”From the template project created by @port60/template-kit, run:
npm run validatenpm run validate:jsonThe validator uses the same contract and dialect enforcement as the upload service. It checks:
manifest.jsonmatches the manifest schema.- Every declared section exists in the section catalogue and has a renderer.
- Every renderer parses under the restricted Liquid dialect.
- Every renderer survives both minimal and sample fixtures.
- Placed islands are declared and available in the island registry.
assets/theme.cssexists and is not empty.- A declared layout contains exactly one
{% content %}slot and renders the layout fixture. - Declared worship and hero imagery support is proven by the rendered output.
- Declared page templates exist and render their documented data fixtures.
- Every
requiresCapabilitiesentry is backed by a section, page template, island or context surface the artifact actually uses.
Errors block packaging and upload. Warnings do not block them, but should be understood before a version is submitted.
Create the uploadable zip
Section titled “Create the uploadable zip”npm run packagePackaging validates again, then creates dist/<name>-<version>.zip (dist/ is recreated on every run, so it only ever holds the current build). Only contract shaped files are
included: the manifest, layout, section and page renderers, and CSS assets. Project notes,
dependencies and source control files are excluded.
What the zip contains
Section titled “What the zip contains”Exactly the contract-shaped set: manifest.json, layout.liquid, sections/*.liquid,
pages/*.liquid and assets/*.css, where assets/theme.css is the one stylesheet the platform
loads. Everything else beside your template stays on your machine: notes, dependencies, preview
content, design references, and any image, font or script file. From kit 0.14.3, package and
publish list what they left out, so a photograph dropped into assets/ is a line in the output
rather than a broken URL on a live site. The upload refuses anything outside the set.
Photographs belong in the charity’s media library, where the charity chooses them and holds them
(a starter media pack a template can offer is on the roadmap). Decorative textures and patterns
fit inside theme.css as data URIs within the stylesheet size limit.
Upload through Studio
Section titled “Upload through Studio”- Sign in to your organisation’s tenant admin.
- Open Studio and select your template.
- Open Versions and upload the zip.
- Review the validation result and preview.
- Submit the version for review.
The platform validates the uploaded bytes again. A successful local run is therefore useful before upload, but the Studio result is the final gate for that exact zip.
Publish from the terminal
Section titled “Publish from the terminal”The kit can also sign you in and publish without leaving your terminal. The Studio upload above still works and is unchanged; this is the same result in one command, for when you would rather stay on the command line or automate the loop.
Sign in once. This opens your browser to approve the device, then stores an offline token in
~/.port60. It finds your studio workspace automatically:
p60-template-kit loginThen, from your template project:
p60-template-kit publishpublish runs the same four stages as above in order: validate, package, upload to your studio and
submit the version for review. Add --no-submit to upload the version without submitting it, and
submit later from Studio. The manifest name must match a template you own (an unclaimed name
creates the template on first publish; a name owned by another studio is refused).
Two more sign-in commands:
p60-template-kit whoami: who is signed in, and which studio workspace.p60-template-kit logout: sign this machine out and revoke its token.
By default the kit talks to Port60’s hosted stack (auth.port60.com / api.port60.com). To point it
at a local or self-hosted environment, set P60_AUTH_BASE, P60_API_BASE, P60_REALM and
P60_CLIENT_ID before running login.
Publish from GitHub Actions
Section titled “Publish from GitHub Actions”Your repository can publish on its own, the way a release pipeline would: push a version tag, the workflow validates and uploads, and the template or its new version arrives in the review queue exactly as an upload from Studio does. Review still decides; nothing is approved automatically.
There is no token to create, store or rotate. GitHub signs every workflow run with a short-lived OIDC token, and the platform verifies that signature and checks it against a repository you trusted in Studio. Remove the trust and publishing stops from the very next run.
1. Trust the repository in Studio
Section titled “1. Trust the repository in Studio”In Studio choose Automate (next to the upload button), paste the repository as owner/name or its
GitHub URL, and add it. That is the whole registration, done once per repository for the whole studio,
the way a trust policy names a repository. From then on the workflow can do what you can from a
terminal: create a template from its manifest or add a version to one you own.
Behind the one field, the platform checks GitHub’s permanent numeric id for the repository on every run, never the name, so a renamed or re-created repository never inherits the trust. For a public repository the id is looked up when you add it; for a private one it is learned from the first workflow run and shown in Studio as verified from then on. Any branch or tag may publish; choose what triggers the workflow in the workflow file itself.
2. Add the workflow
Section titled “2. Add the workflow”Save this as .github/workflows/publish.yml. The id-token permission is what lets GitHub sign the
run for you; no secret is needed.
name: Publish templateon: push: tags: ['v*']permissions: id-token: write contents: readjobs: publish: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 with: { node-version: 22 } - run: npx @port60/template-kit publish --ci3. Release by tag
Section titled “3. Release by tag”Bump version in manifest.json, describe the change in changelog, then tag and push:
git tag v1.2.0git push --tagsThe run validates the template locally, packages it, and posts it with the run’s own token. The job
log shows the validation report and whether the version was submitted for review. Add --no-submit
to upload without submitting.
What CI can and cannot do: it can create a template from the manifest name (the first publish
claims it, label and description included) and add versions to any template the studio owns. It cannot
publish from an untrusted repository, take a name another studio owns, or run more than a modest number
of times a day per repository. Every refusal is explained in the job log and shown under Automate in
Studio.
Immutable versions
Section titled “Immutable versions”A reviewed version cannot be overwritten. For every change:
- Increase
versioninmanifest.jsonusing semantic versioning. - Describe the release in
changelog. - Validate and package again.
- Upload the new zip as a new version.
Sites pinned to an older version continue to render that version until an update is deliberately applied. This protects live sites from unexpected design changes.
Use a development version with real content
Section titled “Use a development version with real content”The local and Studio previews use safe contract fixtures and non-interactive island skeletons. To
check your own site with real navigation, content lengths, imagery, worship data and enabled
features, upload a version such as 1.2.0-dev.1. Once it validates, choose Use on this site in
Studio.
A development version is deliberately restricted:
- only the template owner’s own tenant can activate it;
- its artifact is read from quarantine through an internal tenant-bound route;
- it cannot be submitted for review, promoted or listed in the catalogue;
- the site pin is explicit and responses are served with no-store caching.
Increase the final number for each development build. When the design is ready, upload a stable
version such as 1.2.0 and submit that version for review.

