contextlint

mcp
Security Audit
Fail
Health Pass
  • License Ò€” License: MIT
  • Description Ò€” Repository has a description
  • Active repo Ò€” Last push 0 days ago
  • Community trust Ò€” 26 GitHub stars
Code Fail
  • spawnSync Ò€” Synchronous process spawning in packages/cli/src/commands/commands.test.ts
  • process.env Ò€” Environment variable access in packages/cli/src/commands/commands.test.ts
Permissions Pass
  • Permissions Ò€” No dangerous permissions requested
Purpose
This tool is a rule-based linter that validates structured Markdown documents to catch broken references, duplicate IDs, and structural issues. It is designed to run locally or in CI pipelines to maintain the integrity of documentation dependencies.

Security Assessment
The overall security risk is Low. The tool does not request dangerous permissions, and there are no hardcoded secrets. The automated scan flagged a synchronous process spawn (`spawnSync`) and environment variable access (`process.env`). However, these were found exclusively inside a test file (`commands.test.ts`). This means no risky shell execution or environment reading occurs in the actual production code used by consumers. It does not appear to make external network requests or access sensitive system data.

Quality Assessment
Project quality is good. It is actively maintained (last pushed 0 days ago), uses the highly permissive MIT license, and has clear documentation with multi-language support. With 26 GitHub stars, it is still a relatively early-stage project with a small but growing community. The inclusion of a dedicated CI workflow indicates a professional approach to code stability.

Verdict
Safe to use.
SUMMARY

πŸ“ Rule-based linter for structured Markdown documents

README.md

contextlint

contextlint β€” Markdown Document Integrity Linter

npm version
cli downloads
mcp-server downloads
CI
License: MIT

🌐 ζ—₯本θͺž | δΈ­ζ–‡ | ν•œκ΅­μ–΄

A rule-based linter for structured Markdown documents.
Catch broken references, duplicate IDs, missing sections, and
structural issues β€” deterministically, in seconds, CI-friendly.

Why contextlint?

In the era of AI-driven development, methodologies like
SDD (Spec Driven Development) are gaining traction β€”
writing specifications in Markdown first, then letting AI
generate implementation based on those documents. As projects
adopt document-driven workflows, the number of interconnected
Markdown files grows: requirements, design decisions, API specs,
ADRs, RFCs, and more.

These documents form a dependency graph. IDs reference other IDs,
files link to other files, and stability levels flow downstream.
When this graph breaks β€” a deleted requirement, a mistyped ID,
a missing section β€” the consequences are silent.

contextlint provides deterministic, static validation for
structured Markdown. No AI, no cost, CI-friendly.

contextlint focuses on content semantics and cross-file
integrity
. For Markdown syntax, formatting, and style, use
markdownlint
alongside contextlint β€” they complement each other well.

Quick Start

Install:

npm install -D @contextlint/cli

Generate a config interactively:

npx contextlint init

Or create contextlint.config.json manually:

{
  "$schema": "https://raw.githubusercontent.com/nozomi-koborinai/contextlint/main/schema.json",
  "include": ["docs/**/*.md"],
  "rules": [
    { "rule": "tbl001", "options": { "requiredColumns": ["ID", "Status"] } },
    { "rule": "tbl002", "options": { "columns": ["ID", "Status"] } },
    { "rule": "ref001" }
  ]
}

Run:

npx contextlint

contextlint auto-detects contextlint.config.json from the current
or any parent directory. The include field defines default file
patterns; CLI arguments override it. When neither is set, **/*.md
is used.

Output:

docs/requirements.md
  line 3   warning  Empty cell in column "Status"  TBL-002

docs/design.md
  line 12  error    Link target "./api.md" does not exist  REF-001

1 error, 1 warning in 2 files

Adding $schema enables autocomplete in VS Code, Cursor,
JetBrains, and other editors.

Rules

Table rules

ID Description Config
TBL-001 Required columns must exist in tables requiredColumns, section?, files?
TBL-002 Key columns must not have empty cells columns?, files?
TBL-003 Column values must be from an allowed set column, values, files?
TBL-004 Cell values must match a regex pattern column, pattern, files?
TBL-005 Cross-column conditional constraints when, then, section?, files?
TBL-006 IDs must be unique across all matched files files, column, idPattern?

Section / Structure rules

ID Description Config
SEC-001 Required sections must exist sections, files?
SEC-002 Sections must appear in order order, level?, section?, files?
STR-001 Required files must exist in the project files

Reference rules

ID Description Config
REF-001 Relative links must point to existing files exclude?
REF-002 Defined IDs must be referenced; referenced IDs must exist definitions, references, idColumn, idPattern
REF-003 Stability must not exceed that of dependencies stabilityColumn, stabilityOrder, definitions, references, idColumn?, idPattern?
REF-004 Cross-zone links must be declared in overview zonesDir, dependencySection?
REF-005 Anchor fragments must point to existing headings files?
REF-006 Image references must point to existing files exclude?

Checklist rules

ID Description Config
CHK-001 All checklist items must be checked section?, files?

Context rules

ID Description Config
CTX-001 Sections must contain meaningful content, not placeholders section?, placeholders?, files?
CTX-002 Terms must match glossary definitions glossary, termColumn, aliasColumn?, section?, files?

Graph rules

ID Description Config
GRP-001 Every ID must be traceable through all stages of the document chain chain, idPattern?
GRP-002 Document reference graph must be acyclic (no circular references) files?, exclude?
GRP-003 Every document must have at least one incoming reference files?, entryPoints?

Configuration

{
  "$schema": "https://raw.githubusercontent.com/nozomi-koborinai/contextlint/main/schema.json",

  // Default file patterns (used when no files are specified on CLI)
  "include": ["docs/**/*.md"],

  "rules": [
    // TBL-001: Required columns must exist in tables
    { "rule": "tbl001", "options": { "requiredColumns": ["ID", "Status", "Description"], "files": "**/requirements.md" } },

    // TBL-002: Key columns must not have empty cells
    { "rule": "tbl002", "options": { "columns": ["ID", "Status"], "files": "**/requirements.md" } },

    // TBL-003: Column values must be from an allowed set
    { "rule": "tbl003", "options": { "column": "Status", "values": ["draft", "review", "stable"], "files": "**/requirements.md" } },

    // TBL-004: Cell values must match a regex pattern
    { "rule": "tbl004", "options": { "column": "ID", "pattern": "^[A-Z]+-[A-Z]+-\\d{2}$", "files": "**/requirements.md" } },

    // TBL-005: When a condition on one column is met, another column must satisfy a constraint
    { "rule": "tbl005", "options": { "when": { "column": "Status", "equals": "Done" }, "then": { "column": "Date", "notEmpty": true } } },

    // TBL-006: IDs must be unique across all matched files
    { "rule": "tbl006", "options": { "files": "**/requirements.md", "column": "ID" } },

    // SEC-001: Required sections must exist in the document
    { "rule": "sec001", "options": { "sections": ["Overview", "Requirements"], "files": "**/overview.md" } },

    // SEC-002: Sections must appear in the specified order
    //   Basic β€” check order across the whole file:
    { "rule": "sec002", "options": { "order": ["Overview", "Requirements", "Design"] } },
    //   With level β€” group by parent heading and check each group independently:
    { "rule": "sec002", "options": { "order": ["Overview", "Requirements", "Design"], "level": 3, "files": "**/spec.md" } },
    //   With section β€” scope to a specific parent group only:
    { "rule": "sec002", "options": { "order": ["Endpoints", "Error Handling"], "level": 3, "section": "API" } },

    // STR-001: Required files must exist in the project
    { "rule": "str001", "options": { "files": ["docs/overview.md", "docs/requirements.md"] } },

    // CHK-001: All checklist items must be checked
    { "rule": "chk001", "options": { "section": "Review Checklist", "files": "docs/reviews/*.md" } },

    // CTX-001: Sections must contain meaningful content, not placeholders
    { "rule": "ctx001", "options": { "section": "Overview", "files": "docs/**/*.md" } },

    // REF-001: Relative Markdown links must point to existing files
    { "rule": "ref001", "options": { "exclude": ["_references/**"] } },

    // REF-002: Defined IDs must be referenced; referenced IDs must exist
    {
      "rule": "ref002",
      "options": {
        "definitions": "**/requirements.md",
        "references": ["**/design.md", "**/overview.md"],
        "idColumn": "ID",
        "idPattern": "^REQ-"
      }
    },

    // REF-003: An item's stability must not exceed the stability of items it depends on
    {
      "rule": "ref003",
      "options": {
        "stabilityColumn": "Status",
        "stabilityOrder": ["draft", "review", "stable"],
        "definitions": "**/requirements.md",
        "references": ["**/design.md"]
      }
    },

    // REF-004: Cross-zone links must be declared in the zone's overview
    { "rule": "ref004", "options": { "zonesDir": "docs/zones" } },

    // REF-005: Anchor fragments must point to headings that exist in the target file
    { "rule": "ref005", "options": { "files": "docs/**/*.md" } },

    // REF-006: Image references must point to files that exist
    { "rule": "ref006", "options": { "exclude": ["*.svg"] } },

    // GRP-001: Every ID must be traceable through all stages of the document chain
    {
      "rule": "grp001",
      "options": {
        "chain": [
          { "stage": "Requirements", "files": "**/requirements.md", "idColumn": "ID" },
          { "stage": "Design", "files": "**/design.md", "refColumn": "Requirement" },
          { "stage": "Test", "files": "**/test-plan.md", "refColumn": "Covers" }
        ],
        "idPattern": "^REQ-\\d{3}$"
      }
    },

    // GRP-002: Document reference graph must be acyclic (no circular references)
    { "rule": "grp002", "options": { "files": "docs/**/*.md", "exclude": ["CHANGELOG.md"] } },
    // GRP-003: Every document must have at least one incoming reference
    { "rule": "grp003", "options": { "files": "docs/**/*.md", "entryPoints": ["README.md", "index.md"] } }
  ],

  // Context Compiler: generate SKILL.md for Claude Code
  "compile": {
    "skill": {
      "name": "my-project",
      "description": "Validate and maintain project documentation"
    },
    "outdir": ".claude/skills/my-project",
    "sections": {
      "architecture": true,
      "rules": true,
      "dependencies": true,
      "workflow": true
    }
  }
}

Use cases

These rules are designed to be general-purpose. Some examples:

  • SDD (Spec Driven Development) β€” Validate that specs
    reference existing requirements and that IDs are consistent
    across files
  • ADRs (Architecture Decision Records) β€” Ensure all ADRs
    contain required sections (Status, Context, Decision) and
    that status transitions are valid
  • RFCs (Request for Comments) β€” Check that RFC documents
    include required headings and that cross-references between
    proposals are not broken
  • Any structured Markdown project β€” Catch broken links,
    duplicate IDs, and missing files in CI

Commands

Init

contextlint init                    # Interactive config generation

Generates contextlint.config.json by selecting language, file patterns,
and rule categories interactively. Supports English, Japanese, Chinese,
and Korean.

Lint (default)

contextlint [files...]              # Lint structured Markdown documents
contextlint --format json           # Machine-readable output
contextlint --watch                 # Re-run on file changes

Impact Analysis

contextlint impact <file>           # Analyze change impact + lint affected files
contextlint impact docs/req.md --format json

Context Slice

contextlint slice <query>           # Extract related documents
contextlint slice docs/req.md --depth 3

Document Graph

contextlint graph                   # Show document dependency graph
contextlint graph --format json

Compile

contextlint compile                 # Generate SKILL.md for Claude Code
contextlint compile --dry-run       # Preview without writing
contextlint compile --outdir .claude/skills/my-skill

CLI Options

Option Description
[files...] File or glob patterns to lint (overrides include in config)
--config <path> Path to contextlint.config.json
--format <format> Output format: human (default) or json
--cwd <path> Working directory

JSON output

Use --format json for machine-readable output (useful for CI and editor integrations):

npx contextlint --format json
[
  {
    "file": "docs/requirements.md",
    "line": 12,
    "severity": "error",
    "message": "Required column \"Status\" not found in table",
    "ruleId": "TBL-001"
  }
]

CI Integration

GitHub Actions

A ready-to-use composite action is included in this repository.
It runs contextlint with --format json and creates inline annotations on PRs.

name: contextlint
on:
  pull_request:
    paths: ["docs/**"]
jobs:
  lint:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: nozomi-koborinai/contextlint/.github/actions/contextlint@main
        # with:
        #   config: 'contextlint.config.json'  # optional
        #   files: 'docs/**/*.md'              # optional
        #   version: 'latest'                  # optional

Or run directly:

- run: npx @contextlint/cli

Watch Mode

Re-run validation automatically when files change:

npx contextlint --watch
npx contextlint --watch docs/**/*.md
npx contextlint --watch --config contextlint.config.json

Watch mode runs an initial full lint, then monitors the working directory
for .md file changes. On each change it re-lints all matched files
(required for cross-file rules such as REF-002 and TBL-006), clears the
terminal, and displays the updated results with a timestamp. Rapid changes
are debounced (300 ms). Exit with Ctrl+C.

MCP Server

contextlint can run as an
MCP server, allowing AI
tools like Claude and Cursor to lint Markdown documents
during a conversation.

npm install -D @contextlint/mcp-server

Add to your mcp.json
(e.g. .cursor/mcp.json or claude_desktop_config.json):

{
  "mcpServers": {
    "contextlint": {
      "command": "npx",
      "args": ["@contextlint/mcp-server"]
    }
  }
}

Available tools:

Tool Description
lint Lint Markdown content directly with specified rules
lint-files Lint files matching glob patterns using a config file
context-graph Build and return the document dependency graph for the project
context-slice Extract the minimal set of documents relevant to a given query
impact-analysis Analyze which documents are affected by changes to a given file
compile-context Compile document structure into LLM context text

Programmatic API

Context Graph

@contextlint/core exposes a Context Graph API for analysing
document dependencies programmatically. This is useful for building
tools that need to understand how Markdown documents relate to each
other.

import {
  parseDocument,
  buildContextGraph,
  getImpactSet,
  getContextSlice,
  topologicalSort,
  getComponents,
  classifyImpact,
  compileContext,
} from "@contextlint/core";
import type { ContextGraph, GraphNode, GraphEdge } from "@contextlint/core";
Function Description
buildContextGraph(documents) Build a dependency graph from parsed documents
getImpactSet(graph, filePath) Get all files affected by changing a given file (direct + transitive)
getContextSlice(graph, documents, query, maxDepth?) Get the minimal set of files relevant to a query (file path or ID)
topologicalSort(graph) Topological sort of the document graph (dependency order)
getComponents(graph) Get connected components (clusters of related files)
classifyImpact(graph, filePath) Classify impact as direct vs transitive
compileContext(patterns, config, cwd) Compile documents + config into SKILL.md content

Example:

import { readFileSync } from "node:fs";
import { parseDocument, buildContextGraph, getImpactSet } from "@contextlint/core";

// Parse documents
const documents = new Map();
documents.set("docs/overview.md", parseDocument(readFileSync("docs/overview.md", "utf-8")));
documents.set("docs/requirements.md", parseDocument(readFileSync("docs/requirements.md", "utf-8")));
documents.set("docs/design.md", parseDocument(readFileSync("docs/design.md", "utf-8")));

// Build the graph
const graph = buildContextGraph(documents);

// What files are impacted if requirements.md changes?
const impacted = getImpactSet(graph, "docs/requirements.md");
// => ["docs/design.md", "docs/overview.md"]

Context Compiler

The Context Compiler is a deterministic pipeline that transforms your
documents and config into a SKILL.md file for
Claude Code custom skills.
Same config + same documents always produces the same output -- no LLM
involved.

How it works

  1. Load documents matching include patterns
  2. Build the dependency graph and classify each document's role
    (entry, hub, leaf, bridge, isolated)
  3. Extract document profiles (outline, table schemas, references)
  4. Describe active lint rules in natural language
  5. Synthesize everything into a single SKILL.md

Config

Add a compile section to contextlint.config.json:

{
  "include": ["docs/**/*.md"],
  "compile": {
    "skill": {
      "name": "my-project-docs",
      "description": "Validate and maintain project documentation"
    },
    "outdir": ".claude/skills/my-project",
    "sections": {
      "architecture": true,
      "rules": true,
      "dependencies": true,
      "workflow": true
    }
  },
  "rules": []
}
Field Description
skill.name Skill name for SKILL.md frontmatter (required)
skill.description Skill description for SKILL.md frontmatter (required)
outdir Output directory (default: .claude/skills/contextlint)
sections.architecture Include architecture overview
sections.rules Include active lint rules
sections.dependencies Include dependency graph
sections.workflow Include workflow instructions

Usage

# Generate SKILL.md
contextlint compile

# Preview without writing
contextlint compile --dry-run

# Custom output directory
contextlint compile --outdir .claude/skills/my-skill

CI integration

Add to your CI pipeline to keep SKILL.md in sync with documentation:

- run: npx contextlint compile --dry-run

Packages

Package Description
@contextlint/core Rule engine and Markdown parser
@contextlint/cli CLI entry point (contextlint command)
@contextlint/mcp-server MCP server for AI tool integration

Resources

License

MIT

Reviews (0)

No results found