The Markdown looks fine.
A checklist reads well, but a release gate, owner field, or evidence link can silently drift out of shape.
Package 2.0 | Rich IR document contract 1.0.0 | Local validation
A deterministic parsing and validation boundary for teams that need Markdown to behave like an operational contract, not an unchecked blob of prose.
Plain-language story
Teams often keep serious work in Markdown: release checklists, operating specs, handoff notes, requirements, and agent instructions. Those files are easy for humans to read, but most tools still treat them like loose text.
That means a document can look finished while a required section is missing, a table column was renamed, a release gate has no owner, or an evidence link no longer proves anything. The mistake is usually found later, during review, release, or handoff.
Markdown Engine lets a team write simple rules for the document: these sections must exist, these fields at the top must be present, these IDs must be unique, and these links must point to the right evidence. Then it checks the file locally and returns clear pass/fail results that a person, CI job, or agent can trust.
A checklist reads well, but a release gate, owner field, or evidence link can silently drift out of shape.
A small rules file says which headings, fields, tables, IDs, text, and links the document must contain.
The engine gives the same answer every time and points to what is wrong before the file is reviewed, merged, published, or handed to an agent.
Consumer value
Markdown Engine gives downstream tools a stable document model, deterministic validation, and diagnostics that can be reviewed, stored, diffed, and gated in CI.
Normalize GFM, frontmatter, source ranges, links, lists, tables, sections, and text spans into an engine-owned IR instead of binding consumers to raw parser ASTs.
Express required headings, frontmatter fields, table columns, IDs, literal text, links, and trace references with closed, YAML-friendly profile data.
Run the CLI or API before a release, handoff, or agent task and get structured diagnostics instead of late reviewer discovery.
Profile inputs are data. Regex-like keys, executable-like keys, accessors, proxies, cycles, and unsafe shapes are rejected as inert config errors.
Where it fits
The package is intentionally narrow: parse, normalize, validate, serialize. That makes it useful as the deterministic substrate for docs platforms, release operations, requirements evidence, and future agent runtime lenses.
Keep required document sections, frontmatter, links, tables, and structural IDs consistent across repositories.
Turn release checklists into repeatable local gates before npm packing, publishing, or human approval.
Feed coding agents normalized document contracts and deterministic evidence instead of asking them to infer process from raw Markdown.
Grounded workflows
The first three narratives map to shipped fixture profiles and passing Markdown documents. The `SKILL.md` and `PLAYBOOK.md` patterns show how consumers can define their own document types with the same deterministic contract model.
Operational spec
A platform team wants each operating spec to include objective, constraints, execution plan, risk register, and handoff links. Markdown Engine validates those sections, checks table shape, enforces `OPS-RISK` IDs, and proves the expected handoff link is present.
syntaxVersion: markdown-engine.validation@v1
documentVersion: 1.0.0
rules:
- id: frontmatter.required
select:
target: document
assert:
frontmatterRequired:
fields:
- title
- owner
- status
- id: sections.required
select:
target: document
assert:
sectionsRequired:
order: strict
headings:
- Objective
- Context / Constraints
- Execution Plan
- Risk Register
- Handoff Links
- id: risk.table.columns
select:
target: table
section: Risk Register
header:
- ID
- Mitigation
- Status
assert:
tableColumnsRequired:
columns:
- ID
- Mitigation
- Status
- id: risk.ids.unique
select:
target: tableCell
section: Risk Register
column: ID
assert:
ids:
prefix: OPS-RISK
unique: true
- id: handoff.link
select:
target: link
section: Handoff Links
text: handoff packet
url: ./handoff-packet.md
assert:
exists: true
---
title: Operational Spec Example
owner: platform-team
status: ready
---
# Objective
Mission control uses this structural profile to confirm a small operating spec
has the required sections, handoff links, and risk tracking details.
# Context / Constraints
The example stays generic. It validates Markdown headings, tables, IDs, list
content, literal text, and links without attaching domain meaning to the core
engine.
# Execution Plan
- MUST Validate profile fixtures locally.
- MUST Record evidence before requesting review.
- Keep the checks deterministic and local-only.
# Risk Register
| ID | Mitigation | Status |
| --- | --- | --- |
| OPS-RISK-1 | Keep examples structural. | tracked |
| OPS-RISK-2 | Keep commands local. | closed |
# Handoff Links
The [handoff packet](./handoff-packet.md) records follow-up review notes for the
next operator.
Quickstart
Start with the CLI to inspect behavior against bundled fixtures, then move the same deterministic path into your application code.
Add the engine to the project that owns your Markdown workflow.
npm install @jasonbelmonti/markdown-engine
Validate a real release checklist fixture and inspect JSON output.
npm exec -- markdown-engine validate \
--file node_modules/@jasonbelmonti/markdown-engine/fixtures/declarative-validation/examples/release-checklist/pass.md \
--profile node_modules/@jasonbelmonti/markdown-engine/fixtures/declarative-validation/examples/release-checklist/profile.yaml
Parse, normalize to rich IR, compile the profile, and validate locally.
import {
normalize,
parse,
parseValidationProfile,
validateWithProfile,
} from "@jasonbelmonti/markdown-engine";
const parsed = parse(markdown, { path: "release.md" });
const normalized = normalize(parsed.parsed);
const profileResult = parseValidationProfile(profileYaml);
if (!profileResult.profile) {
throw new Error(profileResult.diagnostics[0]?.message ?? "Invalid profile");
}
const result = validateWithProfile(
normalized.document,
profileResult.profile,
{ includeEvidence: true },
);
console.log(result.valid, result.diagnostics);
Stable contracts
Package 2.0 keeps the serialized rich IR at `documentVersion: "1.0.0"` and makes that shape the default output for `normalize(parsed)`. Legacy consumers can still request the retained `0.0.0` document shape explicitly.