Sitepins CMS Setup
Sitepins is a git-based headless CMS. It never hosts or renders the site — it reads existing content files (Markdown/MDX/JSON/YAML/TOML) straight from the git repository and overlays a visual editor. All CMS behavior for a project lives in one folder committed to the repo:
.sitepins/
config.json # required — folder mapping + commit + sidebar arrangement
schema/*.json # optional — content templates per content folder
snippet/*.json # optional — reusable shortcode/JSX/HTML blocks
Normally a user clicks through the Sitepins web UI to produce these files. This skill's job is to author them directly by inspecting the repo, so the project is CMS-ready without the UI.
Golden rules
- Everything is committed JSON inside
.sitepins/. Never invent a different location. Constants are fixed: schema folder = .sitepins/schema, snippet folder = .sitepins/snippet, config = .sitepins/config.json.
- Ready before you configure, per framework. Content must live in the content folder as frontmatter files — Sitepins cannot manage content hardcoded in components/config/
src/data. Astro/Next.js/TanStack Start/Hugo differ (paths, loaders, validation); defer to the repo's <framework>-template-guidance skill and audit/convert first (references/cms-readiness.md).
- Inspect before you author. Read the real repo — detect the framework, list content folders, open a representative content file per folder — and derive schemas from actual frontmatter. Do not hardcode fields from memory.
- Paths in
config.json are repo-root-relative, no leading slash.
- Use the real runtime field-type vocabulary (
string, number, boolean, Date, media, gallery, Array, object, plus auto-detected color) — not loose names like text/textarea/datetime/select. Long-form text (description, content) is string, not textarea. See references/schema-authoring.md.
- Schemas only for collections, not singletons. A schema templates new files, so it belongs on folders that grow (
blog/, authors/, pages/) — not on one-off pages (homepage/, about/, contact/), which editors open and edit in place. Ask: would anyone click "add new file" here?
- One schema JSON per collection, named by the resolution rule. Schema filename = the content folder path minus the
config.content root (src/content/blog → blog.json; exampleSite/content + …/english/blog → english/blog.json). A misnamed schema silently never loads. Subfolders inherit the parent. See references/schema-authoring.md.
Workflow
- Detect the framework —
astro.config.* → astro, next.config.* → nextjs, config.toml/hugo.* → hugo (exampleSite/ present → hugo_examplesite), a bundler config (vite.config.*/rsbuild.config.*/app.config.*) plus routing evidence (routeTree.gen.ts or routes/__root.tsx) → tanstack.
- Load the template's guidance skill — Astro, Next.js, TanStack Start, and Hugo store and load content differently, so the repo's own
.agents/skills/<framework>-template-guidance/ is the authoritative content model. If it isn't installed, install it first: npx skills add zeon-studio/template-skills --skill <framework>-template-guidance.
- Check CMS readiness — Sitepins can only manage content that lives in the content folder as frontmatter files. If the template hardcodes content in components/config/
src/data, it is not ready: convert it to a content-folder-driven structure before configuring anything. → references/cms-readiness.md
- Map folders →
config.json using framework conventions. → references/config-setup.md
- Author schemas — for collection folders only. Skip singletons like
homepage/, about/, contact/ (a lone -index.md/_index.md is the tell). For each remaining collection, open one existing file, read its frontmatter, and write the schema under the name given by the resolution rule (content folder path minus config.content). → references/schema-authoring.md
- Author snippets (optional) — for shortcodes/components used in content. →
references/snippet-authoring.md
- Author sidebar arrangement (optional) — virtual folders/files/headings inside
config.json. → references/sidebar-arrangement.md
- Verify before reporting:
- Every path in
config.json exists in the repo, is repo-root-relative, and has no leading slash.
- Every schema filename equals
<content folder> − <config.content> (compute it, don't assume) — this is the #1 silent failure.
- No schema was written for a singleton folder (one
-index.md/_index.md and nothing else).
- Every schema's
file points at a content file that actually exists; fileType/fmType match it.
- All JSON parses, and field
type values come from the allowed vocabulary.
- Report the files created and how each was derived.
Routing guide
Read the reference file that matches the task before writing any JSON:
- Is the template CMS-ready? Auditing/converting hardcoded content into the content folder →
references/cms-readiness.md
config.json, framework detection, content/media/public/configs paths, commit mode → references/config-setup.md
- Content schemas, all field types, nested/array/media/dropdown/reference fields, inheritance →
references/schema-authoring.md
- Reusable snippets (shortcodes/JSX/HTML), schema scoping →
references/snippet-authoring.md
- Sidebar arrangement (virtual folders, files, headings, glob include/exclude) →
references/sidebar-arrangement.md
Reference: a complete .sitepins/ for an Astro project
config.json
{
"content": "src/content",
"media": "public/images",
"public": "public",
"configs": ["src/config"],
"custom-commit": false,
"arrangement": []
}
schema/blog.json (derived from a real src/content/blog/*.md)
{
"file": "src/content/blog/example-post.md",
"name": "blog",
"fileType": "md",
"fmType": "yaml",
"template": [
{ "name": "title", "label": "Title", "type": "string", "value": "", "isRequired": true },
{ "name": "date", "label": "Date", "type": "Date", "value": "", "alwaysUseCurrentDate": false },
{ "name": "image", "label": "Image", "type": "media", "value": "" },
{ "name": "draft", "label": "Draft", "type": "boolean", "value": false },
{ "name": "categories", "label": "Categories", "type": "Array", "value": [] }
]
}
snippet/button.json
{ "label": "Button", "schema": [], "code": "<Button label=\"\" href=\"\" />\n" }
Always verify against the actual files in the target repo before committing.
1---2name: sitepins-cms-setup3description: Use this skill to configure a project (repository) for the Sitepins git-based headless CMS by generating the `.sitepins/` folder — `config.json`, content `schema/*.json`, reusable `snippet/*.json`, and sidebar `arrangement`. Use it whenever the user asks to "set up Sitepins", "add Sitepins to this repo", "create Sitepins schemas/snippets/config", "configure the CMS", "generate .sitepins", or wants any Sitepins settings/schema/snippet file authored for a static-site project (Astro, Next.js, TanStack Start, Hugo, Eleventy, Jekyll, etc.).4---56# Sitepins CMS Setup78Sitepins is a **git-based headless CMS**. It never hosts or renders the site — it reads existing content files (Markdown/MDX/JSON/YAML/TOML) straight from the git repository and overlays a visual editor. All CMS behavior for a project lives in **one folder committed to the repo**:910```11.sitepins/12 config.json # required — folder mapping + commit + sidebar arrangement13 schema/*.json # optional — content templates per content folder14 snippet/*.json # optional — reusable shortcode/JSX/HTML blocks15```1617Normally a user clicks through the Sitepins web UI to produce these files. **This skill's job is to author them directly** by inspecting the repo, so the project is CMS-ready without the UI.1819## Golden rules20211. **Everything is committed JSON inside `.sitepins/`.** Never invent a different location. Constants are fixed: schema folder = `.sitepins/schema`, snippet folder = `.sitepins/snippet`, config = `.sitepins/config.json`.222. **Ready before you configure, per framework.** Content must live in the content folder as frontmatter files — Sitepins cannot manage content hardcoded in components/config/`src/data`. Astro/Next.js/TanStack Start/Hugo differ (paths, loaders, validation); defer to the repo's `<framework>-template-guidance` skill and audit/convert first (`references/cms-readiness.md`).233. **Inspect before you author.** Read the real repo — detect the framework, list content folders, open a representative content file per folder — and derive schemas from actual frontmatter. Do not hardcode fields from memory.244. **Paths in `config.json` are repo-root-relative, no leading slash.**255. **Use the real runtime field-type vocabulary** (`string`, `number`, `boolean`, `Date`, `media`, `gallery`, `Array`, `object`, plus auto-detected `color`) — not loose names like `text`/`textarea`/`datetime`/`select`. Long-form text (`description`, `content`) is **`string`**, not `textarea`. See `references/schema-authoring.md`.266. **Schemas only for collections, not singletons.** A schema templates *new* files, so it belongs on folders that grow (`blog/`, `authors/`, `pages/`) — not on one-off pages (`homepage/`, `about/`, `contact/`), which editors open and edit in place. Ask: would anyone click "add new file" here?277. **One schema JSON per collection, named by the resolution rule.** Schema filename = the content folder path **minus the `config.content` root** (`src/content/blog` → `blog.json`; `exampleSite/content` + `…/english/blog` → `english/blog.json`). A misnamed schema silently never loads. Subfolders inherit the parent. See `references/schema-authoring.md`.2829## Workflow30311. **Detect the framework** — `astro.config.*` → astro, `next.config.*` → nextjs, `config.toml`/`hugo.*` → hugo (`exampleSite/` present → `hugo_examplesite`), a bundler config (`vite.config.*`/`rsbuild.config.*`/`app.config.*`) **plus** routing evidence (`routeTree.gen.ts` or `routes/__root.tsx`) → tanstack.322. **Load the template's guidance skill** — Astro, Next.js, TanStack Start, and Hugo store and load content differently, so the repo's own `.agents/skills/<framework>-template-guidance/` is the authoritative content model. **If it isn't installed, install it first:** `npx skills add zeon-studio/template-skills --skill <framework>-template-guidance`.333. **Check CMS readiness** — Sitepins can only manage content that lives in the content folder as frontmatter files. If the template hardcodes content in components/config/`src/data`, it is **not ready**: convert it to a content-folder-driven structure before configuring anything. → `references/cms-readiness.md`344. **Map folders → `config.json`** using framework conventions. → `references/config-setup.md`355. **Author schemas — for collection folders only.** Skip singletons like `homepage/`, `about/`, `contact/` (a lone `-index.md`/`_index.md` is the tell). For each remaining collection, open one existing file, read its frontmatter, and write the schema under the name given by the resolution rule (content folder path minus `config.content`). → `references/schema-authoring.md`366. **Author snippets** (optional) — for shortcodes/components used in content. → `references/snippet-authoring.md`377. **Author sidebar arrangement** (optional) — virtual folders/files/headings inside `config.json`. → `references/sidebar-arrangement.md`388. **Verify before reporting:**39 - Every path in `config.json` exists in the repo, is repo-root-relative, and has no leading slash.40 - Every schema filename equals `<content folder> − <config.content>` (compute it, don't assume) — this is the #1 silent failure.41 - No schema was written for a singleton folder (one `-index.md`/`_index.md` and nothing else).42 - Every schema's `file` points at a content file that actually exists; `fileType`/`fmType` match it.43 - All JSON parses, and field `type` values come from the allowed vocabulary.449. **Report** the files created and how each was derived.4546## Routing guide4748Read the reference file that matches the task before writing any JSON:4950- **Is the template CMS-ready? Auditing/converting hardcoded content into the content folder** → `references/cms-readiness.md`51- **`config.json`, framework detection, content/media/public/configs paths, commit mode** → `references/config-setup.md`52- **Content schemas, all field types, nested/array/media/dropdown/reference fields, inheritance** → `references/schema-authoring.md`53- **Reusable snippets (shortcodes/JSX/HTML), schema scoping** → `references/snippet-authoring.md`54- **Sidebar arrangement (virtual folders, files, headings, glob include/exclude)** → `references/sidebar-arrangement.md`5556## Reference: a complete `.sitepins/` for an Astro project5758`config.json`59```json60{61 "content": "src/content",62 "media": "public/images",63 "public": "public",64 "configs": ["src/config"],65 "custom-commit": false,66 "arrangement": []67}68```6970`schema/blog.json` (derived from a real `src/content/blog/*.md`)71```json72{73 "file": "src/content/blog/example-post.md",74 "name": "blog",75 "fileType": "md",76 "fmType": "yaml",77 "template": [78 { "name": "title", "label": "Title", "type": "string", "value": "", "isRequired": true },79 { "name": "date", "label": "Date", "type": "Date", "value": "", "alwaysUseCurrentDate": false },80 { "name": "image", "label": "Image", "type": "media", "value": "" },81 { "name": "draft", "label": "Draft", "type": "boolean", "value": false },82 { "name": "categories", "label": "Categories", "type": "Array", "value": [] }83 ]84}85```8687`snippet/button.json`88```json89{ "label": "Button", "schema": [], "code": "<Button label=\"\" href=\"\" />\n" }90```9192Always verify against the actual files in the target repo before committing.