Tiredize is a schema-driven markdown validation and linting tool. It parses markdown documents into a structured representation and validates them against user-defined schemas and configurable lint rules. Define what your documents should look like, and tiredize tells you where they don't.
The tool was built to enforce quality control on Technique Research Reports published by TIRED Labs, but it is general-purpose. Document structure is defined via external YAML configuration files, so any project with structured markdown documentation can use it.
Markdown schema validation -- Define the expected section structure of a document: which sections must exist, their heading levels, their ordering, whether sections are optional or repeating, and section name matching via exact string or regex. Tiredize validates the document against the schema and reports missing, unexpected, misordered, or incorrectly leveled sections. Supports both ordered and unordered validation modes.
Linter rules -- A pluggable rule engine for style and formatting checks. Built-in rules cover line length, tab usage, trailing whitespace, and link validation (including HTTP checks, anchor resolution, and relative file path verification). Advanced users can add custom rules by modifying the built-in rules package (for example, via an editable install or project fork).
Markdown parser -- A regex-based parser that extracts headers, sections, code blocks (fenced and inline), links (inline, reference-style, bracket, and bare), images, tables, block quotes, and frontmatter into typed dataclass elements with accurate position tracking. List extraction is planned but not yet implemented.
Frontmatter schema validation -- Validate YAML frontmatter fields
against a user-defined schema. Declare which fields must exist, their
expected types (string, int, float, bool, date, list), and
optionally constrain their values to a set of allowed entries. Detects
duplicate YAML keys, rejects map values, and enforces string-only list
items with no duplicates.
Requires Python 3.10 or later.
pip install tiredizeFor development:
git clone https://github.com/tired-labs/tiredize.git
cd tiredize
pip install -e .
pip install pytest pytest-cov flake8Tiredize runs from the command line. It accepts markdown files as positional arguments and configuration via flags.
tiredize --markdown-schema schema.yaml document.mdtiredize --rules rules.yaml document.mdtiredize --frontmatter-schema frontmatter.yaml document.mdtiredize --markdown-schema schema.yaml --frontmatter-schema frontmatter.yaml --rules rules.yaml document.mdtiredize --markdown-schema schema.yaml docs/*.mdThe command prints rule violations in file:line:col: [rule_id] message
format and returns a nonzero exit code when validation fails, making it
suitable for pre-commit hooks and CI/CD pipelines.
A YAML file defining the expected section structure. Sections can be required or optional, matched by exact name or regex pattern, and allowed to repeat with min/max bounds. Nested sections are supported.
# Enforce that documents have these sections in order
enforce_order: true
allow_extra_sections: false
sections:
- name: "Introduction"
level: 1
sections:
- name: "Background"
level: 2
- name: "Scope"
level: 2
required: false
- name: "Methods"
level: 1
sections:
- pattern: ".+"
level: 2
repeat:
min: 1
- name: "Results"
level: 1
- name: "References"
level: 1See the markdown schema validator specification for the full format reference, including all properties, constraints, and validation algorithm details.
A YAML file defining expected frontmatter fields, their types, and optionally their allowed values.
fields:
status:
type: string
allowed:
- draft
- ready
- active
- done
priority:
type: string
allowed:
- critical
- high
- medium
- low
created:
type: date
tags:
type: list
required: falseSee the frontmatter schema validator specification for the full format reference, including all properties, type mapping, constraints, and error types.
A YAML file where each top-level key is a rule ID and its value is the rule's configuration. Only rules with an entry in the config file are enabled.
line_length:
maximum_length: 80
tabs:
allowed: false
trailing_whitespace:
allowed: false
links:
validate: true
timeout: 5Tiredize discovers linter rules automatically from Python modules. To add a custom rule:
-
Create a Python module (e.g.,
my_rule.py) with avalidatefunction:from tiredize.core_types import Position, RuleResult from tiredize.markdown.types.document import Document def validate( document: Document, config: dict, ) -> list[RuleResult]: results = [] # Your validation logic here. # Return RuleResult instances with rule_id=None # (the engine fills it in from the module name). return results
-
Place the module in the built-in rules package (
tiredize/linter/rules/). This requires an editable install (pip install -e .) or a project fork. The module must be non-private (no leading underscore) and expose avalidatefunction.
The rule ID is derived from the module filename (e.g., my_rule.py
produces rule ID my_rule). Configuration values for your rule are
passed via the config dict from the YAML file.
See the linter specification for the full rule pattern and available configuration helpers.