Reference
Site Architecture Reference
The engine handles file routing, render-time context, storage adapters, and frontmatter typing. You write the templates and content; the engine wires up the rest.
File-based website using LiquidJS templating and Tailwind CSS (compiled by the engine on your machine and served at /tailwind.css). Think Jekyll + WordPress template hierarchy + Next.js dynamic routes, rendered at the edge.
Workspace layout
| Path | Purpose | Editable |
|---|---|---|
pages/ |
Routable pages. .html or .md files map to URLs. Subdirectories become path segments. [param] segments capture dynamic params. |
yes |
pages/index.html |
Homepage. | yes |
pages/{dir}/index.html |
Collection archive page (e.g. pages/blog/index.html). |
yes |
pages/{dir}/{slug}.md |
Collection entry (e.g. a blog post). | yes |
templates/ |
Layouts. templates/layout.html is the base. templates/{dir}/single.html and templates/{dir}/archive.html are collection-specific. |
yes |
templates/components/ |
Partials (Liquid {% render %} targets). |
yes |
data/ |
Site-wide data files (.json for structured records, .yaml for config, .csv for tabular). Exposed as {{ data.* }} in templates. |
yes |
data/site.yaml |
Site config (see SiteConfig). |
yes |
data/forms/{id}.json |
Form definitions (see FormConfig). |
yes |
theme.css |
Tailwind @theme CSS variables and site-wide styling. Optional. |
yes |
assets/ |
Static assets copied as-is on export. | yes |
assets/images/ |
Site images, including uploaded images. | yes |
assets/files/ |
Public downloadable files linked from the site. | yes |
assets/js/ |
Custom JavaScript files. | yes |
.attachments/ |
Private chat attachments and reference docs. Never published. | yes |
_indexes/ |
Derived. Collection index JSON files built by the engine. Do not edit by hand. | no (derived) |
The current working directory is the site root. Tool paths should be root-relative like data/site.yaml, templates/layout.html, and pages/about.html.
Do not prepend site/ or /workspace/site/ to paths.
<workspace-root>/
├── data/
│ ├── site.yaml # Site config (name, description, type, etc.)
│ ├── redirects.json # URL redirects [{from, to, status}]
│ ├── forms/{id}.json # Form configs (fields, validation, honeypot)
│ └── *.json # Custom data → accessible as {{ data.* }} in templates
├── templates/
│ ├── layout.html # Base layout — used as fallback for everything
│ ├── single.html # (optional) layout for all .md posts
│ ├── archive.html # (optional) layout for all index/listing pages
│ ├── page.html # (optional) layout for plain .html pages
│ ├── blog/
│ │ └── single.html # (optional) layout for /blog/*.md only
│ └── components/*.html # Reusable partials ({% render 'name' %} or {% include 'name' %})
├── pages/
│ ├── index.html # Homepage (URL: /)
│ ├── about.html # About page (URL: /about)
│ ├── blog/
│ │ ├── index.html # Blog listing — {{ posts }} and {{ blog }} available
│ │ └── my-post.md # Blog post — automatically uses single.html if it exists
│ ├── products/
│ │ ├── index.html # Products listing — {{ products }} available
│ │ └── [slug].md # Dynamic product page — {{ params.slug }} available
│ └── 404.html # Custom 404 page
├── theme.css # Tailwind v4 @theme tokens; avoid `@apply` component classes
├── assets/
│ ├── images/ # Public images
│ ├── files/ # Public downloadable files (PDFs, docs)
│ └── js/ # JavaScript
├── .attachments/ # Private chat attachments/reference docs (not published)
└── favicon.ico
Prefer utility classes directly in pages/templates for styling and layout. Use theme.css for Tailwind v4 @theme tokens and at most tiny global CSS rules; avoid semantic component classes and avoid @apply there. Use assets/images/ for images, assets/files/ for public downloads, and assets/js/ for custom scripts. .attachments/ is private reference material and never published.
Page System
Pages use frontmatter at the top. The layout field is optional — the system picks the right layout automatically:
---
title: Page Title
description: A short description for SEO
image: https://example.com/og-image.jpg
---
<h1>Page content here</h1>
- File-based routing:
pages/about.html→/about,pages/services/web-design.html→/services/web-design - The rendered page body is injected into the layout as
{{ content }}— every layout must include this placeholder - Use
layout: nameonly when you need to force a specific layout — otherwise omit it - Use
scripts:to inject third-party scripts before</body>on a specific page only:- Single:
scripts: https://js.stripe.com/v3/ - Multiple:
scripts: ["https://js.stripe.com/v3/", "/assets/js/checkout.js"]
- Single:
Frontmatter values use JSON types with a plain-string fallback. Valid JSON values are parsed automatically; anything else stays a string:
featured: true→ boolean — use{% if page.featured %}directlyperPage: 6→ number — handled automatically by the enginetags: ["ai", "web"]→ array — use{% for tag in page.tags %}tags: ai, web→ string (not valid JSON) — use{{ page.tags | split: ", " }}to get an arraytitle: My Page→ string (stays as-is since it's not valid JSON)
No YAML footguns: NO, yes, on, off are all plain strings, not booleans.
Canonical fields
| Field | Type | Required | Notes |
|---|---|---|---|
title |
string |
no | Page title. Used in |
description |
string |
no | Page meta description. Used in , OG:description, search snippets. |
layout |
string |
no | Layout template under templates/ (without extension). Defaults to layout.html; collection pages fall back to {dir}/single.html or {dir}/archive.html. |
image |
string |
no | Hero/social image URL. Used in OG:image, Twitter card, JSON-LD. |
date |
string |
no | ISO date the content was originally authored. Drives collection sort order and RSS. |
publishDate |
string |
no | ISO date the content should go live. Pages with a future publishDate are scheduled and hidden from listings until their date passes. |
perPage |
number |
no | Items per page for paginated collection archives. |
scripts |
string | string[] |
no | Named scripts to inject into the page (e.g. "alpine", "stripe"). Engine emits the corresponding |