Existing Astro sites
An Astro site that keeps its own pages, layout and components can take the kit's core alone. The core changes none of the site's pages. It adds:
- a check that the site builds to static files, which is what Hostsmith serves;
- a description of the site's content,
.hostsmith/schema.json, for CMS editors and checks; - a Decap CMS config generated from it, which Decap CMS and Sveltia CMS can edit the site with;
- page copy: the text a page writes in its markup, moved into files a CMS can edit;
check-fields, which reports how much of each page's text a CMS can edit, andcheck-urlsfor the old site's URLs.
It adds no routes, layout, components, styles or middleware, and sets none of the site's build options. The site keeps its own head, SEO tags and sitemap.
Add the core
- Install the package:
npm install --save-exact @hostsmith/site-kit-astro - Add the core to
astro.config.mjs:import siteKitCore from "@hostsmith/site-kit-astro/core"; import { defineConfig } from "astro/config"; export default defineConfig({ integrations: [siteKitCore()], }); - Add
hostsmith.jsonat the site's root, with the GitHub repository a CMS saves to incms.repo:{ "kit": { "framework": "astro" }, "site": { "id": "" }, "build": { "command": "npm run build", "output": "dist", "node": "24" }, "content": { "schema": { "source": "zod", "path": ".hostsmith/schema.json" }, "root": "src/content" }, "media": { "dir": "public/assets", "publicPath": "/assets" }, "cms": { "repo": "OWNER/REPOSITORY" } } - Write the description of the site's content and its CMS config, then build:
npx site-kit schema npx site-kit decap-config npm run build
Commit.hostsmith/schema.jsonandpublic/admin/config.yml. Run both commands again after a change to a collection's schema: the build fails while either file is out of date.
The site must build to static files. A build with output: "server", or with a page or endpoint that sets export const prerender = false, fails and names it.
Page copy
Text that a page writes in its markup, such as its hero's title, moves into a copy collection, so a CMS can edit it: one YAML file per page in src/content/copy/, each with its own schema.
// src/content.config.ts
import { pageCopy } from "@hostsmith/site-kit-astro/copy";
import { z } from "astro/zod";
export const copy = pageCopy({
home: z.strictObject({ hero: z.strictObject({ title: z.string().min(1) }) }),
});
export const collections = { copy: copy.collection };
# src/content/copy/home.yml
hero:
title: Fresh bread every morning
---
// src/pages/index.astro
import { copy } from "../content.config.ts";
const home = await copy.get("home");
const f = copy.fields("home");
---
<h1 {...f("hero.title")}>{home.hero.title}</h1>
copy.fields gives each element its field attribute, data-field, which tells a CMS and the checks which field the element shows. Bind the element that shows the value, not a container around it. The site's other collections bind their elements with fieldsFor("news", entry.id) from @hostsmith/site-kit-astro/field.
How much a CMS can edit
After a build:
npx site-kit check-fields
It reports, page by page, how much of the visible text is inside an element with a field attribute. Add --min 90 to fail below 90%, such as in CI. Mark text a CMS doesn't edit, such as a legal line in the footer, with data-field-ignore.
Locales
A core site in several languages lists them in hostsmith.json, and keeps its own routing, language switcher and hreflang links:
"content": { "locales": { "default": "en", "codes": ["en", "de"] } }
Each collection keeps its files in a layout a CMS can write: a folder per locale, such as news/en/a.md and news/de/a.md, or the code before the extension, such as news/a.en.md. The default locale needs its own folder or code too. With locales, each copy file holds every locale's copy under its code. When the site also sets Astro's i18n, both must name the same locales.
The README has the layouts and the options in full.
The CMS config
The generated config, public/admin/config.yml, saves to the repository in cms.repo, on its main branch. Every field gets the widget of its type, and a field can set its own, its label and its hint with Zod's .meta(). A field with no widget, such as a union of types, fails decap-config, naming it. The README lists every widget.
The build output never holds admin/, so the config stays in the repository and isn't deployed with the site.
Commands
| Command | In a core site |
|---|---|
npx site-kit schema | writes .hostsmith/schema.json; --check only checks it |
npx site-kit decap-config | generates public/admin/config.yml from it; --check only checks it |
npx site-kit check-fields | reports the text coverage after a build; --min <percent> makes it a gate |
npx site-kit check-urls | checks the old site's URLs, as in Keep old URLs |
npx site-kit section-id, npx site-kit check-styles | fail: they are for kit sites |
Deploy it
A core site deploys with the kit's workflow: copy .github/workflows/hostsmith.yml from the basics example, at the release the site uses, and remove its two style-check steps, "Check styles" and "Check built styles", which are for kit sites. Then set it up as Deploy with Hostsmith says.
The README has the core in full.
