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:

  1. Ensure frontmatter — adds created, updated, title fields
  2. Format markdown — consistent style via mdformat
  3. 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-cli2

Enable pre-commit hooks

# Install hooks into git
pre-commit install
 
# Run on all files (first time)
pre-commit run --all-files

Configuration 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:

RuleSettingReason
MD007disabledmdformat handles list indentation
MD013disabledmdformat handles line wrapping
MD022disabledmdformat handles heading spacing
MD029style: onemdformat uses 1. for all ordered lists
MD031disabledmdformat handles fence spacing
MD033disabledallow inline HTML
MD035disabledallow any horizontal rule style
MD036disabledallow emphasis as headings
MD040disabledallow code blocks without language
MD041disabledfrontmatter comes before first heading
MD060disabledallow 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:

  1. Adds created date if missing (today’s date)
  2. Adds title from filename if missing
  3. Updates updated date on any modification
  4. 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.md

Direct 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.md

What 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-cli2

Hooks not running

pre-commit install --force

Skip hooks temporarily

git commit --no-verify -m "message"