Vault Linting and Formatting Setup
This guide documents the automated linting, formatting, and frontmatter validation setup for the Obsidian vault.
Overview
The setup uses pre-commit hooks to automatically:
- Ensure frontmatter — adds
created,updated,titlefields - Format markdown — consistent style via mdformat
- Lint markdown — catch issues via markdownlint
Installation
Prerequisites
- Python 3.8+
- Node.js 16+
- Git
Install dependencies
# Python packages
pip install pre-commit python-frontmatter jsonschema pyyaml \
mdformat mdformat-obsidian mdformat-frontmatter mdformat-gfm \
mdformat-wikilink mdformat-simple-breaks
# Node.js packages
npm install -g markdownlint-cli2Enable pre-commit hooks
# Install hooks into git
pre-commit install
# Run on all files (first time)
pre-commit run --all-filesConfiguration Files
.pre-commit-config.yaml
Main pre-commit configuration that defines the hook pipeline:
repos:
# Frontmatter validation and auto-update
- repo: local
hooks:
- id: ensure-frontmatter
name: Ensure frontmatter
entry: python scripts/ensure_frontmatter.py
language: python
types: [markdown]
additional_dependencies:
- python-frontmatter
- jsonschema
- pyyaml
# Markdown formatting
- repo: https://github.com/executablebooks/mdformat
rev: 0.7.19
hooks:
- id: mdformat
additional_dependencies:
- mdformat-obsidian # callouts, footnotes, task lists
- mdformat-frontmatter # preserve YAML frontmatter
- mdformat-gfm # GitHub Flavored Markdown
- mdformat-wikilink # preserve [[wikilinks]]
- mdformat-simple-breaks # use --- for horizontal rules
exclude: |
(?x)^(
\.obsidian/.*|
\.git/.*|
\.skills/.*|
\.claude/.*|
\.claude-plugin/.*
)$
# Markdown linting
- repo: https://github.com/DavidAnson/markdownlint-cli2
rev: v0.14.0
hooks:
- id: markdownlint-cli2
exclude: |
(?x)^(
\.obsidian/.*|
\.git/.*|
\.skills/.*|
\.claude/.*|
\.claude-plugin/.*
)$.markdownlint-cli2.yaml
Markdownlint rules configured to match mdformat output:
| Rule | Setting | Reason |
|---|---|---|
| MD007 | disabled | mdformat handles list indentation |
| MD013 | disabled | mdformat handles line wrapping |
| MD022 | disabled | mdformat handles heading spacing |
| MD029 | style: one | mdformat uses 1. for all ordered lists |
| MD031 | disabled | mdformat handles fence spacing |
| MD033 | disabled | allow inline HTML |
| MD035 | disabled | allow any horizontal rule style |
| MD036 | disabled | allow emphasis as headings |
| MD040 | disabled | allow code blocks without language |
| MD041 | disabled | frontmatter comes before first heading |
| MD060 | disabled | allow compact tables |
schemas/note.schema.json
JSON Schema for frontmatter validation:
{
"type": "object",
"required": ["title", "created"],
"properties": {
"title": {"type": "string", "minLength": 1},
"created": {"type": "string", "pattern": "^\\d{4}-\\d{2}-\\d{2}$"},
"updated": {"type": "string", "pattern": "^\\d{4}-\\d{2}-\\d{2}$"},
"tags": {"type": "array", "items": {"type": "string"}},
"type": {"type": "string", "enum": ["note", "profile", "recipe", "deployment", "idea", "guide", "index"]},
"aliases": {"type": "array", "items": {"type": "string"}}
}
}scripts/ensure_frontmatter.py
Python script that:
- Adds
createddate if missing (today’s date) - Adds
titlefrom filename if missing - Updates
updateddate on any modification - Validates against JSON Schema
Skipped files: README.md, tags.md
Skipped directories: .obsidian, .git, node_modules, .claude
Usage
Automatic (on commit)
After pre-commit install, hooks run automatically on every git commit:
$ git commit -m "Add new note"
Ensure frontmatter....................................................Passed
mdformat..............................................................Passed
markdownlint-cli2.....................................................Passed
Manual
# Run all hooks on all files
pre-commit run --all-files
# Run specific hook
pre-commit run mdformat --all-files
# Run on specific files
pre-commit run --files notes/my-note.mdDirect tool usage
# Format single file
mdformat path/to/note.md
# Lint single file
markdownlint-cli2 path/to/note.md
# Update frontmatter
python scripts/ensure_frontmatter.py path/to/note.mdWhat Gets Formatted
mdformat changes
- Adds blank lines around headings
- Normalizes list markers
- Converts ordered lists to
1.style - Preserves wikilinks
[[note]] - Preserves horizontal rules as
--- - Preserves YAML frontmatter
Frontmatter auto-fields
Before:
---
tags:
- example
---After:
---
created: '2026-02-17'
tags:
- example
title: My Note Title
updated: '2026-02-17'
---Troubleshooting
”pre-commit not found"
pip install pre-commit"markdownlint-cli2 not found”
npm install -g markdownlint-cli2Hooks not running
pre-commit install --forceSkip hooks temporarily
git commit --no-verify -m "message"Related
- Quartz — uses formatted markdown for publishing
- System Environment — server configuration