← Corpus / dididecks-ai / agent-skill
dididecks-ai/agent-skills/lossless-flavored-markdown/references/frontmatter-schema
- Path
- agent-skills/lossless-flavored-markdown/references/frontmatter-schema.md
LFM Frontmatter Schema
The recommended frontmatter fields for LFM content, the Zod schema patterns sites use to validate them, and the conventions that overlap with context-vigilance and changelog-conventions.
Field categories
Identity (required)
title: "Some Article"
slug: some-article # auto-derived from filename if omitted
lede: | # 1-3 sentence summary used in popovers, OG, and indexes
Why this matters and what the reader gets.
Dates (ISO 8601, always)
date_authored_initial_draft: 2026-04-01
date_authored_current_draft: 2026-05-05
date_published: 2026-05-05
date_modified: 2026-05-12
ISO 8601 = YYYY-MM-DD for date-only, YYYY-MM-DDTHH:MM:SSZ for datetime. Never use locale-formatted dates in frontmatter — they lose meaning when the file moves between systems.
Classification
tags:
- astro
- markdown
- tooling
category: engineering # one-of from a per-site enum
status: Published # Draft | Review | Published | Archived
The status workflow:
- Draft — author working; do not surface in indexes or sitemaps.
- Review — content complete; awaiting review. May surface to internal previews only.
- Published — public. Surface everywhere.
- Archived — was public, intentionally retired. Keep URL alive (301 to successor or leave with banner) but exclude from indexes.
Sites filter content collections on status === 'Published' for production builds.
Versioning
at_semantic_version: 0.0.1.1 # epoch.major.minor.patch
The four-part scheme is the context-vigilance convention — read that skill for the decision rules. For LFM content the most common pattern:
- epoch — bumped only when the document’s premise changes (rare).
- major — bumped when the structure or main argument changes substantially.
- minor — bumped when sections are added/removed.
- patch — bumped for typo fixes, citation additions, polish.
Display hints
image: /og/some-article.jpg # OG image (absolute URL preferred)
image_prompt: | # for Image-Gin / Ideogram regeneration
Editorial illustration of [subject], muted palette, banner aspect 1200x630.
toc: true # auto-generate table of contents
layout: article # which Astro layout to use
The image_prompt field is the source-of-truth for regenerating the OG image. When the article is updated and the banner needs a refresh, this is what gets fed to the image-gen tool. See the open-graph-share-seo-geo skill for the OG image rules and user-tools-for-image-generation.md for the current preferred tool (Ideogram).
AI co-authorship
augmented_with:
- "claude-opus-4.7"
- "claude-sonnet-4.6"
authors:
- Michael Staton
augmented_with is the Lossless Group’s transparency convention — list any AI tool that materially contributed to the content. Distinct from authors, which lists the humans accountable for it.
Provenance
source_repo: lossless-monorepo/astro-knots
source_path: src/content/posts/some-article.md
canonical_url: https://example.com/posts/some-article
canonical_url matters when content is mirrored across multiple sites — only one is canonical.
Full Zod schema (recommended baseline)
Drop into src/content/config.ts for any Astro Knots site:
import { defineCollection, z } from 'astro:content';
const lfmContent = defineCollection({
type: 'content',
schema: z.object({
// Identity
title: z.string().min(1).max(100),
slug: z.string().regex(/^[a-z0-9-]+$/).optional(),
lede: z.string().min(1).max(500),
// Dates
date_authored_initial_draft: z.coerce.date().optional(),
date_authored_current_draft: z.coerce.date().optional(),
date_published: z.coerce.date().optional(),
date_modified: z.coerce.date().optional(),
// Classification
tags: z.array(z.string()).default([]),
category: z.string().optional(),
status: z.enum(['Draft', 'Review', 'Published', 'Archived']).default('Draft'),
// Versioning
at_semantic_version: z.string().regex(/^\d+\.\d+\.\d+\.\d+$/).optional(),
// Display
image: z.string().url().or(z.string().startsWith('/')).optional(),
image_prompt: z.string().optional(),
toc: z.boolean().default(true),
layout: z.string().default('article'),
// AI co-authorship
augmented_with: z.array(z.string()).default([]),
authors: z.array(z.string()).default([]),
// Provenance
source_repo: z.string().optional(),
source_path: z.string().optional(),
canonical_url: z.string().url().optional(),
}),
});
export const collections = {
posts: lfmContent,
// … other collections
};
Sites extend the baseline with collection-specific fields (e.g., a decks collection adds slide_count, a changelog collection adds version).
Cross-skill conventions
context-vigilance
at_semantic_version— same scheme ascontext-v/files.status— same workflow (Draft → Review → Published → Archived).lede— used incontext-v/for one-line search hits; same role in popovers.
changelog-conventions
- Changelog entries use
publish: true | falseinstead ofstatus(legacy reasons; aligned in spirit). date_publishedanddate_modifiedare universal across content types.ledeis required on changelog entries.
open-graph-share-seo-geo
image(absolute URL) →og:imageandtwitter:image.lede(or first 155 chars of body) →description/og:description.title→<title>(with site-name suffix appended at render).image_promptis not surfaced publicly; it’s a regeneration aid.
What NOT to put in frontmatter
- HTML or markdown formatting in
lede. It gets rendered raw in popovers and OG descriptions. Plain text only. - Long body content. If the value spans more than ~3 lines of YAML, it belongs in the body, not frontmatter.
- Computed values. If something can be derived from the body or another field, derive it. Don’t store it.
- Secrets. Frontmatter ships to the client.