obsidian_update_frontmatter
Update frontmatter in Obsidian notes by merging, replacing, or deleting YAML keys. Specify the note path and values to modify.
Instructions
Set, merge, replace, or delete frontmatter keys in a note.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| vault | No | Optional configured vault name. Defaults to the server default vault. | |
| path | Yes | Vault-relative path. Absolute paths and traversal are rejected. | |
| action | Yes | ||
| values | No | YAML frontmatter object. | |
| keys | No |
Implementation Reference
- src/tools.ts:374-393 (registration)Registration of the 'obsidian_update_frontmatter' tool with schema (vault, path, action, values, keys) and handler that reads the note, performs the update/merge/delete, and writes back.
tool( "obsidian_update_frontmatter", "Set, merge, replace, or delete frontmatter keys in a note.", { vault: vaultArg, path: pathArg, action: z.enum(["merge", "replace", "delete"]), values: frontmatterArg, keys: z.array(z.string()).optional(), }, async (args) => { const read = await vaults.readText(args.path, args.vault); let next: string; if (args.action === "delete") next = deleteFrontmatterKeys(read.text, args.keys ?? []); else next = updateFrontmatter(read.text, args.values ?? {}, args.action); await vaults.writeText(read.path, next, args.vault, { overwrite: true }); return { path: read.path, frontmatter: parseFrontmatter(next).data }; }, { destructiveHint: false, idempotentHint: true }, ); - src/tools.ts:384-393 (handler)The handler function for obsidian_update_frontmatter: reads the note, calls deleteFrontmatterKeys or updateFrontmatter based on action, then writes the result back to the vault.
async (args) => { const read = await vaults.readText(args.path, args.vault); let next: string; if (args.action === "delete") next = deleteFrontmatterKeys(read.text, args.keys ?? []); else next = updateFrontmatter(read.text, args.values ?? {}, args.action); await vaults.writeText(read.path, next, args.vault, { overwrite: true }); return { path: read.path, frontmatter: parseFrontmatter(next).data }; }, { destructiveHint: false, idempotentHint: true }, ); - src/frontmatter.ts:47-55 (helper)The updateFrontmatter helper function that merges or replaces frontmatter data in a markdown string and returns the updated markdown.
export function updateFrontmatter( markdown: string, updates: Record<string, unknown>, mode: "merge" | "replace" = "merge", ): string { const parsed = parseFrontmatter(markdown); const data = mode === "replace" ? { ...updates } : { ...parsed.data, ...updates }; return stringifyFrontmatter(data, parsed.body); } - src/frontmatter.ts:36-45 (helper)The stringifyFrontmatter helper that serializes frontmatter data back into YAML frontmatter format (--- delimited).
export function stringifyFrontmatter(data: Record<string, unknown>, body: string): string { const cleaned = Object.fromEntries( Object.entries(data).filter(([, value]) => value !== undefined), ); if (Object.keys(cleaned).length === 0) { return body.startsWith("\n") ? body.slice(1) : body; } const yaml = YAML.stringify(cleaned).trimEnd(); return `---\n${yaml}\n---\n${body.replace(/^\n+/, "")}`; } - src/frontmatter.ts:12-34 (helper)The parseFrontmatter helper that parses YAML frontmatter from markdown text, returning structured data.
export function parseFrontmatter(markdown: string): FrontmatterParse { const normalized = markdown.replace(/\r\n/g, "\n"); if (!normalized.startsWith(`${FRONTMATTER_OPEN}\n`)) { return { data: {}, body: markdown, raw: null, hasFrontmatter: false }; } const end = normalized.indexOf("\n---", FRONTMATTER_OPEN.length + 1); if (end < 0) { return { data: {}, body: markdown, raw: null, hasFrontmatter: false }; } const closeEnd = normalized.indexOf("\n", end + 1); const raw = normalized.slice(FRONTMATTER_OPEN.length + 1, end); const body = closeEnd >= 0 ? normalized.slice(closeEnd + 1) : ""; let data: Record<string, unknown> = {}; try { const parsed = YAML.parse(raw); if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) { data = parsed as Record<string, unknown>; } } catch { data = {}; } return { data, body, raw, hasFrontmatter: true }; }