Frontmattering makes Markdown safer for agents.
It adds governed frontmatter, task routing, body/frontmatter freshness tethers, and a vendorable validate-only runtime gate so an agent can consume a compact brief without silently relying on stale documentation.
python -m pip install frontmattering
frontmattering --version
frontmattering doctorfrontmattering init . scaffolds a starter router under docs/, and frontmattering new creates governed documents. This block runs verbatim in an empty directory (it is executed as a release gate in CI):
frontmattering init . --set-id MYDOCS --title "My docs"
frontmattering new docs/10_GUIDE.md --profile guide --title "My guide"
frontmattering tether update --add .
frontmattering validate .
frontmattering brief .Already have Markdown under docs/? Add governance to a file you already have with promote, one file or many at once:
frontmattering promote docs/YOUR_GUIDE.md --profile guide --in-place
frontmattering promote docs/guides/*.md --profile guide --in-place # batch: --in-place requiredHave a file that already carries a leading frontmatter block — a legacy or hand-rolled one — you want replaced with a fresh canonical block? Use reauthor. It removes the existing block, writes a shipped starter-profile block over the preserved body, and keeps the document's canonical document_id so inbound references are not orphaned:
frontmattering reauthor docs/LEGACY_GUIDE.md --profile guide --in-place
frontmattering reauthor docs/guides/*.md --profile guide --in-place # batch: --in-place requiredpromote refuses a file that already has a leading block (FRONTMATTERING-PROMOTE-FRONTMATTER-PRESENT — use reauthor); reauthor refuses a plain file with no block (FRONTMATTERING-REAUTHOR-FRONTMATTER-ABSENT — use promote). A multi-file batch is all-or-nothing: every input is built and preflighted before any byte is written, and any failure — including one that would leave the corpus without exactly one router — restores every file. Promoting or reauthoring a file outside the selected corpus fails before the file is touched (FRONTMATTERING-AUTHORING-TARGET-OUTSIDE-CORPUS).
Choose the starter profile that matches the document's role: router, guide, spec, contract, evidence, release, registry, or template (for reusable snippet/template surfaces). Files without a single top-level heading — generated snippets, for example — can be titled from their filename with --title-strategy stem, so a whole batch of headingless files authors in one call:
frontmattering promote docs/generated/snippets/*.md --profile template --in-place --title-strategy stemFor strict freshness enforcement, set validation_profile: trust in .frontmattering/project.yaml, then re-run frontmattering validate . and frontmattering brief ..
If a tool generates or edits governed Markdown, it must not hand-reimplement the body-tether digest — that silently drifts from the model. Use the supported single-file surface instead. frontmattering stamp refreshes one already-governed file's body_tether so it reads FRESH:
frontmattering stamp docs/generated/SNIPPET.md --in-placeIn-process, call the documented public API — it reads the canonical trust-field list from the shipped spec and reuses the exact kernel path the validator trusts, so a stamped file is accepted as FRESH:
from frontmattering.api import stamp_tether
receipt = stamp_tether("docs/generated/SNIPPET.md") # {'operation': 'stamp', 'body_sha256': ..., ...}The model carries a typed relationship graph (relationships, evidence_references), but an empty graph is easy to leave in place. Author edges with link — relationships are not a freshness trust field, so the file stays FRESH and the corpus stays GO:
frontmattering link add docs/RELEASE_NOTES_v2_4.md --to PRFT-RELEASE-NOTES-V2-3 \
--type supersedes --scope release-notes --rationale "v2.4 supersedes v2.3"link add preflights that the target resolves in the corpus and that a supersedes edge names a --scope. Lint the graph for gaps the per-document validator does not catch — dangling same-set targets, and release records that supersede no predecessor:
frontmattering mesh --lintfrontmattering runtime pack --out frontmattering-runtime.pyz
python frontmattering-runtime.pyz validate docs --format jsonThe runtime artifact is validate-only. It does not expose init, promote, reauthor, new, index, tether update, or authoring surfaces.
The .pyz is fully self-contained: it embeds both the validator and its pure-Python dependencies (PyYAML, markdown-it-py, mdit-py-plugins, mdurl), so it validates with no host dependency install — even under python -S (no site-packages). Each report's runtime_identity reports self_contained: true and the exact embedded dependency versions. A corrupted or stripped artifact whose embedded packages cannot import fails closed with a typed BLOCKED / FRONTMATTERING-RUNTIME-DEPENDENCY-MISSING report, never a raw traceback.
# runs with zero third-party packages installed in the host Python:
python -S frontmattering-runtime.pyz validate docs --format jsonGO means every selected document passed — not that every Markdown file under the supplied path was selected. The report always names the boundary: selection.outside_selection_markdown_count (with selection.outside_selection_paths and …_sha256) counts Markdown discovered under the supplied path but outside the configured corpus. Note that discovery is relative to what you validate:
# corpus-only: validates docs/**/*.md; does not discover Markdown elsewhere
python frontmattering-runtime.pyz validate docs --format json
# whole-tree boundary audit: discovers all Markdown under . and reports what the corpus left out
python frontmattering-runtime.pyz validate . --format json | jq '.selection.outside_selection_markdown_count, .selection.outside_selection_paths'Both the runtime and the main CLI emit the identical selection/project evidence, so either surface can gate on the boundary.
The validator proves your frontmatter is valid, current, scoped, and tethered. It does not prove the frontmatter is good — a GO document can still carry a copied summary or a generic deepest intention. The governed prompt pack closes that gap: it makes authoring excellent, body-grounded frontmatter repeatable.
frontmattering prompt list
frontmattering prompt inspect author-category-frontmatter
frontmattering prompt render \
--task author-category-frontmatter \
--category self_protection_layer \
--support-profile frontmattering_only \
--corpus-root docs \
--output rendered_prompt.md --receipt-out render_receipt.yamlprompt render is deterministic: it composes the prompt from a packaged task template, a structured category profile, a support profile, and shared fragments, and binds the rendered bytes to every input's digest — including the authorizing manifest, renderer source, distribution, and serializer identity. The core CLI never executes an LLM — a rendered prompt proves only that the bytes were deterministically composed, not that a model ran or that an authoring result is semantically correct.
Run frontmattering prompt verify (also a doctor step) to confirm the packaged pack renders cleanly, reproduces its worked example, and conforms to its own shipped JSON schemas. Run frontmattering prompt verify-rendered --prompt rendered_prompt.md --receipt render_receipt.yaml --request render_request.yaml to verify a rendered prompt: it re-renders the canonical prompt from the request against the installed pack and compares byte-for-byte, rejecting a non-canonical or re-sealed prompt (FRONTMATTERING-PROMPT-NOT-CANONICAL) and any unauthorized task/category/profile.
This establishes reproducibility — the prompt is the canonical render of that request on this installed pack. It is not, on its own, provenance that the request was authorized: a producer who controls the request and re-renders honestly produces a valid prompt. Hostile-producer provenance requires signing the request/receipt under an independent authority (tracked as deferred in docs/DEFERRED_ITEMS_LEDGER.md).
Frontmattering is source-available. It is free for individual personal use within the scope of LICENSE.md. Professional, organizational, employer, client, CI/CD, hosted, managed-service, platform, consulting, or revenue-connected use is permitted for a 30-day evaluation period under LICENSE.md; continued use after the evaluation requires a paid commercial license.
Frontmattering is not open-source software under the Open Source Definition because professional and organizational use is restricted without a commercial license.
Runtime dependency status is recorded in THIRD_PARTY_NOTICES.md; project notices are recorded in NOTICE.
A FRESH brief means the current body bytes and canonical trust-bearing frontmatter fields match their mechanical tether. It does not prove semantic summary correctness, human approval, external adoption, or production suitability.
A STALE or UNTETHERED summary must not be relied on without reading the body.
This v0.12.0 minor release adds a quality subsystem, a self-evidencing teaching layer, and a fully self-contained runtime. frontmattering quality lint/gate/verify-report/verify-assessment rank frontmatter usefulness, safety, and specificity (deterministic ranks D0–D4) — kept strictly separate from validate, which only certifies admissibility. Quality detects un-customized starter residue (a summary that restates the title, a generic read_when, a placeholder claim boundary), is non-compensatory (a corpus is capped by its worst critical document, not an average), and never runs an LLM — an externally supplied semantic assessment is only ever verified against digest-bound evidence. A new teaching layer ships facet-complete, budget-bounded, claim-bounded guidance (QUICK_REFERENCE, BUILDING_A_GOVERNED_CORPUS, MAINTAINING_A_CORPUS, WORKED_EXAMPLE, AUTHORING_QUALITY_FRONTMATTER, and a generated COMMAND_REFERENCE) guarded by a release-blocking check_teaching gate, routing an author from quality lint findings to the prompt-pack authoring craft. The packed validate-only runtime is now fully self-contained: runtime pack embeds the validator and its pure-Python dependencies, so python -S frontmattering-runtime.pyz validate docs runs with no host dependency install; each report reports self_contained: true and the exact embedded versions, and a stripped/corrupted artifact still fails closed with a typed BLOCKED (this supersedes the 0.9.2 dependency-contract described below). prompt verify stays GO and the validator trust-semantics, frontmatter schema, and canonical model (v0.1.5) are unchanged. Quality ranks and teaching-surface conformance are structural, not semantic: a green quality result is not release approval, semantic correctness, or production readiness. It carries forward the 0.10.0 self-protection layer and the 0.11.0 hardening, and the 0.9.2 work below.
This v0.9.2 minor release closes the architectural findings an external audit tracked against 0.9.1 (the code-addressable deferred-items), plus a fail-closed hardening pass. Every mutating command (tether update, parse --batch, new, single-file promote/reauthor, batch authoring, init) is now operation-wide all-or-nothing through one shared transaction primitive, and tether update writes each document once with final digests. The Markdown parser is deterministic across hosts: mdit-py-plugins is now a required dependency, the declared extended_v1 profile is recorded in the IR, and the loader fails closed if the plugins are absent. The packed runtime declares its dependency contract (not self-contained) and reports a typed BLOCKED — never a raw traceback — on a missing dependency. Dangerous or malformed input is a typed input rejection, never FRONTMATTERING-KERNEL-INTERNAL-BUG. New surfaces: prompt verify-execution (rejects a fabricated COMPLETE execution record), prompt sign + verify-rendered --signature (hostile-producer provenance under an operator key), and validate --require-all-markdown-selected (opt-in corpus-completeness). CI expands to Linux/Windows/macOS × Python 3.10–3.14. LICENSE §3 adds an explicit generated-output grant. prompt verify stays GO and the validator trust-semantics, frontmatter schema, and canonical model (v0.1.5) are unchanged. It carries forward the 0.9.1 corrective fixes below.
The prior v0.9.1 patch release fixes four defects an external audit confirmed against 0.9.0: reauthor deleted authored leading body bytes while its receipt claimed byte preservation (now preserved exactly, and the writer refuses any body-byte change); a symlink under an include glob could import an out-of-corpus file into the governed set (now rejected); a batch could exit 0 leaving the corpus with duplicate document ids (now refused before any write); and untrusted filenames could inject control/bidi characters into derived titles (now rejected). See the changelog for the full list; the audit's remaining findings are the architectural items already tracked in docs/DEFERRED_ITEMS_LEDGER.md.
The prior v0.9.0 minor release closed DIL-21 — the empty relationship/evidence graph the tutorial dogfood surfaced. It adds frontmattering link add/link rm to author typed, schema-complete relationships on a governed document (target resolution is preflighted; a supersedes edge requires an explicit scope), and frontmattering mesh --lint to surface graph gaps the per-document validator does not catch — dangling same-set targets and release records that supersede no predecessor. Because relationships is not a body-tether trust field, authoring an edge keeps the file FRESH and the corpus GO. prompt verify stays GO and the validator trust-semantics, frontmatter schema, prompt-pack canonical model, and canonical model (v0.1.5) are unchanged. It carries forward the 0.8.0 stamping surface below.
The prior v0.8.0 minor release closed DIL-20 — the body-tether correctness hazard the tutorial dogfood surfaced. It adds a supported single-file stamping surface so tools that generate or edit governed Markdown stop re-implementing the closed model's canonicalization by hand (which silently drifts from the validator): a new frontmattering stamp <file> command and a documented, importable frontmattering.api.stamp_tether() that reads the canonical trust-field list from the shipped spec and reuses the exact kernel path the validator trusts. Both refuse a non-governed file (FRONTMATTERING-STAMP-NOT-GOVERNED). prompt verify stays GO and the validator trust-semantics, frontmatter schema, prompt-pack canonical model, and canonical model (v0.1.5) are unchanged. It carries forward the 0.7.0 authoring-completeness work below.
The prior v0.7.0 minor release completed the authoring surface that 0.6.0 began, closing the two gaps the 0.6.0 tutorial dogfood surfaced (tracked as DIL-18 and DIL-19). A template starter profile now emits the canonical template_surface role (kind template, authority advisory) with its own template id, so reusable snippet/template documents no longer have to borrow the authoring-guide template or be hand-authored. --title-strategy {h1,stem} on promote/reauthor lets a file with no single top-level heading be titled from its filename, so a batch of headingless generated files (the tutorial's snippets) authors in one call instead of failing FRONTMATTERING-PROMOTE-TITLE-AMBIGUOUS; the default (h1) is unchanged, and an explicit --title always wins. prompt verify stays GO and the validator trust-semantics, frontmatter schema, prompt-pack canonical model, and canonical model (v0.1.5) are unchanged. It carries forward the 0.6.0 batch authoring + reauthor, the 0.5.7 prompt-pack reasoning/deterministic classification, the 0.5.6 out-of-corpus path identities, the 0.5.5 runtime report-parity fix, the 0.5.4 generated runtime CLI, the 0.5.3 complete CLI help, and the 0.5.2 prompt-evidence layer. Deferred items remain tracked in docs/DEFERRED_ITEMS_LEDGER.md (DIL-20 stamping API and DIL-21 relationship authoring are the next authoring items). Custom license text should still receive legal review before paid commercial sales.