Peter Petschownik380 downloadsAutomatically manages YAML frontmatter fields for all notes. A reliable alternative to Templater formulas for consistent metadata.
MD Butler is an Obsidian plugin that automatically manages YAML frontmatter fields for all your notes. Event-driven, configurable, and a reliable alternative to Templater formulas for consistent metadata.
{{template}} expressions with pipe-chain functions ({{title | upper | replace:a,b}}){{date:YYYY-MM-DD}}, {{now+7d}}{{frontmatter:key}}{{title}}, {{fileName}}, {{fileFolder}} (alias {{folder}}), {{filePath}}, {{oldPath}}, {{oldName}}, {{oldFolder}}upper, lower, trim, replace:X,Y, default:VAL, substr:S,E, date:FMTrequired (default) or if-exists — if-exists only flags a field when the YAML key exists but is empty (useful for fields like LastMoved that are only set under certain circumstances)main.js, manifest.json, and styles.css to VaultFolder/.obsidian/plugins/md-butler/| Command | ID | Description |
|---|---|---|
| Apply Metadata to all Notes | md-butler:apply-all |
Update metadata for all notes respecting scope & filters |
| Force-apply metadata to all notes | md-butler:force-apply |
Overwrite all metadata fields (ignores scope) |
| Full repair | md-butler:full-repair |
Force-apply → cleanup → consistency check |
| Vault Consistency Check | md-butler:check-consistency |
Scan vault for missing fields |
| Clean up old YAML keys | md-butler:cleanup-keys |
Remove orphaned YAML keys from deleted fields |
| Setting | Description |
|---|---|
| Date Format | Moment.js format string for all date values |
| Processing Mode | "New notes only" or "All files" |
| Metadata Fields | Drag-and-drop list of enabled fields with templates, events, and conditions |
| Excluded Folders | Folders to skip (when in exclude mode) |
| Included Folders | Folders to process (when in include mode) |
| Protected YAML Keys | Keys the plugin must never delete or overwrite |
| Field ID | YAML Key | Default Events | Description |
|---|---|---|---|
| fileName | FileName | open, rename, bulk | Current file name without extension |
| filePath | FilePath | open, rename, bulk | Full vault path to the file |
| dateCreated | DateCreated | open, rename, bulk | Date the file was first created |
| noteType | NoteType | open, rename, bulk | Select field: Project, Note (default), Task, Person, Meeting, Reference |
| lastModified | LastModified | modify, rename, bulk | Date the file was last modified |
| lastMoved | LastMoved | rename | Date the file was last renamed/moved (requirement: if-exists) |
| source | Source | open, rename, bulk | Custom field (disabled by default) |
| tags | Tags | modify, bulk | Custom field (disabled by default) |
Fields can be type: "text" (default) or type: "select". Select fields have:
options[] — the allowed values (one per line in settings)defaultValue — set once for new notes if no template is activedefaultValue ?? options[0] for new notesBuilt-in NoteType is a select field. Create your own (Status, Priority, Area, etc.).
Create unlimited custom fields with:
Each field has a requirement mode that controls how the Vault Consistency Check flags it:
| Mode | Behavior |
|---|---|
required (default) |
Field must exist — reported as missing if the YAML key is absent |
if-exists |
Field is only flagged if the YAML key exists but is empty (null, "", or {}) |
Use if-exists for fields that are only set under certain circumstances and should not be flagged when simply absent — e.g. LastMoved (only set when a file has been moved) or optional metadata that is added later.
{{date:YYYY-MM-DD}} → 2026-06-17
{{now+7d}} → 2026-06-24 (relative date)
{{now-1w}} → 2026-06-10 (relative date, supports d/w/M/y)
{{title}} → File name without extension
{{fileName}} → File name with extension
{{fileFolder}} → Parent folder path (alias: {{folder}})
{{filePath}} → Full vault path
{{oldPath}} → Previous path (rename events only)
{{oldFolder}} → Previous folder (rename events only)
{{oldName}} → Previous file name (rename events only)
{{frontmatter:key}} → Value of any frontmatter key
{{title | upper}} → UPPERCASE
{{title | lower}} → lowercase
{{title | trim}} → trimmed
{{title | replace:a,b}} → Replace all 'a' with 'b'
{{title | default:Untitled}} → Fallback if empty
{{title | substr:0,5}} → First 5 characters
{{date:YYYY | upper}} → Chained: format then uppercase
| Type | Operators | Description |
|---|---|---|
| always | — | Always apply (default) |
| frontmatter | exists, equals, matches, contains | Check a frontmatter key value |
| path | equals, matches, contains | Check file path |
| filename | equals, matches, contains | Check file name |
| folder | equals, matches, contains | Check parent folder |
Fields with conditions are auto-removed from frontmatter when their condition no longer matches — the YAML key is deleted on the next event that triggers a write.
# Clone the repo
git clone https://github.com/PPeapps/MD-Butler
cd md-butler
# Install dependencies
npm install
# Development (watch mode)
npm run dev
# Production build
npm run build
# Lint
npm run lint
MIT