Use when writing or editing markdown to proactively enforce linting rules and spelling standards, preventing violations before commit.
Proactively enforce markdown linting rules and spelling standards during writing, preventing violations before they're committed. Auto-fix formatting issues, block for structural decisions requiring context.
Git hooks remain as safety net for non-skill markdown changes.
.markdownlint.json configuration (create with defaults if missing - see Configuration Verification)cspell.json spelling configuration (create with defaults if missing - see Configuration Verification)Do not use for:
On first use in repository, verify configurations exist:
Check .markdownlint.json:
If exists: Parse and validate JSON
If missing: Use Write tool to create with defaults:
{
"default": true,
"MD013": {
"line_length": 120,
"code_blocks": false,
"tables": false
},
"MD024": { "siblings_only": true },
"MD033": false,
"MD041": false
}
If malformed: Error with message to fix or delete
Check cspell.json:
If exists: Parse and validate JSON
If missing: Use Write tool to create with defaults:
{
"version": "0.2",
"language": "en-US",
"words": [],
"ignorePaths": ["node_modules/**", "package-lock.json"]
}
If malformed: Error with message to fix or delete
Load rule configuration:
.markdownlint.jsoncspell.json.markdownlint.json to determine enabled rulescspell.json for spelling configurationFor each markdown content section:
Analyze document structure:
Compose content with validation:
Apply auto-fixes silently:
Block for structural decisions:
Log summary after writing:
ā Markdown validated and auto-fixed:
<!-- markdownlint-enable MD040 -->
- Adjusted 3 lines exceeding 120 characters
- Fixed heading hierarchy (h3 ā h2)
- Added 1 term to cspell dictionary
See Validation Rules Reference for complete list.
Applied silently without interruption:
Require agent decision:
Malformed JSON:
Error: .markdownlint.json is invalid JSON
Line 5: Unexpected token }
Fix syntax or delete file to regenerate with defaults.
```text
**Missing required fields:**
```text
Error: cspell.json missing 'version' field
Add field or delete file to regenerate with defaults.
```text
### Blocking Violations
**Code fence without language:**
```text
ā Markdown validation error:
Line 45: Code fence requires language specification
Current:
```text
npm install
```text
Options:
- bash (recommended for shell commands)
- text (for plain text)
- json, yaml, markdown, etc.
What language should this code fence use?
```text
**Spelling error:**
```text
ā Spelling error detected:
Line 12: Unknown word 'agentskills'
Options:
1. Add to cspell.json custom dictionary (recommended for project terms)
2. Fix spelling
3. Ignore (not recommended)
How should this be handled?
```text
**Duplicate heading:**
```text
ā Duplicate heading detected:
Line 67: "## Implementation" already exists at line 34
This may cause navigation issues. Options:
1. Rename to "## Implementation Details"
2. Rename to "## Implementation (Phase 2)"
3. Keep as-is (not recommended)
How should this be resolved?
```text
### Graceful Degradation
If configuration error prevents full validation:
```text
ā markdown-author skill error: Unable to parse .markdownlint.json
Falling back to basic validation (line length, code fences only)
Full linting will run in pre-commit hook.
Consider fixing configuration: .markdownlint.json
```text
## Example
### Writing New Documentation
```markdown
User: "Create architecture documentation"
Agent: [Loads markdown-author skill]
Agent: [Verifies .markdownlint.json exists]
Agent: [Verifies cspell.json exists]
Agent: [Begins composing architecture.md]
Content composed:
# Architecture Overview
This document describes the system architecture...
[Spell check detects: architecture ā architecture]
ā Spelling error: 'architecture'. Did you mean: 'architecture'?
Agent: [Corrects to 'architecture']
The application uses a microservices approach with the following components:
[Spell check detects: components ā components]
ā Spelling error: 'components'. Did you mean: 'components'?
Agent: [Corrects to 'components']
### API Gateway
[Heading hierarchy: h1 ā h3, auto-corrects to h2]
## API Gateway
Handles all incoming requests and routes to appropriate services. The gateway validates authentication tokens, applies rate limiting, and logs all requests for monitoring purposes.
[Line length: 165 chars, auto-breaks at word boundary]
Handles all incoming requests and routes to appropriate services. The gateway
validates authentication tokens, applies rate limiting, and logs all requests
for monitoring purposes.
```python
def validate_token(token):
return jwt.decode(token)
```text
[Code fence has language: python ā]
ā Markdown validated and auto-fixed:
- Fixed 2 spelling errors
- Adjusted heading hierarchy (h3 ā h2)
- Broke 1 line exceeding 120 characters
```text
### Editing Existing Markdown
```markdown
Agent: [Loads markdown-author skill]
Agent: [Reads existing document structure: h1, h2, h2, h3]
Agent: [Plans to add new section at same level as last h2]
Adding new content:
## New Feature
[Heading level: h2 - correct for sibling section ā]
Implementation details follow...
[Validation passes, writes to file]
```text
## Common Mistakes
- Writing markdown without loading skill first
- Ignoring blocking violations (spelling, code fence language)
- Proceeding when configuration malformed
- Not adding project-specific terms to cspell.json dictionary
- Disabling rules in config without understanding impact
- Using --no-verify to bypass pre-commit hooks (skill should catch issues first)
## Red Flags - STOP
- "I'll skip the code fence language, it's obvious"
- "Spelling check is too strict, I'll ignore it"
- "Line length doesn't matter, I'll disable the rule"
- "I'll fix the linting errors later"
- "The configuration is broken but I'll write anyway"
- "--no-verify is faster, I'll use that"
## Rationalizations (and Reality)
| Excuse | Reality |
| ------------------------------------------- | -------------------------------------------------------- |
| "Line length doesn't affect readability" | 120 chars is readability standard, pre-commit will fail |
| "Code fence language is obvious from code" | Syntax highlighting requires explicit language |
| "Spelling errors are minor" | Breaks cspell pre-commit hook, blocks entire commit |
| "I'll fix linting issues in next commit" | Creates broken window, forces --no-verify bypasses |
| "Configuration is too strict" | Rules exist for consistency, modify config if needed |
| "Pre-commit hooks will catch it" | Hooks are safety net, skill prevents issues proactively |
## Reference Templates
Choose a template based on project needs:
| Template | Use Case | Line Length | HTML |
| ----------------------------------------------------------------- | ---------------------------- | ----------- | --------- |
| [markdownlint-default.json](templates/markdownlint-default.json) | Most projects | 120 | Allowed |
| [markdownlint-strict.json](templates/markdownlint-strict.json) | Documentation-heavy projects | 80 | Limited |
| [markdownlint-minimal.json](templates/markdownlint-minimal.json) | Simple projects | Unlimited | Allowed |
| [cspell-default.json](templates/cspell-default.json) | All projects | N/A | N/A |
### Quick Setup
```bash
# Default configuration (recommended)
cp templates/markdownlint-default.json.template .markdownlint.json
cp templates/cspell-default.json.template cspell.json
# Strict configuration for docs-heavy projects
cp templates/markdownlint-strict.json.template .markdownlint.json
# Minimal configuration for simple projects
cp templates/markdownlint-minimal.json.template .markdownlint.json
```
## See Also
- [Validation Rules Reference](references/validation-rules.md) - Complete markdownlint rule list
- [Spelling Configuration](references/spelling-configuration.md) - cspell setup and custom dictionary
- [Editor Integration](references/editor-integration.md) - VS Code and other editor setup
- Pre-commit hooks: `.husky/pre-commit` and `package.json` lint-staged configuration
- markdownlint rules: <https://github.com/DavidAnson/markdownlint/blob/main/doc/Rules.md>
## Before/After Examples
### Line Length (MD013)
**Before (violation):**
```markdown
This is a very long line that exceeds the configured line length limit of 120 characters and will cause the markdownlint check to fail when committed.
```
**After (fixed):**
```markdown
This is a very long line that exceeds the configured line length limit of 120
characters and will cause the markdownlint check to fail when committed.
```
### Heading Hierarchy (MD001)
**Before (violation):**
```markdown
# Main Title
### Skipped Level
Content here jumps from h1 to h3.
```
**After (fixed):**
```markdown
# Main Title
## Proper Level
Content here follows h1 ā h2 hierarchy.
```
### Code Fence Language (MD040)
**Before (violation):**
````markdown
```
npm install
npm run build
```
After (fixed):
```bash
npm install
npm run build
```
Before (violation):
The agentskills module provides reusable behaviours.
After (fixed - add to dictionary):
// cspell.json
{
"words": ["agentskills"]
}
The agentskills module provides reusable behaviours.
# Validate single file
npx markdownlint-cli2 "path/to/file.md"
# Validate with auto-fix
npx markdownlint-cli2 --fix "path/to/file.md"
# Check spelling
npx cspell "path/to/file.md"
# Validate all markdown files
npx markdownlint-cli2 "**/*.md"
npx cspell "**/*.md"
# Run what pre-commit will run
npx lint-staged --dry-run
# Run lint-staged for real
npx lint-staged
# GitHub Actions example
- name: Lint Markdown
run: npx markdownlint-cli2 "**/*.md"
- name: Check Spelling
run: npx cspell "**/*.md" --no-progress
// .vscode/settings.json
{
"editor.formatOnSave": true,
"markdownlint.config": {
"extends": "./.markdownlint.json"
},
"cSpell.enabled": true
}
#!/bin/bash
# validate-markdown.sh
echo "=== Markdown Validation ==="
# Count files
FILES=$(find . -name "*.md" -not -path "./node_modules/*" | wc -l)
echo "Found $FILES markdown files"
# Run markdownlint
echo ""
echo "Running markdownlint..."
if npx markdownlint-cli2 "**/*.md" --ignore node_modules; then
echo "ā Markdownlint passed"
else
echo "ā Markdownlint failed"
exit 1
fi
# Run cspell
echo ""
echo "Running cspell..."
if npx cspell "**/*.md" --no-progress; then
echo "ā Spelling check passed"
else
echo "ā Spelling check failed"
exit 1
fi
echo ""
echo "=== All checks passed ==="