Structured Markdown is an open semantic layer for Markdown. A parser uses the standard as a semantic contract to parses constrained Markdown into a stable, validated object model with provenance, enabling reliable transformation into downstream systems such as RAG pipelines, JSON-LD, DITA, RSS/Atom, knowledge graphs, static sites, and structured documentation workflows.
The current project is focusing on a layered Python package that parses Markdown and rendered HTML into a normalized structured content hierarchy for validation, publishing transforms, and RAG ingestion.
The parser maps source files into an Article → Unit → Component → Attribute hierarchy defined by the JSON schemas in model/. It produces versioned Pydantic contracts, author-facing diagnostics, and transform-readiness reports — with a CLI and a Python API.
The repository pipeline runs that same parser across nested Markdown folders. It discovers source files, preserves relative paths under an output directory, writes parsed JSON files, writes a CSV inventory report, and optionally writes a log file.
| Capability | Status |
|---|---|
Markdown parsing (.md) |
Complete |
Rendered HTML parsing (.html) |
Complete |
| YAML front matter extraction | Complete |
| Article/unit/component/attribute classification | Complete |
JSON Schema validation against model/ |
Complete (advisory) |
| Reference classification | Complete |
| Local file reference resolution | Complete |
| Author-facing diagnostics (stable codes) | Complete |
| Transform-readiness evaluation (DITA, Schema.org, RAG) | Complete |
| CLI commands | Complete |
| Python API | Complete |
Nested-folder Markdown pipeline (pipe) |
Complete |
| DITA/XML parsing | Deferred (A-004) |
| Complex conref/keyref resolution | Deferred (A-005) |
python -m venv .venv
source .venv/bin/activate # Windows: .venv\Scripts\activate
pip install -e .Parse a file and inspect the structured content model:
structure-parser parse my-article.md
structure-parser inspect-model my-article.md
structure-parser inspect-structure my-article.md
structure-parser inspect-references my-article.md
structure-parser inspect-diagnostics my-article.md
structure-parser transform-readiness my-article.mdValidate against a specific schema:
structure-parser validate-markdown my-article.md --schema artHowto.schema.json
structure-parser validate-markdown my-article.md --schema artArticle.schema.json --strictOutput as JSON:
structure-parser parse my-article.md --jsonRun the parser across a nested Markdown content repository:
structure-parser pipe docs_src --out build/parsedWrite a custom CSV inventory report and optional log:
structure-parser pipe docs_src \
--out build/parsed \
--report build/inventory.csv \
--log-file build/pipeline.jsonl \
--log-format jsonlfrom structure_parser import parse_file, parse_files
from structure_parser.contracts.config import ParserConfig
from structure_parser.contracts.pipeline import PipelineConfig
from structure_parser.pipeline import run_pipeline
# Parse a single file (uses default config)
doc = parse_file("my-article.md")
print(doc.title) # "How to Configure Settings"
print(doc.structured_content.article_type) # ArticleType.howto
print(doc.structured_content.information_type) # InformationType.mixed
for unit in doc.structured_content.content:
print(f" {unit.unit_type.value}: {unit.title}")
# Check diagnostics
if doc.has_errors:
for d in doc.diagnostics:
print(f"[{d.severity.value}] {d.code}: {d.message}")
# Check transform readiness
for target in doc.readiness.targets:
print(f"{target.target}: {target.status.value}")
# Parse multiple files
result = parse_files(["article1.md", "article2.md"])
print(f"Parsed {result.stats.file_count} files in {result.stats.duration_ms:.0f}ms")
# Run the repository pipeline
pipeline_result = run_pipeline(
PipelineConfig(inputs=["docs_src"], output_dir="build/parsed")
)
print(f"Discovered {pipeline_result.stats.discovered_count} Markdown files")The run_pipeline() helper writes parsed JSON outputs and returns a PipelineRunResult. The CLI pipe command writes the CSV inventory report; Python callers can use CsvInventoryReporter when they need the same report.
Configuration:
config = ParserConfig(
validation_mode="strict", # "advisory" (default) or "strict"
resolve_local_references=True, # resolve ./link.md paths
enable_structured_markdown=True, # article/unit/component classification
emit_debug_logs=True, # structured logs to stderr
)
doc = parse_file("my-article.md", config=config){
"schema_version": "1",
"source_path": "tests/fixtures/markdown/clean.md",
"title": "How to Configure Settings",
"article_type": "howto",
"information_type": "mixed",
"units": [
{"unit_type": "introduction", "title": "Introduction", "component_count": 1},
{"unit_type": "prerequisites", "title": "Prerequisites", "component_count": 2},
{"unit_type": "procedure", "title": "Steps", "component_count": 1},
{"unit_type": "procedure", "title": "Example Configuration", "component_count": 1},
{"unit_type": "link-nextstep", "title": "Next Steps", "component_count": 2}
],
"references": [
{"type": "link", "href": "./deploy.md"},
{"type": "link", "href": "./monitor.md"}
],
"diagnostic_count": 1
}Full JSON output (with --json flag or model_dump()):
structure-parser parse tests/fixtures/markdown/clean.md --json| Code | Severity | Meaning |
|---|---|---|
SP-001 |
error | Source file not found |
SP-002 |
error | Unsupported source format |
SP-003 |
error | Parse failed |
SP-010 |
warning | Malformed YAML front matter |
SP-011 |
info | Front matter absent |
SP-020 |
warning | Missing H1 title |
SP-021 |
warning | Heading level skipped |
SP-030 |
warning | Schema validation failed |
SP-031 |
error | Schema file not found |
SP-040 |
info | Content classified as unknown |
SP-041 |
warning | Article type could not be determined |
SP-050 |
warning | Unresolved local reference |
SP-060 |
info | Transform readiness status |
SP-099 |
error | Internal parser error |
Markdown / HTML
│
▼
Format Adapter (adapters/)
│ RawParseModel
▼
Semantic Enricher (enrichment/)
├── Metadata Extractor
├── Structure Builder
├── Reference Classifier
└── Structured Markdown Classifier (structured_markdown/)
│ StructuredContent
▼
Model Validator (validation/)
│
▼
Readiness Evaluator (readiness/)
│
▼
ParsedDocument (contracts/parsed_document.py)
│
├── CLI (cli.py) → human text / JSON
├── API (api.py) → Pydantic models
├── Pipeline (pipeline/) → parsed files / CSV inventory
└── Debug Inspector → structured reports
| Layer | Input | Output |
|---|---|---|
adapters/ |
Source file | RawParseModel |
enrichment/ |
RawParseModel |
ParsedDocument partials |
structured_markdown/ |
RawParseModel |
StructuredContent |
validation/ |
StructuredContent |
ModelValidationResult |
readiness/ |
ParsedDocument |
TransformReadiness |
api.py |
File path + config | ParsedDocument / ParseRunResult |
pipeline/ |
Files or folders + PipelineConfig |
PipelineRunResult / parsed JSON / CSV |
The model/ directory contains the authoritative JSON schemas for the structured Markdown pattern language:
model/
├── articles/
│ ├── artArticle.schema.json # Union of all article types
│ ├── artHowto.schema.json
│ ├── artConcept.schema.json
│ ├── artReference.schema.json
│ └── units/
│ ├── sharedUnits.schema.json
│ ├── unitIntroduction.schema.json
│ ├── unitProcedure.schema.json
│ └── components/
│ ├── compParagraph.schema.json
│ ├── compBlockCode.schema.json
│ ├── compTable.schema.json
│ └── attributes/
│ ├── attText.schema.json
│ ├── attLink.schema.json
│ └── attImage.schema.json
├── model-overview.md
└── schema-index.md
See model/model-overview.md and model/schema-index.md for the full schema hierarchy.
git clone https://github.com/mb/structured-markdown
cd structured-markdown
python -m venv .venv
source .venv/bin/activate
pip install -e ".[dev]"
pre-commit install# Run all tests
pytest
# Run with coverage
pytest --cov=structure_parser --cov-report=term-missing
# Run only unit tests
pytest tests/unit/
# Run only contract tests
pytest tests/contract/
# Run only integration tests
pytest tests/integration/
# Validate fixtures
python tools/validate_fixtures.py# MkDocs Material live preview
mkdocs serve
# MkDocs static build
mkdocs build
# Generate JSON Schema artifacts from Pydantic models
python tools/generate_json_schemas.py
# Update expected contract fixtures from current parser output
python tools/update_expected_contracts.py| Command | Description |
|---|---|
structure-parser parse PATH... |
Parse one or more files; output summary or JSON |
structure-parser validate-markdown PATH... [--schema ID] [--strict] |
Validate structured Markdown authoring model |
structure-parser inspect-structure PATH |
Display heading structure tree |
structure-parser inspect-model PATH |
Display article/unit/component classification |
structure-parser inspect-references PATH |
Display references and resolution states |
structure-parser inspect-diagnostics PATH |
Display diagnostics grouped by severity |
structure-parser transform-readiness PATH [--target dita] |
Evaluate transform-readiness preconditions |
structure-parser validate-contract PATH... |
Validate fixture files against expected behavior |
| Code | Condition |
|---|---|
0 |
No errors; warnings only in advisory mode |
1 |
Parse errors or validation invalid in strict mode |
2 |
Unsupported schema version or configuration error |
3 |
Internal controlled failure |
structured-markdown/
├── pyproject.toml
├── mkdocs.yml
├── model/ # Authoritative JSON schemas
├── src/structure_parser/
│ ├── api.py # Public API: parse_file, parse_files
│ ├── cli.py # Typer CLI
│ ├── logging_config.py
│ ├── adapters/ # Format-specific parsers
│ │ ├── markdown.py # markdown-it-py adapter
│ │ └── html.py # lxml adapter
│ ├── contracts/ # Pydantic boundary contracts
│ │ ├── config.py
│ │ ├── parsed_document.py
│ │ ├── parse_run_result.py
│ │ ├── diagnostics.py
│ │ ├── references.py
│ │ ├── structure.py
│ │ ├── structured_markdown.py
│ │ ├── validation.py
│ │ └── transform_readiness.py
│ ├── domain/ # Enums, errors, diagnostic codes
│ ├── enrichment/ # Semantic enrichment pipeline
│ ├── structured_markdown/ # Article/unit/component classifier
│ ├── validation/ # JSON Schema validation
│ ├── readiness/ # Transform-readiness evaluators
│ ├── resolution/ # Reference resolvers
│ ├── repositories/ # File system and schema I/O
│ ├── serialization/ # JSON serialization
│ ├── reporting/ # Human-readable reporters
│ ├── debug/ # Debug inspector
│ └── application/ # Orchestrator and commands
├── tests/
│ ├── unit/ # Individual model and service tests
│ ├── contract/ # Fixture-based contract tests
│ ├── integration/ # End-to-end API and CLI tests
│ └── fixtures/ # Markdown, HTML, and expected JSON
├── schemas/ # Generated JSON Schema artifacts
│ ├── parser/v1/
│ └── structured_markdown/v1/
├── docs/ # MkDocs documentation source
└── tools/ # Schema generation and fixture scripts
| ID | Question | Impact |
|---|---|---|
| OQ-R1 | Legacy Markdown/HTML output fields requiring compatibility | Blocks final legacy_adapter.py scope |
| OQ-R2 | Required structured Markdown JSON Schemas for MVP validation | Affects model_validator.py profile config |
| OQ-R3 | Required metadata and taxonomy fields per validation profile | Affects author diagnostics |
| OQ-R4 | CI performance thresholds | Affects benchmark gating |
| OQ-R5 | Path-redaction policy for reports | Affects diagnostic output |