
Markdownlint Integration
- 71 installs
- 186 repo stars
- Updated July 19, 2026
- thebushidocollective/han
Helps with code review & quality tasks during AI-assisted development.
About
markdownlint-integration is a Claude Code skill for code review & quality. It helps solo builders move faster with AI-assisted coding.
- markdownlint-integration
- Code Review & Quality
- AI-coding skill
Markdownlint Integration by the numbers
- 71 all-time installs (skills.sh)
- +2 installs in the week ending Jul 27, 2026 (Skillselion tracking)
- Ranked #517 of 1,352 Code Review & Quality skills by installs in the Skillselion catalog
- Data as of Aug 1, 2026 (Skillselion catalog sync)
npx skills add https://github.com/thebushidocollective/han --skill markdownlint-integrationAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 71 |
|---|---|
| repo stars | ★ 186 |
| Last updated | July 19, 2026 |
| Repository | thebushidocollective/han ↗ |
What it does
Helps with code review & quality tasks during AI-assisted development.
Files
Markdownlint Integration
Master integrating markdownlint into development workflows including CLI usage, programmatic API (sync/async/promise), CI/CD pipelines, pre-commit hooks, and editor integration.
Overview
Markdownlint can be integrated into various parts of your development workflow to ensure consistent markdown quality. This includes command-line tools, programmatic usage in Node.js, continuous integration pipelines, Git hooks, and editor plugins.
Command-Line Interface
markdownlint-cli Installation
npm install -g markdownlint-cli
# or as dev dependency
npm install --save-dev markdownlint-cliBasic CLI Usage
# Lint all markdown files in current directory
markdownlint '**/*.md'
# Lint specific files
markdownlint README.md CONTRIBUTING.md
# Lint with configuration file
markdownlint -c .markdownlint.json '**/*.md'
# Ignore specific files
markdownlint '**/*.md' --ignore node_modules
# Fix violations automatically
markdownlint -f '**/*.md'
# Output to file
markdownlint '**/*.md' -o linting-results.txtAdvanced CLI Options
# Use custom config
markdownlint --config config/markdown-lint.json docs/
# Ignore patterns from file
markdownlint --ignore-path .gitignore '**/*.md'
# Use multiple ignore patterns
markdownlint --ignore node_modules --ignore dist '**/*.md'
# Enable specific rules only
markdownlint --rules MD001,MD003,MD013 '**/*.md'
# Disable specific rules
markdownlint --disable MD013 '**/*.md'
# Show output in JSON format
markdownlint --json '**/*.md'
# Quiet mode (exit code only)
markdownlint -q '**/*.md'
# Verbose output
markdownlint --verbose '**/*.md'CLI Configuration File
.markdownlint-cli.json:
{
"config": {
"default": true,
"MD013": {
"line_length": 100
}
},
"files": ["**/*.md"],
"ignores": [
"node_modules/**",
"dist/**",
"build/**"
]
}Use with:
markdownlint --config .markdownlint-cli.jsonProgrammatic API
Callback-Based API
const markdownlint = require('markdownlint');
const options = {
files: ['good.md', 'bad.md'],
config: {
default: true,
'line-length': {
line_length: 100
}
}
};
markdownlint(options, (err, result) => {
if (!err) {
console.log(result.toString());
} else {
console.error(err);
}
});Promise-Based API
import { lint as lintPromise } from 'markdownlint/promise';
const options = {
files: ['README.md', 'docs/**/*.md'],
config: {
default: true,
'no-inline-html': {
allowed_elements: ['br', 'img']
}
}
};
try {
const results = await lintPromise(options);
console.dir(results, { colors: true, depth: null });
} catch (err) {
console.error(err);
}Synchronous API
import { lint as lintSync } from 'markdownlint/sync';
const options = {
files: ['README.md'],
strings: {
'inline-content': '# Test\n\nContent here.'
},
config: {
default: true
}
};
const results = lintSync(options);
console.log(results.toString());Linting Strings
const markdownlint = require('markdownlint');
const options = {
strings: {
'content-1': '# Heading\n\nParagraph text.',
'content-2': '## Another heading\n\nMore content.'
},
config: {
default: true,
'first-line-heading': {
level: 1
}
}
};
markdownlint(options, (err, result) => {
if (!err) {
const resultString = result.toString();
console.log(resultString);
}
});Working with Results
import { lint } from 'markdownlint/promise';
const results = await lint({
files: ['docs/**/*.md'],
config: { default: true }
});
// Results is an object keyed by filename
Object.keys(results).forEach(file => {
const fileResults = results[file];
fileResults.forEach(result => {
console.log(`${file}:${result.lineNumber} ${result.ruleNames.join('/')} ${result.ruleDescription}`);
if (result.errorDetail) {
console.log(` Detail: ${result.errorDetail}`);
}
if (result.errorContext) {
console.log(` Context: ${result.errorContext}`);
}
});
});Reading Configuration
const markdownlint = require('markdownlint');
const { readConfigSync } = require('markdownlint/sync');
// Read configuration from file
const config = readConfigSync('.markdownlint.json');
const options = {
files: ['**/*.md'],
config: config
};
const results = markdownlint.sync(options);
console.log(results.toString());Using Custom Rules
const markdownlint = require('markdownlint');
const customRule = require('./custom-rules/heading-capitalization');
const options = {
files: ['README.md'],
config: {
default: true,
'heading-capitalization': true
},
customRules: [customRule]
};
markdownlint(options, (err, result) => {
if (!err) {
console.log(result.toString());
}
});Applying Fixes Programmatically
applyFix Function
const { applyFix } = require('markdownlint');
const line = ' Text with extra spaces ';
const fixInfo = {
editColumn: 1,
deleteCount: 2,
insertText: ''
};
const fixed = applyFix(line, fixInfo);
console.log(fixed); // 'Text with extra spaces 'applyFixes Function
const { applyFixes } = require('markdownlint');
const input = '# Heading\n\n\nParagraph';
const errors = [
{
lineNumber: 3,
ruleNames: ['MD012'],
ruleDescription: 'Multiple blank lines',
fixInfo: {
lineNumber: 3,
deleteCount: -1
}
}
];
const fixed = applyFixes(input, errors);
console.log(fixed); // '# Heading\n\nParagraph'Auto-Fix Workflow
const fs = require('fs');
const markdownlint = require('markdownlint');
const { applyFixes } = require('markdownlint');
const file = 'README.md';
const content = fs.readFileSync(file, 'utf8');
const options = {
strings: {
[file]: content
},
config: {
default: true
}
};
markdownlint(options, (err, result) => {
if (!err) {
const errors = result[file] || [];
if (errors.length > 0) {
const fixed = applyFixes(content, errors);
fs.writeFileSync(file, fixed, 'utf8');
console.log(`Fixed ${errors.length} issues in ${file}`);
}
}
});CI/CD Integration
GitHub Actions
.github/workflows/markdownlint.yml:
name: Markdownlint
user-invocable: false
on:
push:
branches: [main, develop]
pull_request:
branches: [main]
jobs:
lint:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v3
- name: Setup Node.js
uses: actions/setup-node@v3
with:
node-version: '18'
- name: Install dependencies
run: npm ci
- name: Run markdownlint
run: npx markdownlint '**/*.md' --ignore node_modules
- name: Annotate PR with results
if: failure()
run: |
npx markdownlint '**/*.md' --ignore node_modules -o markdownlint-results.txt
cat markdownlint-results.txtGitHub Actions with markdownlint-cli2
name: Markdownlint
user-invocable: false
on: [push, pull_request]
jobs:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Run markdownlint-cli2
uses: DavidAnson/markdownlint-cli2-action@v9
with:
paths: '**/*.md'GitLab CI
.gitlab-ci.yml:
markdownlint:
image: node:18-alpine
stage: test
before_script:
- npm install -g markdownlint-cli
script:
- markdownlint '**/*.md' --ignore node_modules
only:
- merge_requests
- main
artifacts:
when: on_failure
paths:
- markdownlint-results.txtCircleCI
.circleci/config.yml:
version: 2.1
jobs:
markdownlint:
docker:
- image: cimg/node:18.0
steps:
- checkout
- run:
name: Install markdownlint
command: npm install -g markdownlint-cli
- run:
name: Run linter
command: markdownlint '**/*.md' --ignore node_modules
workflows:
version: 2
build_and_test:
jobs:
- markdownlintJenkins Pipeline
Jenkinsfile:
pipeline {
agent any
stages {
stage('Lint Markdown') {
steps {
sh 'npm install -g markdownlint-cli'
sh 'markdownlint "**/*.md" --ignore node_modules'
}
}
}
post {
always {
cleanWs()
}
failure {
echo 'Markdownlint found issues!'
}
}
}Azure Pipelines
azure-pipelines.yml:
trigger:
- main
pool:
vmImage: 'ubuntu-latest'
steps:
- task: NodeTool@0
inputs:
versionSpec: '18.x'
displayName: 'Install Node.js'
- script: |
npm install -g markdownlint-cli
displayName: 'Install markdownlint'
- script: |
markdownlint '**/*.md' --ignore node_modules
displayName: 'Run markdownlint'Pre-commit Hooks
Using Husky
Install Husky:
npm install --save-dev husky
npx husky installCreate pre-commit hook:
npx husky add .husky/pre-commit "npm run lint:md"Add script to package.json:
{
"scripts": {
"lint:md": "markdownlint '**/*.md' --ignore node_modules",
"lint:md:fix": "markdownlint -f '**/*.md' --ignore node_modules"
}
}Using lint-staged
Install lint-staged:
npm install --save-dev lint-stagedConfigure in package.json:
{
"lint-staged": {
"*.md": [
"markdownlint --fix",
"git add"
]
}
}Update pre-commit hook:
npx husky add .husky/pre-commit "npx lint-staged"Using pre-commit Framework
.pre-commit-config.yaml:
repos:
- repo: https://github.com/igorshubovych/markdownlint-cli
rev: v0.37.0
hooks:
- id: markdownlint
args: ['--fix']
- repo: https://github.com/DavidAnson/markdownlint-cli2
rev: v0.10.0
hooks:
- id: markdownlint-cli2
args: ['--fix']Install and use:
pip install pre-commit
pre-commit install
pre-commit run --all-filesEditor Integration
Visual Studio Code
Install the markdownlint extension:
1. Open VS Code 2. Go to Extensions (Cmd+Shift+X) 3. Search for "markdownlint" 4. Install "markdownlint" by David Anson
Configure in .vscode/settings.json:
{
"markdownlint.config": {
"default": true,
"MD013": {
"line_length": 100
}
},
"markdownlint.ignore": [
"node_modules/**",
"dist/**"
],
"editor.codeActionsOnSave": {
"source.fixAll.markdownlint": true
}
}Vim/Neovim
Using ALE (Asynchronous Lint Engine):
" In .vimrc or init.vim
let g:ale_linters = {
\ 'markdown': ['markdownlint'],
\}
let g:ale_fixers = {
\ 'markdown': ['markdownlint'],
\}
let g:ale_markdown_markdownlint_options = '-c .markdownlint.json'
" Enable fixing on save
let g:ale_fix_on_save = 1Sublime Text
Install via Package Control:
1. Install Package Control 2. Install "SublimeLinter" 3. Install "SublimeLinter-contrib-markdownlint"
Configure in preferences:
{
"linters": {
"markdownlint": {
"args": ["-c", ".markdownlint.json"]
}
}
}Atom
Install packages:
apm install linter-markdownlintConfigure in Atom settings or .atom/config.cson:
"linter-markdownlint":
configPath: ".markdownlint.json"npm Scripts Integration
package.json Scripts
{
"scripts": {
"lint": "npm run lint:md",
"lint:md": "markdownlint '**/*.md' --ignore node_modules",
"lint:md:fix": "markdownlint -f '**/*.md' --ignore node_modules",
"lint:md:ci": "markdownlint '**/*.md' --ignore node_modules -o markdownlint-report.txt",
"test": "npm run lint && npm run test:unit",
"precommit": "lint-staged"
}
}Cross-Platform Compatibility
Using cross-env for environment variables:
{
"scripts": {
"lint:md": "cross-env NODE_ENV=development markdownlint '**/*.md'"
},
"devDependencies": {
"cross-env": "^7.0.3"
}
}Docker Integration
Dockerfile
FROM node:18-alpine
WORKDIR /app
# Install markdownlint globally
RUN npm install -g markdownlint-cli
# Copy markdown files
COPY . .
# Run linter
CMD ["markdownlint", "**/*.md", "--ignore", "node_modules"]docker-compose.yml
version: '3.8'
services:
markdownlint:
image: node:18-alpine
working_dir: /app
volumes:
- .:/app
command: >
sh -c "npm install -g markdownlint-cli &&
markdownlint '**/*.md' --ignore node_modules"Run with:
docker-compose run markdownlintMonorepo Integration
Workspace Configuration
Root .markdownlint.json:
{
"default": true,
"line-length": {
"line_length": 100
}
}Root package.json:
{
"scripts": {
"lint:md": "markdownlint '**/*.md' --ignore node_modules",
"lint:md:packages": "lerna run lint:md",
"lint:md:all": "npm run lint:md && npm run lint:md:packages"
}
}Package-level packages/api/package.json:
{
"scripts": {
"lint:md": "markdownlint '**/*.md'"
}
}Using Lerna
{
"scripts": {
"lint:md": "lerna run lint:md --stream"
}
}Using Turborepo
turbo.json:
{
"pipeline": {
"lint:md": {
"outputs": []
}
}
}Reporting and Metrics
Generate HTML Report
Using a custom script:
const fs = require('fs');
const markdownlint = require('markdownlint');
const options = {
files: ['**/*.md'],
config: { default: true }
};
markdownlint(options, (err, results) => {
if (!err) {
const html = generateHtmlReport(results);
fs.writeFileSync('markdownlint-report.html', html);
}
});
function generateHtmlReport(results) {
let html = '<html><head><title>Markdownlint Report</title></head><body>';
html += '<h1>Markdownlint Results</h1>';
Object.keys(results).forEach(file => {
html += `<h2>${file}</h2>`;
html += '<ul>';
results[file].forEach(result => {
html += `<li>Line ${result.lineNumber}: ${result.ruleDescription}</li>`;
});
html += '</ul>';
});
html += '</body></html>';
return html;
}JSON Output for Tooling
markdownlint '**/*.md' --json > results.jsonProcess with jq:
markdownlint '**/*.md' --json | jq '.[] | select(length > 0)'When to Use This Skill
- Setting up markdownlint in new projects
- Integrating linting into CI/CD pipelines
- Configuring pre-commit hooks
- Automating documentation quality checks
- Setting up editor integration
- Building custom linting workflows
- Creating automated fix scripts
- Implementing documentation standards
Best Practices
1. CI/CD Integration - Always run linting in continuous integration 2. Pre-commit Hooks - Catch issues before they reach version control 3. Editor Integration - Get real-time feedback while writing 4. Consistent Configuration - Use same config across all environments 5. Auto-fix When Possible - Use -f flag to automatically fix violations 6. Fail Fast - Configure CI to fail on linting errors 7. Ignore Generated Files - Exclude build artifacts and dependencies 8. Version Lock - Pin markdownlint version in package.json 9. Document Standards - Keep documentation on linting rules 10. Progressive Enhancement - Start with relaxed rules, tighten over time 11. Team Communication - Discuss rule changes before applying 12. Regular Updates - Keep markdownlint updated for bug fixes 13. Performance Optimization - Use appropriate glob patterns 14. Error Reporting - Configure meaningful error output 15. Backup Before Auto-fix - Always commit before running fixes
Common Pitfalls
1. Missing Ignore Patterns - Linting node_modules or build directories 2. Wrong Glob Patterns - Incorrect file matching in CLI 3. Config Not Found - Configuration file in wrong location 4. Async/Sync Mismatch - Using sync API with async rules 5. CI Timeout - Linting too many files without optimization 6. No Exit Code Check - Not failing CI on linting errors 7. Overwriting Files - Using auto-fix without version control 8. Missing Dependencies - Not installing markdownlint in CI 9. Platform Differences - Path separators differ between OS 10. Large Binary Files - Accidentally linting non-markdown files 11. Outdated Cache - Cached node_modules with old markdownlint 12. Silent Failures - Not capturing error output in CI 13. Config Conflicts - Multiple config files conflicting 14. Missing Editor Config - Local linting differs from CI 15. No Pre-commit Hook - Issues not caught before commit