Template frontmatter — schema + conventions¶
Audience: anyone authoring or modifying a templates/**/*.md file. Closes compliance-architecture forward-work P9 at v0.58.0.
What this guide covers: the YAML frontmatter schema enforced by scripts/lint-template-frontmatter.py (CI gate added at v0.58.0). Every template carries frontmatter; the schema is hard-fail.
For module.yaml schema, see scripts/lint-module-yaml.py. For document-control workflow that consumes the frontmatter fields, see docs/guide/doc-control.md.
Why frontmatter is required¶
Frontmatter makes the template machine-readable. The CI pipeline (engine-tests.yml workflow at v0.58.0) parses the YAML block + validates against schema before pytest runs. This means:
- Authors can't ship a template with a typo'd or missing required field — CI catches it
- The doc-control workflow consumes the same fields without re-parsing
- Schema gives adopters confidence that every template they fork has the same baseline metadata
The schema¶
Required fields¶
| Field | Type | Pattern | Notes |
|---|---|---|---|
document_id |
string | ^[A-Za-z0-9][A-Za-z0-9_\-\[\]]*$ |
Stable identifier; e.g., SOP-IDM-001. Leading digit OK (510K-XXX). Adopter fill-in brackets OK (DI-[PRODUCT]-001). Use -XXX as the adopter-fill-in suffix. |
version |
string | ^\d+\.\d+(\.\d+)?$ |
Semver-ish: 1.0, 0.1.0, 2.3.4 all accepted. Two-part or three-part. |
owner |
string | non-empty | Role or named individual. Use [Role] placeholder for adopter fill-in. |
status |
string | one of recognized states | See state lists below. |
one of: effective_date · issued_date · issue_date · opened_date · assessment_date · notification_date · approval_date |
string | YYYY-MM-DD or literal YYYY-MM-DD placeholder |
At least one date field is required. Use the field most appropriate for the record kind. |
Recognized status values¶
Two lifecycle families coexist:
| Family | States | Use for |
|---|---|---|
| Document lifecycle | draft · review · approved · effective · superseded |
SOPs, policies, manuals, controlled procedures, templates-as-documents |
| Record lifecycle | open · closed · cancelled |
Deviations, OOS investigations, CAPA records, change-controls, traceability records |
Status may include a parenthetical qualifier (e.g., draft (pending NHTSA acceptance)); the schema checks the head token only.
Optional fields¶
Anything you need. Templates frequently carry domain-specific frontmatter like:
title:— display titleapproved_by:+approval_date:— approval evidencereview_cadence:— when the document is due for next reviewnext_review:— explicit date for next reviewaddresses:— list of clause IDs this template binds tolinked_*:— references to related artifactsphi_classification:— for HIPAA-touching templatesregulatory_framework_in_scope:— for cross-jurisdiction templatesworker_consultation:— for ISO 45001 templatesqa_approval:— for GLP templatesarchive_location:— for retention-bearing templates
The schema is permissive on extras — domain-specific fields are encouraged.
Minimal frontmatter for a new template¶
Copy + adapt:
---
document_id: PREFIX-XXX
version: "1.0"
effective_date: YYYY-MM-DD
owner: "[Role / Team]"
status: draft
---
Then add optional fields as appropriate for the document kind.
How to know what PREFIX to use¶
Existing prefixes by template group:
| Group | Prefix |
|---|---|
templates/qms-policy/ |
POL, SOP, IDM (identity-mapping SOP) |
templates/qms-bcms/ |
BCP, BCM |
templates/qms-capa/ |
CAPA |
templates/qms-management-review/ |
MR, MGMT-RVW |
templates/qms-recall/ |
REC, NHTSA-OWN, DIR |
templates/qms-privacy/ |
PRIV-* |
templates/qms-hipaa/ |
HIPAA-* |
templates/qms-logistics/ |
LOG-* |
templates/qms-ohs/ |
OHS-* |
templates/qms-environmental/ |
ENV |
templates/qms-energy/ |
EN, ENP |
templates/qms-abms/ |
ABM |
templates/qms-sops/ |
SOP-* |
templates/product-dhf/ |
DI (design input), DO (design output), 510K, RMF |
templates/product-pharma/ |
MBR, VMP, APQR, BCOA, STAB, COMP, etc. |
templates/product-atmp/ |
DON-ELIG, TRACE |
templates/product-chemicals/ |
CHEM-* |
templates/product-food/ |
HACCP, PRP |
templates/product-sw/ |
SWR (software requirements), SWA (architecture), SWTEST, SOUP, etc. |
Add to this list when introducing new prefixes.
Running the linter locally¶
# Lint all templates
python3 scripts/lint-template-frontmatter.py
# Lint a specific subdirectory
python3 scripts/lint-template-frontmatter.py templates/qms-hipaa
Exit code 0 = clean; exit code 1 = at least one error.
What the schema does NOT validate (yet)¶
These are intentional gaps that map to other forward-work items in docs/compliance-architecture.md:
- State-machine enforcement of status transitions — forward-work P5 will add
draft → review → approved → effective → supersededtransition rules + hard-fail when an out-of-order transition appears addresses:cross-check against in-module clause IDs — currently done byscripts/lint-module-yaml.pyfrom the module side; not by the template schema lintnext_reviewdate drift — no per-template warning when the date has passed (could be added; tracked as future improvement)- Reviewer-qualification linkage to
BUSINESS/regulatory_review_cadence.md— for regulatory-review-bearing templates only; intentionally manual today
Linkage to other Open QMS controls¶
- OQ-013 per-module validation harness — module YAML linting (in place since v0.40.0)
- OQ-122 template frontmatter schema validation — this guide's subject (in place since v0.58.0)
docs/guide/doc-control.md— consumes the schema-validated fields in the doc-control workflowscripts/lint-template-frontmatter.py— the linter itself; runs in CI as a pre-pytest gateengine/openqms/template_schema.py— schema definition; pure Python module with no external dependencies beyond PyYAML