How lazysite wraps page content in HTML layouts.
A person running or building the site: what a layout and a theme are, where they
live, how the engine picks them, and how to install and switch them by hand or in
the manager. An AI agent changing a layout or theme reads
AI briefing - layouts and themes as well, which has
the template contract, the theme.json schema and how an agent stages and
activates a change.
Every page on a lazysite site is rendered through a layout.
The processor converts the page's Markdown to HTML, then passes
it to the layout as the [% content %] variable. The layout
provides the surrounding HTML structure: <head>, navigation,
header, footer, main container, script tags, footer. A theme
sits on top of a layout and supplies colours, fonts, spacing,
and assets.
layout.tt Template Toolkit file plus optional
layout.json. Defines the full HTML chrome around every page.
Installed at lazysite/layouts/NAME/.
lazysite/layouts/LAYOUT/themes/THEME/,
and declares the layouts it fits in theme.json's layouts[]
array. Web-accessible assets mirror to
/lazysite-assets/LAYOUT/THEME/.
On disk:
lazysite/
layouts/
default/
layout.tt
layout.json
themes/
mytheme/
theme.json
main.css
assets/
manager/
layout.tt
assets/manager.css
lazysite-assets/
default/
mytheme/
main.css
assets/
The manager has its own internal template at
lazysite/manager/layout.tt, outside the layout and theme system.
lazysite includes a minimal layout embedded in the processor. It activates when no layout is configured or the named layout isn't installed. The fallback is functional but plain - content, navigation, search, auth state, and an edit button when permitted.
The fallback footer notes it's active:
no layout.tt found, using built-in fallback.
If the fallback appears unexpectedly, check:
layout: is set in lazysite.conflazysite/layouts/NAME/layout.tt exists and parseslayout: in the page's front matter (per-page override)layout: in lazysite.conf (site-wide default)For a named layout, the processor checks
lazysite/layouts/NAME/layout.tt. Both layout: and theme:
are sanitised to [A-Za-z0-9_-] at resolve time.
A remote URL in layout: is fetched and cached; see
remote layouts.
theme: in lazysite.conftheme.json at
lazysite/layouts/LAYOUT/themes/THEME/theme.json is parsedtheme.json.layouts[] must contain the active layout; if
it doesn't, the theme is ignored (no styling) and the page
renders layout-onlyWhen theme.json.layouts does not contain the active layout:
theme not declared for layouttheme_css is emptytheme_assets is unsettheme is an empty hashlazysite.confsite_name: My Site
layout: default
theme: mytheme
---
title: Landing Page
layout: campaign
---
On /manager/appearance, click "Browse releases" to list published
releases of the configured layouts_repo. Each release zipball
may carry multiple themes; each installs once per layout it
declares compatibility with.
Create the nested directory and drop files:
mkdir -p public_html/lazysite/layouts/default/themes/mytheme
cp -r mytheme/. public_html/lazysite/layouts/default/themes/mytheme/
mkdir -p public_html/lazysite-assets/default/mytheme
cp -r mytheme/assets/. public_html/lazysite-assets/default/mytheme/
Then set theme: mytheme in lazysite.conf.
A theme zip (uploaded via Manager > Themes > Upload theme) must contain at minimum:
theme.json
And typically:
main.css
assets/
logo.svg
fonts/...
theme.json declares metadata, compatibility, and design
tokens - see theme.json.
If a theme with the same name already exists under the target
layout, the install directory is prefixed with today's date
(e.g. 20260422-mytheme). Rename via Manager > Themes.
Set theme: in lazysite.conf and clear the page cache:
find public_html -name "*.html" -delete
Or use Manager > Cache > Clear all if the manager is enabled. The admin-bar theme switcher (visible to managers when more than one compatible theme is installed) does both atomically. An agent switches through the control API instead - see Activating layout + theme.
Writing a layout is writing a Template Toolkit file that
references the variables listed in
layouts.md. A working
starting point is the
minimum layout.tt
in the layouts briefing, and its
<head> contract
says which variables belong in <title> and the description.
Navigation uses the [% nav %] array populated from nav.conf.
See nav.conf.
When a theme's assets (CSS, images, fonts) need to be
web-accessible, they live under
lazysite-assets/LAYOUT/THEME/. The processor sets
[% theme_assets %] to /lazysite-assets/LAYOUT/THEME when a
compatible theme is active, and a layout links its stylesheet
from there. Remote layouts use a flat
/lazysite-assets/CACHE_KEY/ path - see
remote layouts.
How the mirror is built on activation, and what to do when it
answers 404, is in
Theme assets and the activation mirror.