SKILL.md
Markdown Author
Overview
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.
Prerequisites
.markdownlint.jsonconfiguration (create with defaults if missing - see Configuration Verification)cspell.jsonspelling configuration (create with defaults if missing - see Configuration Verification)- markdownlint-cli2 and cspell installed (via package.json)
When to Use
- Writing new markdown files (.md)
- Editing existing markdown files
- Creating documentation, README files, plans
- Writing skill specifications
Do not use for:
- Non-markdown files
- Generated markdown (tool output)
- Third-party markdown (node_modules, etc.)
Configuration Verification (First Use)
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:
``json { "default": true, "MD013": { "linelength": 120, "codeblocks": 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:
``json { "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:
- Read enabled rules from .markdownlint.json - Read spelling locale and custom dictionary from cspell.json - Cache for session (don't re-read for each file)
Core Workflow
Before Writing Markdown
- Load markdown-author skill if not already loaded
- Verify configurations exist (first use only)
- Read
.markdownlint.jsonto determine enabled rules - Read
cspell.jsonfor spelling configuration
During Writing
For each markdown content section:
- Analyze document structure:
- Identify existing heading levels - Determine appropriate next heading level - Note any lists, blockquotes, tables
- Compose content with validation:
- Check line length as writing (120 char default) - Validate heading hierarchy - Check spelling against cspell configuration - Detect code fences without language
- Apply auto-fixes silently:
- Break long lines at word boundaries - Adjust heading levels to maintain hierarchy - Strip trailing whitespace - Normalize list spacing - Fix emphasis/link syntax
- Block for structural decisions:
- Code fence missing language → Prompt for language - Spelling error → Fix or add to dictionary - Duplicate heading → Rename or confirm
- Log summary after writing:
<!-- markdownlint-disable MD040 -->
`` ✓ 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 ``
After Writing
- Write validated markdown to file
- Git hooks run as safety net (markdownlint-cli2, cspell)
- If hooks fail, investigate why skill didn't catch violation
Validation Rules
See [Validation Rules Reference](references/validation-rules.md) for complete list.
Auto-Fixable Rules
Applied silently without interruption:
- MD001: Heading hierarchy - Auto-adjust levels to maintain proper structure
- MD013: Line length - Break at word boundaries, respect code/table exclusions
- MD009: Trailing spaces - Strip automatically
- MD010: Hard tabs - Replace with spaces
- MD012: Multiple blank lines - Collapse to single
- MD030/MD032: List spacing - Normalize
- All formatting rules: Applied per .markdownlint.json configuration
Blocking Rules
Require agent decision:
- MD040: Code fence language - Agent must specify (bash, python, csharp, text, etc.)
- MD024: Duplicate headings - Agent must rename or confirm
- MD045: Image alt text - Agent must provide
- Spelling errors: Agent must fix or add to cspell.json dictionary
Error Handling
Configuration Errors
Malformed JSON:
`````text Error: .markdownlint.json is invalid JSON Line 5: Unexpected token }
Fix syntax or delete file to regenerate with defaults.
**Missing required fields:**
Error: cspell.json missing 'version' field
Add field or delete file to regenerate with defaults.
### Blocking Violations
**Code fence without language:**
⚠ Markdown validation error: Line 45: Code fence requires language specification
Current:
npm install
Options:
- bash (recommended for shell commands)
- text (for plain text)
- json, yaml, markdown, etc.
What language should this code fence use?
**Spelling error:**
⚠ Spelling error detected: Line 12: Unknown word 'agentskills'
Options:
- Add to cspell.json custom dictionary (recommended for project terms)
- Fix spelling
- Ignore (not recommended)
How should this be handled?
**Duplicate heading:**
⚠ Duplicate heading detected: Line 67: "## Implementation" already exists at line 34
This may cause navigation issues. Options:
- Rename to "## Implementation Details"
- Rename to "## Implementation (Phase 2)"
- Keep as-is (not recommended)
How should this be resolved?
### Graceful Degradation
If configuration error prevents full validation:
⚠ 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
## Example
### Writing New Documentation
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.
def validate_token(token):
return jwt.decode(token)
[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
### Editing Existing 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]
## 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
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):**
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):**
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):**
Main Title
Skipped Level
Content here jumps from h1 to h3.
**After (fixed):**
Main Title
Proper Level
Content here follows h1 → h2 hierarchy.
### Code Fence Language (MD040)
**Before (violation):**
````markdown
npm install npm run build
`````
**After (fixed):**
````markdown
npm install npm run build
````
### Spelling Error
**Before (violation):**
The agentskills module provides reusable behaviours.
**After (fixed - add to dictionary):**
// cspell.json { "words": ["agentskills"] }
The agentskills module provides reusable behaviours.
## Validation Commands
### Quick Validation
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"
### Pre-Commit Validation
Run what pre-commit will run
npx lint-staged --dry-run
Run lint-staged for real
npx lint-staged
### CI Validation
GitHub Actions example
- name: Lint Markdown
run: npx markdownlint-cli2 "**/*.md"
- name: Check Spelling
run: npx cspell "**/*.md" --no-progress
### VS Code Integration
// .vscode/settings.json { "editor.formatOnSave": true, "markdownlint.config": { "extends": "./.markdownlint.json" }, "cSpell.enabled": true }
### Validation Script
#!/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 ==="