Ship it
Pack a checked template into its submission zip — what pack puts in it, what makes it refuse, and what HomePages does with it next.
You have a section that renders and a check that passes. One command turns that into the only artifact HomePages accepts: a zip holding the template’s source, the lockfile that reproduces its build, and a record that the gate was green when it was built. Run it, read what came out, and the track is done.
Pack it
Section titled “Pack it”Run the gate first:
npm run check> check> template-kit check
✓ startercheck passedThen pack:
npm run pack -- starter> pack> template-kit pack starter
template-kit pack wrote starter.zip sha256:8dafb3f2f77a1f0b19ebcaa4e4295479757988ff82e2f82b2750d617154d1063 kit 2.0.0-dev-20260728131506Both of those lines will read differently for you: the hash is of your source, and the version is whichever kit your workspace installed.
The -- belongs to npm, not to the command — it passes what follows through to
template-kit pack instead of consuming it. Naming the template is optional; omit it
and pack infers one from the directory you are standing in. Name it anyway. The
submission unit is a single template, and in a workspace holding several, which zip
you get should not depend on where you happened to be.
The gate runs whether or not you ask for it. pack re-runs the same check before
it writes anything, so running it yourself first is a faster feedback loop rather than
a separate requirement — a red check reports every problem in one pass, and a red pack
reports the same list with a longer wait in front of it. Expect that wait: on a
workspace this small, each of these two commands takes a minute or two.
What’s in the zip
Section titled “What’s in the zip”unzip -l starter.zipArchive: starter.zip Length Date Time Name--------- ---------- ----- ---- 239 1980-01-01 00:00 pack-manifest.json 895 1980-01-01 00:00 package.json 168330 1980-01-01 00:00 package-lock.json 945 1980-01-01 00:00 templates/starter/sections/main/Renderer.tsx 1171 1980-01-01 00:00 templates/starter/sections/main/fixtures.ts 1706 1980-01-01 00:00 templates/starter/sections/main/section.ts 921 1980-01-01 00:00 templates/starter/template.ts 679 1980-01-01 00:00 templates/starter/theme.css 669 1980-01-01 00:00 templates/starter/theme.ts--------- ------- 175555 9 filesNine files, and three things.
The manifest — pack-manifest.json, written by the pack itself:
{ "kitVersion": "2.0.0-dev-20260728131506", "template": "starter", "contentHash": "sha256:8dafb3f2f77a1f0b19ebcaa4e4295479757988ff82e2f82b2750d617154d1063", "packedAt": "2026-07-28T13:47:28.486Z", "check": { "ok": true }}Those two values will read differently for you as well, for the same reasons as
above — and the version especially: a …-dev-… suffix marks a development build of the
kit, so on a released one you will see that release’s own version in its place.
Five fields, each a claim about this submission and nothing else: which template it is, the kit version its source was validated against, a content hash of the template tree — the same one the command printed — the moment it was packed, and a flag recording that the check passed. That last field is why packing and checking are not two independent acts: the verdict travels inside the artifact. The kit version travels with it for a different reason, and it is the one worth remembering — a submission is judged against the version it names, not against whatever is current. See Versioning.
The two root manifests — package.json and package-lock.json, copied from the
workspace root so the build reproduces with npm ci. The lockfile is what pins the
versions your template is built against, which is the argument for committing it. It
is also most of the payload: 168 KB of the 175 KB the archive holds.
One template’s source — templates/starter/, and no other template. Its sections
(all three files of each, fixtures.ts included), template.ts, theme.ts and the
theme.css generated from it. Nothing else from the workspace root travels: not
README.md, not tsconfig.json, not the lint config, and certainly not
node_modules. Those are yours; the reserved files are the contract.
Every entry is dated 1980-01-01 00:00. That is deliberate — a zip entry carries a
modification time, and real ones would make the same source pack to a different byte
stream on every run. Fixing the date is what lets identical source produce an
identical archive, which is what makes a content hash worth recording.
One rough edge to know about: the scaffolded .gitignore does not mention the zip.
Commit with a wide net after packing and you will commit the archive too.
When pack refuses
Section titled “When pack refuses”It writes no zip at all when:
- the check is not green — fix the problems it reports and pack again.
- the workspace has no lockfile — run
npm installso one exists, and commit it. - a dependency points at a local path (
file:orlink:) — nothing outside the zip reaches our build, so depend on a published version instead.
Each refusal names its cause. Prepare a submission
has the full mechanics, and pack its arguments and exit
codes.
What happens next
Section titled “What happens next”You send the zip to HomePages. We ingest it into our own registry, review it, and publish it; from then on the platform can build deliverables from your template, fill it from a property’s facts, and hand the result to an agent to edit — the pipeline the first page of this track described, now running on your section.
You never see our repositories, and nothing in your workspace depends on them. The zip is the entire interface between what you author and what we run, which is why it holds so little: one template’s source, the lockfile that rebuilds it, and a manifest saying what it was validated against.
Verify
Section titled “Verify”starter.zipsits at the workspace root, named in the pack output.unzip -l starter.ziplists three things and only three:pack-manifest.json, the rootpackage.jsonandpackage-lock.json, andtemplates/starter/— one template’s source, with nothing else from the workspace beside it.unzip -p starter.zip pack-manifest.jsonprints the samesha256:hash the pack output showed, and records the check as having passed.
That is the track. You can scaffold a workspace, render a section, read the three files it is made of, add slots the platform fills two different ways, and pack the result for submission. Everything after this is more of the same loop with a wider vocabulary:
- Guides — the task router. An image slot the editor can crop, a repeating list, an interactive island, a second template: find the task, copy the shape.
- The pipeline — the platform’s stages at concept depth, and the doorway to the rest of the concepts tier.