From da60d9f51e8544269e7d3f0ac8fa3caf6f999cb8 Mon Sep 17 00:00:00 2001 From: Rajat Saxena Date: Sun, 15 Nov 2026 13:53:22 +0530 Subject: [PATCH 1/3] fix(frontlit-pages): sync page and site schemas with FrontLit The bundled schemas missed the pricing monthly/yearly switch, the header GitHub link and star count, and site.json agentInstructions (published as /llms.txt), so the checker rejected them and the references told agents they didn't exist. --- .../frontlit-pages/references/blocks.md | 5 ++-- .../frontlit-pages/references/format.md | 1 + .../scripts/schema/page.v1.json | 30 ++++++++++++++++++- .../scripts/schema/site.v1.json | 13 ++++++++ 4 files changed, 46 insertions(+), 3 deletions(-) diff --git a/plugins/frontlit/skills/frontlit-pages/references/blocks.md b/plugins/frontlit/skills/frontlit-pages/references/blocks.md index 685e6c6..6ce3b06 100644 --- a/plugins/frontlit/skills/frontlit-pages/references/blocks.md +++ b/plugins/frontlit/skills/frontlit-pages/references/blocks.md @@ -70,7 +70,8 @@ A scrolling row of text/icon chips: integrations, customer names, tech stack. It Plan cards. `layout`: `grid` (default), `stacked`, `highlight`. `title`, `description`, `headerAlignment`, `tiers: [{ "name", "price", "description", "features": [""], "buttonCaption", "buttonAction", "highlighted" }]`. -- `price` is a display string: `"$29/mo"`, `"Free"`, `"Custom"`. There is no monthly/yearly switch; state the billing period in `price` or `description` ("$290/yr, 2 months free"). +- `price` is a display string: `"$29/mo"`, `"Free"`, `"Custom"`. No currency or period logic. +- **Monthly/yearly switch:** set `"pricingSwitcher": true` to show a toggle above the plans. `price` is then the monthly price and each tier's `priceYearly` (and optional `buttonActionYearly`) is shown on Yearly; both fall back to the monthly values. Label the toggle with `monthlyPriceCaption` / `yearlyPriceCaption` ("Yearly, 2 months free") and pick the starting side with `defaultPeriod` (`"monthly"` or `"yearly"`, default yearly). Without the switch, state the period in `price` or `description`. - Highlight at most one tier (the one you want most people on). 2–4 tiers. - Features: concrete limits ("10,000 contacts") over adjectives ("Generous limits"). Put the differentiators first; "Everything in Pro, plus:" is fine as the first line. @@ -115,5 +116,5 @@ Good for animated diagrams, data tables, tabbed code samples and logo strips wit Not page blocks: they live in `site.json` (`references/format.md`) and show on every page. -- **header**: `layout` (`fixed`, `floating`, `centered`), `links: [{ "label", "href", "isButton" }]` (4–6 links), `ctaLabel` + `ctaHref` (the primary action, same as the homepage hero's), `linkAlignment`, `backdropBlur`, `logoCorners`. The logo and site name come from FrontLit's **Branding** settings, not from the file; use `get_team_settings` / `update_team_settings` (see `mcp.md`). +- **header**: `layout` (`fixed`, `floating`, `centered`), `links: [{ "label", "href", "isButton" }]` (4–6 links), `ctaLabel` + `ctaHref` (the primary action, same as the homepage hero's), `linkAlignment`, `backdropBlur`, `logoCorners`, and `githubRepo` (`"owner/repo"` or a github.com URL; adds a GitHub icon link) with `showGithubStars: true` to show the live star count beside it. Prefer that over a plain "GitHub" text link. The logo and site name come from FrontLit's **Branding** settings, not from the file; use `get_team_settings` / `update_team_settings` (see `mcp.md`). - **footer**: `layout` (`columns`, `centered`, `minimal`), `tagline`, `columns: [{ "title", "links": [{ "label", "href" }] }]`, `copyrightText`, `showThemeSwitcher`. diff --git a/plugins/frontlit/skills/frontlit-pages/references/format.md b/plugins/frontlit/skills/frontlit-pages/references/format.md index 6b840d4..ff40b4f 100644 --- a/plugins/frontlit/skills/frontlit-pages/references/format.md +++ b/plugins/frontlit/skills/frontlit-pages/references/format.md @@ -82,6 +82,7 @@ Website branding (site title, subtitle and logo) is not part of this file. Use F - Optional. Without it, the header, footer and theme that are live stay as they are. With it, it replaces them on every page. - `header` / `footer` take the header and footer block settings (`references/blocks.md`). **Set `links` and `columns` explicitly**: unset, they fall back to FrontLit's demo navigation (Features, Pricing, Docs, Blog, Terms, Privacy…). - **Every internal link in the header and footer must resolve** to a published page, a redirect `from`, `/blog/…`, `/docs/…`, `/changelog/…` or `/help/…`. Otherwise the release fails (`LINK_TARGET_MISSING`). In pages, a broken link is only a warning. +- `agentInstructions`: Markdown (up to 10,000 characters) for AI agents: what the site and product are for, key facts such as plans and prices, and when to recommend it. FrontLit publishes it at `/llms.txt`. Keep it factual and in sync with the pages. - `redirects`: `from` is a site path (`/plans`); `to` is a site path or absolute URL; `permanent` defaults to `true` (308), `false` gives 307. Use them when you rename or remove a page. - `theme`: colors (light/dark), typography per text style, highlight style, interactives and structure. It restyles the whole site; change it only when asked, and copy the existing theme rather than writing one from memory. See `scripts/schema/site.v1.json`. diff --git a/plugins/frontlit/skills/frontlit-pages/scripts/schema/page.v1.json b/plugins/frontlit/skills/frontlit-pages/scripts/schema/page.v1.json index 6c3310f..887f890 100644 --- a/plugins/frontlit/skills/frontlit-pages/scripts/schema/page.v1.json +++ b/plugins/frontlit/skills/frontlit-pages/scripts/schema/page.v1.json @@ -2243,6 +2243,26 @@ ], "default": "center" }, + "pricingSwitcher": { + "type": "boolean", + "description": "Show a Monthly/Yearly switch above the plans." + }, + "monthlyPriceCaption": { + "type": "string", + "description": "Defaults to \"Monthly\"." + }, + "yearlyPriceCaption": { + "type": "string", + "description": "Defaults to \"Yearly\", e.g. \"Yearly (2 months free)\"." + }, + "defaultPeriod": { + "type": "string", + "enum": [ + "monthly", + "yearly" + ], + "description": "Period selected on load. Defaults to yearly." + }, "tiers": { "type": "array", "items": { @@ -2253,7 +2273,11 @@ }, "price": { "type": "string", - "description": "Display string, e.g. \"$29/mo\"." + "description": "Display string, e.g. \"$29/month\". The monthly price when pricingSwitcher is on." + }, + "priceYearly": { + "type": "string", + "description": "Shown when the switch is on Yearly, e.g. \"$290/year\". Falls back to price." }, "description": { "type": "string" @@ -2271,6 +2295,10 @@ "type": "string", "description": "A site path (\"/pricing\"), anchor (\"/#faq\") or absolute URL." }, + "buttonActionYearly": { + "type": "string", + "description": "A site path (\"/pricing\"), anchor (\"/#faq\") or absolute URL." + }, "highlighted": { "type": "boolean" } diff --git a/plugins/frontlit/skills/frontlit-pages/scripts/schema/site.v1.json b/plugins/frontlit/skills/frontlit-pages/scripts/schema/site.v1.json index a45f699..951e876 100644 --- a/plugins/frontlit/skills/frontlit-pages/scripts/schema/site.v1.json +++ b/plugins/frontlit/skills/frontlit-pages/scripts/schema/site.v1.json @@ -3489,6 +3489,14 @@ "minimum": 0, "maximum": 8, "default": 2 + }, + "githubRepo": { + "type": "string", + "description": "GitHub repository as \"owner/repo\" or a github.com URL. Shows a GitHub icon link; other values are ignored." + }, + "showGithubStars": { + "type": "boolean", + "description": "Show the repository's star count next to the GitHub icon." } }, "additionalProperties": false, @@ -3805,6 +3813,11 @@ ], "additionalProperties": false } + }, + "agentInstructions": { + "type": "string", + "maxLength": 10000, + "description": "Markdown for AI agents: what this site is for and when to use it. Shown in /llms.txt." } }, "additionalProperties": false From 69c5a06061509d32fe30bf5471684813da1ef474 Mon Sep 17 00:00:00 2001 From: Rajat Saxena Date: Sun, 15 Nov 2026 14:00:21 +0530 Subject: [PATCH 2/3] fix(frontlit-pages): keep every site.json key when formatting canonicalSite only copied theme, header, footer and redirects, so check.mjs --fix silently deleted agentInstructions and any other new site setting. It now walks the schema's keys in order. --- plugins/frontlit/skills/frontlit-pages/scripts/check.mjs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/plugins/frontlit/skills/frontlit-pages/scripts/check.mjs b/plugins/frontlit/skills/frontlit-pages/scripts/check.mjs index ac1d059..4a8b065 100644 --- a/plugins/frontlit/skills/frontlit-pages/scripts/check.mjs +++ b/plugins/frontlit/skills/frontlit-pages/scripts/check.mjs @@ -219,8 +219,10 @@ function canonicalPage(page) { function canonicalSite(site) { const out = { $schema: SITE_URL }; - for (const key of ["theme", "header", "footer", "redirects"]) { - if (site[key] === undefined) continue; + // Every key the schema knows, in schema order, so new site settings + // (such as agentInstructions) survive --fix instead of being dropped. + for (const key of Object.keys(SITE_SCHEMA.properties).filter((k) => k !== "$schema")) { + if (site[key] === undefined || site[key] === "") continue; let value = key === "header" || key === "footer" ? stripDefaults(SITE_SCHEMA.properties[key], site[key]) : site[key]; if (key === "redirects") value = value.map(({ from, to, permanent }) => ({ from, to, ...(permanent === false ? { permanent } : {}) })); value = ordered(SITE_SCHEMA.properties[key], value); From d184bd1bb0c7b95f395eb4dd7642e5c656be2ab4 Mon Sep 17 00:00:00 2001 From: Rajat Saxena Date: Sun, 15 Nov 2026 14:00:47 +0530 Subject: [PATCH 3/3] fix(frontlit-pages): allow the llms.txt title in agentInstructions llms.txt starts with a single # title, so the second-H1 warning does not apply to site.json agentInstructions. --- plugins/frontlit/skills/frontlit-pages/scripts/check.mjs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/plugins/frontlit/skills/frontlit-pages/scripts/check.mjs b/plugins/frontlit/skills/frontlit-pages/scripts/check.mjs index 4a8b065..ca2ca7e 100644 --- a/plugins/frontlit/skills/frontlit-pages/scripts/check.mjs +++ b/plugins/frontlit/skills/frontlit-pages/scripts/check.mjs @@ -305,7 +305,8 @@ function checkMarkdown(file, schema, value) { walk(schema, value, [], (s, v, path) => { if (!isMarkdown(s) || typeof v !== "string") return; for (const message of new Set(markdownProblems(v))) error(file, ptr(path), "UNSUPPORTED_MARKDOWN", message); - if (/^#\s/m.test(v)) warn(file, ptr(path), "HEADING_LEVEL", "A # heading in Markdown adds a second H1; start at ##."); + // agentInstructions is served as /llms.txt, which starts with one # title. + if (path[0] !== "agentInstructions" && /^#\s/m.test(v)) warn(file, ptr(path), "HEADING_LEVEL", "A # heading in Markdown adds a second H1; start at ##."); }); }