AI briefing - content authoring
Guide for AI assistants helping users write content on a lazysite site.
Who this is for
This document briefs an AI assistant helping a user author content on a lazysite site. It covers the page format, front matter, Markdown extensions, and URL conventions. For view/theme authoring, see AI briefing - views. For configuration, see AI briefing - configuration.
Page format
Every page is a plain text file ending in .md. Pages begin with a
YAML front matter block delimited by ---, followed by the page body
in Markdown:
---
title: Page Title
subtitle: Optional subtitle shown below title
register:
- llms.txt
- sitemap.xml
---
Page content in Markdown.
The content body is converted to HTML and inserted into the site's
view template at [% content %]. The view wraps it with navigation,
header, and footer.
Front matter keys
title-
Page title. Required for most pages. Used in the
<title>tag and the page<h1>. subtitle- Short description shown below the title. Optional.
ttl-
Cache TTL in seconds. The page regenerates after this interval rather
than on
.mdfile edit. Example:ttl: 300. register-
List of registry files the page appears in. Values match template
filenames in
lazysite/templates/registries/without the.ttextension. Common values:llms.txt,sitemap.xml,feed.rss,feed.atom. date-
Publication date in
YYYY-MM-DDformat. Used in feed entries. Falls back to file mtime if not set. tt_page_var-
Page-scoped Template Toolkit variables. Supports
url:,scan:, and${ENV}prefixes. Page variables override site variables.
tt_page_var:
hero_image: /img/landing.jpg
latest_release: url:https://raw.githubusercontent.com/example/repo/main/VERSION
blog_posts: scan:/blog/*.md sort=date desc
raw-
raw: trueoutputs the converted body without the view wrapper. Useful for fragments, AJAX partials, or API-style endpoints. api-
api: trueserves the page as a JSON API endpoint. Default content type isapplication/json; charset=utf-8. Combine withtt_page_varandquery_paramsfor dynamic JSON. content_type-
Overrides the HTTP Content-type header. Example:
content_type: text/html; charset=utf-8. layout-
Per-page view override. Names a theme under
lazysite/themes/. auth-
Authentication requirement.
required,optional, ornone(default). auth_groups- List of group names. User must be in one of them.
payment- Payment requirement for the x402 payment flow. See Payment.
query_params-
List of accepted URL query parameter names. Matched parameters are
available as
[% query.NAME %]and bypass the cache. tags- Tags for page scan results. YAML list, comma-separated, or single value.
search-
trueorfalse. Controls whether the page appears in search. Defaults to the site'ssearch_defaultsetting. form-
Enables form processing for the page and names the form. Requires a
matching
lazysite/forms/NAME.conf.
Markdown elements
Headings
# H1 is reserved - the page title is rendered by the view template.
Start content headings at ##.
Text, links, lists
Standard Markdown. Internal links should be extensionless:
Docs not Docs.
Tables
Standard GFM pipe tables are supported.
Code blocks
Fenced code blocks with language identifiers produce highlighted output:
```bash
curl https://example.com/
```
Inline code and fenced code blocks are protected from Template Toolkit
processing - [% tags %] inside code appear literally.
Fenced divs
Wrap content in a named CSS class:
::: classname
Content here. Standard Markdown works inside.
:::
Produces <div class="classname">...</div>. Class names must contain
only word characters and hyphens.
Common classes in the default theme:
widebox- full-width coloured bandtextbox- 60% width highlighted boxmarginbox- pull quote in the marginexamplebox- evidence or example highlight
oEmbed
::: oembed
https://www.youtube.com/watch?v=abc123
:::
Works with YouTube, Vimeo, SoundCloud, and any oEmbed provider.
Content includes
Inline local or remote content at render time:
::: include
partials/note.md
:::
.md files have their front matter stripped. Code files are wrapped in
syntax-highlighted code blocks. .html files are inserted bare.
Includes are single-pass - includes inside included files are not processed.
Template Toolkit in page content
TT variables are expanded in the page content before Markdown
conversion. Site variables come from lazysite.conf, page variables
from tt_page_var. Automatic variables (page_title, page_subtitle,
content) are set by the processor.
Current version: [% latest_release %]
[% IF beta %]
<div class="textbox">
This feature is in beta.
</div>
[% END %]
Inline code and fenced code blocks are protected from TT. Put TT tags outside code blocks if you want them to render.
Markdown link URLs do not reliably resolve TT variables (the Markdown
parser processes links before TT runs). Use HTML <a> tags when the
href contains a TT variable:
<a href="[% download_base %]/release-[% version %].tar.gz">Download</a>
URL structure
Page URLs derive from file paths, always without extension:
DOCROOT/index.md -> /
DOCROOT/about.md -> /about
DOCROOT/docs/install.md -> /docs/install
DOCROOT/docs/index.md -> /docs/
Always use extensionless URLs for internal links.
Remote pages
A .url file contains a single URL. The processor fetches the Markdown
from that URL, processes it through the full pipeline, and caches the
result.
# File: docs/install.url
https://raw.githubusercontent.com/example/repo/main/docs/INSTALL.md
The remote file should include YAML front matter. Cache TTL defaults to one hour.
Page scan
scan:/path/*.md returns an array of page metadata. Use in
lazysite.conf or tt_page_var:
tt_page_var:
blog_posts: scan:/blog/*.md sort=date desc
[% FOREACH post IN blog_posts %]
## [% post.title %]
[% post.subtitle %] - [% post.date %]
[% post.url %]
[% END %]
Each item has url, title, subtitle, date, and path.
Search
Pages are searchable by default. Set search: false in front matter to
exclude a page from search. The site default is controlled by
search_default in lazysite.conf.
Registries
Pages declare which registry files they appear in via register:.
Common registries: sitemap.xml, llms.txt, feed.rss, feed.atom.
Each name maps to a Template Toolkit template in
lazysite/templates/registries/. Registries regenerate after their
TTL expires (default 4 hours).
Tasks
Creating a new page
- Ask the user for: title, URL path, brief description.
- Create a file at
DOCROOT/PATH.md(e.g./docs/installbecomesDOCROOT/docs/install.md). - Write front matter with
title:and optionallysubtitle:. - Register in relevant feeds:
sitemap.xml,llms.txt, andfeed.rssorfeed.atomif it is a dated article. - Write the body in Markdown, starting headings at
##.
Creating a blog/news index with scan
- Confirm blog posts live in a single directory, e.g.
/blog/. - Create
DOCROOT/blog/index.mdwithtt_page_var:
---
title: Blog
tt_page_var:
posts: scan:/blog/*.md sort=date desc
---
[% FOREACH p IN posts %]
## [[% p.title %]]([% p.url %])
[% p.subtitle %] - [% p.date %]
[% END %]
Creating a members-only page
- Confirm the required group name in
lazysite/auth/groups. - Write the page normally, then set:
---
title: Members area
auth: required
auth_groups:
- members
---
Protected pages are never cached.