Frontmatter management CLI for Obsidian vaults. Validate metadata against a schema, auto-fix missing fields, sync markdown to external destinations like Astro content collections, rename fields, and prepend dates to filenames -- all async with parallel threads for great performance on large vaults. Every command comes with dry-run support to preview the operations, your notes are precious, and we value that! We're Obsidian weirdos too.
The tool is still very early, there is much more to come.
The easiest way to install if you're a Python user is via uv, but there's also a compiled binary (via PyInstaller) available on Homebrew for macOS and Linux:
# uv (recommended)
uv tool install rematter
# Homebrew
brew install supermodellabs/tap/rematter# Validate frontmatter against a schema
rematter validate ~/vault/notes
# Auto-fix missing fields with defaults
rematter validate ~/vault/notes --fix
# Sync to an Astro content collection
rematter sync ~/vault/notes --dest ~/site/src/content/notes
# Preview any command without writing
rematter sync ~/vault/notes -nrematter validate <directory> [--schema PATH] [--fix] [--recursive] [--dry-run]Validates every markdown file against the .rematter.yaml schema in the target directory. Report-only by default -- exits 1 on failures. Unrecognized fields always error.
--fix sets defaults for missing properties and reorders keys to match schema order. Combine with --dry-run (-n) to preview what would change.
rematter sync [source] [--dest PATH] [--link-path-prefix PREFIX] [--recursive] [--dry-run]Syncs publishable markdown files to an external directory. The pipeline per file:
- Skip files where
publishis nottrue - Slugify the filename for the destination
- Skip if dest has the same
modifiedvalue (no changes) - Extract type from capitalized Obsidian tags (
#Book->type: book) - Validate against schema
- Resolve creator wikilinks to
{name, slug}objects - Resolve body wikilinks to markdown links (broken links -> plain text)
- Resolve media references and rewrite hero image paths
- Stamp
syncedtimestamp, settitlefrom source filename - Strip
sync: falsefields from destination output - Write dest file, copy referenced media, stamp
syncedback on source
Requires a .rematter.yaml config with at least dest (or pass --dest). CLI flags override config values.
rematter transform <directory> --field OLD --to NEW [--recursive] [--dry-run]Renames a field across all markdown files. Key order is preserved. Files where the target name already exists are skipped with an error.
rematter date-extract <directory> [--field DATE_FIELD] [--recursive] [--dry-run]Reads a date field (default: Date), prepends YYYY-MM-DD - to the filename, and removes the field from frontmatter. Already-prefixed files are skipped. Useful for systems like Notion that export a date field, when you want to pull that out into the filename for Obsidian's filesystem-centric approach.
Each directory can be given a .rematter.yaml that combines sync config and frontmatter schema:
# Sync config
link_path_prefix: /notes
dest: ~/site/src/content/notes/
ignore:
- draft-*
- private/*
media:
source: _media
dest: src/assets
link_prefix: /assets
# Frontmatter schema
properties:
status:
type: string
required: false
enum: [not_started, in_progress, on_hold, done, cancelled]
default: not_started
creators:
type: list
required: false
own:
type: bool
required: false
default: false
sync: false # validated but stripped from dest
hero:
type: string
required: false
requires: [heroAlt] # co-dependency: both or neither
heroAlt:
type: string
required: false
requires: [hero]
created:
type: timestamp
required: true
default: "%Y-%m-%d %H:%M" # strftime format, stamps current time on --fix
sync: false
modified:
type: timestamp
required: true
default: "%Y-%m-%d %H:%M"
publish:
type: bool
required: true
default: false
sync: false| Field | Purpose |
|---|---|
type |
timestamp, bool, string, list, int, float |
required |
Key must exist (null values are valid) |
default |
Value set by --fix when missing. strftime string for timestamps, literal for others, null for explicit null |
enum |
Allowed values (string fields) |
requires |
Companion fields that must also have values (co-dependency) |
sync |
true (default) or false -- field is validated but stripped from dest during sync |
| Field | Purpose |
|---|---|
dest |
Destination directory (overridable via --dest) |
link_path_prefix |
URL prefix for resolved wikilinks (overridable via --link-path-prefix) |
ignore |
Glob patterns for files to skip |
media.source |
Source media directory name (relative to vault dir) |
media.dest |
Destination media directory (relative to dest root) |
media.link_prefix |
URL prefix for media links in dest output |
uv sync --dev # install deps
uv run pytest -v # run tests
uv run rematter --help # run locally