Skip to content

Semantic vs syntax linters

contextlint’s tagline is “markdownlint for syntax. contextlint for meaning.” This is not a tool that overlaps with markdownlint — the two are complementary, each owning a different layer. This page lays out the difference between a semantic linter and a syntax linter.

Linters split into layers depending on what they validate.

LayerWhat it validatesExamples
SyntaxWhether the notation follows the grammarHeading levels, list notation, table syntax
FormatWhether the notation style is consistentTrailing spaces, list marker consistency
SemanticWhether the content is logically consistentRequired columns, ID uniqueness, existence of reference targets

markdownlint owns syntax and format. contextlint owns semantic integrity and cross-file integrity. The two do not compete — they sit at different layers.

Aspectmarkdownlintcontextlint
Markdown syntax
Format and style
Heading-level consistency
Table syntax correctness
Data integrity inside tables
Existence of required sections
Order of required sections
ID uniqueness
Cross-file reference integrity
Dependency graph validation
Term consistency

Given the same table, the two linters look at different aspects.

| ID | Status | Description |
| ----------- | ------ | ----------- |
| REQ-AUTH-01 | | Login requirement |
| REQ-AUTH-01 | stable | |
  • What markdownlint sees: pipe count, separator-row formatting, whitespace handling — whether the table is valid Markdown
  • What contextlint sees:
    • The Status column has an empty cell (TBL-002)
    • The ID column contains a duplicate (TBL-006)
    • The Description column has an empty cell (TBL-002)
    • Whether the table content is consistent at the domain level

Combining the two covers both how it is written and what it says, from each side.

The area a syntax linter cannot cover only becomes more visible as documentation scales up.

  • A link can be written in valid Markdown notation yet point to a file that does not exist
  • A table can be syntactically correct Markdown yet have a required column missing
  • The same ID can be defined across multiple files, and Markdown itself raises no issue
  • A stable requirement can depend on a draft requirement, and Markdown syntax never flags it as an error

These are problems invisible at the Markdown layer. They live at the semantic layer rather than the grammatical layer, which is why a separate linter is needed.

contextlint does not replace markdownlint. Documents are validated in layers only when the two are used together.

  • markdownlint — “Is this written correctly as Markdown?”
  • contextlint — “Is the content consistent?”

In a CI pipeline, the recommended approach is to run both in sequence: markdownlint for syntax, contextlint for meaning — letting each focus on its area of strength.

  • Why contextlint exists — the background that made a semantic linter necessary
  • Rules — specifications of every rule contextlint provides