Skip to main content

Custom Rules DSL

[[custom_rules]] lets you declare project-specific lint rules directly in zenzic.toml. Each rule applies a regular expression line-by-line to every .md file and produces a finding when the pattern matches. No Python is required — the DSL is pure TOML.


Syntax

[[custom_rules]]
id = "ZZ-NOINTERNAL"
pattern = "internal\\.corp\\.example\\.com"
message = "Internal hostname must not appear in public documentation."
severity = "error"

[[custom_rules]]
id = "ZZ-NODRAFT"
pattern = "(?i)\\bDRAFT\\b"
message = "Remove DRAFT marker before publishing."
severity = "warning"

Each [[custom_rules]] header appends one rule to the list. Use double brackets — that is the TOML array-of-tables syntax.


Fields

FieldTypeRequiredDescription
idstringStable unique identifier shown in findings (e.g. "ZZ001", "ZZ-NODRAFT")
patternstringRegular expression applied to each content line
messagestringHuman-readable explanation shown in the finding
severity"error" | "warning" | "info"Default: "error"

Severity behaviour

SeverityBlocks pipelineWith --strict
"error"Yes (exit code 1)Yes
"warning"NoYes
"info"NoNo

Rules with severity = "error" cause zenzic check all to exit 1. "warning" findings are surfaced in the report but do not affect the exit code unless --strict is passed.


Output format

When a custom rule fires, Zenzic prints the finding with a visual snippet showing the offending line:

[ZZ-NODRAFT] docs/guide/install.md:14 — Remove DRAFT marker before publishing.
│ > DRAFT: section under construction

For "error" severity the rule ID is printed in red; for "warning" in yellow. The line shows the raw source line exactly as it appears in the file.

Rules with severity = "info" are printed without the snippet.


Adapter-independence

Custom rules are adapter-independent. A rule searching for DRAFT fires identically whether the project uses MkDocsAdapter, ZensicalAdapter, or VanillaAdapter. The rule engine operates on raw Markdown text; it has no knowledge of the build engine. This means:

  • Rules you write for a MkDocs project require no changes after migrating to Zensical.
  • Rules are safe to write before deciding which build engine a project will use.

Performance

Patterns are compiled once at config-load time, not per file. There is no performance penalty for having many rules. Invalid regex patterns raise a ConfigurationError at startup with the offending pattern and the regex error message.


TOML placement

Place all [[custom_rules]] blocks before the [build_context] section. [build_context] must be the last section in zenzic.toml — TOML table headers apply to all subsequent keys, so any top-level field written after [build_context] would silently become a build_context sub-key.

# Correct ordering
docs_dir = "docs"

[[custom_rules]]
id = "ZZ-NODRAFT"
pattern = "(?i)\\bDRAFT\\b"
message = "Remove DRAFT marker before publishing."
severity = "warning"

[build_context] # ← always last
engine = "mkdocs"

Pattern tips

GoalPattern
Case-insensitive word boundary(?i)\\bDRAFT\\b
Literal dot (hostname)internal\\.corp\\.example\\.com
Match anywhere on lineTODO (no anchors needed — matching is per-line)
Exclude false positivesUse word boundaries \\b to avoid matching TODOS when looking for TODO

All patterns are applied with Python re.search — a match anywhere on the line triggers the finding. Use ^ and $ anchors only when you need to constrain to the start or end of the line.